Added role based authentication(not to be confused with authorization) for shiro

This commit is contained in:
Sohaib Iftikhar 2017-05-19 15:04:18 +02:00
parent c61e08de1f
commit f706b22298
2 changed files with 92 additions and 0 deletions

View file

@ -128,6 +128,10 @@ Change the following values in the Shiro.ini file, and uncomment the line:
### LDAP
Two options exist for configuring an LDAP Realm. The simpler to use is the LdapGroupRealm. How ever it has limited
flexibility with mapping of ldap groups to users and for authorization for user groups. A sample configuration file for
this realm is given below.
```
ldapRealm = org.apache.zeppelin.realm.LdapGroupRealm
# search base for ldap groups (only relevant for LdapGroupRealm):
@ -137,6 +141,46 @@ ldapRealm.userDnTemplate = uid={0},ou=Users,dc=COMPANY,dc=COM
ldapRealm.contextFactory.authenticationMechanism = simple
```
The other more flexible option is to use the LdapRealm. It allows for mapping of ldapgroups to roles and also allows for
role/group based authentication into the zeppelin server. Sample configuration for this realm is given below.
```
[main]
ldapRealm=org.apache.zeppelin.realm.LdapRealm
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}
# enable support for nested groups using the LDAP_MATCHING_RULE_IN_CHAIN operator
ldapRealm.groupSearchEnableMatchingRuleInChain = true
# 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
# optional list of roles that are allowed to authenticate. Incase not present all groups are allowed to authenticate (login).
# This changes nothing for url specific permissions that will continue to work as specified in [urls].
ldapRealm.allowedRolesForAuthentication = admin_role,user_role
ldapRealm.permissionsByRole= user_role = *:ToDoItemsJdo:*:*, *:ToDoItem:*:*; admin_role = *
securityManager.sessionManager = $sessionManager
securityManager.realms = $ldapRealm
```
### PAM
[PAM](https://en.wikipedia.org/wiki/Pluggable_authentication_module) authentication support allows the reuse of existing authentication
moduls on the host where Zeppelin is running. On a typical system modules are configured per service for example sshd, passwd, etc. under `/etc/pam.d/`. You can

View file

@ -109,6 +109,9 @@ import javax.naming.ldap.PagedResultsControl;
* <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># optional list of roles that are allowed to authenticate
* ldapRealm.allowedRolesForAuthentication = admin_role,user_role
*
* <p>ldapRealm.permissionsByRole=\ user_role = *:ToDoItemsJdo:*:*,\
* *:ToDoItem:*:*; \ self-install_role = *:ToDoItemsFixturesService:install:* ;
@ -176,6 +179,7 @@ public class LdapRealm extends JndiLdapRealm {
private String memberAttributeValueSuffix = "";
private final Map<String, String> rolesByGroup = new LinkedHashMap<String, String>();
private final List<String> allowedRolesForAuthentication = new ArrayList<String>();
private final Map<String, List<String>> permissionsByRole =
new LinkedHashMap<String, List<String>>();
@ -202,6 +206,29 @@ public class LdapRealm extends JndiLdapRealm {
}
}
/**
* This overrides the implementation of queryForAuthenticationInfo inside JndiLdapRealm.
* In addition to calling the super method for authentication it also tries to validate
* if this user has atleast one of the allowed roles for authentication. In case the property
* allowedRolesForAuthentication is empty this check always returns true.
*
* @param token the submitted authentication token that triggered the authentication attempt.
* @param ldapContextFactory factory used to retrieve LDAP connections.
* @return AuthenticationInfo instance representing the authenticated user's information.
* @throws NamingException if any LDAP errors occur.
*/
@Override
protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token,
LdapContextFactory ldapContextFactory)
throws NamingException {
AuthenticationInfo info = super.queryForAuthenticationInfo(token, ldapContextFactory);
// Credentials were verified. Verify that the principal has all allowedRulesForAuthentication
if (!hasAllowedAuthenticationRules(info.getPrincipals(), ldapContextFactory)) {
throw new NamingException("Principal does not have any of the allowedRolesForAuthentication");
}
return info;
}
/**
* Get groups from LDAP.
*
@ -231,6 +258,23 @@ public class LdapRealm extends JndiLdapRealm {
return simpleAuthorizationInfo;
}
private boolean hasAllowedAuthenticationRules(PrincipalCollection principals,
final LdapContextFactory ldapContextFactory)
throws NamingException {
boolean allowed = allowedRolesForAuthentication.isEmpty();
if (!allowed) {
Set<String> roles = getRoles(principals, ldapContextFactory);
for (String allowedRole: allowedRolesForAuthentication) {
if (roles.contains(allowedRole)) {
log.debug("Allowed role for user [" + allowedRole + "] found.");
allowed = true;
break;
}
}
}
return allowed;
}
private Set<String> getRoles(PrincipalCollection principals,
final LdapContextFactory ldapContextFactory)
throws NamingException {
@ -524,6 +568,10 @@ public class LdapRealm extends JndiLdapRealm {
this.memberAttributeValueSuffix = suffix;
}
public void setAllowedRolesForAuthentication(List<String> allowedRolesForAuthencation) {
this.allowedRolesForAuthentication.addAll(allowedRolesForAuthencation);
}
public void setRolesByGroup(Map<String, String> rolesByGroup) {
this.rolesByGroup.putAll(rolesByGroup);
}