You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by jo...@apache.org on 2016/11/20 22:21:17 UTC

zeppelin git commit: ZEPPELIN-1472 - Create new LdapRealm based on Apache Knox LdapRealm: Provides LdapRealm Functionality similar to Apache Knox

Repository: zeppelin
Updated Branches:
  refs/heads/master 85c50a8ab -> 8aad9ea39


ZEPPELIN-1472 - Create new LdapRealm based on Apache Knox LdapRealm: Provides LdapRealm Functionality similar to Apache Knox

### What is this PR for?
ZEPPELIN-1472 - Create new LdapRealm based on Apache Knox LdapRealm: Provides LdapRealm Functionality similar to what Apache Knox provides. This is critical as in large enterprise environments Active Directory Global Catalogs are used for lookup with samAccountName and using a DN Template is not an option as their are multiple OUs. Also searching on "userPrincipalName" is risky in an AD environment since the explicit UPN vs Implicit UPN can be different this is definitely the case with environments using Office 365. And the LDAP userPrincipalName attribute is the explicit UPN which can be defined by the directory administrator to any value and it can be duplicated. SamAccountName is unique per domain and Microsoft states best practice is to not allow duplicate samAccountName's across the forest.

In addition to the above changes I have adjusted and moved the LdapGroupRealm and ActiveDirectoryGroupRealm into the org.apache.zeppelin.realm package structure to make all Realm's consistent.

The LdapRealm class also works with role to group mapping for usage within Zeppelin for notebook authorization.

I have adjusted SecurityUtils to use ClassName vs realmName in determining what to use as you may have companies that decide to use their own custom realmname in shiro.ini and may not realize you cannot so using className is much safer.

Example - SecurityUtils
        String name = realm.getClass().getName();
        if (name.equals("org.apache.shiro.realm.text.IniRealm")) {
          allRoles = ((IniRealm) realm).getIni().get("roles");
          break;
        } else if (name.equals("org.apache.zeppelin.realm.LdapRealm")) {
          allRoles = ((LdapRealm) realm).getListRoles();
          break;
        }

Example - SecurityRestApi:
          String name = realm.getClass().getName();
          if (LOG.isDebugEnabled()) {
            LOG.debug("RealmClass.getName: " + name);
          }
          if (name.equals("org.apache.shiro.realm.text.IniRealm")) {
            usersList.addAll(getUserListObj.getUserList((IniRealm) realm));
            rolesList.addAll(getUserListObj.getRolesList((IniRealm) realm));
          } else if (name.equals("org.apache.zeppelin.realm.LdapGroupRealm")) {
            usersList.addAll(getUserListObj.getUserList((JndiLdapRealm) realm, searchText));
          } else if (name.equals("org.apache.zeppelin.realm.LdapRealm")) {
            usersList.addAll(getUserListObj.getUserList((LdapRealm) realm, searchText));
            rolesList.addAll(getUserListObj.getRolesList((LdapRealm) realm));
          } else if (name.equals("org.apache.zeppelin.realm.ActiveDirectoryGroupRealm")) {
            usersList.addAll(getUserListObj.getUserList((ActiveDirectoryGroupRealm) realm,
                searchText));
          } else if (name.equals("org.apache.shiro.realm.jdbc.JdbcRealm")) {
            usersList.addAll(getUserListObj.getUserList((JdbcRealm) realm));
          }

Please see feedback from previous PRs related to this JIRA:
https://github.com/apache/zeppelin/pull/1513

### What type of PR is it?
[Improvement]

### Todos
* [ ] - Task

### What is the Jira issue?
https://issues.apache.org/jira/browse/ZEPPELIN-1472

### How should this be tested?
Update shiro.ini to use configuration similar to below:
# Sample LDAP configuration, for user Authentication, currently tested for single Realm
[main]
ldapADGCRealm = org.apache.zeppelin.realm.LdapRealm
ldapADGCRealm.contextFactory.systemUsername = CN=hdplookup,OU=hadoop,DC=hdpusr,DC=senia,DC=org
ldapADGCRealm.contextFactory.systemPassword = ldapBindPassword
ldapADGCRealm.searchBase = dc=hdpusr,dc=senia,dc=org
ldapADGCRealm.userSearchBase = dc=hdpusr,dc=senia,dc=org
ldapADGCRealm.groupSearchBase = dc=hdpusr,dc=senia,dc=org
ldapADGCRealm.authorizationEnabled = true
ldapADGCRealm.contextFactory.url = ldap://seniadc1.hdpusr.senia.org:3268
ldapADGCRealm.userSearchAttributeName = sAMAccountName
ldapADGCRealm.contextFactory.authenticationMechanism = simple
ldapADGCRealm.groupObjectClass = group
ldapADGCRealm.memberAttribute = member
ldapADGCRealm.rolesByGroup = hdpeng: admin, \
 hadoopusers: user

securityManager.realms = $ldapADGCRealm

sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager

### If caching of user is required then uncomment below lines
#cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
#securityManager.cacheManager = $cacheManager

securityManager.sessionManager = $sessionManager
# 86,400,000 milliseconds = 24 hour
securityManager.sessionManager.globalSessionTimeout = 86400000
shiro.loginUrl = /api/login

[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
user = *

[urls]
# anon means the access is anonymous.
# authcBasic means Basic Auth Security
# authc means Form based Auth Security
# To enfore security, comment the line below and uncomment the next one
#/api/version = anon
#/** = anon
/api/interpreter/** = authc, roles[admin]
/api/configurations/** = authc, roles[admin]
/api/credential/** = authc, roles[admin]
/api/login = authc
/api/login/logout = authc
/api/security/ticket = authc
/** = authc, roles[admin, user]

### Screenshots (if appropriate)

### Questions:
* Does the licenses files need update? n
* Is there breaking changes for older versions? n
* Does this needs documentation? y

merge latest commits

Author: gss2002 <gr...@senia.org>
Author: gss2002 <gs...@apache.org>

Closes #1614 from gss2002/ZEPPELIN-1472 and squashes the following commits:

d6a7cea [gss2002] ZEPPELIN-1472 - LdapRealm Additions based on Knox LdapRealm and support of using roles with LdapRealms. Also adjusted to use className and not actual name of the realm in shiro.ini. As using realmName in code could cause problems for people who want to use alternate names. Also migrated the LdapGroupRealm and ActiveDirectoryRealm to org.apache.zeppelin.realm packages per a recommendation.
1702cc5 [gss2002] Merge pull request #1 from apache/master


Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/8aad9ea3
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/8aad9ea3
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/8aad9ea3

Branch: refs/heads/master
Commit: 8aad9ea392f0f98ac830163f32f37e5f6d6ed5cc
Parents: 85c50a8
Author: gss2002 <gr...@senia.org>
Authored: Tue Nov 8 13:14:46 2016 -0500
Committer: Jongyoul Lee <jo...@apache.org>
Committed: Sun Nov 20 23:21:04 2016 +0100

----------------------------------------------------------------------
 .../realm/ActiveDirectoryGroupRealm.java        | 330 ++++++++
 .../apache/zeppelin/realm/LdapGroupRealm.java   |  94 +++
 .../org/apache/zeppelin/realm/LdapRealm.java    | 842 +++++++++++++++++++
 .../org/apache/zeppelin/rest/GetUserList.java   |  71 +-
 .../apache/zeppelin/rest/SecurityRestApi.java   |  19 +-
 .../server/ActiveDirectoryGroupRealm.java       | 330 --------
 .../apache/zeppelin/server/LdapGroupRealm.java  |  94 ---
 .../apache/zeppelin/utils/SecurityUtils.java    |  13 +-
 8 files changed, 1359 insertions(+), 434 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/8aad9ea3/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ActiveDirectoryGroupRealm.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ActiveDirectoryGroupRealm.java b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ActiveDirectoryGroupRealm.java
new file mode 100644
index 0000000..d89719c
--- /dev/null
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ActiveDirectoryGroupRealm.java
@@ -0,0 +1,330 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zeppelin.realm;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.alias.CredentialProvider;
+import org.apache.hadoop.security.alias.CredentialProviderFactory;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.Realm;
+import org.apache.shiro.realm.ldap.AbstractLdapRealm;
+import org.apache.shiro.realm.ldap.DefaultLdapContextFactory;
+import org.apache.shiro.realm.ldap.LdapContextFactory;
+import org.apache.shiro.realm.ldap.LdapUtils;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapContext;
+import java.util.*;
+
+
+/**
+ * A {@link Realm} that authenticates with an active directory LDAP
+ * server to determine the roles for a particular user.  This implementation
+ * queries for the user's groups and then maps the group names to roles using the
+ * {@link #groupRolesMap}.
+ *
+ * @since 0.1
+ */
+public class ActiveDirectoryGroupRealm extends AbstractLdapRealm {
+
+  private static final Logger log = LoggerFactory.getLogger(ActiveDirectoryGroupRealm.class);
+
+  private static final String ROLE_NAMES_DELIMETER = ",";
+
+  String KEYSTORE_PASS = "activeDirectoryRealm.systemPassword";
+  private String hadoopSecurityCredentialPath;
+
+  public void setHadoopSecurityCredentialPath(String hadoopSecurityCredentialPath) {
+    this.hadoopSecurityCredentialPath = hadoopSecurityCredentialPath;
+  }
+
+    /*--------------------------------------------
+    |    I N S T A N C E   V A R I A B L E S    |
+    ============================================*/
+
+  /**
+   * Mapping from fully qualified active directory
+   * group names (e.g. CN=Group,OU=Company,DC=MyDomain,DC=local)
+   * as returned by the active directory LDAP server to role names.
+   */
+  private Map<String, String> groupRolesMap;
+
+    /*--------------------------------------------
+    |         C O N S T R U C T O R S           |
+    ============================================*/
+
+  public void setGroupRolesMap(Map<String, String> groupRolesMap) {
+    this.groupRolesMap = groupRolesMap;
+  }
+
+    /*--------------------------------------------
+    |               M E T H O D S               |
+    ============================================*/
+
+  LdapContextFactory ldapContextFactory;
+
+  public LdapContextFactory getLdapContextFactory() {
+    if (this.ldapContextFactory == null) {
+      if (log.isDebugEnabled()) {
+        log.debug("No LdapContextFactory specified - creating a default instance.");
+      }
+
+      DefaultLdapContextFactory defaultFactory = new DefaultLdapContextFactory();
+      defaultFactory.setPrincipalSuffix(this.principalSuffix);
+      defaultFactory.setSearchBase(this.searchBase);
+      defaultFactory.setUrl(this.url);
+      defaultFactory.setSystemUsername(this.systemUsername);
+      defaultFactory.setSystemPassword(getSystemPassword());
+      this.ldapContextFactory = defaultFactory;
+    }
+
+    return this.ldapContextFactory;
+  }
+
+  private String getSystemPassword() {
+    String password = "";
+    if (StringUtils.isEmpty(this.hadoopSecurityCredentialPath)) {
+      password = this.systemPassword;
+    } else {
+      try {
+        Configuration configuration = new Configuration();
+        configuration.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH,
+          this.hadoopSecurityCredentialPath);
+        CredentialProvider provider =
+          CredentialProviderFactory.getProviders(configuration).get(0);
+        CredentialProvider.CredentialEntry credEntry = provider.getCredentialEntry(
+            KEYSTORE_PASS);
+        if (credEntry != null) {
+          password = new String(credEntry.getCredential());
+        }
+      } catch (Exception e) {
+
+      }
+    }
+    return password;
+  }
+
+  /**
+   * Builds an {@link AuthenticationInfo} object by querying the active directory LDAP context for
+   * the specified username.  This method binds to the LDAP server using the provided username
+   * and password - which if successful, indicates that the password is correct.
+   * <p/>
+   * This method can be overridden by subclasses to query the LDAP server in a more complex way.
+   *
+   * @param token              the authentication token provided by the user.
+   * @param ldapContextFactory the factory used to build connections to the LDAP server.
+   * @return an {@link AuthenticationInfo} instance containing information retrieved from LDAP.
+   * @throws NamingException if any LDAP errors occur during the search.
+   */
+  protected AuthenticationInfo queryForAuthenticationInfo(
+      AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException {
+
+    UsernamePasswordToken upToken = (UsernamePasswordToken) token;
+
+    // Binds using the username and password provided by the user.
+    LdapContext ctx = null;
+    try {
+      String userPrincipalName = upToken.getUsername();
+      if (userPrincipalName == null) {
+        return null;
+      }
+      if (this.principalSuffix != null) {
+        userPrincipalName = upToken.getUsername() + this.principalSuffix;
+      }
+      ctx = ldapContextFactory.getLdapContext(
+          userPrincipalName, upToken.getPassword());
+    } finally {
+      LdapUtils.closeContext(ctx);
+    }
+
+    return buildAuthenticationInfo(upToken.getUsername(), upToken.getPassword());
+  }
+
+  protected AuthenticationInfo buildAuthenticationInfo(String username, char[] password) {
+    return new SimpleAuthenticationInfo(username, password, getName());
+  }
+
+
+  /**
+   * Builds an {@link org.apache.shiro.authz.AuthorizationInfo} object by querying the active
+   * directory LDAP context for the groups that a user is a member of.  The groups are then
+   * translated to role names by using the configured {@link #groupRolesMap}.
+   * <p/>
+   * This implementation expects the <tt>principal</tt> argument to be a String username.
+   * <p/>
+   * Subclasses can override this method to determine authorization data (roles, permissions, etc)
+   * in a more complex way.  Note that this default implementation does not support permissions,
+   * only roles.
+   *
+   * @param principals         the principal of the Subject whose account is being retrieved.
+   * @param ldapContextFactory the factory used to create LDAP connections.
+   * @return the AuthorizationInfo for the given Subject principal.
+   * @throws NamingException if an error occurs when searching the LDAP server.
+   */
+  protected AuthorizationInfo queryForAuthorizationInfo(
+      PrincipalCollection principals,
+      LdapContextFactory ldapContextFactory) throws NamingException {
+
+    String username = (String) getAvailablePrincipal(principals);
+
+    // Perform context search
+    LdapContext ldapContext = ldapContextFactory.getSystemLdapContext();
+
+    Set<String> roleNames;
+
+    try {
+      roleNames = getRoleNamesForUser(username, ldapContext);
+    } finally {
+      LdapUtils.closeContext(ldapContext);
+    }
+
+    return buildAuthorizationInfo(roleNames);
+  }
+
+  protected AuthorizationInfo buildAuthorizationInfo(Set<String> roleNames) {
+    return new SimpleAuthorizationInfo(roleNames);
+  }
+
+  public List<String> searchForUserName(String containString, LdapContext ldapContext) throws
+      NamingException {
+    List<String> userNameList = new ArrayList<>();
+
+    SearchControls searchCtls = new SearchControls();
+    searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+    String searchFilter = "(&(objectClass=*)(userPrincipalName=*" + containString + "*))";
+    Object[] searchArguments = new Object[]{containString};
+
+    NamingEnumeration answer = ldapContext.search(searchBase, searchFilter, searchArguments,
+        searchCtls);
+
+    while (answer.hasMoreElements()) {
+      SearchResult sr = (SearchResult) answer.next();
+
+      if (log.isDebugEnabled()) {
+        log.debug("Retrieving userprincipalname names for user [" + sr.getName() + "]");
+      }
+
+      Attributes attrs = sr.getAttributes();
+      if (attrs != null) {
+        NamingEnumeration ae = attrs.getAll();
+        while (ae.hasMore()) {
+          Attribute attr = (Attribute) ae.next();
+          if (attr.getID().toLowerCase().equals("cn")) {
+            userNameList.addAll(LdapUtils.getAllAttributeValues(attr));
+          }
+        }
+      }
+    }
+    return userNameList;
+  }
+
+  private Set<String> getRoleNamesForUser(String username, LdapContext ldapContext)
+      throws NamingException {
+    Set<String> roleNames = new LinkedHashSet<>();
+
+    SearchControls searchCtls = new SearchControls();
+    searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+    String userPrincipalName = username;
+    if (principalSuffix != null) {
+      userPrincipalName += principalSuffix;
+    }
+
+    String searchFilter = "(&(objectClass=*)(userPrincipalName=" + userPrincipalName + "))";
+    Object[] searchArguments = new Object[]{userPrincipalName};
+
+    NamingEnumeration answer = ldapContext.search(searchBase, searchFilter, searchArguments,
+        searchCtls);
+
+    while (answer.hasMoreElements()) {
+      SearchResult sr = (SearchResult) answer.next();
+
+      if (log.isDebugEnabled()) {
+        log.debug("Retrieving group names for user [" + sr.getName() + "]");
+      }
+
+      Attributes attrs = sr.getAttributes();
+
+      if (attrs != null) {
+        NamingEnumeration ae = attrs.getAll();
+        while (ae.hasMore()) {
+          Attribute attr = (Attribute) ae.next();
+
+          if (attr.getID().equals("memberOf")) {
+
+            Collection<String> groupNames = LdapUtils.getAllAttributeValues(attr);
+
+            if (log.isDebugEnabled()) {
+              log.debug("Groups found for user [" + username + "]: " + groupNames);
+            }
+
+            Collection<String> rolesForGroups = getRoleNamesForGroups(groupNames);
+            roleNames.addAll(rolesForGroups);
+          }
+        }
+      }
+    }
+    return roleNames;
+  }
+
+  /**
+   * This method is called by the default implementation to translate Active Directory group names
+   * to role names.  This implementation uses the {@link #groupRolesMap} to map group names to role
+   * names.
+   *
+   * @param groupNames the group names that apply to the current user.
+   * @return a collection of roles that are implied by the given role names.
+   */
+  protected Collection<String> getRoleNamesForGroups(Collection<String> groupNames) {
+    Set<String> roleNames = new HashSet<>(groupNames.size());
+
+    if (groupRolesMap != null) {
+      for (String groupName : groupNames) {
+        String strRoleNames = groupRolesMap.get(groupName);
+        if (strRoleNames != null) {
+          for (String roleName : strRoleNames.split(ROLE_NAMES_DELIMETER)) {
+
+            if (log.isDebugEnabled()) {
+              log.debug("User is member of group [" + groupName + "] so adding role [" +
+                  roleName + "]");
+            }
+
+            roleNames.add(roleName);
+
+          }
+        }
+      }
+    }
+    return roleNames;
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/8aad9ea3/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapGroupRealm.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapGroupRealm.java b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapGroupRealm.java
new file mode 100644
index 0000000..4133ce0
--- /dev/null
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapGroupRealm.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zeppelin.realm;
+
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.ldap.JndiLdapRealm;
+import org.apache.shiro.realm.ldap.LdapContextFactory;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapContext;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+
+/**
+ * Created for org.apache.zeppelin.server on 09/06/16.
+ */
+public class LdapGroupRealm extends JndiLdapRealm {
+  private static final Logger LOG = LoggerFactory.getLogger(LdapGroupRealm.class);
+
+  public AuthorizationInfo queryForAuthorizationInfo(
+      PrincipalCollection principals,
+      LdapContextFactory ldapContextFactory) throws NamingException {
+    String username = (String) getAvailablePrincipal(principals);
+    LdapContext ldapContext = ldapContextFactory.getSystemLdapContext();
+    Set<String> roleNames = getRoleNamesForUser(username, ldapContext, getUserDnTemplate());
+    return new SimpleAuthorizationInfo(roleNames);
+  }
+
+
+  public Set<String> getRoleNamesForUser(String username,
+                                         LdapContext ldapContext,
+                                         String userDnTemplate) throws NamingException {
+    try {
+      Set<String> roleNames = new LinkedHashSet<>();
+
+      SearchControls searchCtls = new SearchControls();
+      searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+      String searchFilter = "(&(objectClass=groupOfNames)(member=" + userDnTemplate + "))";
+      Object[] searchArguments = new Object[]{username};
+
+      NamingEnumeration<?> answer = ldapContext.search(
+          String.valueOf(ldapContext.getEnvironment().get("ldap.searchBase")),
+          searchFilter,
+          searchArguments,
+          searchCtls);
+
+      while (answer.hasMoreElements()) {
+        SearchResult sr = (SearchResult) answer.next();
+        Attributes attrs = sr.getAttributes();
+        if (attrs != null) {
+          NamingEnumeration<?> ae = attrs.getAll();
+          while (ae.hasMore()) {
+            Attribute attr = (Attribute) ae.next();
+            if (attr.getID().equals("cn")) {
+              roleNames.add((String) attr.get());
+            }
+          }
+        }
+      }
+      return roleNames;
+
+    } catch (Exception e) {
+      LOG.error("Error", e);
+    }
+
+    return new HashSet<>();
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/8aad9ea3/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapRealm.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapRealm.java b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapRealm.java
new file mode 100644
index 0000000..34dcaa4
--- /dev/null
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapRealm.java
@@ -0,0 +1,842 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.zeppelin.realm;
+
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.crypto.hash.DefaultHashService;
+import org.apache.shiro.crypto.hash.Hash;
+import org.apache.shiro.crypto.hash.HashRequest;
+import org.apache.shiro.crypto.hash.HashService;
+import org.apache.shiro.realm.ldap.JndiLdapRealm;
+import org.apache.shiro.realm.ldap.LdapContextFactory;
+import org.apache.shiro.realm.ldap.LdapUtils;
+import org.apache.shiro.subject.MutablePrincipalCollection;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.util.StringUtils;
+import org.mortbay.log.Log;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.naming.AuthenticationException;
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.PartialResultException;
+import javax.naming.SizeLimitExceededException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.Control;
+import javax.naming.ldap.LdapContext;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.PagedResultsControl;
+
+
+/**
+ * Implementation of {@link org.apache.shiro.realm.ldap.JndiLdapRealm} that also
+ * returns each user's groups. This implementation is heavily based on
+ * org.apache.isis.security.shiro.IsisLdapRealm.
+ * 
+ * <p>This implementation saves looked up ldap groups in Shiro Session to make them
+ * easy to be looked up outside of this object
+ * 
+ * <p>Sample config for <tt>shiro.ini</tt>:
+ * 
+ * <p>[main] 
+ * ldapRealm=org.apache.zeppelin.realm.LdapRealm
+ * ldapRealm.contextFactory=$ldapGroupContextFactory
+ * ldapRealm.contextFactory.authenticationMechanism=simple
+ * ldapRealm.contextFactory.url=ldap://localhost:33389
+ * ldapRealm.userDnTemplate=uid={0},ou=people,dc=hadoop,dc=apache,dc=org
+ * # Ability to set ldap paging Size if needed default is 100
+ * ldapRealm.pagingSize = 200
+ * ldapRealm.authorizationEnabled=true
+ * ldapRealm.contextFactory.systemAuthenticationMechanism=simple
+ * ldapRealm.searchBase=dc=hadoop,dc=apache,dc=org
+ * ldapRealm.userSearchBase = dc=hadoop,dc=apache,dc=org
+ * ldapRealm.groupSearchBase = ou=groups,dc=hadoop,dc=apache,dc=org
+ * ldapRealm.groupObjectClass=groupofnames
+ * # Allow userSearchAttribute to be customized
+ * ldapRealm.userSearchAttributeName = sAMAccountName
+ * ldapRealm.memberAttribute=member
+ * # force usernames returned from ldap to lowercase useful for AD
+ * ldapRealm.userLowerCase = true 
+ * # ability set searchScopes subtree (default), one, base
+ * ldapRealm.userSearchScope = subtree;
+ * ldapRealm.groupSearchScope = subtree;
+ * ldapRealm.memberAttributeValueTemplate=cn={0},ou=people,dc=hadoop,dc=apache,
+ * dc=org
+ * ldapRealm.contextFactory.systemUsername=uid=guest,ou=people,dc=hadoop,dc=
+ * apache,dc=org 
+ * ldapRealm.contextFactory.systemPassword=S{ALIAS=ldcSystemPassword} [urls]
+ * **=authcBasic
+ *
+ * <p># optional mapping from physical groups to logical application roles
+ * ldapRealm.rolesByGroup = \ LDN_USERS: user_role,\ NYK_USERS: user_role,\
+ * HKG_USERS: user_role,\ GLOBAL_ADMIN: admin_role,\ DEMOS: self-install_role
+ * 
+ * <p>ldapRealm.permissionsByRole=\ user_role = *:ToDoItemsJdo:*:*,\
+ * *:ToDoItem:*:*; \ self-install_role = *:ToDoItemsFixturesService:install:* ;
+ * \ admin_role = *
+ * 
+ * <p>securityManager.realms = $ldapRealm
+ * 
+ */
+public class LdapRealm extends JndiLdapRealm {
+
+  private static final SearchControls SUBTREE_SCOPE = new SearchControls();
+  private static final SearchControls ONELEVEL_SCOPE = new SearchControls();
+  private static final SearchControls OBJECT_SCOPE = new SearchControls();
+  private static final String SUBJECT_USER_ROLES = "subject.userRoles";
+  private static final String SUBJECT_USER_GROUPS = "subject.userGroups";
+  private static final String MEMBER_URL = "memberUrl";
+  private static final String POSIX_GROUP = "posixGroup";
+
+  private static Pattern TEMPLATE_PATTERN = Pattern.compile("\\{(\\d+?)\\}");
+  private static String DEFAULT_PRINCIPAL_REGEX = "(.*)";
+  private static final String MEMBER_SUBSTITUTION_TOKEN = "{0}";
+  private static final String HASHING_ALGORITHM = "SHA-1";
+  private static final Logger log = LoggerFactory.getLogger(LdapRealm.class);
+
+
+  static {
+    SUBTREE_SCOPE.setSearchScope(SearchControls.SUBTREE_SCOPE);
+    ONELEVEL_SCOPE.setSearchScope(SearchControls.ONELEVEL_SCOPE);
+    OBJECT_SCOPE.setSearchScope(SearchControls.OBJECT_SCOPE);
+  }
+
+  private String searchBase;
+  private String userSearchBase;
+  private int pagingSize = 100;
+  private boolean userLowerCase;
+  private String principalRegex = DEFAULT_PRINCIPAL_REGEX;
+  private Pattern principalPattern = Pattern.compile(DEFAULT_PRINCIPAL_REGEX);
+  private String userDnTemplate = "{0}";
+  private String userSearchFilter = null;
+  private String userSearchAttributeTemplate = "{0}";
+  private String userSearchScope = "subtree";
+  private String groupSearchScope = "subtree";
+
+
+  private String groupSearchBase;
+
+  private String groupObjectClass = "groupOfNames";
+
+  // typical value: member, uniqueMember, meberUrl
+  private String memberAttribute = "member";
+
+  private String groupIdAttribute = "cn";
+
+  private String memberAttributeValuePrefix = "uid={0}";
+  private String memberAttributeValueSuffix = "";
+
+  private final Map<String, String> rolesByGroup = new LinkedHashMap<String, String>();
+  private final Map<String, List<String>> permissionsByRole = 
+      new LinkedHashMap<String, List<String>>();
+
+  private boolean authorizationEnabled;
+
+  private String userSearchAttributeName;
+  private String userObjectClass = "person";
+
+  private HashService hashService = new DefaultHashService();
+
+  public LdapRealm() {
+    HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(HASHING_ALGORITHM);
+    setCredentialsMatcher(credentialsMatcher);
+  }
+
+  @Override
+
+  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
+      throws org.apache.shiro.authc.AuthenticationException {
+    try {
+      return super.doGetAuthenticationInfo(token);
+    } catch (org.apache.shiro.authc.AuthenticationException ae) {
+      throw ae;
+    }
+  }
+
+  /**
+  * Get groups from LDAP.
+  * 
+  * @param principals
+  *            the principals of the Subject whose AuthenticationInfo should
+  *            be queried from the LDAP server.
+  * @param ldapContextFactory
+  *            factory used to retrieve LDAP connections.
+  * @return an {@link AuthorizationInfo} instance containing information
+  *         retrieved from the LDAP server.
+  * @throws NamingException
+  *             if any LDAP errors occur during the search.
+  */
+  @Override
+  protected AuthorizationInfo queryForAuthorizationInfo(final PrincipalCollection principals,
+      final LdapContextFactory ldapContextFactory) throws NamingException {
+    if (!isAuthorizationEnabled()) {
+      return null;
+    }
+    final Set<String> roleNames = getRoles(principals, ldapContextFactory);
+    if (log.isDebugEnabled()) {
+      log.debug("RolesNames Authorization: " + roleNames);
+    }
+    SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(roleNames);
+    Set<String> stringPermissions = permsFor(roleNames);
+    simpleAuthorizationInfo.setStringPermissions(stringPermissions);
+    return simpleAuthorizationInfo;
+  }
+
+  private Set<String> getRoles(PrincipalCollection principals, 
+        final LdapContextFactory ldapContextFactory)
+      throws NamingException {
+    final String username = (String) getAvailablePrincipal(principals);
+
+    LdapContext systemLdapCtx = null;
+    try {
+      systemLdapCtx = ldapContextFactory.getSystemLdapContext();
+      return rolesFor(principals, username, systemLdapCtx, ldapContextFactory);
+    } catch (AuthenticationException ae) {
+      ae.printStackTrace();
+      return Collections.emptySet();
+    } finally {
+      LdapUtils.closeContext(systemLdapCtx);
+    }
+  }
+
+  private Set<String> rolesFor(PrincipalCollection principals, 
+        String userNameIn, final LdapContext ldapCtx,
+      final LdapContextFactory ldapContextFactory) throws NamingException {
+    final Set<String> roleNames = new HashSet<>();
+    final Set<String> groupNames = new HashSet<>();
+    final String userName;
+    if (getUserLowerCase()) {
+      log.debug("userLowerCase true");
+      userName = userNameIn.toLowerCase();
+    } else {
+      userName = userNameIn;
+    }
+    
+    String userDn;
+    if (userSearchAttributeName == null || userSearchAttributeName.isEmpty()) {
+      // memberAttributeValuePrefix and memberAttributeValueSuffix 
+      // were computed from memberAttributeValueTemplate
+      userDn = memberAttributeValuePrefix + userName + memberAttributeValueSuffix;      
+    } else {
+      userDn = getUserDn(userName);
+    }
+
+    // Activate paged results
+    int pageSize = getPagingSize();
+    if (log.isDebugEnabled()) {
+      log.debug("Ldap PagingSize: " + pageSize);
+    }
+    int numResults = 0;
+    byte[] cookie = null;
+    try {
+      ldapCtx.addToEnvironment(Context.REFERRAL, "ignore");
+        
+      ldapCtx.setRequestControls(new Control[]{new PagedResultsControl(pageSize, 
+            Control.NONCRITICAL)});
+        
+      do {
+        // ldapsearch -h localhost -p 33389 -D
+        // uid=guest,ou=people,dc=hadoop,dc=apache,dc=org -w guest-password
+        // -b dc=hadoop,dc=apache,dc=org -s sub '(objectclass=*)'
+        NamingEnumeration<SearchResult> searchResultEnum = null;
+        SearchControls searchControls = getGroupSearchControls();
+        try {
+          searchResultEnum = ldapCtx.search(
+                getGroupSearchBase(),
+                "objectClass=" + groupObjectClass,
+                searchControls);
+
+          while (searchResultEnum != null && searchResultEnum.hasMore()) { 
+            // searchResults contains all the groups in search scope
+            numResults++;
+            final SearchResult group = searchResultEnum.next();
+            addRoleIfMember(userDn, group, roleNames, groupNames, ldapContextFactory);
+          }
+        } catch (PartialResultException e) {
+          log.debug("Ignoring PartitalResultException");
+        } finally {
+          if (searchResultEnum != null) {
+            searchResultEnum.close();
+          }
+        }
+        // Re-activate paged results
+        ldapCtx.setRequestControls(new Control[]{new PagedResultsControl(pageSize, 
+              cookie, Control.CRITICAL)});
+      } while (cookie != null);
+    } catch (SizeLimitExceededException e) {
+      log.info("Only retrieved first " + numResults + 
+            " groups due to SizeLimitExceededException.");
+    } catch (IOException e) {
+      log.error("Unabled to setup paged results");
+    }
+    // save role names and group names in session so that they can be
+    // easily looked up outside of this object
+    SecurityUtils.getSubject().getSession().setAttribute(SUBJECT_USER_ROLES, roleNames);
+    SecurityUtils.getSubject().getSession().setAttribute(SUBJECT_USER_GROUPS, groupNames);
+    if (!groupNames.isEmpty() && (principals instanceof MutablePrincipalCollection)) {
+      ((MutablePrincipalCollection) principals).addAll(groupNames, getName());
+    }
+    if (log.isDebugEnabled()) {
+      log.debug("User RoleNames: " + userName + "::" + roleNames);  
+    }
+    return roleNames;
+  }
+
+  private void addRoleIfMember(final String userDn, final SearchResult group, 
+        final Set<String> roleNames, final Set<String> groupNames, 
+        final LdapContextFactory ldapContextFactory) throws NamingException {
+
+    NamingEnumeration<? extends Attribute> attributeEnum = null;
+    NamingEnumeration<?> ne = null;
+    try {
+      LdapName userLdapDn = new LdapName(userDn);
+      Attribute attribute = group.getAttributes().get(getGroupIdAttribute());
+      String groupName = attribute.get().toString();
+
+      attributeEnum = group.getAttributes().getAll();
+      while (attributeEnum.hasMore()) {
+        final Attribute attr = attributeEnum.next();
+        if (!memberAttribute.equalsIgnoreCase(attr.getID())) {
+          continue;
+        }
+        ne = attr.getAll();
+        while (ne.hasMore()) {
+          String attrValue = ne.next().toString();
+          if (memberAttribute.equalsIgnoreCase(MEMBER_URL)) {
+            boolean dynamicGroupMember = isUserMemberOfDynamicGroup(userLdapDn, attrValue,
+                  ldapContextFactory);
+            if (dynamicGroupMember) {
+              groupNames.add(groupName);
+              String roleName = roleNameFor(groupName);
+              if (roleName != null) {
+                roleNames.add(roleName);
+              } else {
+                roleNames.add(groupName);
+              }
+            }
+          } else {
+            if (groupObjectClass.equalsIgnoreCase(POSIX_GROUP)) {
+              attrValue = memberAttributeValuePrefix + attrValue + memberAttributeValueSuffix;
+            }
+            if (userLdapDn.equals(new LdapName(attrValue))) {
+              groupNames.add(groupName);
+              String roleName = roleNameFor(groupName);
+              if (roleName != null) {
+                roleNames.add(roleName);
+              } else {
+                roleNames.add(groupName);
+              }
+              break;
+            }
+          }
+        }
+      }
+    } finally {
+      try {
+        if (attributeEnum != null) {
+          attributeEnum.close();
+        }
+      } finally {
+        if (ne != null) {
+          ne.close();
+        }
+      }
+    }
+  }
+  
+  public Map<String, String> getListRoles() {
+    Map<String, String> groupToRoles = getRolesByGroup();
+    Map<String, String> roles = new HashMap<>();
+    for (Map.Entry<String, String> entry : groupToRoles.entrySet()){
+      roles.put(entry.getValue(), entry.getKey());
+    }
+    return roles;
+  }
+
+  private String roleNameFor(String groupName) {
+    return !rolesByGroup.isEmpty() ? rolesByGroup.get(groupName) : groupName;
+  }
+
+  private Set<String> permsFor(Set<String> roleNames) {
+    Set<String> perms = new LinkedHashSet<String>(); // preserve order
+    for (String role : roleNames) {
+      List<String> permsForRole = permissionsByRole.get(role);
+      if (log.isDebugEnabled()) {
+        log.debug("PermsForRole: " + role);
+        log.debug("PermByRole: " + permsForRole);
+      }
+      if (permsForRole != null) {
+        perms.addAll(permsForRole);
+      }
+    }
+    return perms;
+  }
+
+  public String getSearchBase() {
+    return searchBase;
+  }
+
+  public void setSearchBase(String searchBase) {
+    this.searchBase = searchBase;
+  }
+
+  public String getUserSearchBase() {
+    return (userSearchBase != null && !userSearchBase.isEmpty()) ? userSearchBase : searchBase;
+  }
+
+  public void setUserSearchBase(String userSearchBase) {
+    this.userSearchBase = userSearchBase;
+  }
+
+  public int getPagingSize() {
+    return pagingSize;
+  }
+  
+  public void setPagingSize(int pagingSize) {
+    this.pagingSize = pagingSize;
+  }
+
+  public String getGroupSearchBase() {
+    return (groupSearchBase != null && !groupSearchBase.isEmpty()) ? groupSearchBase : searchBase;
+  }
+
+  public void setGroupSearchBase(String groupSearchBase) {
+    this.groupSearchBase = groupSearchBase;
+  }
+
+  public String getGroupObjectClass() {
+    return groupObjectClass;
+  }
+
+  public void setGroupObjectClass(String groupObjectClassAttribute) {
+    this.groupObjectClass = groupObjectClassAttribute;
+  }
+
+  public String getMemberAttribute() {
+    return memberAttribute;
+  }
+
+  public void setMemberAttribute(String memberAttribute) {
+    this.memberAttribute = memberAttribute;
+  }
+
+  public String getGroupIdAttribute() {
+    return groupIdAttribute;
+  }
+
+  public void setGroupIdAttribute(String groupIdAttribute) {
+    this.groupIdAttribute = groupIdAttribute;
+  }
+  
+  /**
+  * Set Member Attribute Template for LDAP.
+  * 
+  * @param template
+  *            DN template to be used to query ldap.
+  * @throws IllegalArgumentException
+  *             if template is empty or null.
+  */
+  public void setMemberAttributeValueTemplate(String template) {
+    if (!StringUtils.hasText(template)) {
+      String msg = "User DN template cannot be null or empty.";
+      throw new IllegalArgumentException(msg);
+    }
+    int index = template.indexOf(MEMBER_SUBSTITUTION_TOKEN);
+    if (index < 0) {
+      String msg = "Member attribute value template must contain the '" + MEMBER_SUBSTITUTION_TOKEN
+            + "' replacement token to understand how to " + "parse the group members.";
+      throw new IllegalArgumentException(msg);
+    }
+    String prefix = template.substring(0, index);
+    String suffix = template.substring(prefix.length() + MEMBER_SUBSTITUTION_TOKEN.length());
+    this.memberAttributeValuePrefix = prefix;
+    this.memberAttributeValueSuffix = suffix;
+  }
+
+  public void setRolesByGroup(Map<String, String> rolesByGroup) {
+    this.rolesByGroup.putAll(rolesByGroup);
+  }
+  
+  public Map<String, String> getRolesByGroup() {
+    return rolesByGroup;
+  }
+
+  public void setPermissionsByRole(String permissionsByRoleStr) {
+    permissionsByRole.putAll(parsePermissionByRoleString(permissionsByRoleStr));
+  }
+  
+  public Map<String, List<String>> getPermissionsByRole() {
+    return permissionsByRole;
+  }
+
+  public boolean isAuthorizationEnabled() {
+    return authorizationEnabled;
+  }
+
+  public void setAuthorizationEnabled(boolean authorizationEnabled) {
+    this.authorizationEnabled = authorizationEnabled;
+  }
+
+  public String getUserSearchAttributeName() {
+    return userSearchAttributeName;
+  }
+  
+  /**
+  * Set User Search Attribute Name for LDAP.
+  * 
+  * @param userSearchAttributeName
+  *            userAttribute to search ldap.
+  */
+  public void setUserSearchAttributeName(String userSearchAttributeName) {
+    if (userSearchAttributeName != null) {
+      userSearchAttributeName = userSearchAttributeName.trim();
+    }
+    this.userSearchAttributeName = userSearchAttributeName;
+  }
+
+  public String getUserObjectClass() {
+    return userObjectClass;
+  }
+
+  public void setUserObjectClass(String userObjectClass) {
+    this.userObjectClass = userObjectClass;
+  }
+
+  private Map<String, List<String>> parsePermissionByRoleString(String permissionsByRoleStr) {
+    Map<String, List<String>> perms = new HashMap<String, List<String>>();
+
+    // split by semicolon ; then by eq = then by comma ,
+    StringTokenizer stSem = new StringTokenizer(permissionsByRoleStr, ";");
+    while (stSem.hasMoreTokens()) {
+      String roleAndPerm = stSem.nextToken();
+      StringTokenizer stEq = new StringTokenizer(roleAndPerm, "=");
+      if (stEq.countTokens() != 2) {
+        continue;
+      }
+      String role = stEq.nextToken().trim();
+      String perm = stEq.nextToken().trim();
+      StringTokenizer stCom = new StringTokenizer(perm, ",");
+      List<String> permList = new ArrayList<String>();
+      while (stCom.hasMoreTokens()) {
+        permList.add(stCom.nextToken().trim());
+      }
+      perms.put(role, permList);
+    }
+    return perms;
+  }
+
+  boolean isUserMemberOfDynamicGroup(LdapName userLdapDn, String memberUrl,
+        final LdapContextFactory ldapContextFactory) throws NamingException {
+
+    // ldap://host:port/dn?attributes?scope?filter?extensions
+
+    if (memberUrl == null) {
+      return false;
+    }
+    String[] tokens = memberUrl.split("\\?");
+    if (tokens.length < 4) {
+      return false;
+    }
+
+    String searchBaseString = tokens[0].substring(tokens[0].lastIndexOf("/") + 1);
+    String searchScope = tokens[2];
+    String searchFilter = tokens[3];
+
+    LdapName searchBaseDn = new LdapName(searchBaseString);
+
+    // do scope test
+    if (searchScope.equalsIgnoreCase("base")) {
+      log.debug("DynamicGroup SearchScope base");
+      return false;
+    }
+    if (!userLdapDn.toString().endsWith(searchBaseDn.toString())) {
+      return false;
+    }
+    if (searchScope.equalsIgnoreCase("one") && (userLdapDn.size() != searchBaseDn.size() - 1)) {
+      log.debug("DynamicGroup SearchScope one");
+      return false;
+    }
+    // search for the filter, substituting base with userDn
+    // search for base_dn=userDn, scope=base, filter=filter
+    LdapContext systemLdapCtx = null;
+    systemLdapCtx = ldapContextFactory.getSystemLdapContext();
+    boolean member = false;
+    NamingEnumeration<SearchResult> searchResultEnum = null;
+    try {
+      searchResultEnum = systemLdapCtx.search(userLdapDn, searchFilter,
+            searchScope.equalsIgnoreCase("sub") ? SUBTREE_SCOPE : ONELEVEL_SCOPE);
+      if (searchResultEnum.hasMore()) {
+        return true;
+      }
+    } finally {
+      try {
+        if (searchResultEnum != null) {
+          searchResultEnum.close();
+        }
+      } finally {
+        LdapUtils.closeContext(systemLdapCtx);
+      }
+    }
+    return member;
+  }
+
+  public String getPrincipalRegex() {
+    return principalRegex;
+  }
+  
+  /**
+  * Set Regex for Principal LDAP.
+  * 
+  * @param regex
+  *            regex to use to search for principal in shiro.
+  */
+  public void setPrincipalRegex(String regex) {
+    if (regex == null || regex.trim().isEmpty()) {
+      principalPattern = Pattern.compile(DEFAULT_PRINCIPAL_REGEX);
+      principalRegex = DEFAULT_PRINCIPAL_REGEX;
+    } else {
+      regex = regex.trim();
+      Pattern pattern = Pattern.compile(regex);
+      principalPattern = pattern;
+      principalRegex = regex;
+    }
+  }
+
+  public String getUserSearchAttributeTemplate() {
+    return userSearchAttributeTemplate;
+  }
+
+  public void setUserSearchAttributeTemplate(final String template) {
+    this.userSearchAttributeTemplate = (template == null ? null : template.trim());
+  }
+
+  public String getUserSearchFilter() {
+    return userSearchFilter;
+  }
+
+  public void setUserSearchFilter(final String filter) {
+    this.userSearchFilter = (filter == null ? null : filter.trim());
+  }
+  
+  public boolean getUserLowerCase() {
+    return userLowerCase;
+  }
+  
+  public void setUserLowerCase(boolean userLowerCase) {
+    this.userLowerCase = userLowerCase;
+  }
+  
+  public String getUserSearchScope() {
+    return userSearchScope;
+  }
+
+  public void setUserSearchScope(final String scope) {
+    this.userSearchScope = (scope == null ? null : scope.trim().toLowerCase());
+  }
+
+  public String getGroupSearchScope() {
+    return groupSearchScope;
+  }
+
+  public void setGroupSearchScope(final String scope) {
+    this.groupSearchScope = (scope == null ? null : scope.trim().toLowerCase());
+  }
+
+  private SearchControls getUserSearchControls() {
+    SearchControls searchControls = SUBTREE_SCOPE;
+    if ("onelevel".equalsIgnoreCase(userSearchScope)) {
+      searchControls = ONELEVEL_SCOPE;
+    } else if ("object".equalsIgnoreCase(userSearchScope)) {
+      searchControls = OBJECT_SCOPE;
+    }
+    return searchControls;
+  }
+  
+  private SearchControls getGroupSearchControls() {
+    SearchControls searchControls = SUBTREE_SCOPE;
+    if ("onelevel".equalsIgnoreCase(groupSearchScope)) {
+      searchControls = ONELEVEL_SCOPE;
+    } else if ("object".equalsIgnoreCase(groupSearchScope)) {
+      searchControls = OBJECT_SCOPE;
+    }
+    return searchControls;
+  }
+
+  @Override
+  public void setUserDnTemplate(final String template) throws IllegalArgumentException {
+    userDnTemplate = template;
+  }
+
+  private Matcher matchPrincipal(final String principal) {
+    Matcher matchedPrincipal = principalPattern.matcher(principal);
+    if (!matchedPrincipal.matches()) {
+      throw new IllegalArgumentException("Principal " 
+            + principal + " does not match " + principalRegex);
+    }
+    return matchedPrincipal;
+  }
+
+  /**
+  * Returns the LDAP User Distinguished Name (DN) to use when acquiring an
+  * {@link javax.naming.ldap.LdapContext LdapContext} from the
+  * {@link LdapContextFactory}.
+  * <p/>
+  * If the the {@link #getUserDnTemplate() userDnTemplate} property has been
+  * set, this implementation will construct the User DN by substituting the
+  * specified {@code principal} into the configured template. If the
+  * {@link #getUserDnTemplate() userDnTemplate} has not been set, the method
+  * argument will be returned directly (indicating that the submitted
+  * authentication token principal <em>is</em> the User DN).
+  *
+  * @param principal
+  *            the principal to substitute into the configured
+  *            {@link #getUserDnTemplate() userDnTemplate}.
+  * @return the constructed User DN to use at runtime when acquiring an
+  *         {@link javax.naming.ldap.LdapContext}.
+  * @throws IllegalArgumentException
+  *             if the method argument is null or empty
+  * @throws IllegalStateException
+  *             if the {@link #getUserDnTemplate userDnTemplate} has not been
+  *             set.
+  * @see LdapContextFactory#getLdapContext(Object, Object)
+  */
+  @Override
+  protected String getUserDn(final String principal) throws IllegalArgumentException, 
+        IllegalStateException {
+    String userDn;
+    Matcher matchedPrincipal = matchPrincipal(principal);
+    String userSearchBase = getUserSearchBase();
+    String userSearchAttributeName = getUserSearchAttributeName();
+
+    // If not searching use the userDnTemplate and return.
+    if ((userSearchBase == null || userSearchBase.isEmpty()) || (userSearchAttributeName == null
+          && userSearchFilter == null && !"object".equalsIgnoreCase(userSearchScope))) {
+      userDn = expandTemplate(userDnTemplate, matchedPrincipal);
+      if (log.isDebugEnabled()) {
+        log.debug("LDAP UserDN and Principal: " + userDn + "," + principal);
+      }
+      return userDn;
+    }
+
+    // Create the searchBase and searchFilter from config.
+    String searchBase = expandTemplate(getUserSearchBase(), matchedPrincipal);
+    String searchFilter = null;
+    if (userSearchFilter == null) {
+      if (userSearchAttributeName == null) {
+        searchFilter = String.format("(objectclass=%1$s)", getUserObjectClass());
+      } else {
+        searchFilter = String.format("(&(objectclass=%1$s)(%2$s=%3$s))", getUserObjectClass(),
+              userSearchAttributeName, expandTemplate(getUserSearchAttributeTemplate(), 
+              matchedPrincipal));
+      }
+    } else {
+      searchFilter = expandTemplate(userSearchFilter, matchedPrincipal);
+    }
+    SearchControls searchControls = getUserSearchControls();
+
+    // Search for userDn and return.
+    LdapContext systemLdapCtx = null;
+    NamingEnumeration<SearchResult> searchResultEnum = null;
+    try {
+      systemLdapCtx = getContextFactory().getSystemLdapContext();
+      if (log.isDebugEnabled()) {
+        log.debug("SearchBase,SearchFilter,UserSearchScope: " + searchBase 
+              + "," + searchFilter + "," + userSearchScope);
+      }
+      searchResultEnum = systemLdapCtx.search(searchBase, searchFilter, searchControls);
+      // SearchResults contains all the entries in search scope
+      if (searchResultEnum.hasMore()) {
+        SearchResult searchResult = searchResultEnum.next();
+        userDn = searchResult.getNameInNamespace();
+        if (log.isDebugEnabled()) {
+          log.debug("UserDN Returned,Principal: " + userDn + "," + principal);
+        }
+        return userDn;
+      } else {
+        throw new IllegalArgumentException("Illegal principal name: " + principal);
+      }
+    } catch (AuthenticationException ne) {
+      ne.printStackTrace();
+      throw new IllegalArgumentException("Illegal principal name: " + principal);
+    } catch (NamingException ne) {
+      throw new IllegalArgumentException("Hit NamingException: " + ne.getMessage());
+    } finally {
+      try {
+        if (searchResultEnum != null) {
+          searchResultEnum.close();
+        }
+      } catch (NamingException ne) {
+        // Ignore exception on close.
+      } finally {
+        LdapUtils.closeContext(systemLdapCtx);
+      }
+    }
+  }
+
+  @Override
+  protected AuthenticationInfo createAuthenticationInfo(AuthenticationToken token, 
+        Object ldapPrincipal,
+        Object ldapCredentials, LdapContext ldapContext) throws NamingException {
+    HashRequest.Builder builder = new HashRequest.Builder();
+    Hash credentialsHash = hashService
+          .computeHash(builder.setSource(token.getCredentials())
+                .setAlgorithmName(HASHING_ALGORITHM).build());
+    return new SimpleAuthenticationInfo(token.getPrincipal(), 
+          credentialsHash.toHex(), credentialsHash.getSalt(),
+          getName());
+  }
+
+  private static final String expandTemplate(final String template, final Matcher input) {
+    String output = template;
+    Matcher matcher = TEMPLATE_PATTERN.matcher(output);
+    while (matcher.find()) {
+      String lookupStr = matcher.group(1);
+      int lookupIndex = Integer.parseInt(lookupStr);
+      String lookupValue = input.group(lookupIndex);
+      output = matcher.replaceFirst(lookupValue == null ? "" : lookupValue);
+      matcher = TEMPLATE_PATTERN.matcher(output);
+    }
+    return output;
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/8aad9ea3/zeppelin-server/src/main/java/org/apache/zeppelin/rest/GetUserList.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/GetUserList.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/GetUserList.java
index f1a895c..f0e3740 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/GetUserList.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/GetUserList.java
@@ -24,7 +24,8 @@ import org.apache.shiro.realm.ldap.JndiLdapContextFactory;
 import org.apache.shiro.realm.ldap.JndiLdapRealm;
 import org.apache.shiro.realm.text.IniRealm;
 import org.apache.shiro.util.JdbcUtils;
-import org.apache.zeppelin.server.ActiveDirectoryGroupRealm;
+import org.apache.zeppelin.realm.ActiveDirectoryGroupRealm;
+import org.apache.zeppelin.realm.LdapRealm;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -114,8 +115,76 @@ public class GetUserList {
     } catch (Exception e) {
       LOG.error("Error retrieving User list from Ldap Realm", e);
     }
+    LOG.info("UserList: " + userList);
     return userList;
   }
+  
+  /**
+   * function to extract users from Zeppelin LdapRealm
+   */
+  public List<String> getUserList(LdapRealm r, String searchText) {
+    List<String> userList = new ArrayList<>();
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("SearchText: " + searchText);
+    }
+    String userAttribute = r.getUserSearchAttributeName();
+    String userSearchRealm = r.getUserSearchBase();
+    String userObjectClass = r.getUserObjectClass();
+    JndiLdapContextFactory CF = (JndiLdapContextFactory) r.getContextFactory();
+    try {
+      LdapContext ctx = CF.getSystemLdapContext();
+      SearchControls constraints = new SearchControls();
+      constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
+      String[] attrIDs = {userAttribute};
+      constraints.setReturningAttributes(attrIDs);
+      NamingEnumeration result = ctx.search(userSearchRealm, "(&(objectclass=" + 
+            userObjectClass + ")(" 
+            + userAttribute + "=" + searchText + "))", constraints);
+      while (result.hasMore()) {
+        Attributes attrs = ((SearchResult) result.next()).getAttributes();
+        if (attrs.get(userAttribute) != null) {
+          String currentUser;
+          if (r.getUserLowerCase()) {
+            LOG.debug("userLowerCase true");
+            currentUser = ((String) attrs.get(userAttribute).get()).toLowerCase();
+          } else {
+            LOG.debug("userLowerCase false");
+            currentUser = (String) attrs.get(userAttribute).get();            
+          }
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("CurrentUser: " + currentUser);
+          }
+          userList.add(currentUser.trim());
+        }
+      }
+    } catch (Exception e) {
+      LOG.error("Error retrieving User list from Ldap Realm", e);
+    }
+    return userList;
+  }
+  
+  /***
+   * Get user roles from shiro.ini for Zeppelin LdapRealm
+   * @param r
+   * @return
+   */
+  public List<String> getRolesList(LdapRealm r) {
+    List<String> roleList = new ArrayList<>();
+    Map<String, String> roles = r.getListRoles();
+    if (roles != null) {
+      Iterator it = roles.entrySet().iterator();
+      while (it.hasNext()) {
+        Map.Entry pair = (Map.Entry) it.next();
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("RoleKeyValue: " + pair.getKey() + 
+                " = " + pair.getValue());
+        }
+        roleList.add((String) pair.getKey());
+      }
+    }
+    return roleList;
+  }
+  
 
   public List<String> getUserList(ActiveDirectoryGroupRealm r, String searchText) {
     List<String> userList = new ArrayList<>();

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/8aad9ea3/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java
index 7af52c8..742af9e 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java
@@ -25,7 +25,8 @@ import org.apache.shiro.realm.ldap.JndiLdapRealm;
 import org.apache.shiro.realm.text.IniRealm;
 import org.apache.zeppelin.annotation.ZeppelinApi;
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
-import org.apache.zeppelin.server.ActiveDirectoryGroupRealm;
+import org.apache.zeppelin.realm.ActiveDirectoryGroupRealm;
+import org.apache.zeppelin.realm.LdapRealm;
 import org.apache.zeppelin.server.JsonResponse;
 import org.apache.zeppelin.ticket.TicketContainer;
 import org.apache.zeppelin.utils.SecurityUtils;
@@ -105,16 +106,22 @@ public class SecurityRestApi {
       if (realmsList != null) {
         for (Iterator<Realm> iterator = realmsList.iterator(); iterator.hasNext(); ) {
           Realm realm = iterator.next();
-          String name = realm.getName();
-          if (name.equals("iniRealm")) {
+          String name = realm.getClass().getName();
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("RealmClass.getName: " + name);
+          }
+          if (name.equals("org.apache.shiro.realm.text.IniRealm")) {
             usersList.addAll(getUserListObj.getUserList((IniRealm) realm));
             rolesList.addAll(getUserListObj.getRolesList((IniRealm) realm));
-          } else if (name.equals("ldapRealm")) {
+          } else if (name.equals("org.apache.zeppelin.realm.LdapGroupRealm")) {
             usersList.addAll(getUserListObj.getUserList((JndiLdapRealm) realm, searchText));
-          } else if (name.equals("activeDirectoryRealm")) {
+          } else if (name.equals("org.apache.zeppelin.realm.LdapRealm")) {
+            usersList.addAll(getUserListObj.getUserList((LdapRealm) realm, searchText));
+            rolesList.addAll(getUserListObj.getRolesList((LdapRealm) realm));
+          } else if (name.equals("org.apache.zeppelin.realm.ActiveDirectoryGroupRealm")) {
             usersList.addAll(getUserListObj.getUserList((ActiveDirectoryGroupRealm) realm,
                 searchText));
-          } else if (name.equals("jdbcRealm")) {
+          } else if (name.equals("org.apache.shiro.realm.jdbc.JdbcRealm")) {
             usersList.addAll(getUserListObj.getUserList((JdbcRealm) realm));
           }
         }

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/8aad9ea3/zeppelin-server/src/main/java/org/apache/zeppelin/server/ActiveDirectoryGroupRealm.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ActiveDirectoryGroupRealm.java b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ActiveDirectoryGroupRealm.java
deleted file mode 100644
index 0c7c56d..0000000
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ActiveDirectoryGroupRealm.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.zeppelin.server;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.security.alias.CredentialProvider;
-import org.apache.hadoop.security.alias.CredentialProviderFactory;
-import org.apache.shiro.authc.AuthenticationInfo;
-import org.apache.shiro.authc.AuthenticationToken;
-import org.apache.shiro.authc.SimpleAuthenticationInfo;
-import org.apache.shiro.authc.UsernamePasswordToken;
-import org.apache.shiro.authz.AuthorizationInfo;
-import org.apache.shiro.authz.SimpleAuthorizationInfo;
-import org.apache.shiro.realm.Realm;
-import org.apache.shiro.realm.ldap.AbstractLdapRealm;
-import org.apache.shiro.realm.ldap.DefaultLdapContextFactory;
-import org.apache.shiro.realm.ldap.LdapContextFactory;
-import org.apache.shiro.realm.ldap.LdapUtils;
-import org.apache.shiro.subject.PrincipalCollection;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-import javax.naming.ldap.LdapContext;
-import java.util.*;
-
-
-/**
- * A {@link Realm} that authenticates with an active directory LDAP
- * server to determine the roles for a particular user.  This implementation
- * queries for the user's groups and then maps the group names to roles using the
- * {@link #groupRolesMap}.
- *
- * @since 0.1
- */
-public class ActiveDirectoryGroupRealm extends AbstractLdapRealm {
-
-  private static final Logger log = LoggerFactory.getLogger(ActiveDirectoryGroupRealm.class);
-
-  private static final String ROLE_NAMES_DELIMETER = ",";
-
-  String KEYSTORE_PASS = "activeDirectoryRealm.systemPassword";
-  private String hadoopSecurityCredentialPath;
-
-  public void setHadoopSecurityCredentialPath(String hadoopSecurityCredentialPath) {
-    this.hadoopSecurityCredentialPath = hadoopSecurityCredentialPath;
-  }
-
-    /*--------------------------------------------
-    |    I N S T A N C E   V A R I A B L E S    |
-    ============================================*/
-
-  /**
-   * Mapping from fully qualified active directory
-   * group names (e.g. CN=Group,OU=Company,DC=MyDomain,DC=local)
-   * as returned by the active directory LDAP server to role names.
-   */
-  private Map<String, String> groupRolesMap;
-
-    /*--------------------------------------------
-    |         C O N S T R U C T O R S           |
-    ============================================*/
-
-  public void setGroupRolesMap(Map<String, String> groupRolesMap) {
-    this.groupRolesMap = groupRolesMap;
-  }
-
-    /*--------------------------------------------
-    |               M E T H O D S               |
-    ============================================*/
-
-  LdapContextFactory ldapContextFactory;
-
-  public LdapContextFactory getLdapContextFactory() {
-    if (this.ldapContextFactory == null) {
-      if (log.isDebugEnabled()) {
-        log.debug("No LdapContextFactory specified - creating a default instance.");
-      }
-
-      DefaultLdapContextFactory defaultFactory = new DefaultLdapContextFactory();
-      defaultFactory.setPrincipalSuffix(this.principalSuffix);
-      defaultFactory.setSearchBase(this.searchBase);
-      defaultFactory.setUrl(this.url);
-      defaultFactory.setSystemUsername(this.systemUsername);
-      defaultFactory.setSystemPassword(getSystemPassword());
-      this.ldapContextFactory = defaultFactory;
-    }
-
-    return this.ldapContextFactory;
-  }
-
-  private String getSystemPassword() {
-    String password = "";
-    if (StringUtils.isEmpty(this.hadoopSecurityCredentialPath)) {
-      password = this.systemPassword;
-    } else {
-      try {
-        Configuration configuration = new Configuration();
-        configuration.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH,
-          this.hadoopSecurityCredentialPath);
-        CredentialProvider provider =
-          CredentialProviderFactory.getProviders(configuration).get(0);
-        CredentialProvider.CredentialEntry credEntry = provider.getCredentialEntry(
-            KEYSTORE_PASS);
-        if (credEntry != null) {
-          password = new String(credEntry.getCredential());
-        }
-      } catch (Exception e) {
-
-      }
-    }
-    return password;
-  }
-
-  /**
-   * Builds an {@link AuthenticationInfo} object by querying the active directory LDAP context for
-   * the specified username.  This method binds to the LDAP server using the provided username
-   * and password - which if successful, indicates that the password is correct.
-   * <p/>
-   * This method can be overridden by subclasses to query the LDAP server in a more complex way.
-   *
-   * @param token              the authentication token provided by the user.
-   * @param ldapContextFactory the factory used to build connections to the LDAP server.
-   * @return an {@link AuthenticationInfo} instance containing information retrieved from LDAP.
-   * @throws NamingException if any LDAP errors occur during the search.
-   */
-  protected AuthenticationInfo queryForAuthenticationInfo(
-      AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException {
-
-    UsernamePasswordToken upToken = (UsernamePasswordToken) token;
-
-    // Binds using the username and password provided by the user.
-    LdapContext ctx = null;
-    try {
-      String userPrincipalName = upToken.getUsername();
-      if (userPrincipalName == null) {
-        return null;
-      }
-      if (this.principalSuffix != null) {
-        userPrincipalName = upToken.getUsername() + this.principalSuffix;
-      }
-      ctx = ldapContextFactory.getLdapContext(
-          userPrincipalName, upToken.getPassword());
-    } finally {
-      LdapUtils.closeContext(ctx);
-    }
-
-    return buildAuthenticationInfo(upToken.getUsername(), upToken.getPassword());
-  }
-
-  protected AuthenticationInfo buildAuthenticationInfo(String username, char[] password) {
-    return new SimpleAuthenticationInfo(username, password, getName());
-  }
-
-
-  /**
-   * Builds an {@link org.apache.shiro.authz.AuthorizationInfo} object by querying the active
-   * directory LDAP context for the groups that a user is a member of.  The groups are then
-   * translated to role names by using the configured {@link #groupRolesMap}.
-   * <p/>
-   * This implementation expects the <tt>principal</tt> argument to be a String username.
-   * <p/>
-   * Subclasses can override this method to determine authorization data (roles, permissions, etc)
-   * in a more complex way.  Note that this default implementation does not support permissions,
-   * only roles.
-   *
-   * @param principals         the principal of the Subject whose account is being retrieved.
-   * @param ldapContextFactory the factory used to create LDAP connections.
-   * @return the AuthorizationInfo for the given Subject principal.
-   * @throws NamingException if an error occurs when searching the LDAP server.
-   */
-  protected AuthorizationInfo queryForAuthorizationInfo(
-      PrincipalCollection principals,
-      LdapContextFactory ldapContextFactory) throws NamingException {
-
-    String username = (String) getAvailablePrincipal(principals);
-
-    // Perform context search
-    LdapContext ldapContext = ldapContextFactory.getSystemLdapContext();
-
-    Set<String> roleNames;
-
-    try {
-      roleNames = getRoleNamesForUser(username, ldapContext);
-    } finally {
-      LdapUtils.closeContext(ldapContext);
-    }
-
-    return buildAuthorizationInfo(roleNames);
-  }
-
-  protected AuthorizationInfo buildAuthorizationInfo(Set<String> roleNames) {
-    return new SimpleAuthorizationInfo(roleNames);
-  }
-
-  public List<String> searchForUserName(String containString, LdapContext ldapContext) throws
-      NamingException {
-    List<String> userNameList = new ArrayList<>();
-
-    SearchControls searchCtls = new SearchControls();
-    searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-
-    String searchFilter = "(&(objectClass=*)(userPrincipalName=*" + containString + "*))";
-    Object[] searchArguments = new Object[]{containString};
-
-    NamingEnumeration answer = ldapContext.search(searchBase, searchFilter, searchArguments,
-        searchCtls);
-
-    while (answer.hasMoreElements()) {
-      SearchResult sr = (SearchResult) answer.next();
-
-      if (log.isDebugEnabled()) {
-        log.debug("Retrieving userprincipalname names for user [" + sr.getName() + "]");
-      }
-
-      Attributes attrs = sr.getAttributes();
-      if (attrs != null) {
-        NamingEnumeration ae = attrs.getAll();
-        while (ae.hasMore()) {
-          Attribute attr = (Attribute) ae.next();
-          if (attr.getID().toLowerCase().equals("cn")) {
-            userNameList.addAll(LdapUtils.getAllAttributeValues(attr));
-          }
-        }
-      }
-    }
-    return userNameList;
-  }
-
-  private Set<String> getRoleNamesForUser(String username, LdapContext ldapContext)
-      throws NamingException {
-    Set<String> roleNames = new LinkedHashSet<>();
-
-    SearchControls searchCtls = new SearchControls();
-    searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-    String userPrincipalName = username;
-    if (principalSuffix != null) {
-      userPrincipalName += principalSuffix;
-    }
-
-    String searchFilter = "(&(objectClass=*)(userPrincipalName=" + userPrincipalName + "))";
-    Object[] searchArguments = new Object[]{userPrincipalName};
-
-    NamingEnumeration answer = ldapContext.search(searchBase, searchFilter, searchArguments,
-        searchCtls);
-
-    while (answer.hasMoreElements()) {
-      SearchResult sr = (SearchResult) answer.next();
-
-      if (log.isDebugEnabled()) {
-        log.debug("Retrieving group names for user [" + sr.getName() + "]");
-      }
-
-      Attributes attrs = sr.getAttributes();
-
-      if (attrs != null) {
-        NamingEnumeration ae = attrs.getAll();
-        while (ae.hasMore()) {
-          Attribute attr = (Attribute) ae.next();
-
-          if (attr.getID().equals("memberOf")) {
-
-            Collection<String> groupNames = LdapUtils.getAllAttributeValues(attr);
-
-            if (log.isDebugEnabled()) {
-              log.debug("Groups found for user [" + username + "]: " + groupNames);
-            }
-
-            Collection<String> rolesForGroups = getRoleNamesForGroups(groupNames);
-            roleNames.addAll(rolesForGroups);
-          }
-        }
-      }
-    }
-    return roleNames;
-  }
-
-  /**
-   * This method is called by the default implementation to translate Active Directory group names
-   * to role names.  This implementation uses the {@link #groupRolesMap} to map group names to role
-   * names.
-   *
-   * @param groupNames the group names that apply to the current user.
-   * @return a collection of roles that are implied by the given role names.
-   */
-  protected Collection<String> getRoleNamesForGroups(Collection<String> groupNames) {
-    Set<String> roleNames = new HashSet<>(groupNames.size());
-
-    if (groupRolesMap != null) {
-      for (String groupName : groupNames) {
-        String strRoleNames = groupRolesMap.get(groupName);
-        if (strRoleNames != null) {
-          for (String roleName : strRoleNames.split(ROLE_NAMES_DELIMETER)) {
-
-            if (log.isDebugEnabled()) {
-              log.debug("User is member of group [" + groupName + "] so adding role [" +
-                  roleName + "]");
-            }
-
-            roleNames.add(roleName);
-
-          }
-        }
-      }
-    }
-    return roleNames;
-  }
-
-}
-

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/8aad9ea3/zeppelin-server/src/main/java/org/apache/zeppelin/server/LdapGroupRealm.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/server/LdapGroupRealm.java b/zeppelin-server/src/main/java/org/apache/zeppelin/server/LdapGroupRealm.java
deleted file mode 100644
index e53027c..0000000
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/server/LdapGroupRealm.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.zeppelin.server;
-
-import org.apache.shiro.authz.AuthorizationInfo;
-import org.apache.shiro.authz.SimpleAuthorizationInfo;
-import org.apache.shiro.realm.ldap.JndiLdapRealm;
-import org.apache.shiro.realm.ldap.LdapContextFactory;
-import org.apache.shiro.subject.PrincipalCollection;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-import javax.naming.ldap.LdapContext;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-
-/**
- * Created for org.apache.zeppelin.server on 09/06/16.
- */
-public class LdapGroupRealm extends JndiLdapRealm {
-  private static final Logger LOG = LoggerFactory.getLogger(LdapGroupRealm.class);
-
-  public AuthorizationInfo queryForAuthorizationInfo(
-      PrincipalCollection principals,
-      LdapContextFactory ldapContextFactory) throws NamingException {
-    String username = (String) getAvailablePrincipal(principals);
-    LdapContext ldapContext = ldapContextFactory.getSystemLdapContext();
-    Set<String> roleNames = getRoleNamesForUser(username, ldapContext, getUserDnTemplate());
-    return new SimpleAuthorizationInfo(roleNames);
-  }
-
-
-  public Set<String> getRoleNamesForUser(String username,
-                                         LdapContext ldapContext,
-                                         String userDnTemplate) throws NamingException {
-    try {
-      Set<String> roleNames = new LinkedHashSet<>();
-
-      SearchControls searchCtls = new SearchControls();
-      searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-
-      String searchFilter = "(&(objectClass=groupOfNames)(member=" + userDnTemplate + "))";
-      Object[] searchArguments = new Object[]{username};
-
-      NamingEnumeration<?> answer = ldapContext.search(
-          String.valueOf(ldapContext.getEnvironment().get("ldap.searchBase")),
-          searchFilter,
-          searchArguments,
-          searchCtls);
-
-      while (answer.hasMoreElements()) {
-        SearchResult sr = (SearchResult) answer.next();
-        Attributes attrs = sr.getAttributes();
-        if (attrs != null) {
-          NamingEnumeration<?> ae = attrs.getAll();
-          while (ae.hasMore()) {
-            Attribute attr = (Attribute) ae.next();
-            if (attr.getID().equals("cn")) {
-              roleNames.add((String) attr.get());
-            }
-          }
-        }
-      }
-      return roleNames;
-
-    } catch (Exception e) {
-      LOG.error("Error", e);
-    }
-
-    return new HashSet<>();
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/8aad9ea3/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java b/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java
index 186a324..6385a63 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java
@@ -34,6 +34,10 @@ import org.apache.shiro.subject.Subject;
 import org.apache.shiro.util.ThreadContext;
 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
+import org.apache.zeppelin.realm.LdapRealm;
+import org.mortbay.log.Log;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.Sets;
 
@@ -45,6 +49,7 @@ public class SecurityUtils {
   private static final String ANONYMOUS = "anonymous";
   private static final HashSet<String> EMPTY_HASHSET = Sets.newHashSet();
   private static boolean isEnabled = false;
+  private static final Logger log = LoggerFactory.getLogger(SecurityUtils.class);
   
   public static void initSecurityManager(String shiroPath) {
     IniSecurityManagerFactory factory = new IniSecurityManagerFactory("file:" + shiroPath);
@@ -119,13 +124,15 @@ public class SecurityUtils {
       Collection realmsList = SecurityUtils.getRealmsList();
       for (Iterator<Realm> iterator = realmsList.iterator(); iterator.hasNext(); ) {
         Realm realm = iterator.next();
-        String name = realm.getName();
-        if (name.equals("iniRealm")) {
+        String name = realm.getClass().getName();
+        if (name.equals("org.apache.shiro.realm.text.IniRealm")) {
           allRoles = ((IniRealm) realm).getIni().get("roles");
           break;
+        } else if (name.equals("org.apache.zeppelin.realm.LdapRealm")) {
+          allRoles = ((LdapRealm) realm).getListRoles();
+          break;
         }
       }
-
       if (allRoles != null) {
         Iterator it = allRoles.entrySet().iterator();
         while (it.hasNext()) {