From: Olivier Lamy Date: Fri, 4 Jan 2013 19:00:15 +0000 (+0000) Subject: move ldap role mapper to ldap common X-Git-Tag: redback-2.1~152 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e12526fa50abfe415d8bbfef39dce074cf38cc8d;p=archiva.git move ldap role mapper to ldap common git-svn-id: https://svn.apache.org/repos/asf/archiva/redback/redback-core/trunk@1429033 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/redback-common/redback-common-ldap/pom.xml b/redback-common/redback-common-ldap/pom.xml index b54570171..7f945e6d8 100644 --- a/redback-common/redback-common-ldap/pom.xml +++ b/redback-common/redback-common-ldap/pom.xml @@ -52,17 +52,27 @@ commons-lang commons-lang - + org.slf4j slf4j-simple test + + org.easytesting + fest-assert + test + + + org.apache.archiva.redback.components + spring-apacheds + test + + + org.apache.archiva.redback + redback-policy + test + @@ -89,6 +99,34 @@ + + org.codehaus.mojo + build-helper-maven-plugin + + + allocate-ldap-port + process-classes + + reserve-network-port + + + + ldapPort + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${ldapPort} + ${basedir} + + + 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 new file mode 100644 index 000000000..721ea61e8 --- /dev/null +++ b/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/DefaultLdapRoleMapper.java @@ -0,0 +1,386 @@ +package org.apache.archiva.redback.common.ldap.role; +/* + * 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. + */ + +import org.apache.archiva.redback.common.ldap.MappingException; +import org.apache.archiva.redback.common.ldap.connection.LdapConnection; +import org.apache.archiva.redback.common.ldap.connection.LdapConnectionFactory; +import org.apache.archiva.redback.common.ldap.connection.LdapException; +import org.apache.archiva.redback.configuration.UserConfiguration; +import org.apache.archiva.redback.configuration.UserConfigurationKeys; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Named; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.DirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * @author Olivier Lamy + * @since 2.1 + */ +@Service( "ldapRoleMapper#default" ) +public class DefaultLdapRoleMapper + implements LdapRoleMapper +{ + + private Logger log = LoggerFactory.getLogger( getClass() ); + + @Inject + private LdapConnectionFactory ldapConnectionFactory; + + @Inject + @Named( value = "userConfiguration#default" ) + private UserConfiguration userConf; + + //--------------------------- + // fields + //--------------------------- + + private String ldapGroupClass = "groupOfUniqueNames"; + + private String groupsDn; + + private String baseDn; + + @PostConstruct + public void initialize() + { + this.ldapGroupClass = userConf.getString( UserConfigurationKeys.LDAP_GROUPS_CLASS, this.ldapGroupClass ); + + this.groupsDn = userConf.getString( UserConfigurationKeys.LDAP_GROUPS_BASEDN, this.groupsDn ); + + this.baseDn = userConf.getString( UserConfigurationKeys.LDAP_BASEDN, this.baseDn ); + } + + public String getLdapGroup( String role ) + { + return userConf.getString( UserConfigurationKeys.LDAP_GROUPS_ROLE_START_KEY + role ); + } + + public List getAllGroups() + throws MappingException + { + LdapConnection ldapConnection = null; + + NamingEnumeration namingEnumeration = null; + try + { + ldapConnection = ldapConnectionFactory.getConnection(); + + DirContext context = ldapConnection.getDirContext(); + + SearchControls searchControls = new SearchControls(); + + searchControls.setDerefLinkFlag( true ); + searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE ); + + String filter = "objectClass=" + getLdapGroupClass(); + + namingEnumeration = context.search( getGroupsDn(), filter, searchControls ); + + List allGroups = new ArrayList(); + + while ( namingEnumeration.hasMore() ) + { + SearchResult searchResult = namingEnumeration.next(); + + String groupName = searchResult.getName(); + // cn=blabla we only want bla bla + groupName = StringUtils.substringAfter( groupName, "=" ); + + log.debug( "found groupName: '{}", groupName ); + + allGroups.add( groupName ); + + } + + return allGroups; + } + catch ( LdapException e ) + { + throw new MappingException( e.getMessage(), e ); + } + catch ( NamingException e ) + { + throw new MappingException( e.getMessage(), e ); + } + + finally + { + if ( ldapConnection != null ) + { + ldapConnection.close(); + } + if ( namingEnumeration != null ) + { + try + { + namingEnumeration.close(); + } + catch ( NamingException e ) + { + log.warn( "failed to close search results", e ); + } + } + } + } + + public List getGroupsMember( String group ) + throws MappingException + { + LdapConnection ldapConnection = null; + + NamingEnumeration namingEnumeration = null; + try + { + ldapConnection = ldapConnectionFactory.getConnection(); + + DirContext context = ldapConnection.getDirContext(); + + SearchControls searchControls = new SearchControls(); + + searchControls.setDerefLinkFlag( true ); + searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE ); + + String filter = "objectClass=" + getLdapGroupClass(); + + namingEnumeration = context.search( "cn=" + group + "," + getGroupsDn(), filter, searchControls ); + + List allMembers = new ArrayList(); + + while ( namingEnumeration.hasMore() ) + { + SearchResult searchResult = namingEnumeration.next(); + + Attribute uniqueMemberAttr = searchResult.getAttributes().get( "uniquemember" ); + + if ( uniqueMemberAttr != null ) + { + NamingEnumeration allMembersEnum = (NamingEnumeration) uniqueMemberAttr.getAll(); + while ( allMembersEnum.hasMore() ) + { + String userName = allMembersEnum.next(); + // uid=blabla we only want bla bla + userName = StringUtils.substringAfter( userName, "=" ); + userName = StringUtils.substringBefore( userName, "," ); + log.debug( "found userName for group {}: '{}", group, userName ); + + allMembers.add( userName ); + } + close( allMembersEnum ); + } + + + } + + return allMembers; + } + catch ( LdapException e ) + { + throw new MappingException( e.getMessage(), e ); + } + catch ( NamingException e ) + { + throw new MappingException( e.getMessage(), e ); + } + + finally + { + if ( ldapConnection != null ) + { + ldapConnection.close(); + } + close( namingEnumeration ); + } + } + + public List getGroups( String username ) + throws MappingException + { + + List userGroups = new ArrayList(); + + LdapConnection ldapConnection = null; + + NamingEnumeration namingEnumeration = null; + try + { + ldapConnection = ldapConnectionFactory.getConnection(); + + DirContext context = ldapConnection.getDirContext(); + + SearchControls searchControls = new SearchControls(); + + searchControls.setDerefLinkFlag( true ); + searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE ); + + String filter = + new StringBuilder().append( "(&" ).append( "(objectClass=" + getLdapGroupClass() + ")" ).append( + "(uniquemember=" ).append( "uid=" + username + "," + this.getBaseDn() ).append( ")" ).append( + ")" ).toString(); + + log.debug( "filter: {}", filter ); + + namingEnumeration = context.search( getGroupsDn(), filter, searchControls ); + + while ( namingEnumeration.hasMore() ) + { + SearchResult searchResult = namingEnumeration.next(); + + List allMembers = new ArrayList(); + + Attribute uniqueMemberAttr = searchResult.getAttributes().get( "uniquemember" ); + + if ( uniqueMemberAttr != null ) + { + NamingEnumeration allMembersEnum = (NamingEnumeration) uniqueMemberAttr.getAll(); + while ( allMembersEnum.hasMore() ) + { + String userName = allMembersEnum.next(); + // uid=blabla we only want bla bla + userName = StringUtils.substringAfter( userName, "=" ); + userName = StringUtils.substringBefore( userName, "," ); + allMembers.add( userName ); + } + close( allMembersEnum ); + } + + if ( allMembers.contains( username ) ) + { + String groupName = searchResult.getName(); + // cn=blabla we only want bla bla + groupName = StringUtils.substringAfter( groupName, "=" ); + userGroups.add( groupName ); + + } + + + } + + return userGroups; + } + catch ( LdapException e ) + { + throw new MappingException( e.getMessage(), e ); + } + catch ( NamingException e ) + { + throw new MappingException( e.getMessage(), e ); + } + + finally + { + if ( ldapConnection != null ) + { + ldapConnection.close(); + } + close( namingEnumeration ); + } + + } + + private void close( NamingEnumeration namingEnumeration ) + { + if ( namingEnumeration != null ) + { + try + { + namingEnumeration.close(); + } + catch ( NamingException e ) + { + log.warn( "fail to close namingEnumeration: {}", e.getMessage() ); + } + } + } + + public String getGroupsDn() + { + return this.groupsDn; + } + + public String getLdapGroupClass() + { + return this.ldapGroupClass; + } + + public void addLdapMapping( String role, String ldapGroup ) + { + log.warn( "addLdapMapping not implemented" ); + } + + public void removeLdapMapping( String role ) + { + log.warn( "removeLdapMapping not implemented" ); + } + + public Map getLdapGroupMappings() + { + log.warn( "getLdapGroupMappings not implemented" ); + return Collections.emptyMap(); + } + + //--------------------------------- + // setters for unit tests + //--------------------------------- + + + public void setGroupsDn( String groupsDn ) + { + this.groupsDn = groupsDn; + } + + public void setLdapGroupClass( String ldapGroupClass ) + { + this.ldapGroupClass = ldapGroupClass; + } + + public void setUserConf( UserConfiguration userConf ) + { + this.userConf = userConf; + } + + public void setLdapConnectionFactory( LdapConnectionFactory ldapConnectionFactory ) + { + this.ldapConnectionFactory = ldapConnectionFactory; + } + + public String getBaseDn() + { + return baseDn; + } + + public void setBaseDn( String baseDn ) + { + this.baseDn = baseDn; + } +} 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 new file mode 100644 index 000000000..e37cfa34e --- /dev/null +++ b/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/LdapRoleMapper.java @@ -0,0 +1,96 @@ +package org.apache.archiva.redback.common.ldap.role; +/* + * 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. + */ + +import org.apache.archiva.redback.common.ldap.MappingException; + +import java.util.List; +import java.util.Map; + +/** + * will map ldap group to redback role + * + * @author Olivier Lamy + * @since 2.1 + */ +public interface LdapRoleMapper +{ + /** + * @param role redback role + * @return corresponding LDAP group + */ + String getLdapGroup( String role ) + throws MappingException; + + // for continuum ? + //String getLdapGroup( String role, String resource ); + + + /** + * @return all LDAP groups + */ + List getAllGroups() + throws MappingException; + + + /** + * @return the base dn which contains all ldap groups + */ + String getGroupsDn(); + + /** + * @return the class used for group usually groupOfUniqueNames + */ + String getLdapGroupClass(); + + /** + * @param group ldap group + * @return uids of group members + * @throws MappingException + */ + List getGroupsMember( String group ) + throws MappingException; + + List getGroups( String username ) + throws MappingException; + + /** + * add mapping redback role <-> ldap group + * + * @param role redback role + * @param ldapGroup ldap group + */ + void addLdapMapping( String role, String ldapGroup ) + throws MappingException; + + /** + * remove a mapping + * + * @param role redback role + */ + void removeLdapMapping( String role ) + throws MappingException; + + /** + * @return Map of corresponding Redback role (key) and LDAP group (value) + */ + Map getLdapGroupMappings() + throws MappingException; + +} diff --git a/redback-common/redback-common-ldap/src/test/java/org/apache/archiva/redback/common/ldap/role/TestLdapRoleMapper.java b/redback-common/redback-common-ldap/src/test/java/org/apache/archiva/redback/common/ldap/role/TestLdapRoleMapper.java new file mode 100644 index 000000000..c519784a8 --- /dev/null +++ b/redback-common/redback-common-ldap/src/test/java/org/apache/archiva/redback/common/ldap/role/TestLdapRoleMapper.java @@ -0,0 +1,314 @@ +package org.apache.archiva.redback.common.ldap.role; +/* + * 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. + */ + +import junit.framework.TestCase; +import org.apache.archiva.redback.components.apacheds.ApacheDs; +import org.apache.archiva.redback.policy.PasswordEncoder; +import org.apache.archiva.redback.policy.encoders.SHA1PasswordEncoder; +import org.fest.assertions.Assertions; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.BasicAttribute; +import javax.naming.directory.BasicAttributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Olivier Lamy + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration( + locations = { "classpath*:/META-INF/spring-context.xml", "classpath:/spring-context-role-mapper.xml" }) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +public class TestLdapRoleMapper + extends TestCase +{ + + Logger log = LoggerFactory.getLogger( getClass() ); + + @Inject + @Named( value = "apacheDS#test" ) + private ApacheDs apacheDs; + + private String suffix; + + private String groupSuffix; + + private PasswordEncoder passwordEncoder; + + //@Inject + //private LdapCacheService ldapCacheService; + + @Inject + @Named(value = "ldapRoleMapper#test") + LdapRoleMapper ldapRoleMapper; + + private Map> usersPerGroup; + + private List users; + + @Before + public void setUp() + throws Exception + { + super.setUp(); + + usersPerGroup = new HashMap>( 3 ); + + usersPerGroup.put( "internal-repo-manager", Arrays.asList( "admin", "user.9" ) ); + usersPerGroup.put( "internal-repo-observer", Arrays.asList( "admin", "user.7", "user.8" ) ); + usersPerGroup.put( "archiva-admin", Arrays.asList( "admin", "user.7" ) ); + + users = new ArrayList( 4 ); + users.add( "admin" ); + users.add( "user.7" ); + users.add( "user.8" ); + users.add( "user.9" ); + + passwordEncoder = new SHA1PasswordEncoder(); + + groupSuffix = apacheDs.addSimplePartition( "test", new String[]{ "archiva", "apache", "org" } ).getSuffix(); + + log.info( "groupSuffix: {}", groupSuffix ); + + suffix = "ou=People,dc=archiva,dc=apache,dc=org"; + + log.info( "DN Suffix: {}", suffix ); + + apacheDs.startServer(); + + BasicAttribute objectClass = new BasicAttribute( "objectClass" ); + objectClass.add( "top" ); + objectClass.add( "organizationalUnit" ); + + Attributes attributes = new BasicAttributes( true ); + attributes.put( objectClass ); + attributes.put( "organizationalUnitName", "foo" ); + //attributes.put( "ou", "People" ); + + apacheDs.getAdminContext().createSubcontext( suffix, attributes ); + + makeUsers(); + + createGroups(); + } + + @After + public void tearDown() + throws Exception + { + // clear cache + //ldapCacheService.removeAllUsers(); + + InitialDirContext context = apacheDs.getAdminContext(); + + for ( String uid : users ) + { + context.unbind( createDn( uid ) ); + } + + for ( Map.Entry> group : usersPerGroup.entrySet() ) + { + context.unbind( createGroupDn( group.getKey() ) ); + } + + context.unbind( suffix ); + + apacheDs.stopServer(); + + super.tearDown(); + } + + private void createGroups() + throws Exception + { + InitialDirContext context = apacheDs.getAdminContext(); + + for ( Map.Entry> group : usersPerGroup.entrySet() ) + { + createGroup( context, group.getKey(), createGroupDn( group.getKey() ), group.getValue() ); + } + + } + + private void createGroup( DirContext context, String groupName, String dn, List users ) + throws Exception + { + + Attributes attributes = new BasicAttributes( true ); + BasicAttribute objectClass = new BasicAttribute( "objectClass" ); + objectClass.add( "top" ); + objectClass.add( "groupOfUniqueNames" ); + attributes.put( objectClass ); + attributes.put( "cn", groupName ); + BasicAttribute basicAttribute = new BasicAttribute( "uniquemember" ); + for ( String user : users ) + { + basicAttribute.add( "uid=" + user + "," + suffix );// dc=archiva,dc=apache,dc=org" ); + } + + attributes.put( basicAttribute ); + context.createSubcontext( dn, attributes ); + } + + private void bindUserObject( DirContext context, String cn, String dn ) + throws Exception + { + Attributes attributes = new BasicAttributes( true ); + BasicAttribute objectClass = new BasicAttribute( "objectClass" ); + objectClass.add( "top" ); + objectClass.add( "inetOrgPerson" ); + objectClass.add( "person" ); + objectClass.add( "organizationalperson" ); + attributes.put( objectClass ); + attributes.put( "cn", cn ); + attributes.put( "sn", "foo" ); + attributes.put( "mail", cn + "@apache.org" ); + attributes.put( "userPassword", passwordEncoder.encodePassword( "foo" ) ); + attributes.put( "givenName", "foo" ); + context.createSubcontext( dn, attributes ); + } + + private void makeUsers() + throws Exception + { + + for ( String uid : users ) + { + makeUser( uid ); + } + + } + + private void makeUser( String uid ) + throws Exception + { + InitialDirContext context = apacheDs.getAdminContext(); + + bindUserObject( context, uid, createDn( uid ) ); + assertExist( context, createDn( uid ), "cn", uid ); + } + + + private void assertExist( DirContext context, String dn, String attribute, String value ) + throws NamingException + { + SearchControls ctls = new SearchControls(); + + ctls.setDerefLinkFlag( true ); + ctls.setSearchScope( SearchControls.ONELEVEL_SCOPE ); + ctls.setReturningAttributes( new String[]{ "*" } ); + + BasicAttributes matchingAttributes = new BasicAttributes(); + matchingAttributes.put( attribute, value ); + BasicAttribute objectClass = new BasicAttribute( "objectClass" ); + objectClass.add( "inetOrgPerson" ); + matchingAttributes.put( objectClass ); + + NamingEnumeration results = context.search( suffix, matchingAttributes ); + + assertTrue( results.hasMoreElements() ); + SearchResult result = results.nextElement(); + Attributes attrs = result.getAttributes(); + Attribute testAttr = attrs.get( attribute ); + assertEquals( value, testAttr.get() ); + + } + + private String createDn( String cn ) + { + return "cn=" + cn + "," + suffix; + } + + private String createGroupDn( String cn ) + { + return "cn=" + cn + "," + groupSuffix; + } + + @Test + public void getAllGroups() + throws Exception + { + List allGroups = ldapRoleMapper.getAllGroups(); + + log.info( "allGroups: {}", allGroups ); + + Assertions.assertThat( allGroups ).isNotNull().isNotEmpty().contains( "archiva-admin", + "internal-repo-manager" ); + } + + @Test + public void getGroupsMember() + throws Exception + { + List users = ldapRoleMapper.getGroupsMember( "archiva-admin" ); + + log.info( "users for archiva-admin: {}", users ); + + Assertions.assertThat( users ).isNotNull().isNotEmpty().hasSize( 2 ).contains( "admin", "user.7" ); + + users = ldapRoleMapper.getGroupsMember( "internal-repo-observer" ); + + Assertions.assertThat( users ).isNotNull().isNotEmpty().hasSize( 3 ).contains( "admin", "user.7", "user.8" ); + } + + @Test + public void getGroups() + throws Exception + { + List roles = ldapRoleMapper.getGroups( "admin" ); + + log.info( "roles for admin: {}", roles ); + + Assertions.assertThat( roles ).isNotNull().isNotEmpty().hasSize( 3 ).contains( "archiva-admin", + "internal-repo-manager", + "internal-repo-observer" ); + + roles = ldapRoleMapper.getGroups( "user.8" ); + + Assertions.assertThat( roles ).isNotNull().isNotEmpty().hasSize( 1 ).contains( "internal-repo-observer" ); + + roles = ldapRoleMapper.getGroups( "user.7" ); + + Assertions.assertThat( roles ).isNotNull().isNotEmpty().hasSize( 2 ).contains( "archiva-admin", + "internal-repo-observer" ); + } +} diff --git a/redback-common/redback-common-ldap/src/test/resources/spring-context-role-mapper.xml b/redback-common/redback-common-ldap/src/test/resources/spring-context-role-mapper.xml new file mode 100755 index 000000000..c30308064 --- /dev/null +++ b/redback-common/redback-common-ldap/src/test/resources/spring-context-role-mapper.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/java/org/apache/archiva/redback/rbac/ldap/DefaultLdapRoleMapper.java b/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/java/org/apache/archiva/redback/rbac/ldap/DefaultLdapRoleMapper.java deleted file mode 100644 index 466ad2ed3..000000000 --- a/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/java/org/apache/archiva/redback/rbac/ldap/DefaultLdapRoleMapper.java +++ /dev/null @@ -1,386 +0,0 @@ -package org.apache.archiva.redback.rbac.ldap; -/* - * 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. - */ - -import org.apache.archiva.redback.common.ldap.MappingException; -import org.apache.archiva.redback.common.ldap.connection.LdapConnection; -import org.apache.archiva.redback.common.ldap.connection.LdapConnectionFactory; -import org.apache.archiva.redback.common.ldap.connection.LdapException; -import org.apache.archiva.redback.configuration.UserConfiguration; -import org.apache.archiva.redback.configuration.UserConfigurationKeys; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import javax.inject.Named; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.DirContext; -import javax.naming.directory.SearchControls; -import javax.naming.directory.SearchResult; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * @author Olivier Lamy - * @since 2.1 - */ -@Service( "ldapRoleMapper#default" ) -public class DefaultLdapRoleMapper - implements LdapRoleMapper -{ - - private Logger log = LoggerFactory.getLogger( getClass() ); - - @Inject - private LdapConnectionFactory ldapConnectionFactory; - - @Inject - @Named( value = "userConfiguration#default" ) - private UserConfiguration userConf; - - //--------------------------- - // fields - //--------------------------- - - private String ldapGroupClass = "groupOfUniqueNames"; - - private String groupsDn; - - private String baseDn; - - @PostConstruct - public void initialize() - { - this.ldapGroupClass = userConf.getString( UserConfigurationKeys.LDAP_GROUPS_CLASS, this.ldapGroupClass ); - - this.groupsDn = userConf.getString( UserConfigurationKeys.LDAP_GROUPS_BASEDN, this.groupsDn ); - - this.baseDn = userConf.getString( UserConfigurationKeys.LDAP_BASEDN, this.baseDn ); - } - - public String getLdapGroup( String role ) - { - return userConf.getString( UserConfigurationKeys.LDAP_GROUPS_ROLE_START_KEY + role ); - } - - public List getAllGroups() - throws MappingException - { - LdapConnection ldapConnection = null; - - NamingEnumeration namingEnumeration = null; - try - { - ldapConnection = ldapConnectionFactory.getConnection(); - - DirContext context = ldapConnection.getDirContext(); - - SearchControls searchControls = new SearchControls(); - - searchControls.setDerefLinkFlag( true ); - searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE ); - - String filter = "objectClass=" + getLdapGroupClass(); - - namingEnumeration = context.search( getGroupsDn(), filter, searchControls ); - - List allGroups = new ArrayList(); - - while ( namingEnumeration.hasMore() ) - { - SearchResult searchResult = namingEnumeration.next(); - - String groupName = searchResult.getName(); - // cn=blabla we only want bla bla - groupName = StringUtils.substringAfter( groupName, "=" ); - - log.debug( "found groupName: '{}", groupName ); - - allGroups.add( groupName ); - - } - - return allGroups; - } - catch ( LdapException e ) - { - throw new MappingException( e.getMessage(), e ); - } - catch ( NamingException e ) - { - throw new MappingException( e.getMessage(), e ); - } - - finally - { - if ( ldapConnection != null ) - { - ldapConnection.close(); - } - if ( namingEnumeration != null ) - { - try - { - namingEnumeration.close(); - } - catch ( NamingException e ) - { - log.warn( "failed to close search results", e ); - } - } - } - } - - public List getGroupsMember( String group ) - throws MappingException - { - LdapConnection ldapConnection = null; - - NamingEnumeration namingEnumeration = null; - try - { - ldapConnection = ldapConnectionFactory.getConnection(); - - DirContext context = ldapConnection.getDirContext(); - - SearchControls searchControls = new SearchControls(); - - searchControls.setDerefLinkFlag( true ); - searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE ); - - String filter = "objectClass=" + getLdapGroupClass(); - - namingEnumeration = context.search( "cn=" + group + "," + getGroupsDn(), filter, searchControls ); - - List allMembers = new ArrayList(); - - while ( namingEnumeration.hasMore() ) - { - SearchResult searchResult = namingEnumeration.next(); - - Attribute uniqueMemberAttr = searchResult.getAttributes().get( "uniquemember" ); - - if ( uniqueMemberAttr != null ) - { - NamingEnumeration allMembersEnum = (NamingEnumeration) uniqueMemberAttr.getAll(); - while ( allMembersEnum.hasMore() ) - { - String userName = allMembersEnum.next(); - // uid=blabla we only want bla bla - userName = StringUtils.substringAfter( userName, "=" ); - userName = StringUtils.substringBefore( userName, "," ); - log.debug( "found userName for group {}: '{}", group, userName ); - - allMembers.add( userName ); - } - close( allMembersEnum ); - } - - - } - - return allMembers; - } - catch ( LdapException e ) - { - throw new MappingException( e.getMessage(), e ); - } - catch ( NamingException e ) - { - throw new MappingException( e.getMessage(), e ); - } - - finally - { - if ( ldapConnection != null ) - { - ldapConnection.close(); - } - close( namingEnumeration ); - } - } - - public List getGroups( String username ) - throws MappingException - { - - List userGroups = new ArrayList(); - - LdapConnection ldapConnection = null; - - NamingEnumeration namingEnumeration = null; - try - { - ldapConnection = ldapConnectionFactory.getConnection(); - - DirContext context = ldapConnection.getDirContext(); - - SearchControls searchControls = new SearchControls(); - - searchControls.setDerefLinkFlag( true ); - searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE ); - - String filter = - new StringBuilder().append( "(&" ).append( "(objectClass=" + getLdapGroupClass() + ")" ).append( - "(uniquemember=" ).append( "uid=" + username + "," + this.getBaseDn() ).append( ")" ).append( - ")" ).toString(); - - log.debug( "filter: {}", filter ); - - namingEnumeration = context.search( getGroupsDn(), filter, searchControls ); - - while ( namingEnumeration.hasMore() ) - { - SearchResult searchResult = namingEnumeration.next(); - - List allMembers = new ArrayList(); - - Attribute uniqueMemberAttr = searchResult.getAttributes().get( "uniquemember" ); - - if ( uniqueMemberAttr != null ) - { - NamingEnumeration allMembersEnum = (NamingEnumeration) uniqueMemberAttr.getAll(); - while ( allMembersEnum.hasMore() ) - { - String userName = allMembersEnum.next(); - // uid=blabla we only want bla bla - userName = StringUtils.substringAfter( userName, "=" ); - userName = StringUtils.substringBefore( userName, "," ); - allMembers.add( userName ); - } - close( allMembersEnum ); - } - - if ( allMembers.contains( username ) ) - { - String groupName = searchResult.getName(); - // cn=blabla we only want bla bla - groupName = StringUtils.substringAfter( groupName, "=" ); - userGroups.add( groupName ); - - } - - - } - - return userGroups; - } - catch ( LdapException e ) - { - throw new MappingException( e.getMessage(), e ); - } - catch ( NamingException e ) - { - throw new MappingException( e.getMessage(), e ); - } - - finally - { - if ( ldapConnection != null ) - { - ldapConnection.close(); - } - close( namingEnumeration ); - } - - } - - private void close( NamingEnumeration namingEnumeration ) - { - if ( namingEnumeration != null ) - { - try - { - namingEnumeration.close(); - } - catch ( NamingException e ) - { - log.warn( "fail to close namingEnumeration: {}", e.getMessage() ); - } - } - } - - public String getGroupsDn() - { - return this.groupsDn; - } - - public String getLdapGroupClass() - { - return this.ldapGroupClass; - } - - public void addLdapMapping( String role, String ldapGroup ) - { - log.warn( "addLdapMapping not implemented" ); - } - - public void removeLdapMapping( String role ) - { - log.warn( "removeLdapMapping not implemented" ); - } - - public Map getLdapGroupMappings() - { - log.warn( "getLdapGroupMappings not implemented" ); - return Collections.emptyMap(); - } - - //--------------------------------- - // setters for unit tests - //--------------------------------- - - - public void setGroupsDn( String groupsDn ) - { - this.groupsDn = groupsDn; - } - - public void setLdapGroupClass( String ldapGroupClass ) - { - this.ldapGroupClass = ldapGroupClass; - } - - public void setUserConf( UserConfiguration userConf ) - { - this.userConf = userConf; - } - - public void setLdapConnectionFactory( LdapConnectionFactory ldapConnectionFactory ) - { - this.ldapConnectionFactory = ldapConnectionFactory; - } - - public String getBaseDn() - { - return baseDn; - } - - public void setBaseDn( String baseDn ) - { - this.baseDn = baseDn; - } -} diff --git a/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/java/org/apache/archiva/redback/rbac/ldap/LdapRoleMapper.java b/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/java/org/apache/archiva/redback/rbac/ldap/LdapRoleMapper.java deleted file mode 100644 index 949e9b5a3..000000000 --- a/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/java/org/apache/archiva/redback/rbac/ldap/LdapRoleMapper.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.apache.archiva.redback.rbac.ldap; -/* - * 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. - */ - -import org.apache.archiva.redback.common.ldap.MappingException; - -import java.util.List; -import java.util.Map; - -/** - * will map ldap group to redback role - * - * @author Olivier Lamy - * @since 2.1 - */ -public interface LdapRoleMapper -{ - /** - * @param role redback role - * @return corresponding LDAP group - */ - String getLdapGroup( String role ) - throws MappingException; - - // for continuum ? - //String getLdapGroup( String role, String resource ); - - - /** - * @return all LDAP groups - */ - List getAllGroups() - throws MappingException; - - - /** - * @return the base dn which contains all ldap groups - */ - String getGroupsDn(); - - /** - * @return the class used for group usually groupOfUniqueNames - */ - String getLdapGroupClass(); - - /** - * @param group ldap group - * @return uids of group members - * @throws MappingException - */ - List getGroupsMember( String group ) - throws MappingException; - - List getGroups( String username ) - throws MappingException; - - /** - * add mapping redback role <-> ldap group - * - * @param role redback role - * @param ldapGroup ldap group - */ - void addLdapMapping( String role, String ldapGroup ) - throws MappingException; - - /** - * remove a mapping - * - * @param role redback role - */ - void removeLdapMapping( String role ) - throws MappingException; - - /** - * @return Map of corresponding Redback role (key) and LDAP group (value) - */ - Map getLdapGroupMappings() - throws MappingException; - -} diff --git a/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/test/java/org/apache/archiva/redback/rbac/ldap/TestLdapRoleMapper.java b/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/test/java/org/apache/archiva/redback/rbac/ldap/TestLdapRoleMapper.java deleted file mode 100644 index bf977ea90..000000000 --- a/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/test/java/org/apache/archiva/redback/rbac/ldap/TestLdapRoleMapper.java +++ /dev/null @@ -1,320 +0,0 @@ -package org.apache.archiva.redback.rbac.ldap; -/* - * 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. - */ - -import junit.framework.TestCase; -import org.apache.archiva.redback.components.apacheds.ApacheDs; -import org.apache.archiva.redback.policy.PasswordEncoder; -import org.apache.archiva.redback.policy.encoders.SHA1PasswordEncoder; -import org.apache.archiva.redback.users.UserManager; -import org.apache.archiva.redback.users.ldap.service.LdapCacheService; -import org.fest.assertions.Assertions; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.naming.NameClassPair; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import javax.naming.directory.BasicAttribute; -import javax.naming.directory.BasicAttributes; -import javax.naming.directory.DirContext; -import javax.naming.directory.InitialDirContext; -import javax.naming.directory.SearchControls; -import javax.naming.directory.SearchResult; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @author Olivier Lamy - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = { "classpath*:/META-INF/spring-context.xml", "classpath*:/spring-context.xml" }) -@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) -public class TestLdapRoleMapper - extends TestCase -{ - - Logger log = LoggerFactory.getLogger( getClass() ); - - @Inject - @Named(value = "userManager#ldap") - private UserManager userManager; - - @Inject - @Named(value = "apacheDS#test") - private ApacheDs apacheDs; - - private String suffix; - - private String groupSuffix; - - private PasswordEncoder passwordEncoder; - - @Inject - private LdapCacheService ldapCacheService; - - @Inject - @Named(value = "ldapRoleMapper#test") - LdapRoleMapper ldapRoleMapper; - - private Map> usersPerGroup; - - private List users; - - @Before - public void setUp() - throws Exception - { - super.setUp(); - - usersPerGroup = new HashMap>( 3 ); - - usersPerGroup.put( "internal-repo-manager", Arrays.asList( "admin", "user.9" ) ); - usersPerGroup.put( "internal-repo-observer", Arrays.asList( "admin", "user.7", "user.8" ) ); - usersPerGroup.put( "archiva-admin", Arrays.asList( "admin", "user.7" ) ); - - users = new ArrayList( 4 ); - users.add( "admin" ); - users.add( "user.7" ); - users.add( "user.8" ); - users.add( "user.9" ); - - passwordEncoder = new SHA1PasswordEncoder(); - - groupSuffix = apacheDs.addSimplePartition( "test", new String[]{ "archiva", "apache", "org" } ).getSuffix(); - - log.info( "groupSuffix: {}", groupSuffix ); - - suffix = "ou=People,dc=archiva,dc=apache,dc=org"; - - log.info( "DN Suffix: {}", suffix ); - - apacheDs.startServer(); - - BasicAttribute objectClass = new BasicAttribute( "objectClass" ); - objectClass.add( "top" ); - objectClass.add( "organizationalUnit" ); - - Attributes attributes = new BasicAttributes( true ); - attributes.put( objectClass ); - attributes.put( "organizationalUnitName", "foo" ); - //attributes.put( "ou", "People" ); - - apacheDs.getAdminContext().createSubcontext( suffix, attributes ); - - makeUsers(); - - createGroups(); - } - - @After - public void tearDown() - throws Exception - { - // clear cache - ldapCacheService.removeAllUsers(); - - InitialDirContext context = apacheDs.getAdminContext(); - - for ( String uid : users ) - { - context.unbind( createDn( uid ) ); - } - - for ( Map.Entry> group : usersPerGroup.entrySet() ) - { - context.unbind( createGroupDn( group.getKey() ) ); - } - - context.unbind( suffix ); - - apacheDs.stopServer(); - - super.tearDown(); - } - - private void createGroups() - throws Exception - { - InitialDirContext context = apacheDs.getAdminContext(); - - for ( Map.Entry> group : usersPerGroup.entrySet() ) - { - createGroup( context, group.getKey(), createGroupDn( group.getKey() ), group.getValue() ); - } - - } - - private void createGroup( DirContext context, String groupName, String dn, List users ) - throws Exception - { - - Attributes attributes = new BasicAttributes( true ); - BasicAttribute objectClass = new BasicAttribute( "objectClass" ); - objectClass.add( "top" ); - objectClass.add( "groupOfUniqueNames" ); - attributes.put( objectClass ); - attributes.put( "cn", groupName ); - BasicAttribute basicAttribute = new BasicAttribute( "uniquemember" ); - for ( String user : users ) - { - basicAttribute.add( "uid=" + user + "," + suffix );// dc=archiva,dc=apache,dc=org" ); - } - - attributes.put( basicAttribute ); - context.createSubcontext( dn, attributes ); - } - - private void bindUserObject( DirContext context, String cn, String dn ) - throws Exception - { - Attributes attributes = new BasicAttributes( true ); - BasicAttribute objectClass = new BasicAttribute( "objectClass" ); - objectClass.add( "top" ); - objectClass.add( "inetOrgPerson" ); - objectClass.add( "person" ); - objectClass.add( "organizationalperson" ); - attributes.put( objectClass ); - attributes.put( "cn", cn ); - attributes.put( "sn", "foo" ); - attributes.put( "mail", cn + "@apache.org" ); - attributes.put( "userPassword", passwordEncoder.encodePassword( "foo" ) ); - attributes.put( "givenName", "foo" ); - context.createSubcontext( dn, attributes ); - } - - private void makeUsers() - throws Exception - { - - for ( String uid : users ) - { - makeUser( uid ); - } - - } - - private void makeUser( String uid ) - throws Exception - { - InitialDirContext context = apacheDs.getAdminContext(); - - bindUserObject( context, uid, createDn( uid ) ); - assertExist( context, createDn( uid ), "cn", uid ); - } - - - private void assertExist( DirContext context, String dn, String attribute, String value ) - throws NamingException - { - SearchControls ctls = new SearchControls(); - - ctls.setDerefLinkFlag( true ); - ctls.setSearchScope( SearchControls.ONELEVEL_SCOPE ); - ctls.setReturningAttributes( new String[]{ "*" } ); - - BasicAttributes matchingAttributes = new BasicAttributes(); - matchingAttributes.put( attribute, value ); - BasicAttribute objectClass = new BasicAttribute( "objectClass" ); - objectClass.add( "inetOrgPerson" ); - matchingAttributes.put( objectClass ); - - NamingEnumeration results = context.search( suffix, matchingAttributes ); - - assertTrue( results.hasMoreElements() ); - SearchResult result = results.nextElement(); - Attributes attrs = result.getAttributes(); - Attribute testAttr = attrs.get( attribute ); - assertEquals( value, testAttr.get() ); - - } - - private String createDn( String cn ) - { - return "cn=" + cn + "," + suffix; - } - - private String createGroupDn( String cn ) - { - return "cn=" + cn + "," + groupSuffix; - } - - @Test - public void getAllGroups() - throws Exception - { - List allGroups = ldapRoleMapper.getAllGroups(); - - log.info( "allGroups: {}", allGroups ); - - Assertions.assertThat( allGroups ).isNotNull().isNotEmpty().contains( "archiva-admin", - "internal-repo-manager" ); - } - - @Test - public void getGroupsMember() - throws Exception - { - List users = ldapRoleMapper.getGroupsMember( "archiva-admin" ); - - log.info( "users for archiva-admin: {}", users ); - - Assertions.assertThat( users ).isNotNull().isNotEmpty().hasSize( 2 ).contains( "admin", "user.7" ); - - users = ldapRoleMapper.getGroupsMember( "internal-repo-observer" ); - - Assertions.assertThat( users ).isNotNull().isNotEmpty().hasSize( 3 ).contains( "admin", "user.7", "user.8" ); - } - - @Test - public void getGroups() - throws Exception - { - List roles = ldapRoleMapper.getGroups( "admin" ); - - log.info( "roles for admin: {}", roles ); - - Assertions.assertThat( roles ).isNotNull().isNotEmpty().hasSize( 3 ).contains( "archiva-admin", - "internal-repo-manager", - "internal-repo-observer" ); - - roles = ldapRoleMapper.getGroups( "user.8" ); - - Assertions.assertThat( roles ).isNotNull().isNotEmpty().hasSize( 1 ).contains( "internal-repo-observer" ); - - roles = ldapRoleMapper.getGroups( "user.7" ); - - Assertions.assertThat( roles ).isNotNull().isNotEmpty().hasSize( 2 ).contains( "archiva-admin", - "internal-repo-observer" ); - } -} diff --git a/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/test/resources/spring-context.xml b/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/test/resources/spring-context.xml index c87f86ddc..c30308064 100755 --- a/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/test/resources/spring-context.xml +++ b/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/test/resources/spring-context.xml @@ -51,7 +51,7 @@ - +