Improve Security
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 5 Nov 2011 13:23:44 +0000 (13:23 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 5 Nov 2011 13:23:44 +0000 (13:23 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@4888 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

15 files changed:
security/modules/org.argeo.security.dao.ldap/META-INF/spring/security-ldap.xml
security/modules/org.argeo.security.dao.ldap/ldap.properties
security/modules/org.argeo.security.services/.project [deleted file]
security/modules/org.argeo.security.services/META-INF/spring/osgi.xml [deleted file]
security/modules/org.argeo.security.services/META-INF/spring/services.xml [deleted file]
security/modules/org.argeo.security.services/build.properties [deleted file]
security/modules/org.argeo.security.services/pom.xml [deleted file]
security/modules/org.argeo.security.services/security.properties [deleted file]
security/modules/pom.xml
security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/wizards/NewUserWizard.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/UserAdminDao.java [deleted file]
security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/ArgeoLdapUserDetailsManager.java
security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java [deleted file]
security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/ArgeoUserAdminDaoLdap.java [new file with mode: 0644]
security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java

index 8ce3081e423babc24fca6f19a122eddea511005d..a31f79dc124416260fd4e4f17b3e1513ae5bd8af 100644 (file)
        <!-- </bean> -->
 
        <!-- USER DETAILS -->
-       <bean id="userAdminDao" class="org.argeo.security.ldap.ArgeoSecurityDaoLdap">
+       <bean id="userDetailsManager" class="org.argeo.security.ldap.ArgeoLdapUserDetailsManager">
+               <constructor-arg ref="contextSource" />
+               <property name="groupSearchBase" value="${argeo.ldap.groupBase}" />
+               <property name="groupMemberAttributeName" value="${argeo.ldap.groupMemberAttribute}" />
+               <property name="usernameMapper" ref="usernameMapper" />
+               <property name="userDetailsMapper" ref="jcrLdapSynchronizer" />
+               <property name="userAdminDao" ref="userAdminDao" />
+               <property name="passwordEncoder" ref="passwordEncoder" />
+               <property name="passwordAttributeName" value="${argeo.ldap.passwordAttribute}" />
+       </bean>
+
+       <bean id="userAdminDao" class="org.argeo.security.ldap.ArgeoUserAdminDaoLdap">
                <constructor-arg ref="contextSource" />
                <property name="userBase" value="${argeo.ldap.userBase}" />
                <property name="usernameAttribute" value="${argeo.ldap.usernameAttribute}" />
                <property name="rolePrefix" value="${argeo.security.rolePrefix}" />
        </bean>
 
-       <bean id="userDetailsManager" class="org.argeo.security.ldap.ArgeoLdapUserDetailsManager">
-               <constructor-arg ref="contextSource" />
-               <property name="groupSearchBase" value="${argeo.ldap.groupBase}" />
-               <property name="groupMemberAttributeName" value="${argeo.ldap.groupMemberAttribute}" />
-               <property name="usernameMapper" ref="usernameMapper" />
-               <property name="userDetailsMapper" ref="jcrLdapSynchronizer" />
-               <property name="userAdminDao" ref="userAdminDao" />
-               <property name="passwordEncoder" ref="passwordEncoder" />
-               <property name="passwordAttributeName" value="${argeo.ldap.passwordAttribute}" />
-       </bean>
-
        <!-- LDAP LOW LEVEL -->
        <bean id="contextSource"
                class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
index b96150b192f633ec52e199b2e22056f9a659858d..b00b5261f311c6f4842884260746b7c775f9a3d9 100644 (file)
@@ -15,6 +15,7 @@ argeo.ldap.manager.password=secret
 
 # USER
 argeo.ldap.userClass=inetOrgPerson
+argeo.ldap.osUserClass=posixAccount
 argeo.ldap.userBase=ou=People
 argeo.ldap.usernameAttribute=uid
 argeo.ldap.passwordAttribute=userPassword
@@ -23,5 +24,10 @@ argeo.ldap.groupClass=groupOfNames
 argeo.ldap.groupBase=ou=Roles
 argeo.ldap.groupRoleAttribute=cn
 argeo.ldap.groupMemberAttribute=member
+# OS GROUPS
+argeo.ldap.osGroupClass=posixGroup
+argeo.ldap.osGroupBase=ou=Group
+argeo.ldap.osGroupNameAttribute=cn
+argeo.ldap.osGroupMemberAttribute=memberUid
 
 argeo.ldap.password.useSalt=false
\ No newline at end of file
diff --git a/security/modules/org.argeo.security.services/.project b/security/modules/org.argeo.security.services/.project
deleted file mode 100644 (file)
index e2c51e6..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.security.services</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.pde.ManifestBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.SchemaBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.pde.PluginNature</nature>
-       </natures>
-</projectDescription>
diff --git a/security/modules/org.argeo.security.services/META-INF/spring/osgi.xml b/security/modules/org.argeo.security.services/META-INF/spring/osgi.xml
deleted file mode 100644 (file)
index 1730348..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>\r
-<beans:beans xmlns="http://www.springframework.org/schema/osgi"\r
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"\r
-       xsi:schemaLocation="http://www.springframework.org/schema/osgi  \r
-       http://www.springframework.org/schema/osgi/spring-osgi-1.1.xsd\r
-       http://www.springframework.org/schema/beans   \r
-       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">\r
-\r
-       <!-- REFERENCES -->\r
-       <list id="authenticationProviders"\r
-               interface="org.springframework.security.providers.AuthenticationProvider"\r
-               cardinality="0..N">\r
-               <listener ref="authenticationProvidersRegister" bind-method="register"\r
-                       unbind-method="unregister" />\r
-       </list>\r
-\r
-       <!-- SERVICES -->\r
-       <service ref="systemExecutionService" interface="org.argeo.security.SystemExecutionService" />\r
-\r
-       <service ref="authenticationManager"\r
-               interface="org.springframework.security.AuthenticationManager" />\r
-</beans:beans>
\ No newline at end of file
diff --git a/security/modules/org.argeo.security.services/META-INF/spring/services.xml b/security/modules/org.argeo.security.services/META-INF/spring/services.xml
deleted file mode 100644 (file)
index 1a56b85..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<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-2.5.xsd">
-
-       <bean
-               class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
-               <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
-               <property name="locations">
-                       <value>osgibundle:security.properties</value>
-               </property>
-       </bean>
-
-       <bean id="systemExecutionService" class="org.argeo.security.core.KeyBasedSystemExecutionService">
-               <property name="authenticationManager" ref="authenticationManager" />
-               <property name="systemAuthenticationKey" value="${argeo.security.systemKey}" />
-       </bean>
-
-       <bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
-               <property name="providers">
-                       <bean factory-bean="authenticationProvidersRegister"
-                               factory-method="getProviders" />
-               </property>
-       </bean>
-       <bean id="authenticationProvidersRegister" class="org.argeo.security.core.AuthenticationProvidersRegister">
-               <property name="defaultProviders">
-                       <list>
-                               <bean class="org.springframework.security.adapters.AuthByAdapterProvider">
-                                       <property name="key" value="${argeo.security.systemKey}" />
-                               </bean>
-                               <bean class="org.argeo.security.core.OsAuthenticationProvider" />
-                               <bean
-                                       class="org.springframework.security.providers.anonymous.AnonymousAuthenticationProvider">
-                                       <property name="key" value="${argeo.security.systemKey}" />
-                               </bean>
-                       </list>
-               </property>
-       </bean>
-</beans>
\ No newline at end of file
diff --git a/security/modules/org.argeo.security.services/build.properties b/security/modules/org.argeo.security.services/build.properties
deleted file mode 100644 (file)
index 5f22cdd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-bin.includes = META-INF/
diff --git a/security/modules/org.argeo.security.services/pom.xml b/security/modules/org.argeo.security.services/pom.xml
deleted file mode 100644 (file)
index 17f86f0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<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.argeo.commons.security</groupId>
-               <version>0.3.4-SNAPSHOT</version>
-               <artifactId>modules</artifactId>
-               <relativePath>..</relativePath>
-       </parent>
-       <artifactId>org.argeo.security.services</artifactId>
-       <name>Commons Security Services</name>
-</project>
\ No newline at end of file
diff --git a/security/modules/org.argeo.security.services/security.properties b/security/modules/org.argeo.security.services/security.properties
deleted file mode 100644 (file)
index ae7aa87..0000000
+++ /dev/null
@@ -1 +0,0 @@
-argeo.security.systemKey=argeo
index 8d10e4d9214b6dcbe238f0d55eba1084763c6e21..7a05b23dc404f01d624cff9e2ccc83327b4d377b 100644 (file)
@@ -15,7 +15,6 @@
                <module>org.argeo.security.dao.os</module>
                <module>org.argeo.security.dao.jackrabbit</module>
                <module>org.argeo.security.dao.ldap</module>
-               <module>org.argeo.security.services</module>
                <module>org.argeo.security.webapp</module>
        </modules>
        <build>
index aa1351815eb130f5af1e8614a8b8811d9ca3344f..3af4fa954f7ee87d3537e95cc98ea6b264dc2777 100644 (file)
@@ -41,8 +41,8 @@ public class NewUserWizard extends Wizard {
                String username = mainUserInfo.getUsername();
                try {
                        Node userProfile = JcrUtils.createUserProfile(session, username);
-                       session.getWorkspace().getVersionManager()
-                                       .checkout(userProfile.getPath());
+                       // session.getWorkspace().getVersionManager()
+                       // .checkout(userProfile.getPath());
                        mainUserInfo.mapToProfileNode(userProfile);
                        String password = mainUserInfo.getPassword();
                        // TODO add roles
diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/UserAdminDao.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/UserAdminDao.java
deleted file mode 100644 (file)
index cf8c77b..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.argeo.security;
-
-import java.util.Set;
-
-/**
- * Access to the users and roles referential (dependent from the underlying
- * storage, e.g. LDAP).
- */
-public interface UserAdminDao {
-       /** List all users */
-       public Set<String> listUsers();
-
-       /** List roles that can be modified */
-       public Set<String> listEditableRoles();
-
-       /**
-        * Creates a new role in the underlying storage. <b>DO NOT CALL DIRECTLY</b>
-        * use {@link ArgeoSecurityService#newRole(String)} instead.
-        */
-       public void createRole(String role, String superuserName);
-
-       public void deleteRole(String role);
-
-       /** List all users having this role. */
-       public Set<String> listUsersInRole(String role);
-
-}
index 392ac4a27edcea9d2ef911097e3a83659f03dc0c..5de5f7bb73174ba59c7fa924d41169e7811ffbc1 100644 (file)
@@ -11,7 +11,6 @@ import java.util.Set;
 import java.util.TreeSet;
 
 import org.argeo.ArgeoException;
-import org.argeo.security.UserAdminDao;
 import org.argeo.security.UserAdminService;
 import org.springframework.ldap.core.ContextSource;
 import org.springframework.security.Authentication;
@@ -25,7 +24,7 @@ import org.springframework.security.userdetails.ldap.LdapUserDetailsManager;
 public class ArgeoLdapUserDetailsManager extends LdapUserDetailsManager
                implements UserAdminService {
        private String superUsername = "root";
-       private UserAdminDao userAdminDao;
+       private ArgeoUserAdminDaoLdap userAdminDao;
        private PasswordEncoder passwordEncoder;
        private final Random random;
 
@@ -124,7 +123,7 @@ public class ArgeoLdapUserDetailsManager extends LdapUserDetailsManager
                this.superUsername = superUsername;
        }
 
-       public void setUserAdminDao(UserAdminDao userAdminDao) {
+       public void setUserAdminDao(ArgeoUserAdminDaoLdap userAdminDao) {
                this.userAdminDao = userAdminDao;
        }
 
diff --git a/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java b/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java
deleted file mode 100644 (file)
index dc6cd63..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.argeo.security.ldap;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-
-import javax.naming.Name;
-import javax.naming.NamingException;
-import javax.naming.directory.DirContext;
-
-import org.argeo.security.UserAdminDao;
-import org.springframework.ldap.core.ContextExecutor;
-import org.springframework.ldap.core.ContextMapper;
-import org.springframework.ldap.core.DirContextAdapter;
-import org.springframework.ldap.core.DistinguishedName;
-import org.springframework.ldap.core.LdapTemplate;
-import org.springframework.ldap.core.support.BaseLdapPathContextSource;
-import org.springframework.security.ldap.LdapUsernameToDnMapper;
-import org.springframework.security.ldap.LdapUtils;
-
-/**
- * Wraps a Spring LDAP user details manager, providing additional methods to
- * manage roles.
- */
-public class ArgeoSecurityDaoLdap implements UserAdminDao {
-       private String userBase;
-       private String usernameAttribute;
-       private String groupBase;
-       private String[] groupClasses;
-
-       private String groupRoleAttribute;
-       private String groupMemberAttribute;
-       private String defaultRole;
-       private String rolePrefix;
-
-       private final LdapTemplate ldapTemplate;
-       private LdapUsernameToDnMapper usernameMapper;
-
-       /**
-        * Standard constructor, using the LDAP context source shared with Spring
-        * Security components.
-        */
-       public ArgeoSecurityDaoLdap(BaseLdapPathContextSource contextSource) {
-               this.ldapTemplate = new LdapTemplate(contextSource);
-       }
-
-       @SuppressWarnings("unchecked")
-       public synchronized Set<String> listUsers() {
-               List<String> usernames = (List<String>) ldapTemplate.listBindings(
-                               new DistinguishedName(userBase), new ContextMapper() {
-                                       public Object mapFromContext(Object ctxArg) {
-                                               DirContextAdapter ctx = (DirContextAdapter) ctxArg;
-                                               return ctx.getStringAttribute(usernameAttribute);
-                                       }
-                               });
-
-               return Collections
-                               .unmodifiableSortedSet(new TreeSet<String>(usernames));
-       }
-
-       @SuppressWarnings("unchecked")
-       public Set<String> listEditableRoles() {
-               return Collections.unmodifiableSortedSet(new TreeSet<String>(
-                               ldapTemplate.listBindings(groupBase, new ContextMapper() {
-                                       public Object mapFromContext(Object ctxArg) {
-                                               String groupName = ((DirContextAdapter) ctxArg)
-                                                               .getStringAttribute(groupRoleAttribute);
-                                               String roleName = convertGroupToRole(groupName);
-                                               return roleName;
-                                       }
-                               })));
-       }
-
-       @SuppressWarnings("unchecked")
-       public Set<String> listUsersInRole(String role) {
-               return (Set<String>) ldapTemplate.lookup(
-                               buildGroupDn(convertRoleToGroup(role)), new ContextMapper() {
-                                       public Object mapFromContext(Object ctxArg) {
-                                               DirContextAdapter ctx = (DirContextAdapter) ctxArg;
-                                               String[] userDns = ctx
-                                                               .getStringAttributes(groupMemberAttribute);
-                                               TreeSet<String> set = new TreeSet<String>();
-                                               for (String userDn : userDns) {
-                                                       DistinguishedName dn = new DistinguishedName(userDn);
-                                                       String username = dn.getValue(usernameAttribute);
-                                                       set.add(username);
-                                               }
-                                               return Collections.unmodifiableSortedSet(set);
-                                       }
-                               });
-       }
-
-       public void createRole(String role, final String superuserName) {
-               String group = convertRoleToGroup(role);
-               DistinguishedName superuserDn = (DistinguishedName) ldapTemplate
-                               .executeReadWrite(new ContextExecutor() {
-                                       public Object executeWithContext(DirContext ctx)
-                                                       throws NamingException {
-                                               return LdapUtils.getFullDn(
-                                                               usernameMapper.buildDn(superuserName), ctx);
-                                       }
-                               });
-
-               Name groupDn = buildGroupDn(group);
-               DirContextAdapter context = new DirContextAdapter();
-               context.setAttributeValues("objectClass", groupClasses);
-               context.setAttributeValue("cn", group);
-               // Add superuser because cannot create empty group
-               context.setAttributeValue(groupMemberAttribute, superuserDn.toString());
-               ldapTemplate.bind(groupDn, context, null);
-       }
-
-       public void deleteRole(String role) {
-               String group = convertRoleToGroup(role);
-               Name dn = buildGroupDn(group);
-               ldapTemplate.unbind(dn);
-       }
-
-       /** Maps a role (ROLE_XXX) to the related LDAP group (xxx) */
-       protected String convertRoleToGroup(String role) {
-               String group = role;
-               if (group.startsWith(rolePrefix)) {
-                       group = group.substring(rolePrefix.length());
-                       group = group.toLowerCase();
-               }
-               return group;
-       }
-
-       /** Maps anLDAP group (xxx) to the related role (ROLE_XXX) */
-       protected String convertGroupToRole(String groupName) {
-               groupName = groupName.toUpperCase();
-
-               return rolePrefix + groupName;
-       }
-
-       protected Name buildGroupDn(String name) {
-               return new DistinguishedName(groupRoleAttribute + "=" + name + ","
-                               + groupBase);
-       }
-
-       public void setUserBase(String userBase) {
-               this.userBase = userBase;
-       }
-
-       public void setUsernameAttribute(String usernameAttribute) {
-               this.usernameAttribute = usernameAttribute;
-       }
-
-       public void setGroupBase(String groupBase) {
-               this.groupBase = groupBase;
-       }
-
-       public void setGroupRoleAttribute(String groupRoleAttributeName) {
-               this.groupRoleAttribute = groupRoleAttributeName;
-       }
-
-       public void setGroupMemberAttribute(String groupMemberAttributeName) {
-               this.groupMemberAttribute = groupMemberAttributeName;
-       }
-
-       public void setDefaultRole(String defaultRole) {
-               this.defaultRole = defaultRole;
-       }
-
-       public void setRolePrefix(String rolePrefix) {
-               this.rolePrefix = rolePrefix;
-       }
-
-       public void setUsernameMapper(LdapUsernameToDnMapper usernameMapper) {
-               this.usernameMapper = usernameMapper;
-       }
-
-       public String getDefaultRole() {
-               return defaultRole;
-       }
-
-       public void setGroupClasses(String[] groupClasses) {
-               this.groupClasses = groupClasses;
-       }
-}
diff --git a/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/ArgeoUserAdminDaoLdap.java b/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/ArgeoUserAdminDaoLdap.java
new file mode 100644 (file)
index 0000000..082e737
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.argeo.security.ldap;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+
+import org.springframework.ldap.core.ContextExecutor;
+import org.springframework.ldap.core.ContextMapper;
+import org.springframework.ldap.core.DirContextAdapter;
+import org.springframework.ldap.core.DistinguishedName;
+import org.springframework.ldap.core.LdapTemplate;
+import org.springframework.ldap.core.support.BaseLdapPathContextSource;
+import org.springframework.security.ldap.LdapUsernameToDnMapper;
+import org.springframework.security.ldap.LdapUtils;
+
+/**
+ * Wraps low-level LDAP operation on user and roles, used by
+ * {@link ArgeoLdapUserDetailsManager}
+ */
+public class ArgeoUserAdminDaoLdap {
+       private String userBase;
+       private String usernameAttribute;
+       private String groupBase;
+       private String[] groupClasses;
+
+       private String groupRoleAttribute;
+       private String groupMemberAttribute;
+       private String defaultRole;
+       private String rolePrefix;
+
+       private final LdapTemplate ldapTemplate;
+       private LdapUsernameToDnMapper usernameMapper;
+
+       /**
+        * Standard constructor, using the LDAP context source shared with Spring
+        * Security components.
+        */
+       public ArgeoUserAdminDaoLdap(BaseLdapPathContextSource contextSource) {
+               this.ldapTemplate = new LdapTemplate(contextSource);
+       }
+
+       @SuppressWarnings("unchecked")
+       public synchronized Set<String> listUsers() {
+               List<String> usernames = (List<String>) ldapTemplate.listBindings(
+                               new DistinguishedName(userBase), new ContextMapper() {
+                                       public Object mapFromContext(Object ctxArg) {
+                                               DirContextAdapter ctx = (DirContextAdapter) ctxArg;
+                                               return ctx.getStringAttribute(usernameAttribute);
+                                       }
+                               });
+
+               return Collections
+                               .unmodifiableSortedSet(new TreeSet<String>(usernames));
+       }
+
+       @SuppressWarnings("unchecked")
+       public Set<String> listEditableRoles() {
+               return Collections.unmodifiableSortedSet(new TreeSet<String>(
+                               ldapTemplate.listBindings(groupBase, new ContextMapper() {
+                                       public Object mapFromContext(Object ctxArg) {
+                                               String groupName = ((DirContextAdapter) ctxArg)
+                                                               .getStringAttribute(groupRoleAttribute);
+                                               String roleName = convertGroupToRole(groupName);
+                                               return roleName;
+                                       }
+                               })));
+       }
+
+       @SuppressWarnings("unchecked")
+       public Set<String> listUsersInRole(String role) {
+               return (Set<String>) ldapTemplate.lookup(
+                               buildGroupDn(convertRoleToGroup(role)), new ContextMapper() {
+                                       public Object mapFromContext(Object ctxArg) {
+                                               DirContextAdapter ctx = (DirContextAdapter) ctxArg;
+                                               String[] userDns = ctx
+                                                               .getStringAttributes(groupMemberAttribute);
+                                               TreeSet<String> set = new TreeSet<String>();
+                                               for (String userDn : userDns) {
+                                                       DistinguishedName dn = new DistinguishedName(userDn);
+                                                       String username = dn.getValue(usernameAttribute);
+                                                       set.add(username);
+                                               }
+                                               return Collections.unmodifiableSortedSet(set);
+                                       }
+                               });
+       }
+
+       public void createRole(String role, final String superuserName) {
+               String group = convertRoleToGroup(role);
+               DistinguishedName superuserDn = (DistinguishedName) ldapTemplate
+                               .executeReadWrite(new ContextExecutor() {
+                                       public Object executeWithContext(DirContext ctx)
+                                                       throws NamingException {
+                                               return LdapUtils.getFullDn(
+                                                               usernameMapper.buildDn(superuserName), ctx);
+                                       }
+                               });
+
+               Name groupDn = buildGroupDn(group);
+               DirContextAdapter context = new DirContextAdapter();
+               context.setAttributeValues("objectClass", groupClasses);
+               context.setAttributeValue("cn", group);
+               // Add superuser because cannot create empty group
+               context.setAttributeValue(groupMemberAttribute, superuserDn.toString());
+               ldapTemplate.bind(groupDn, context, null);
+       }
+
+       public void deleteRole(String role) {
+               String group = convertRoleToGroup(role);
+               Name dn = buildGroupDn(group);
+               ldapTemplate.unbind(dn);
+       }
+
+       /** Maps a role (ROLE_XXX) to the related LDAP group (xxx) */
+       protected String convertRoleToGroup(String role) {
+               String group = role;
+               if (group.startsWith(rolePrefix)) {
+                       group = group.substring(rolePrefix.length());
+                       group = group.toLowerCase();
+               }
+               return group;
+       }
+
+       /** Maps anLDAP group (xxx) to the related role (ROLE_XXX) */
+       protected String convertGroupToRole(String groupName) {
+               groupName = groupName.toUpperCase();
+
+               return rolePrefix + groupName;
+       }
+
+       protected Name buildGroupDn(String name) {
+               return new DistinguishedName(groupRoleAttribute + "=" + name + ","
+                               + groupBase);
+       }
+
+       public void setUserBase(String userBase) {
+               this.userBase = userBase;
+       }
+
+       public void setUsernameAttribute(String usernameAttribute) {
+               this.usernameAttribute = usernameAttribute;
+       }
+
+       public void setGroupBase(String groupBase) {
+               this.groupBase = groupBase;
+       }
+
+       public void setGroupRoleAttribute(String groupRoleAttributeName) {
+               this.groupRoleAttribute = groupRoleAttributeName;
+       }
+
+       public void setGroupMemberAttribute(String groupMemberAttributeName) {
+               this.groupMemberAttribute = groupMemberAttributeName;
+       }
+
+       public void setDefaultRole(String defaultRole) {
+               this.defaultRole = defaultRole;
+       }
+
+       public void setRolePrefix(String rolePrefix) {
+               this.rolePrefix = rolePrefix;
+       }
+
+       public void setUsernameMapper(LdapUsernameToDnMapper usernameMapper) {
+               this.usernameMapper = usernameMapper;
+       }
+
+       public String getDefaultRole() {
+               return defaultRole;
+       }
+
+       public void setGroupClasses(String[] groupClasses) {
+               this.groupClasses = groupClasses;
+       }
+}
index 3a644a6939209abb0213837c747fb72aedc04928..0f59f1ee528c11561e8d9a67b6d4a3c13bb4b1d0 100644 (file)
@@ -336,9 +336,12 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                        Node userProfile = securitySession.getNode(
                                        jcrUserDetails.getHomePath()).getNode(ARGEO_PROFILE);
                        for (String jcrProperty : propertyToAttributes.keySet()) {
-                               ModificationItem mi = jcrToLdap(jcrProperty, userProfile
-                                               .getProperty(jcrProperty).getString());
-                               ctx.setAttribute(mi.getAttribute());
+                               if (userProfile.hasProperty(jcrProperty)) {
+                                       ModificationItem mi = jcrToLdap(jcrProperty, userProfile
+                                                       .getProperty(jcrProperty).getString());
+                                       if (mi != null)
+                                               ctx.setAttribute(mi.getAttribute());
+                               }
                        }
                        if (log.isTraceEnabled())
                                log.trace("Mapped " + userProfile + " to " + ctx.getDn());