]> source.dussan.org Git - archiva.git/commitdiff
add a ldap role mapper
authorOlivier Lamy <olamy@apache.org>
Thu, 3 Jan 2013 17:02:10 +0000 (17:02 +0000)
committerOlivier Lamy <olamy@apache.org>
Thu, 3 Jan 2013 17:02:10 +0000 (17:02 +0000)
git-svn-id: https://svn.apache.org/repos/asf/archiva/redback/redback-core/trunk@1428472 13f79535-47bb-0310-9956-ffa450edef68

redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/LdapUserMapper.java
redback-configuration/src/main/java/org/apache/archiva/redback/configuration/UserConfigurationKeys.java
redback-rbac/redback-rbac-providers/pom.xml
redback-rbac/redback-rbac-providers/redback-rbac-ldap/pom.xml [new file with mode: 0644]
redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/java/org/apache/archiva/redback/rbac/ldap/DefaultLdapRoleMapper.java [new file with mode: 0644]
redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/java/org/apache/archiva/redback/rbac/ldap/LdapRbacManager.java [new file with mode: 0644]
redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/java/org/apache/archiva/redback/rbac/ldap/LdapRoleMapper.java [new file with mode: 0644]
redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/resources/META-INF/spring-context.xml [new file with mode: 0644]
redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/test/java/org/apache/archiva/redback/rbac/ldap/TestLdapRoleMapper.java [new file with mode: 0644]
redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/test/resources/spring-context.xml [new file with mode: 0755]

index 032d87a05d7d8582cdc166005dea1d6160a54cd6..6cf3d859c67ff47ce9b4dea265faf5dbf71103c8 100644 (file)
@@ -193,7 +193,7 @@ public class LdapUserMapper
         String nameAttribute = getUserFullNameAttribute();
         String passwordAttribute = getPasswordAttribute();
 
-        String userId = ( LdapUtils.getAttributeValue( attributes, userIdAttribute, "username" ) );
+        String userId = LdapUtils.getAttributeValue( attributes, userIdAttribute, "username" );
 
         LdapUser user = new LdapUser( userId );
         user.setOriginalAttributes( attributes );
index 18f8cc9a615b3faa7ffd6ef9f7dc07ae2ec0fc2e..d6f0fd93ae8e3b6a96bf8e0df812a705a967261f 100644 (file)
@@ -72,6 +72,12 @@ public interface UserConfigurationKeys
 
     String LDAP_BINDDN = "ldap.config.bind.dn";
 
+    String LDAP_GROUPS_CLASS = "ldap.config.groups.class";
+
+    String LDAP_GROUPS_BASEDN = "ldap.config.groups.base.dn";
+
+    String LDAP_GROUPS_ROLE_START_KEY = "ldap.config.groups.role.";
+
     String APPLICATION_URL = "application.url";
 
     String EMAIL_URL_PATH = "email.url.path";
index cd42db3cbf54cc227eaef1e19c942049db847833..4717d9f1ebd36d7199a5543582161cd7211e4e46 100644 (file)
@@ -31,6 +31,6 @@
     <module>redback-rbac-jdo</module>
     <module>redback-rbac-memory</module>
     <module>redback-rbac-cached</module>
-    <!--module>redback-rbac-ldap</module-->
+    <module>redback-rbac-ldap</module>
   </modules>
 </project>
diff --git a/redback-rbac/redback-rbac-providers/redback-rbac-ldap/pom.xml b/redback-rbac/redback-rbac-providers/redback-rbac-ldap/pom.xml
new file mode 100644 (file)
index 0000000..0423d7d
--- /dev/null
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.archiva.redback</groupId>
+    <artifactId>redback-rbac-providers</artifactId>
+    <version>2.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>redback-rbac-ldap</artifactId>
+  <packaging>bundle</packaging>
+  <name>Redback :: RBAC Provider :: Ldap</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.archiva.redback</groupId>
+      <artifactId>redback-system</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva.redback</groupId>
+      <artifactId>redback-authorization-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva.redback</groupId>
+      <artifactId>redback-rbac-model</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva.redback</groupId>
+      <artifactId>redback-common-ldap</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva.redback.components.cache</groupId>
+      <artifactId>spring-cache-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva.redback.components.cache</groupId>
+      <artifactId>spring-cache-ehcache</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>net.sf.ehcache</groupId>
+      <artifactId>ehcache-core</artifactId>
+    </dependency>     
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context-support</artifactId>
+    </dependency>   
+    <dependency>
+      <groupId>javax.annotation</groupId>
+      <artifactId>jsr250-api</artifactId>
+    </dependency>    
+    <dependency>
+      <groupId>org.apache.archiva.redback</groupId>
+      <artifactId>redback-users-ldap</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva.redback</groupId>
+      <artifactId>redback-rbac-tests</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.hsqldb</groupId>
+      <artifactId>hsqldb</artifactId>
+      <scope>test</scope>
+    </dependency>    
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.easytesting</groupId>
+      <artifactId>fest-assert</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
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
new file mode 100644 (file)
index 0000000..ba2e153
--- /dev/null
@@ -0,0 +1,306 @@
+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;
+
+    @PostConstruct
+    public void initialize()
+    {
+        this.ldapGroupClass = userConf.getString( UserConfigurationKeys.LDAP_GROUPS_CLASS, this.ldapGroupClass );
+
+        this.groupsDn = userConf.getString( UserConfigurationKeys.LDAP_GROUPS_BASEDN, this.groupsDn );
+    }
+
+    public String getLdapGroup( String role )
+    {
+        return userConf.getString( UserConfigurationKeys.LDAP_GROUPS_ROLE_START_KEY + role );
+    }
+
+    public List<String> getAllGroups()
+        throws MappingException
+    {
+        // TODO caching
+        LdapConnection ldapConnection = null;
+
+        NamingEnumeration<SearchResult> 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<String> allGroups = new ArrayList<String>();
+
+            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<String> getGroupsMember( String group )
+        throws MappingException
+    {
+        // TODO caching
+        LdapConnection ldapConnection = null;
+
+        NamingEnumeration<SearchResult> 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<String> allMembers = new ArrayList<String>();
+
+            while ( namingEnumeration.hasMore() )
+            {
+                SearchResult searchResult = namingEnumeration.next();
+
+                Attribute uniqueMemberAttr = searchResult.getAttributes().get( "uniquemember" );
+
+                if ( uniqueMemberAttr != null )
+                {
+                    NamingEnumeration<String> allMembersEnum = (NamingEnumeration<String>) 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<String> getGroups( String username )
+        throws MappingException
+    {
+        // TODO caching and a filter with uid
+        List<String> allGroups = getAllGroups();
+        List<String> userGroups = new ArrayList<String>();
+        for ( String group : allGroups )
+        {
+            List<String> users = getGroupsMember( group );
+            if ( users.contains( username ) )
+            {
+                userGroups.add( group );
+            }
+        }
+        return userGroups;
+    }
+
+    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<String, String> 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;
+    }
+}
diff --git a/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/java/org/apache/archiva/redback/rbac/ldap/LdapRbacManager.java b/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/java/org/apache/archiva/redback/rbac/ldap/LdapRbacManager.java
new file mode 100644 (file)
index 0000000..afe54ba
--- /dev/null
@@ -0,0 +1,475 @@
+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.connection.LdapConnectionFactory;
+import org.apache.archiva.redback.rbac.AbstractRBACManager;
+import org.apache.archiva.redback.rbac.AbstractRole;
+import org.apache.archiva.redback.rbac.AbstractUserAssignment;
+import org.apache.archiva.redback.rbac.Operation;
+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.RbacObjectInvalidException;
+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.springframework.stereotype.Service;
+
+import javax.inject.Inject;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author Olivier Lamy
+ * @since 2.1
+ */
+@Service( "rbacManager#ldap" )
+public class LdapRbacManager
+    extends AbstractRBACManager
+    implements RBACManager
+{
+
+    @Inject
+    private LdapConnectionFactory ldapConnectionFactory;
+
+    public Role createRole( String name )
+    {
+        return new MockRole();
+    }
+
+    public Role saveRole( Role role )
+        throws RbacManagerException
+    {
+        return role;
+    }
+
+    public void saveRoles( Collection<Role> roles )
+        throws RbacManagerException
+    {
+        // no op
+    }
+
+    public Role getRole( String roleName )
+        throws RbacManagerException
+    {
+        // TODO
+        return null;
+    }
+
+    public List<Role> getAllRoles()
+        throws RbacManagerException
+    {
+        // TODO
+        return Collections.emptyList();
+    }
+
+    public void removeRole( Role role )
+        throws RbacManagerException
+    {
+        // no op
+    }
+
+    public Permission createPermission( String name )
+        throws RbacManagerException
+    {
+        return new MockPermission();
+    }
+
+    public Permission createPermission( String name, String operationName, String resourceIdentifier )
+        throws RbacManagerException
+    {
+        return new MockPermission();
+    }
+
+    public Permission savePermission( Permission permission )
+        throws RbacManagerException
+    {
+        return permission;
+    }
+
+    public Permission getPermission( String permissionName )
+        throws RbacManagerException
+    {
+        return new MockPermission();
+    }
+
+    public List<Permission> getAllPermissions()
+        throws RbacManagerException
+    {
+        // TODO
+        return Collections.emptyList();
+    }
+
+    public void removePermission( Permission permission )
+        throws RbacManagerException
+    {
+        // no op
+    }
+
+    public Operation createOperation( String name )
+        throws RbacManagerException
+    {
+        return new MockOperation();
+    }
+
+    public Operation saveOperation( Operation operation )
+        throws RbacManagerException
+    {
+        return operation;
+    }
+
+    public Operation getOperation( String operationName )
+        throws RbacManagerException
+    {
+        return new MockOperation();
+    }
+
+    public List<Operation> getAllOperations()
+        throws RbacManagerException
+    {
+        // TODO
+        return Collections.emptyList();
+    }
+
+    public void removeOperation( Operation operation )
+        throws RbacManagerException
+    {
+        // no op
+    }
+
+    public Resource createResource( String identifier )
+        throws RbacManagerException
+    {
+        return new MockResource();
+    }
+
+    public Resource saveResource( Resource resource )
+        throws RbacManagerException
+    {
+        return resource;
+    }
+
+    public Resource getResource( String resourceIdentifier )
+        throws RbacManagerException
+    {
+        // TODO
+        return new MockResource();
+    }
+
+    public List<Resource> getAllResources()
+        throws RbacManagerException
+    {
+        // TODO
+        return Collections.emptyList();
+    }
+
+    public void removeResource( Resource resource )
+        throws RbacManagerException
+    {
+        // no op
+    }
+
+    public UserAssignment createUserAssignment( String principal )
+        throws RbacManagerException
+    {
+        return new MockUserAssignment();
+    }
+
+    public UserAssignment saveUserAssignment( UserAssignment userAssignment )
+        throws RbacManagerException
+    {
+        return userAssignment;
+    }
+
+    public UserAssignment getUserAssignment( String principal )
+        throws RbacManagerException
+    {
+        // TODO
+        return new MockUserAssignment();
+    }
+
+    public List<UserAssignment> getAllUserAssignments()
+        throws RbacManagerException
+    {
+        // TODO
+        return Collections.emptyList();
+    }
+
+    public List<UserAssignment> getUserAssignmentsForRoles( Collection<String> roleNames )
+        throws RbacManagerException
+    {
+        // TODO
+        return Collections.emptyList();
+    }
+
+    public void removeUserAssignment( UserAssignment userAssignment )
+        throws RbacManagerException
+    {
+        // no op
+    }
+
+    public void eraseDatabase()
+    {
+        // no op
+    }
+
+    //-------------------------------
+    // Mock classes
+    //-------------------------------
+
+    private static class MockRole
+        extends AbstractRole
+        implements Role
+    {
+        public void addPermission( Permission permission )
+        {
+            // no op
+        }
+
+        public void addChildRoleName( String name )
+        {
+            // no op
+        }
+
+        public List<String> getChildRoleNames()
+        {
+            return Collections.emptyList();
+        }
+
+        public String getDescription()
+        {
+            return null;
+        }
+
+        public String getName()
+        {
+            return null;
+        }
+
+        public List<Permission> getPermissions()
+        {
+            return Collections.emptyList();
+        }
+
+        public boolean isAssignable()
+        {
+            return false;
+        }
+
+        public void removePermission( Permission permission )
+        {
+            // no op
+        }
+
+        public void setAssignable( boolean assignable )
+        {
+            // no op
+        }
+
+        public void setChildRoleNames( List<String> names )
+        {
+            // no op
+        }
+
+        public void setDescription( String description )
+        {
+            // no op
+        }
+
+        public void setName( String name )
+        {
+            // no op
+        }
+
+        public void setPermissions( List<Permission> permissions )
+        {
+            //To change body of implemented methods use File | Settings | File Templates.
+        }
+
+        public boolean isPermanent()
+        {
+            return false;
+        }
+
+        public void setPermanent( boolean permanent )
+        {
+            // no op
+        }
+    }
+
+    private static class MockPermission
+        implements Permission
+    {
+        public String getDescription()
+        {
+            return null;
+        }
+
+        public String getName()
+        {
+            return null;
+        }
+
+        public Operation getOperation()
+        {
+            return null;
+        }
+
+        public Resource getResource()
+        {
+            return null;
+        }
+
+        public void setDescription( String description )
+        {
+            // no op
+        }
+
+        public void setName( String name )
+        {
+            // no op
+        }
+
+        public void setOperation( Operation operation )
+        {
+            // no op
+        }
+
+        public void setResource( Resource resource )
+        {
+            // no op
+        }
+
+        public boolean isPermanent()
+        {
+            return false;
+        }
+
+        public void setPermanent( boolean permanent )
+        {
+            // no op
+        }
+    }
+
+    private static class MockOperation
+        implements Operation
+    {
+        public String getDescription()
+        {
+            return null;
+        }
+
+        public String getName()
+        {
+            return null;
+        }
+
+        public void setDescription( String description )
+        {
+            // no op
+        }
+
+        public void setName( String name )
+        {
+            // no op
+        }
+
+        public boolean isPermanent()
+        {
+            return false;
+        }
+
+        public void setPermanent( boolean permanent )
+        {
+            // no op
+        }
+    }
+
+    private static class MockResource
+        implements Resource
+    {
+        public String getIdentifier()
+        {
+            return null;
+        }
+
+        public boolean isPattern()
+        {
+            return false;
+        }
+
+        public void setIdentifier( String identifier )
+        {
+            // no op
+        }
+
+        public void setPattern( boolean pattern )
+        {
+            // no op
+        }
+
+        public boolean isPermanent()
+        {
+            return false;
+        }
+
+        public void setPermanent( boolean permanent )
+        {
+            // no op
+        }
+    }
+
+    private static class MockUserAssignment
+        extends AbstractUserAssignment
+        implements UserAssignment
+    {
+        public String getPrincipal()
+        {
+            return null;
+        }
+
+        public List<String> getRoleNames()
+        {
+            return Collections.emptyList();
+        }
+
+        public void setPrincipal( String principal )
+        {
+            // no op
+        }
+
+        public void setRoleNames( List<String> roles )
+        {
+            // no op
+        }
+
+        public boolean isPermanent()
+        {
+            return false;
+        }
+
+        public void setPermanent( boolean permanent )
+        {
+            // no op
+        }
+    }
+}
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
new file mode 100644 (file)
index 0000000..949e9b5
--- /dev/null
@@ -0,0 +1,96 @@
+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<String> 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<String> getGroupsMember( String group )
+        throws MappingException;
+
+    List<String> 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<String, String> getLdapGroupMappings()
+        throws MappingException;
+
+}
diff --git a/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/resources/META-INF/spring-context.xml b/redback-rbac/redback-rbac-providers/redback-rbac-ldap/src/main/resources/META-INF/spring-context.xml
new file mode 100644 (file)
index 0000000..dc93717
--- /dev/null
@@ -0,0 +1,115 @@
+<?xml version="1.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.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+           http://www.springframework.org/schema/context 
+           http://www.springframework.org/schema/context/spring-context-3.0.xsd"
+       default-lazy-init="true">
+
+  <context:annotation-config />
+  <context:component-scan 
+    base-package="org.apache.archiva.redback.rbac.ldap"/>
+
+  <bean name="cache#operations" class="org.apache.archiva.redback.components.cache.ehcache.EhcacheCache"
+      init-method="initialize">
+    <property name="diskPersistent" value="false"/>
+    <property name="eternal" value="false"/>
+    <property name="maxElementsInMemory" value="1000"/>
+    <property name="memoryEvictionPolicy" value="LRU"/>
+    <property name="name" value="operations"/>
+    <property name="timeToIdleSeconds" value="1800"/>
+    <property name="timeToLiveSeconds" value="14400"/>
+  </bean>
+
+  <bean name="cache#permissions" class="org.apache.archiva.redback.components.cache.ehcache.EhcacheCache"
+      init-method="initialize">
+    <property name="diskPersistent" value="false"/>
+    <property name="eternal" value="false"/>
+    <property name="maxElementsInMemory" value="1000"/>
+    <property name="memoryEvictionPolicy" value="LRU"/>
+    <property name="name" value="permissions"/>
+    <property name="timeToIdleSeconds" value="1800"/>
+    <property name="timeToLiveSeconds" value="14400"/>
+  </bean>
+
+  <bean name="cache#resources" class="org.apache.archiva.redback.components.cache.ehcache.EhcacheCache"
+      init-method="initialize">
+    <property name="diskPersistent" value="false"/>
+    <property name="eternal" value="false"/>
+    <property name="maxElementsInMemory" value="1000"/>
+    <property name="memoryEvictionPolicy" value="LRU"/>
+    <property name="name" value="resources"/>
+    <property name="timeToIdleSeconds" value="1800"/>
+    <property name="timeToLiveSeconds" value="14400"/>
+  </bean>
+
+  <bean name="cache#roles" class="org.apache.archiva.redback.components.cache.ehcache.EhcacheCache"
+      init-method="initialize">
+    <property name="diskPersistent" value="false"/>
+    <property name="eternal" value="false"/>
+    <property name="maxElementsInMemory" value="1000"/>
+    <property name="memoryEvictionPolicy" value="LRU"/>
+    <property name="name" value="roles"/>
+    <property name="timeToIdleSeconds" value="1800"/>
+    <property name="timeToLiveSeconds" value="14400"/>
+  </bean>
+
+  <bean name="cache#effectiveRoleSet" class="org.apache.archiva.redback.components.cache.ehcache.EhcacheCache"
+      init-method="initialize">
+    <property name="diskPersistent" value="false"/>
+    <property name="eternal" value="false"/>
+    <property name="maxElementsInMemory" value="1000"/>
+    <property name="memoryEvictionPolicy" value="LRU"/>
+    <property name="name" value="effectiveRoleSet"/>
+    <property name="timeToIdleSeconds" value="1800"/>
+    <property name="timeToLiveSeconds" value="14400"/>
+  </bean>
+
+  <!-- ================================================================
+         Caches with Short Term entries
+       ================================================================ -->
+
+  <bean name="cache#userAssignments" class="org.apache.archiva.redback.components.cache.ehcache.EhcacheCache"
+      init-method="initialize">
+    <property name="diskPersistent" value="false"/>
+    <property name="eternal" value="false"/>
+    <property name="maxElementsInMemory" value="1000"/>
+    <property name="memoryEvictionPolicy" value="LRU"/>
+    <property name="name" value="userAssignments"/>
+    <property name="timeToIdleSeconds" value="300"/>
+    <property name="timeToLiveSeconds" value="600"/>
+  </bean>
+
+  <bean name="cache#userPermissions" class="org.apache.archiva.redback.components.cache.ehcache.EhcacheCache"
+      init-method="initialize">
+    <property name="diskPersistent" value="false"/>
+    <property name="eternal" value="false"/>
+    <property name="maxElementsInMemory" value="1000"/>
+    <property name="memoryEvictionPolicy" value="LRU"/>
+    <property name="name" value="userPermissions"/>
+    <property name="timeToIdleSeconds" value="300"/>
+    <property name="timeToLiveSeconds" value="600"/>
+  </bean>
+
+</beans>
\ No newline at end of file
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
new file mode 100644 (file)
index 0000000..c556cfd
--- /dev/null
@@ -0,0 +1,85 @@
+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.fest.assertions.Assertions;
+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 java.util.List;
+
+/**
+ * @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 = "ldapRoleMapper#test" )
+    LdapRoleMapper ldapRoleMapper;
+
+
+    @Test
+    public void getAllGroups()
+        throws Exception
+    {
+        List<String> 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<String> users = ldapRoleMapper.getGroupsMember( "archiva-admin" );
+
+        log.info( "users for archiva-admin: {}", users );
+
+        Assertions.assertThat( users ).isNotNull().isNotEmpty().contains( "admin", "user.7" );
+    }
+
+    @Test
+    public void getGroups()
+        throws Exception
+    {
+        List<String> roles = ldapRoleMapper.getGroups( "admin" );
+
+        log.info( "roles for admin: {}", roles );
+
+        Assertions.assertThat( roles ).isNotNull().isNotEmpty().contains( "archiva-admin", "internal-repo-manager" );
+    }
+}
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
new file mode 100755 (executable)
index 0000000..403f419
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.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.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
+       default-lazy-init="false">
+
+  <alias name="userConfiguration#redback" alias="userConfiguration#default"/>
+
+  <bean name="ldapConnectionFactory#configurable" class="org.apache.archiva.redback.common.ldap.connection.ConfigurableLdapConnectionFactory">
+    <property name="hostname" value="localhost"/>
+    <property name="port" value="1389"/>
+    <!--property name="baseDn" value="dc=redback,dc=plexus,dc=codehaus,dc=org"/-->
+    <property name="baseDn" value="dc=archiva,dc=apache,dc=org"/>
+    <property name="contextFactory" value="com.sun.jndi.ldap.LdapCtxFactory"/>
+    <property name="password" value="theadmin"/>
+    <!--property name="bindDn" value="uid=admin,ou=system"/-->
+    <property name="bindDn" value="uid=admin,ou=People,dc=archiva,dc=apache,dc=org"/>
+    <property name="userConf" ref="userConfiguration#default"/>
+  </bean>
+
+
+
+  <bean name="ldapRoleMapper#test" class="org.apache.archiva.redback.rbac.ldap.DefaultLdapRoleMapper">
+    <property name="groupsDn" value="dc=archiva,dc=apache,dc=org"/>
+    <property name="ldapGroupClass" value="groupOfUniqueNames"/>
+    <property name="ldapConnectionFactory" ref="ldapConnectionFactory#configurable"/>
+    <property name="userConf" ref="userConfiguration#default"/>
+  </bean>
+
+</beans>
\ No newline at end of file