From 066e3560454adad19c637bd9f535db5e4ab3a923 Mon Sep 17 00:00:00 2001 From: Olivier Lamy Date: Tue, 8 Jan 2013 22:46:30 +0000 Subject: [PATCH] [MRM-1736] map roles to ldap groups git-svn-id: https://svn.apache.org/repos/asf/archiva/redback/redback-core/trunk@1430601 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/test/resources/security.properties | 1 + .../redback-authorization-ldap/pom.xml | 12 +- .../authorization/ldap/LdapAuthorizer.java | 261 ++++++++++++++++++ .../ldap/role/DefaultLdapRoleMapper.java | 12 +- .../common/ldap/role/LdapRoleMapper.java | 2 +- .../redback/config-defaults.properties | 1 + .../configuration/UserConfigurationKeys.java | 2 + .../redback/config-defaults.properties | 1 + .../redback/config-defaults.properties | 1 + .../security/GuestUserEnvironmentCheck.java | 9 +- .../rest/services/DefaultUserService.java | 2 +- .../redback/rbac/AbstractRBACManager.java | 2 +- 12 files changed, 297 insertions(+), 9 deletions(-) diff --git a/redback-authentication/redback-authentication-providers/redback-authentication-ldap/src/test/resources/security.properties b/redback-authentication/redback-authentication-providers/redback-authentication-ldap/src/test/resources/security.properties index 7a36cb330..c84059f1e 100644 --- a/redback-authentication/redback-authentication-providers/redback-authentication-ldap/src/test/resources/security.properties +++ b/redback-authentication/redback-authentication-providers/redback-authentication-ldap/src/test/resources/security.properties @@ -17,4 +17,5 @@ user.manager.impl=ldap ldap.bind.authenticator.enabled=true redback.default.admin=adminuser +redback.default.guest=guest security.policy.password.expiration.enabled=false diff --git a/redback-authorization/redback-authorization-providers/redback-authorization-ldap/pom.xml b/redback-authorization/redback-authorization-providers/redback-authorization-ldap/pom.xml index ad56691fa..747e94c1c 100644 --- a/redback-authorization/redback-authorization-providers/redback-authorization-ldap/pom.xml +++ b/redback-authorization/redback-authorization-providers/redback-authorization-ldap/pom.xml @@ -36,6 +36,10 @@ org.apache.archiva.redback redback-authorization-api + + org.apache.archiva.redback + redback-rbac-model + org.springframework spring-context-support @@ -62,7 +66,13 @@ org.apache.archiva.redback.authorization;version=${project.version}, - org.springframework.stereotype;version="[3,4)" + org.springframework.stereotype;version="[3,4)", + javax.inject, + org.apache.archiva.redback.common.ldap, + org.apache.archiva.redback.common.ldap.role, + org.apache.archiva.redback.rbac, + org.apache.commons.lang, + org.slf4j diff --git a/redback-authorization/redback-authorization-providers/redback-authorization-ldap/src/main/java/org/apache/archiva/redback/authorization/ldap/LdapAuthorizer.java b/redback-authorization/redback-authorization-providers/redback-authorization-ldap/src/main/java/org/apache/archiva/redback/authorization/ldap/LdapAuthorizer.java index f7191a853..22ecb5765 100644 --- a/redback-authorization/redback-authorization-providers/redback-authorization-ldap/src/main/java/org/apache/archiva/redback/authorization/ldap/LdapAuthorizer.java +++ b/redback-authorization/redback-authorization-providers/redback-authorization-ldap/src/main/java/org/apache/archiva/redback/authorization/ldap/LdapAuthorizer.java @@ -22,8 +22,33 @@ import org.apache.archiva.redback.authorization.AuthorizationDataSource; import org.apache.archiva.redback.authorization.AuthorizationException; import org.apache.archiva.redback.authorization.AuthorizationResult; import org.apache.archiva.redback.authorization.Authorizer; +import org.apache.archiva.redback.common.ldap.MappingException; +import org.apache.archiva.redback.common.ldap.role.LdapRoleMapper; +import org.apache.archiva.redback.rbac.Permission; +import org.apache.archiva.redback.rbac.RBACManager; +import org.apache.archiva.redback.rbac.RbacManagerException; +import org.apache.archiva.redback.rbac.RbacObjectNotFoundException; +import org.apache.archiva.redback.rbac.Resource; +import org.apache.archiva.redback.rbac.Role; +import org.apache.archiva.redback.rbac.UserAssignment; +import org.apache.archiva.redback.users.UserManagerException; +import org.apache.archiva.redback.users.UserNotFoundException; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; +import javax.inject.Inject; +import javax.inject.Named; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + /** * @author Olivier Lamy * @since 2.1 @@ -32,6 +57,17 @@ import org.springframework.stereotype.Service; public class LdapAuthorizer implements Authorizer { + + private Logger log = LoggerFactory.getLogger( getClass() ); + + @Inject + @Named( value = "rbacManager#cached" ) + private RBACManager rbacManager; + + @Inject + private LdapRoleMapper ldapRoleMapper; + + public String getId() { return "ldap"; @@ -40,7 +76,232 @@ public class LdapAuthorizer public AuthorizationResult isAuthorized( AuthorizationDataSource source ) throws AuthorizationException { + + String userName = StringUtils.isEmpty( source.getPrincipal() ) ? "guest" : source.getPrincipal(); + String operation = source.getPermission(); + String resource = source.getResource(); + try + { + List ldapGroups = ldapRoleMapper.getGroups( userName ); + + List roles = mapLdapGroups( ldapGroups ); + + Map> permissionMap = getAssignedPermissionMap( roles ); + + if ( permissionMap.keySet().contains( operation ) ) + { + for ( Permission permission : permissionMap.get( operation ) ) + { + + log.debug( "checking permission {} for operation {} resource {}", + ( permission != null ? permission.getName() : "null" ), operation, resource ); + + if ( evaluate( permission, operation, resource, userName ) ) + { + return new AuthorizationResult( true, permission, null ); + } + } + + log.debug( "no permission found for operation {} resource {}", operation, resource ); + } + else + { + log.debug( "permission map does not contain operation: {}", operation ); + } + + } + catch ( MappingException e ) + { + log.info( "skip MappingException trying to find LDAP roles for user: '{}", userName ); + } + catch ( RbacManagerException e ) + { + log.info( "skip RbacManagerException trying to find LDAP roles for user: '{}", userName ); + } return null; + + } + + protected List mapLdapGroups( List groups ) + throws MappingException + { + List roles = new ArrayList(); + + Map mapping = ldapRoleMapper.getLdapGroupMappings(); + + for ( String group : groups ) + { + String role = mapping.get( group ); + if ( role != null ) + { + roles.add( role ); + } + } + + return roles; + } + + public Map> getAssignedPermissionMap( List roles ) + throws RbacObjectNotFoundException, RbacManagerException + { + return getPermissionMapByOperation( getAssignedPermissions( roles ) ); + } + + public Set getAssignedPermissions( List roles ) + throws RbacObjectNotFoundException, RbacManagerException + { + + Set permissionSet = new HashSet(); + + boolean childRoleNamesUpdated = false; + + Iterator it = roles.iterator(); + while ( it.hasNext() ) + { + String roleName = it.next(); + try + { + Role role = rbacManager.getRole( roleName ); + gatherUniquePermissions( role, permissionSet ); + } + catch ( RbacObjectNotFoundException e ) + { + // Found a bad role name. remove it! + it.remove(); + childRoleNamesUpdated = true; + } + } + + return permissionSet; + } + + private void gatherUniquePermissions( Role role, Collection coll ) + throws RbacManagerException + { + if ( role.getPermissions() != null ) + { + for ( Permission permission : role.getPermissions() ) + { + if ( !coll.contains( permission ) ) + { + coll.add( permission ); + } + } + } + + if ( role.hasChildRoles() ) + { + Map childRoles = getChildRoles( role ); + Iterator it = childRoles.values().iterator(); + while ( it.hasNext() ) + { + Role child = it.next(); + gatherUniquePermissions( child, coll ); + } + } + } + + public Map getChildRoles( Role role ) + throws RbacManagerException + { + Map childRoles = new HashMap(); + + boolean childRoleNamesUpdated = false; + + Iterator it = role.getChildRoleNames().listIterator(); + while ( it.hasNext() ) + { + String roleName = it.next(); + try + { + Role child = rbacManager.getRole( roleName ); + childRoles.put( child.getName(), child ); + } + catch ( RbacObjectNotFoundException e ) + { + // Found a bad roleName! - remove it. + it.remove(); + childRoleNamesUpdated = true; + } + } + + return childRoles; + } + + + private Map> getPermissionMapByOperation( Collection permissions ) + { + Map> userPermMap = new HashMap>(); + + for ( Permission permission : permissions ) + { + List permList = userPermMap.get( permission.getOperation().getName() ); + + if ( permList != null ) + { + permList.add( permission ); + } + else + { + List newPermList = new ArrayList( permissions.size() ); + newPermList.add( permission ); + userPermMap.put( permission.getOperation().getName(), newPermList ); + } + } + + return userPermMap; + } + + public boolean evaluate( Permission permission, String operation, String resource, String principal ) + { + String permissionResource = permission.getResource().getIdentifier(); + + // expression evaluation checking + /*if ( permissionResource.startsWith( "${" ) ) + { + String tempStr = permissionResource.substring( 2, permissionResource.indexOf( '}' ) ); + + if ( "username".equals( tempStr ) ) + { + try + { + permissionResource = userManager.findUser( principal ).getUsername(); + } + catch ( UserNotFoundException e ) + { + throw new PermissionEvaluationException( "unable to locate user to retrieve username", e ); + } + catch ( UserManagerException e ) + { + throw new PermissionEvaluationException( "trouble finding user: " + e.getMessage(), e ); + } + } + }*/ + + // check if this permission applies to the operation at all + if ( permission.getOperation().getName().equals( operation ) ) + { + // check if it is a global resource, if it is then since the operations match we return true + if ( Resource.GLOBAL.equals( permission.getResource().getIdentifier() ) ) + { + return true; + } + + // if we are not checking a specific resource, the operation is enough + if ( resource == null ) + { + return true; + } + + // check if the resource identifier of the permission matches the resource we are checking against + // if it does then return true + if ( permissionResource.equals( resource ) ) + { + return true; + } + } + + return false; } public boolean isFinalImplementation() diff --git a/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/DefaultLdapRoleMapper.java b/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/DefaultLdapRoleMapper.java index 721ea61e8..82e978814 100644 --- a/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/DefaultLdapRoleMapper.java +++ b/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/DefaultLdapRoleMapper.java @@ -40,6 +40,7 @@ import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -76,9 +77,9 @@ public class DefaultLdapRoleMapper { this.ldapGroupClass = userConf.getString( UserConfigurationKeys.LDAP_GROUPS_CLASS, this.ldapGroupClass ); - this.groupsDn = userConf.getString( UserConfigurationKeys.LDAP_GROUPS_BASEDN, this.groupsDn ); + this.groupsDn = userConf.getConcatenatedList( UserConfigurationKeys.LDAP_GROUPS_BASEDN, this.groupsDn ); - this.baseDn = userConf.getString( UserConfigurationKeys.LDAP_BASEDN, this.baseDn ); + this.baseDn = userConf.getConcatenatedList( UserConfigurationKeys.LDAP_BASEDN, this.baseDn ); } public String getLdapGroup( String role ) @@ -345,8 +346,11 @@ public class DefaultLdapRoleMapper public Map getLdapGroupMappings() { - log.warn( "getLdapGroupMappings not implemented" ); - return Collections.emptyMap(); + Map map = new HashMap(); + map.put( "archiva-admin", "System Administrator" ); + //log.warn( "getLdapGroupMappings not implemented" ); + //return Collections.emptyMap(); + return map; } //--------------------------------- diff --git a/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/LdapRoleMapper.java b/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/LdapRoleMapper.java index e37cfa34e..3ba48c07b 100644 --- a/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/LdapRoleMapper.java +++ b/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/LdapRoleMapper.java @@ -88,7 +88,7 @@ public interface LdapRoleMapper throws MappingException; /** - * @return Map of corresponding Redback role (key) and LDAP group (value) + * @return Map of corresponding LDAP group (key) and Redback role (value) */ Map getLdapGroupMappings() throws MappingException; diff --git a/redback-common/redback-common-test-resources/src/main/resources/org/apache/archiva/redback/config-defaults.properties b/redback-common/redback-common-test-resources/src/main/resources/org/apache/archiva/redback/config-defaults.properties index 31b0bb2a9..4290cb4cf 100644 --- a/redback-common/redback-common-test-resources/src/main/resources/org/apache/archiva/redback/config-defaults.properties +++ b/redback-common/redback-common-test-resources/src/main/resources/org/apache/archiva/redback/config-defaults.properties @@ -78,6 +78,7 @@ security.signon.timeout=30 # -------------------------------------------------------------------- # Default Username Values redback.default.admin=admin +redback.default.guest=guest # -------------------------------------------------------------------- # Security Policies diff --git a/redback-configuration/src/main/java/org/apache/archiva/redback/configuration/UserConfigurationKeys.java b/redback-configuration/src/main/java/org/apache/archiva/redback/configuration/UserConfigurationKeys.java index b6d401d96..cde2c962e 100644 --- a/redback-configuration/src/main/java/org/apache/archiva/redback/configuration/UserConfigurationKeys.java +++ b/redback-configuration/src/main/java/org/apache/archiva/redback/configuration/UserConfigurationKeys.java @@ -28,6 +28,8 @@ public interface UserConfigurationKeys String DEFAULT_ADMIN = "redback.default.admin"; + String DEFAULT_GUEST = "redback.default.guest"; + String EMAIL_FROM_ADDRESS = "email.from.address"; String EMAIL_FROM_NAME = "email.from.name"; diff --git a/redback-configuration/src/main/resources/org/apache/archiva/redback/config-defaults.properties b/redback-configuration/src/main/resources/org/apache/archiva/redback/config-defaults.properties index 26b6e8d82..402aaf97a 100644 --- a/redback-configuration/src/main/resources/org/apache/archiva/redback/config-defaults.properties +++ b/redback-configuration/src/main/resources/org/apache/archiva/redback/config-defaults.properties @@ -83,6 +83,7 @@ security.signon.timeout=30 # -------------------------------------------------------------------- # Default Username Values redback.default.admin=admin +redback.default.guest=guest # -------------------------------------------------------------------- # Security Policies diff --git a/redback-data-management/src/test/resources/org/apache/archiva/redback/config-defaults.properties b/redback-data-management/src/test/resources/org/apache/archiva/redback/config-defaults.properties index eeecfea0e..f749aae8f 100644 --- a/redback-data-management/src/test/resources/org/apache/archiva/redback/config-defaults.properties +++ b/redback-data-management/src/test/resources/org/apache/archiva/redback/config-defaults.properties @@ -82,6 +82,7 @@ security.signon.timeout=30 # -------------------------------------------------------------------- # Default Username Values redback.default.admin=admin +redback.default.guest=guest # -------------------------------------------------------------------- # Security Policies diff --git a/redback-integrations/redback-common-integrations/src/main/java/org/apache/archiva/redback/integration/checks/security/GuestUserEnvironmentCheck.java b/redback-integrations/redback-common-integrations/src/main/java/org/apache/archiva/redback/integration/checks/security/GuestUserEnvironmentCheck.java index 17d891ab8..fcbcb94f1 100644 --- a/redback-integrations/redback-common-integrations/src/main/java/org/apache/archiva/redback/integration/checks/security/GuestUserEnvironmentCheck.java +++ b/redback-integrations/redback-common-integrations/src/main/java/org/apache/archiva/redback/integration/checks/security/GuestUserEnvironmentCheck.java @@ -19,6 +19,8 @@ package org.apache.archiva.redback.integration.checks.security; * under the License. */ +import org.apache.archiva.redback.configuration.UserConfiguration; +import org.apache.archiva.redback.configuration.UserConfigurationKeys; import org.apache.archiva.redback.policy.UserSecurityPolicy; import org.apache.archiva.redback.role.RoleManagerException; import org.apache.archiva.redback.users.User; @@ -31,6 +33,7 @@ import org.apache.archiva.redback.users.UserManager; import org.springframework.stereotype.Service; import javax.inject.Inject; +import javax.inject.Named; import java.util.List; /** @@ -49,6 +52,10 @@ public class GuestUserEnvironmentCheck @Inject private SecuritySystem securitySystem; + @Inject + @Named( value = "userConfiguration#default" ) + private UserConfiguration config; + /** * boolean detailing if this environment check has been executed */ @@ -86,7 +93,7 @@ public class GuestUserEnvironmentCheck try { - roleManager.assignRole( "guest", guest.getUsername() ); + roleManager.assignRole( config.getString( UserConfigurationKeys.DEFAULT_GUEST ), guest.getUsername() ); } catch ( RoleManagerException rpe ) { diff --git a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/DefaultUserService.java b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/DefaultUserService.java index 909383912..eb9f06e2e 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/DefaultUserService.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/DefaultUserService.java @@ -453,7 +453,7 @@ public class DefaultUserService org.apache.archiva.redback.users.User user = userManager.createGuestUser(); user.setPasswordChangeRequired( false ); user = userManager.updateUser( user, false ); - roleManager.assignRole( "guest", user.getUsername() ); + roleManager.assignRole( config.getString( UserConfigurationKeys.DEFAULT_GUEST ), user.getUsername() ); return getSimpleUser( user ); } catch ( RoleManagerException e ) diff --git a/redback-rbac/redback-rbac-model/src/main/java/org/apache/archiva/redback/rbac/AbstractRBACManager.java b/redback-rbac/redback-rbac-model/src/main/java/org/apache/archiva/redback/rbac/AbstractRBACManager.java index 6dec253e7..a7fd7ac5d 100644 --- a/redback-rbac/redback-rbac-model/src/main/java/org/apache/archiva/redback/rbac/AbstractRBACManager.java +++ b/redback-rbac/redback-rbac-model/src/main/java/org/apache/archiva/redback/rbac/AbstractRBACManager.java @@ -723,7 +723,7 @@ public abstract class AbstractRBACManager Iterator it = role.getChildRoleNames().listIterator(); while ( it.hasNext() ) { - String roleName = (String) it.next(); + String roleName = it.next(); try { Role child = getRole( roleName ); -- 2.39.5