Improve user admin configuration
authorMathieu Baudier <mbaudier@argeo.org>
Tue, 15 Sep 2015 14:52:42 +0000 (14:52 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Tue, 15 Sep 2015 14:52:42 +0000 (14:52 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@8400 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

15 files changed:
demo/argeo_node_rap.properties
org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapNames.java [deleted file]
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapProperties.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapUserAdmin.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifAuthorization.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifName.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/cm/LdapUserAdminFactory.java [deleted file]
org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminPlugin.java

index 5ea26176484b9b3bda2597c8147614fdba49869e..2c9d5d8423490e25a8f4e22ba7d0d29be773633a 100644 (file)
@@ -12,7 +12,13 @@ org.eclipse.gemini.blueprint.extender
 argeo.osgi.start.4.workbench=\
 org.eclipse.equinox.http.registry,\
 
-#argeo.node.useradmin.uri=ldap://localhost:10389/
+#argeo.node.useradmin.uri="\
+#ldap://uid=admin,ou=system:secret\
+#@localhost:10389\
+#/dc=example,dc=com\
+#?readOnly=false\
+#&userObjectClass=inetOrgPerson \
+#dc=example,dc=org.ldif"
 
 org.osgi.framework.security=osgi
 java.security.policy=file:../../all.policy
index 6246a1b1b7f9cafb1070878656564ce5fb3cbda4..189dd08d769b14f602391c14961caa98308e07fa 100644 (file)
@@ -100,8 +100,6 @@ final class Kernel implements ServiceListener {
                        repositoryFactory = new OsgiJackrabbitRepositoryFactory();
 
                        // Authentication
-                       nodeSecurity.getUserAdmin().setSyncRegistry(
-                                       transactionManager.getTransactionSynchronizationRegistry());
                        nodeSecurity.getUserAdmin().setTransactionManager(
                                        transactionManager);
 
index 63fe750be2c8693f400cfb1587112a255d932602..e0d237da194591ca89322843a8feabebe82024b1 100644 (file)
@@ -17,7 +17,8 @@ public interface KernelConstants {
        final static String REPO_MAX_VOLATILE_INDEX_SIZE = "argeo.node.repo.maxVolatileIndexSize";
 
        // Node Security
-       /** URI to an LDIF file used as initialization or backend */
+       final static String ROLES_URI = "argeo.node.roles.uri";
+       /** URI to an LDIF file or LDAP server used as initialization or backend */
        final static String USERADMIN_URI = "argeo.node.useradmin.uri";
        final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd",
                        "/org/argeo/cms/cms.cnd" };
index 912d9fa995d2c58ea38fb350361ca4c219fa5092..579138c0f2e111965eb5b0748941322563af9c76 100644 (file)
@@ -76,6 +76,7 @@ class KernelUtils implements KernelConstants {
        }
 
        // Security
+       @Deprecated
        static void anonymousLogin(AuthenticationManager authenticationManager) {
                try {
                        List<GrantedAuthorityPrincipal> anonAuthorities = Collections
index f2cffb3ad8d479220c7e0485d93a6699ca6a1e6c..aed824fbdff830b3b21f0cbd7ba22c39e48e6821 100644 (file)
@@ -8,6 +8,7 @@ import java.security.KeyStore;
 import java.security.Provider;
 import java.security.Security;
 import java.util.Arrays;
+import java.util.Hashtable;
 
 import javax.security.auth.Subject;
 import javax.security.auth.callback.Callback;
@@ -19,14 +20,10 @@ import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
 import javax.security.auth.x500.X500Principal;
 
-import org.apache.commons.io.FileUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.cms.CmsException;
 import org.argeo.cms.KernelHeader;
-import org.argeo.osgi.useradmin.AbstractUserDirectory;
-import org.argeo.osgi.useradmin.LdapUserAdmin;
-import org.argeo.osgi.useradmin.LdifUserAdmin;
 import org.argeo.security.crypto.PkiUtils;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.osgi.framework.BundleContext;
@@ -57,14 +54,7 @@ class NodeSecurity implements AuthenticationManager {
        private final NodeUserAdmin userAdmin;
        private final Subject kernelSubject;
 
-       // private final OsAuthenticationProvider osAuth;
-       // private final InternalAuthenticationProvider internalAuth;
-       // private final AnonymousAuthenticationProvider anonymousAuth;
-       // private final JackrabbitUserAdminService userAdminService;
-
        private ServiceRegistration<AuthenticationManager> authenticationManagerReg;
-       // private ServiceRegistration<UserAdminService> userAdminServiceReg;
-       // private ServiceRegistration<UserDetailsManager> userDetailsManagerReg;
 
        private ServiceRegistration<UserAdmin> userAdminReg;
 
@@ -77,69 +67,7 @@ class NodeSecurity implements AuthenticationManager {
 
                this.bundleContext = bundleContext;
                this.kernelSubject = logKernel();
-
-               // osAuth = new OsAuthenticationProvider();
-               // internalAuth = new InternalAuthenticationProvider(
-               // Activator.getSystemKey());
-               // anonymousAuth = new AnonymousAuthenticationProvider(
-               // Activator.getSystemKey());
-
-               // user admin
-               // userAdminService = new JackrabbitUserAdminService();
-               // userAdminService.setRepository(node);
-               // userAdminService.setSecurityModel(new SimpleJcrSecurityModel());
-               // userAdminService.init();
-
                userAdmin = new NodeUserAdmin();
-
-               File osgiInstanceDir = KernelUtils.getOsgiInstanceDir();
-               File homeDir = new File(osgiInstanceDir, "node");
-               homeDir.mkdirs();
-
-               String userAdminUri = KernelUtils
-                               .getFrameworkProp(KernelConstants.USERADMIN_URI);
-               String baseDn = "dc=example,dc=com";
-               if (userAdminUri == null) {
-                       File businessRolesFile = new File(homeDir, baseDn + ".ldif");
-                       // userAdminUri = getClass().getResource(baseDn +
-                       // ".ldif").toString();
-                       if (!businessRolesFile.exists())
-                               try {
-                                       FileUtils.copyInputStreamToFile(getClass()
-                                                       .getResourceAsStream(baseDn + ".ldif"),
-                                                       businessRolesFile);
-                               } catch (IOException e) {
-                                       throw new CmsException("Cannot copy demo resource", e);
-                               }
-                       userAdminUri = businessRolesFile.toURI().toString();
-               }
-
-               AbstractUserDirectory businessRoles;
-               if (userAdminUri.startsWith("ldap"))
-                       businessRoles = new LdapUserAdmin(userAdminUri);
-               else {
-                       businessRoles = new LdifUserAdmin(userAdminUri);
-               }
-               businessRoles.init();
-               userAdmin.addUserAdmin(baseDn, businessRoles);
-
-               String baseNodeRoleDn = KernelHeader.ROLES_BASEDN;
-               File nodeRolesFile = new File(homeDir, baseNodeRoleDn + ".ldif");
-               if (!nodeRolesFile.exists())
-                       try {
-                               FileUtils.copyInputStreamToFile(
-                                               getClass().getResourceAsStream("demo.ldif"),
-                                               nodeRolesFile);
-                       } catch (IOException e) {
-                               throw new CmsException("Cannot copy demo resource", e);
-                       }
-               LdifUserAdmin nodeRoles = new LdifUserAdmin(nodeRolesFile.toURI()
-                               .toString(), false);
-               nodeRoles.setExternalRoles(userAdmin);
-               nodeRoles.init();
-               // nodeRoles.createRole(KernelHeader.ROLE_ADMIN, Role.GROUP);
-               userAdmin.addUserAdmin(baseNodeRoleDn, nodeRoles);
-
        }
 
        private Subject logKernel() {
@@ -175,25 +103,17 @@ class NodeSecurity implements AuthenticationManager {
        public void publish() {
                authenticationManagerReg = bundleContext.registerService(
                                AuthenticationManager.class, this, null);
-               // userAdminServiceReg = bundleContext.registerService(
-               // UserAdminService.class, userAdminService, null);
-               // userDetailsManagerReg = bundleContext.registerService(
-               // UserDetailsManager.class, userAdminService, null);
+               Hashtable<String, Object> properties = new Hashtable<String, Object>();
+               // properties.put(KernelConstants.USERADMIN_URI,
+               // userAdmin.asConfigUris());
                userAdminReg = bundleContext.registerService(UserAdmin.class,
-                               userAdmin, null);
+                               userAdmin, properties);
        }
 
        void destroy() {
-               // try {
-               // userAdminService.destroy();
-               // } catch (RepositoryException e) {
-               // log.error("Error while destroying Jackrabbit useradmin");
-               // }
-               // userDetailsManagerReg.unregister();
-               // userAdminServiceReg.unregister();
                authenticationManagerReg.unregister();
 
-               // userAdmin.destroy();
+               userAdmin.destroy();
                userAdminReg.unregister();
 
                // Logout kernel
@@ -219,21 +139,9 @@ class NodeSecurity implements AuthenticationManager {
        @Override
        public Authentication authenticate(Authentication authentication)
                        throws AuthenticationException {
-               log.error("Authentication manager is deprectaed and should not be used.");
-               // Authentication auth = null;
-               // if (authentication instanceof InternalAuthentication)
-               // auth = internalAuth.authenticate(authentication);
-               // else if (authentication instanceof AnonymousAuthenticationToken)
-               // auth = anonymousAuth.authenticate(authentication);
-               // else if (authentication instanceof
-               // UsernamePasswordAuthenticationToken)
-               // auth = userAdminService.authenticate(authentication);
-               // else if (authentication instanceof OsAuthenticationToken)
-               // auth = osAuth.authenticate(authentication);
-               // if (auth == null)
-               // throw new CmsException("Could not authenticate " + authentication);
+               log.error("Authentication manager is deprecated and should not be used.");
                throw new ProviderNotFoundException(
-                               "Authentication manager is deprectaed and should not be used.");
+                               "Authentication manager is deprecated and should not be used.");
        }
 
        private void createKeyStoreIfNeeded() {
@@ -248,12 +156,10 @@ class NodeSecurity implements AuthenticationManager {
                                PkiUtils.generateSelfSignedCertificate(keyStore,
                                                new X500Principal(KernelHeader.ROLE_KERNEL), keyPwd);
                                PkiUtils.saveKeyStore(keyStoreFile, ksPwd, keyStore);
-
                        } catch (Exception e) {
                                throw new CmsException("Cannot create key store "
                                                + keyStoreFile, e);
                        }
                }
        }
-
 }
index 9dd516137ebe72e268689df709c625132e290e22..e396ca09e6b7d5e0e0b0c314b0715505d09789d3 100644 (file)
@@ -1,7 +1,12 @@
 package org.argeo.cms.internal.kernel;
 
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -10,12 +15,17 @@ import java.util.Set;
 
 import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
-import javax.transaction.Transaction;
 import javax.transaction.TransactionManager;
-import javax.transaction.TransactionSynchronizationRegistry;
 
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
 import org.argeo.cms.KernelHeader;
 import org.argeo.osgi.useradmin.AbstractUserDirectory;
+import org.argeo.osgi.useradmin.LdapProperties;
+import org.argeo.osgi.useradmin.LdapUserAdmin;
+import org.argeo.osgi.useradmin.LdifUserAdmin;
 import org.argeo.osgi.useradmin.UserAdminAggregator;
 import org.argeo.osgi.useradmin.UserDirectoryException;
 import org.osgi.framework.InvalidSyntaxException;
@@ -25,6 +35,7 @@ import org.osgi.service.useradmin.User;
 import org.osgi.service.useradmin.UserAdmin;
 
 public class NodeUserAdmin implements UserAdmin, UserAdminAggregator {
+       private final static Log log = LogFactory.getLog(NodeUserAdmin.class);
        final static LdapName ROLES_BASE;
        static {
                try {
@@ -38,9 +49,125 @@ public class NodeUserAdmin implements UserAdmin, UserAdminAggregator {
        private UserAdmin nodeRoles = null;
        private Map<LdapName, UserAdmin> userAdmins = new HashMap<LdapName, UserAdmin>();
 
-       private TransactionSynchronizationRegistry syncRegistry;
        private TransactionManager transactionManager;
 
+       public NodeUserAdmin() {
+               File osgiInstanceDir = KernelUtils.getOsgiInstanceDir();
+               File nodeBaseDir = new File(osgiInstanceDir, "node");
+               nodeBaseDir.mkdirs();
+
+               String userAdminUri = KernelUtils
+                               .getFrameworkProp(KernelConstants.USERADMIN_URI);
+               if (userAdminUri == null) {
+                       String demoBaseDn = "dc=example,dc=com";
+                       File businessRolesFile = new File(nodeBaseDir, demoBaseDn + ".ldif");
+                       if (!businessRolesFile.exists())
+                               try {
+                                       FileUtils.copyInputStreamToFile(getClass()
+                                                       .getResourceAsStream(demoBaseDn + ".ldif"),
+                                                       businessRolesFile);
+                               } catch (IOException e) {
+                                       throw new CmsException("Cannot copy demo resource", e);
+                               }
+                       userAdminUri = businessRolesFile.toURI().toString();
+               }
+
+               String[] uris = userAdminUri.split(" ");
+               for (String uri : uris) {
+                       URI u;
+                       try {
+                               u = new URI(uri);
+                               if (u.getScheme() == null) {
+                                       if (uri.startsWith("/"))
+                                               u = new File(uri).getAbsoluteFile().toURI();
+                                       else if (!uri.contains("/"))
+                                               u = new File(nodeBaseDir, uri).getAbsoluteFile()
+                                                               .toURI();
+                                       else
+                                               throw new CmsException("Cannot interpret " + uri
+                                                               + " as an uri");
+                               }
+                       } catch (URISyntaxException e) {
+                               throw new CmsException(
+                                               "Cannot interpret " + uri + " as an uri", e);
+                       }
+                       Dictionary<String, ?> properties = LdapProperties.uriAsProperties(u
+                                       .toString());
+                       AbstractUserDirectory businessRoles;
+                       if (u.getScheme().startsWith("ldap")) {
+                               businessRoles = new LdapUserAdmin(properties);
+                       } else {
+                               businessRoles = new LdifUserAdmin(properties);
+                       }
+                       businessRoles.init();
+                       addUserAdmin(businessRoles.getBaseDn(), businessRoles);
+                       if (log.isDebugEnabled())
+                               log.debug("User directory " + businessRoles.getBaseDn() + " ["
+                                               + u.getScheme() + "] enabled.");
+               }
+
+               // NOde roles
+               String nodeRolesUri = KernelUtils
+                               .getFrameworkProp(KernelConstants.ROLES_URI);
+               String baseNodeRoleDn = KernelHeader.ROLES_BASEDN;
+               if (nodeRolesUri == null) {
+                       File nodeRolesFile = new File(nodeBaseDir, baseNodeRoleDn + ".ldif");
+                       if (!nodeRolesFile.exists())
+                               try {
+                                       FileUtils.copyInputStreamToFile(getClass()
+                                                       .getResourceAsStream("demo.ldif"), nodeRolesFile);
+                               } catch (IOException e) {
+                                       throw new CmsException("Cannot copy demo resource", e);
+                               }
+                       nodeRolesUri = nodeRolesFile.toURI().toString();
+               }
+
+               Dictionary<String, ?> nodeRolesProperties = LdapProperties
+                               .uriAsProperties(nodeRolesUri);
+               if (!nodeRolesProperties.get(LdapProperties.baseDn.getFullName())
+                               .equals(baseNodeRoleDn)) {
+                       throw new CmsException("Invalid base dn for node roles");
+                       // TODO deal with "mounted" roles with a different baseDN
+               }
+               AbstractUserDirectory nodeRoles;
+               if (nodeRolesUri.startsWith("ldap")) {
+                       nodeRoles = new LdapUserAdmin(nodeRolesProperties);
+               } else {
+                       nodeRoles = new LdifUserAdmin(nodeRolesProperties);
+               }
+               nodeRoles.setExternalRoles(this);
+               nodeRoles.init();
+               addUserAdmin(baseNodeRoleDn, nodeRoles);
+               if (log.isTraceEnabled())
+                       log.trace("Node roles enabled.");
+       }
+
+       String asConfigUris() {
+               StringBuilder buf = new StringBuilder();
+               for (LdapName name : userAdmins.keySet()) {
+                       buf.append('/').append(name.toString());
+                       if (userAdmins.get(name) instanceof AbstractUserDirectory) {
+                               AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins
+                                               .get(name);
+                               if (userDirectory.isReadOnly())
+                                       buf.append('?').append(LdapProperties.readOnly.name())
+                                                       .append("=true");
+                       }
+                       buf.append(' ');
+               }
+               return buf.toString();
+       }
+
+       public void destroy() {
+               for (LdapName name : userAdmins.keySet()) {
+                       if (userAdmins.get(name) instanceof AbstractUserDirectory) {
+                               AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins
+                                               .get(name);
+                               userDirectory.destroy();
+                       }
+               }
+       }
+
        @Override
        public Role createRole(String name, int type) {
                return findUserAdmin(name).createRole(name, type);
@@ -99,9 +226,6 @@ public class NodeUserAdmin implements UserAdmin, UserAdminAggregator {
        //
        @Override
        public synchronized void addUserAdmin(String baseDn, UserAdmin userAdmin) {
-               if (userAdmin instanceof AbstractUserDirectory)
-                       ((AbstractUserDirectory) userAdmin).setSyncRegistry(syncRegistry);
-
                if (baseDn.equals(KernelHeader.ROLES_BASEDN)) {
                        nodeRoles = userAdmin;
                        return;
@@ -132,9 +256,7 @@ public class NodeUserAdmin implements UserAdmin, UserAdminAggregator {
                if (!userAdmins.containsKey(base))
                        throw new UserDirectoryException("There is no user admin for "
                                        + base);
-               UserAdmin userAdmin = userAdmins.remove(base);
-               if (userAdmin instanceof AbstractUserDirectory)
-                       ((AbstractUserDirectory) userAdmin).setSyncRegistry(null);
+               userAdmins.remove(base);
        }
 
        private UserAdmin findUserAdmin(String name) {
@@ -173,16 +295,4 @@ public class NodeUserAdmin implements UserAdmin, UserAdminAggregator {
                                                .setTransactionManager(transactionManager);
                }
        }
-
-       public void setSyncRegistry(TransactionSynchronizationRegistry syncRegistry) {
-               this.syncRegistry = syncRegistry;
-               if (nodeRoles instanceof AbstractUserDirectory)
-                       ((AbstractUserDirectory) nodeRoles).setSyncRegistry(syncRegistry);
-               for (UserAdmin userAdmin : userAdmins.values()) {
-                       if (userAdmin instanceof AbstractUserDirectory)
-                               ((AbstractUserDirectory) userAdmin)
-                                               .setSyncRegistry(syncRegistry);
-               }
-       }
-
 }
index d034e2233e90edfd4a55159dd39645042570f8ae..c7448b574366679cdaf575cb65b021eb940f010b 100644 (file)
@@ -1,8 +1,17 @@
 package org.argeo.osgi.useradmin;
 
+import static org.argeo.osgi.useradmin.LdifName.inetOrgPerson;
+import static org.argeo.osgi.useradmin.LdifName.objectClass;
+import static org.argeo.osgi.useradmin.LdifName.organizationalPerson;
+import static org.argeo.osgi.useradmin.LdifName.person;
+import static org.argeo.osgi.useradmin.LdifName.top;
+
+import java.io.File;
 import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -36,6 +45,12 @@ import org.osgi.service.useradmin.UserAdmin;
 public abstract class AbstractUserDirectory implements UserAdmin {
        private final static Log log = LogFactory
                        .getLog(AbstractUserDirectory.class);
+
+       private Dictionary<String, ?> properties;
+       private String baseDn = "dc=example,dc=com";
+       private String userObjectClass;
+       private String groupObjectClass;
+
        private boolean isReadOnly;
        private URI uri;
 
@@ -54,14 +69,38 @@ public abstract class AbstractUserDirectory implements UserAdmin {
        private ThreadLocal<WorkingCopy> workingCopy = new ThreadLocal<AbstractUserDirectory.WorkingCopy>();
        private Xid editingTransactionXid = null;
 
-       public AbstractUserDirectory() {
-       }
+       public AbstractUserDirectory(Dictionary<String, ?> properties) {
+               // TODO make a copy?
+               this.properties = properties;
 
-       public AbstractUserDirectory(URI uri, boolean isReadOnly) {
-               this.uri = uri;
-               this.isReadOnly = isReadOnly;
+               String uriStr = LdapProperties.uri.getValue(properties);
+               if (uriStr == null)
+                       uri = null;
+               else
+                       try {
+                               uri = new URI(uriStr);
+                       } catch (URISyntaxException e) {
+                               throw new UserDirectoryException("Badly formatted URI", e);
+                       }
+
+               baseDn = LdapProperties.baseDn.getValue(properties).toString();
+               String isReadOnly = LdapProperties.readOnly.getValue(properties);
+               if (isReadOnly == null)
+                       this.isReadOnly = readOnlyDefault(uri);
+               else
+                       this.isReadOnly = new Boolean(isReadOnly);
+               
+               this.userObjectClass = LdapProperties.userObjectClass
+                               .getValue(properties);
+               this.groupObjectClass = LdapProperties.groupObjectClass
+                               .getValue(properties);
        }
 
+       // public AbstractUserDirectory(URI uri, boolean isReadOnly) {
+       // this.uri = uri;
+       // this.isReadOnly = isReadOnly;
+       // }
+
        /** Returns the {@link Group}s this user is a direct member of. */
        protected abstract List<? extends DirectoryGroup> getDirectGroups(User user);
 
@@ -250,18 +289,23 @@ public abstract class AbstractUserDirectory implements UserAdmin {
 
        protected DirectoryUser newRole(LdapName dn, int type, Attributes attrs) {
                LdifUser newRole;
-               BasicAttribute objectClass = new BasicAttribute("objectClass");
+               BasicAttribute objClass = new BasicAttribute(objectClass.name());
                if (type == Role.USER) {
-                       objectClass.add("inetOrgPerson");
-                       objectClass.add("organizationalPerson");
-                       objectClass.add("person");
-                       objectClass.add("top");
-                       attrs.put(objectClass);
+                       String userObjClass = getUserObjectClass();
+                       objClass.add(userObjClass);
+                       if (inetOrgPerson.name().equals(userObjClass)) {
+                               objClass.add(organizationalPerson.name());
+                               objClass.add(person.name());
+                       } else if (organizationalPerson.name().equals(userObjClass)) {
+                               objClass.add(person.name());
+                       }
+                       objClass.add(top);
+                       attrs.put(objClass);
                        newRole = new LdifUser(this, dn, attrs);
                } else if (type == Role.GROUP) {
-                       objectClass.add("groupOfNames");
-                       objectClass.add("top");
-                       attrs.put(objectClass);
+                       objClass.add(getGroupObjectClass());
+                       objClass.add(top);
+                       attrs.put(objClass);
                        newRole = new LdifGroup(this, dn, attrs);
                } else
                        throw new UserDirectoryException("Unsupported type " + type);
@@ -337,6 +381,16 @@ public abstract class AbstractUserDirectory implements UserAdmin {
                this.isReadOnly = isReadOnly;
        }
 
+       private static boolean readOnlyDefault(URI uri) {
+               if (uri == null)
+                       return true;
+               if (uri.getScheme().equals("file")) {
+                       File file = new File(uri);
+                       return !file.canWrite();
+               }
+               return true;
+       }
+
        public boolean isReadOnly() {
                return isReadOnly;
        }
@@ -345,12 +399,20 @@ public abstract class AbstractUserDirectory implements UserAdmin {
                return externalRoles;
        }
 
-       public void setExternalRoles(UserAdmin externalRoles) {
-               this.externalRoles = externalRoles;
+       public String getBaseDn() {
+               return baseDn;
        }
 
-       public void setSyncRegistry(TransactionSynchronizationRegistry syncRegistry) {
-               // this.syncRegistry = syncRegistry;
+       protected String getUserObjectClass() {
+               return userObjectClass;
+       }
+
+       protected String getGroupObjectClass() {
+               return groupObjectClass;
+       }
+
+       public void setExternalRoles(UserAdmin externalRoles) {
+               this.externalRoles = externalRoles;
        }
 
        public void setTransactionManager(TransactionManager transactionManager) {
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapNames.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapNames.java
deleted file mode 100644 (file)
index 62f4b2b..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-/**
- * Standard LDAP attributes and object classes leverages in ths implementation
- * of user admin.
- */
-public interface LdapNames {
-       public final static String LDAP_PREFIX = "ldap:";
-
-       // Attributes
-       public final static String LDAP_CN = LDAP_PREFIX + "cn";
-       public final static String LDAP_SN = LDAP_PREFIX + "sn";
-       public final static String LDAP_UID = LDAP_PREFIX + "uid";
-       public final static String LDAP_DISPLAY_NAME = LDAP_PREFIX + "displayName";
-
-}
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapProperties.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapProperties.java
new file mode 100644 (file)
index 0000000..749c8fe
--- /dev/null
@@ -0,0 +1,148 @@
+package org.argeo.osgi.useradmin;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLDecoder;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.naming.Context;
+
+public enum LdapProperties {
+       /** Base DN */
+       baseDn("dc=example,dc=com"),
+
+       /** URI of the underlying resource */
+       uri("ldap://localhost:10389"),
+
+       /** User objectClass */
+       userObjectClass("inetOrgPerson"),
+
+       /** Groups objectClass */
+       groupObjectClass("groupOfNames"),
+
+       /** Read-only source */
+       readOnly(null);
+
+       private static String PREFIX = "argeo.ldap.";
+
+       /** The default value. */
+       private Object def;
+
+       LdapProperties(Object def) {
+               this.def = def;
+       }
+
+       public Object getDefault() {
+               return def;
+       }
+
+       public String getFullName() {
+               return getPrefix() + name();
+       }
+
+       public String getPrefix() {
+               return PREFIX;
+       }
+
+       public String getValue(Dictionary<String, ?> properties) {
+               Object res = getRawValue(properties);
+               if (res == null)
+                       return null;
+               return res.toString();
+       }
+
+       @SuppressWarnings("unchecked")
+       public <T> T getRawValue(Dictionary<String, ?> properties) {
+               Object res = properties.get(getFullName());
+               if (res == null)
+                       res = getDefault();
+               return (T) res;
+       }
+
+       public static Dictionary<String, ?> uriAsProperties(String uriStr) {
+               try {
+                       Hashtable<String, Object> res = new Hashtable<String, Object>();
+                       URI u = new URI(uriStr);
+                       String scheme = u.getScheme();
+                       String path = u.getPath();
+                       String bDn = path.substring(path.lastIndexOf('/') + 1,
+                                       path.length());
+                       String principal = null;
+                       String credentials = null;
+                       if (scheme != null)
+                               if (scheme.equals("ldap") || scheme.equals("ldaps")) {
+                                       // TODO additional checks
+                                       String[] userInfo = u.getUserInfo().split(":");
+                                       principal = userInfo.length > 0 ? userInfo[0] : null;
+                                       credentials = userInfo.length > 1 ? userInfo[1] : null;
+                               } else if (scheme.equals("file")) {
+                                       if (bDn.endsWith(".ldif")) {
+                                               bDn = bDn.substring(0, bDn.length() - ".ldif".length());
+                                       }
+                               } else
+                                       throw new UserDirectoryException("Unsupported scheme "
+                                                       + scheme);
+                       Map<String, List<String>> query = splitQuery(u.getQuery());
+                       for (String key : query.keySet()) {
+                               LdapProperties ldapProp = LdapProperties.valueOf(key);
+                               List<String> values = query.get(key);
+                               if (values.size() == 1) {
+                                       res.put(ldapProp.getFullName(), values.get(0));
+                               } else {
+                                       throw new UserDirectoryException(
+                                                       "Only single values are supported");
+                               }
+                       }
+                       res.put(baseDn.getFullName(), bDn);
+                       if (principal != null)
+                               res.put(Context.SECURITY_PRINCIPAL, principal);
+                       if (credentials != null)
+                               res.put(Context.SECURITY_CREDENTIALS, credentials);
+                       if (scheme != null) {
+                               URI bareUri = new URI(scheme, null, u.getHost(), u.getPort(),
+                                               scheme.equals("file") ? u.getPath() : null, null, null);
+                               res.put(uri.getFullName(), bareUri.toString());
+                       }
+                       return res;
+               } catch (Exception e) {
+                       throw new UserDirectoryException("Cannot convert " + uri
+                                       + " to properties", e);
+               }
+       }
+
+       public static Map<String, List<String>> splitQuery(String query)
+                       throws UnsupportedEncodingException {
+               final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
+               if (query == null)
+                       return query_pairs;
+               final String[] pairs = query.split("&");
+               for (String pair : pairs) {
+                       final int idx = pair.indexOf("=");
+                       final String key = idx > 0 ? URLDecoder.decode(
+                                       pair.substring(0, idx), "UTF-8") : pair;
+                       if (!query_pairs.containsKey(key)) {
+                               query_pairs.put(key, new LinkedList<String>());
+                       }
+                       final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder
+                                       .decode(pair.substring(idx + 1), "UTF-8") : null;
+                       query_pairs.get(key).add(value);
+               }
+               return query_pairs;
+       }
+
+       public static void main(String[] args) {
+               System.out.println(uriAsProperties("ldap://"
+                               + "uid=admin,ou=system:secret@localhost:10389"
+                               + "/dc=example,dc=com"
+                               + "?readOnly=false&userObjectClass=person"));
+               System.out
+                               .println(uriAsProperties("file://some/dir/dc=example,dc=com.ldif"));
+               System.out
+                               .println(uriAsProperties("/dc=example,dc=com.ldif?readOnly=true"));
+       }
+}
index 0cb435f073e39e25b24efde6a49ac696badd0c85..7129cfb56190a1e68d8b9b124e334ed08f7fa960 100644 (file)
@@ -1,7 +1,9 @@
 package org.argeo.osgi.useradmin;
 
-import java.net.URI;
+import static org.argeo.osgi.useradmin.LdifName.objectClass;
+
 import java.util.ArrayList;
+import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.List;
 
@@ -12,42 +14,31 @@ import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 import javax.naming.directory.Attributes;
 import javax.naming.directory.DirContext;
-import javax.naming.directory.ModificationItem;
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 import javax.naming.ldap.InitialLdapContext;
-import javax.naming.ldap.LdapContext;
 import javax.naming.ldap.LdapName;
-import javax.transaction.xa.XAException;
-import javax.transaction.xa.Xid;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.ArgeoException;
 import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.useradmin.Authorization;
-import org.osgi.service.useradmin.Group;
-import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.User;
 
 public class LdapUserAdmin extends AbstractUserDirectory {
        private final static Log log = LogFactory.getLog(LdapUserAdmin.class);
 
-       private String baseDn = "dc=example,dc=com";
        private InitialLdapContext initialLdapContext = null;
 
-       public LdapUserAdmin(String uri) {
+       public LdapUserAdmin(Dictionary<String, ?> properties) {
+               super(properties);
                try {
-                       setUri(new URI(uri));
                        Hashtable<String, Object> connEnv = new Hashtable<String, Object>();
                        connEnv.put(Context.INITIAL_CONTEXT_FACTORY,
                                        "com.sun.jndi.ldap.LdapCtxFactory");
                        connEnv.put(Context.PROVIDER_URL, getUri().toString());
-                       connEnv.put("java.naming.ldap.attributes.binary", "userPassword");
-                       // connEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
-                       // connEnv.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
-                       // connEnv.put(Context.SECURITY_CREDENTIALS, "secret");
+                       connEnv.put("java.naming.ldap.attributes.binary",
+                                       LdifName.userPassword.name());
 
                        initialLdapContext = new InitialLdapContext(connEnv, null);
                        // StartTlsResponse tls = (StartTlsResponse) ctx
@@ -55,14 +46,21 @@ public class LdapUserAdmin extends AbstractUserDirectory {
                        // tls.negotiate();
                        initialLdapContext.addToEnvironment(
                                        Context.SECURITY_AUTHENTICATION, "simple");
-                       initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL,
-                                       "uid=admin,ou=system");
-                       initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS,
-                                       "secret");
-                       LdapContext ldapContext = (LdapContext) initialLdapContext
-                                       .lookup("uid=root,ou=users,dc=example,dc=com");
-                       log.debug(initialLdapContext.getAttributes(
-                                       "uid=root,ou=users,dc=example,dc=com").get("cn"));
+                       Object principal = properties.get(Context.SECURITY_PRINCIPAL);
+                       if (principal != null) {
+                               initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL,
+                                               principal.toString());
+                               Object creds = properties.get(Context.SECURITY_CREDENTIALS);
+                               if (creds != null) {
+                                       initialLdapContext.addToEnvironment(
+                                                       Context.SECURITY_CREDENTIALS, creds.toString());
+
+                               }
+                       }
+                       // initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL,
+                       // "uid=admin,ou=system");
+                       // initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS,
+                       // "secret");
                } catch (Exception e) {
                        throw new UserDirectoryException("Cannot connect to LDAP", e);
                }
@@ -77,6 +75,10 @@ public class LdapUserAdmin extends AbstractUserDirectory {
                }
        }
 
+       protected InitialLdapContext getLdapContext() {
+               return initialLdapContext;
+       }
+
        @Override
        protected Boolean daoHasRole(LdapName dn) {
                return daoGetRole(dn) != null;
@@ -85,13 +87,14 @@ public class LdapUserAdmin extends AbstractUserDirectory {
        @Override
        protected DirectoryUser daoGetRole(LdapName name) {
                try {
-                       Attributes attrs = initialLdapContext.getAttributes(name);
+                       Attributes attrs = getLdapContext().getAttributes(name);
                        if (attrs.size() == 0)
                                return null;
                        LdifUser res;
-                       if (attrs.get("objectClass").contains("groupOfNames"))
+                       if (attrs.get(objectClass.name()).contains(getGroupObjectClass()))
                                res = new LdifGroup(this, name, attrs);
-                       else if (attrs.get("objectClass").contains("inetOrgPerson"))
+                       else if (attrs.get(objectClass.name()).contains(
+                                       getUserObjectClass()))
                                res = new LdifUser(this, name, attrs);
                        else
                                throw new UserDirectoryException("Unsupported LDAP type for "
@@ -106,24 +109,27 @@ public class LdapUserAdmin extends AbstractUserDirectory {
        protected List<DirectoryUser> doGetRoles(Filter f) {
                // TODO Auto-generated method stub
                try {
-                       String searchFilter = f != null ? f.toString()
-                                       : "(|(objectClass=inetOrgPerson)(objectClass=groupOfNames))";
+                       String searchFilter = f != null ? f.toString() : "(|("
+                                       + objectClass + "=" + getUserObjectClass() + ")("
+                                       + objectClass + "=" + getGroupObjectClass() + "))";
                        SearchControls searchControls = new SearchControls();
                        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
 
-                       String searchBase = baseDn;
-                       NamingEnumeration<SearchResult> results = initialLdapContext
-                                       .search(searchBase, searchFilter, searchControls);
+                       String searchBase = getBaseDn();
+                       NamingEnumeration<SearchResult> results = getLdapContext().search(
+                                       searchBase, searchFilter, searchControls);
 
                        ArrayList<DirectoryUser> res = new ArrayList<DirectoryUser>();
                        while (results.hasMoreElements()) {
                                SearchResult searchResult = results.next();
                                Attributes attrs = searchResult.getAttributes();
                                LdifUser role;
-                               if (attrs.get("objectClass").contains("groupOfNames"))
+                               if (attrs.get(objectClass.name()).contains(
+                                               getGroupObjectClass()))
                                        role = new LdifGroup(this, toDn(searchBase, searchResult),
                                                        attrs);
-                               else if (attrs.get("objectClass").contains("inetOrgPerson"))
+                               else if (attrs.get(objectClass.name()).contains(
+                                               getUserObjectClass()))
                                        role = new LdifUser(this, toDn(searchBase, searchResult),
                                                        attrs);
                                else
@@ -143,15 +149,15 @@ public class LdapUserAdmin extends AbstractUserDirectory {
        protected void doGetUser(String key, String value,
                        List<DirectoryUser> collectedUsers) {
                try {
-                       String searchFilter = "(&(objectClass=inetOrgPerson)(" + key + "="
-                                       + value + "))";
+                       String searchFilter = "(&(" + objectClass + "="
+                                       + getUserObjectClass() + ")(" + key + "=" + value + "))";
 
                        SearchControls searchControls = new SearchControls();
                        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
 
-                       String searchBase = baseDn;
-                       NamingEnumeration<SearchResult> results = initialLdapContext
-                                       .search(searchBase, searchFilter, searchControls);
+                       String searchBase = getBaseDn();
+                       NamingEnumeration<SearchResult> results = getLdapContext().search(
+                                       searchBase, searchFilter, searchControls);
 
                        SearchResult searchResult = null;
                        if (results.hasMoreElements()) {
@@ -169,96 +175,26 @@ public class LdapUserAdmin extends AbstractUserDirectory {
 
        }
 
-       @Override
-       public User getUser(String key, String value) {
-               if (key == null) {
-                       List<User> users = new ArrayList<User>();
-                       for (String prop : getIndexedUserProperties()) {
-                               User user = getUser(prop, value);
-                               if (user != null)
-                                       users.add(user);
-                       }
-                       if (users.size() == 1)
-                               return users.get(0);
-                       else
-                               return null;
-               }
-
-               try {
-                       String searchFilter = "(&(objectClass=inetOrgPerson)(" + key + "="
-                                       + value + "))";
-
-                       SearchControls searchControls = new SearchControls();
-                       searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-
-                       String searchBase = baseDn;
-                       NamingEnumeration<SearchResult> results = initialLdapContext
-                                       .search(searchBase, searchFilter, searchControls);
-
-                       SearchResult searchResult = null;
-                       if (results.hasMoreElements()) {
-                               searchResult = (SearchResult) results.nextElement();
-                               if (results.hasMoreElements())
-                                       searchResult = null;
-                       }
-                       if (searchResult == null)
-                               return null;
-                       return new LdifUser(this, toDn(searchBase, searchResult),
-                                       searchResult.getAttributes());
-               } catch (Exception e) {
-                       throw new UserDirectoryException("Cannot get user with " + key
-                                       + "=" + value, e);
-               }
-       }
-
        private LdapName toDn(String baseDn, Binding binding)
                        throws InvalidNameException {
                return new LdapName(binding.isRelative() ? binding.getName() + ","
                                + baseDn : binding.getName());
        }
 
-       // void populateDirectMemberOf(LdifUser user) {
-       //
-       // try {
-       // String searchFilter = "(&(objectClass=groupOfNames)(member="
-       // + user.getName() + "))";
-       //
-       // SearchControls searchControls = new SearchControls();
-       // searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-       //
-       // String searchBase = "ou=node";
-       // NamingEnumeration<SearchResult> results = initialLdapContext
-       // .search(searchBase, searchFilter, searchControls);
-       //
-       // // TODO synchro
-       // //user.directMemberOf.clear();
-       // while (results.hasMoreElements()) {
-       // SearchResult searchResult = (SearchResult) results
-       // .nextElement();
-       // LdifGroup group = new LdifGroup(toDn(searchBase, searchResult),
-       // searchResult.getAttributes());
-       // populateDirectMemberOf(group);
-       // //user.directMemberOf.add(group);
-       // }
-       // } catch (Exception e) {
-       // throw new ArgeoException("Cannot populate direct members of "
-       // + user, e);
-       // }
-       // }
-
        @Override
        protected List<DirectoryGroup> getDirectGroups(User user) {
                List<DirectoryGroup> directGroups = new ArrayList<DirectoryGroup>();
                try {
-                       String searchFilter = "(&(objectClass=groupOfNames)(member="
-                                       + user.getName() + "))";
+                       String searchFilter = "(&(" + objectClass + "="
+                                       + getGroupObjectClass() + ")(" + getMemberAttributeId()
+                                       + "=" + user.getName() + "))";
 
                        SearchControls searchControls = new SearchControls();
                        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
 
-                       String searchBase = getGroupsSearchBase();
-                       NamingEnumeration<SearchResult> results = initialLdapContext
-                                       .search(searchBase, searchFilter, searchControls);
+                       String searchBase = getBaseDn();
+                       NamingEnumeration<SearchResult> results = getLdapContext().search(
+                                       searchBase, searchFilter, searchControls);
 
                        while (results.hasMoreElements()) {
                                SearchResult searchResult = (SearchResult) results
@@ -274,16 +210,10 @@ public class LdapUserAdmin extends AbstractUserDirectory {
                }
        }
 
-       protected String getGroupsSearchBase() {
-               // TODO configure group search base
-               return baseDn;
-       }
-
        @Override
        protected void prepare(WorkingCopy wc) {
                try {
-                       initialLdapContext.reconnect(initialLdapContext
-                                       .getConnectControls());
+                       getLdapContext().reconnect(getLdapContext().getConnectControls());
                        // delete
                        for (LdapName dn : wc.getDeletedUsers().keySet()) {
                                if (!entryExists(dn))
@@ -308,7 +238,7 @@ public class LdapUserAdmin extends AbstractUserDirectory {
        }
 
        private boolean entryExists(LdapName dn) throws NamingException {
-               return initialLdapContext.getAttributes(dn).size() != 0;
+               return getLdapContext().getAttributes(dn).size() != 0;
        }
 
        @Override
@@ -316,17 +246,17 @@ public class LdapUserAdmin extends AbstractUserDirectory {
                try {
                        // delete
                        for (LdapName dn : wc.getDeletedUsers().keySet()) {
-                               initialLdapContext.destroySubcontext(dn);
+                               getLdapContext().destroySubcontext(dn);
                        }
                        // add
                        for (LdapName dn : wc.getNewUsers().keySet()) {
                                DirectoryUser user = wc.getNewUsers().get(dn);
-                               initialLdapContext.createSubcontext(dn, user.getAttributes());
+                               getLdapContext().createSubcontext(dn, user.getAttributes());
                        }
                        // modify
                        for (LdapName dn : wc.getModifiedUsers().keySet()) {
                                Attributes modifiedAttrs = wc.getModifiedUsers().get(dn);
-                               initialLdapContext.modifyAttributes(dn,
+                               getLdapContext().modifyAttributes(dn,
                                                DirContext.REPLACE_ATTRIBUTE, modifiedAttrs);
                        }
                } catch (NamingException e) {
@@ -336,8 +266,7 @@ public class LdapUserAdmin extends AbstractUserDirectory {
 
        @Override
        protected void rollback(WorkingCopy wc) {
-               // TODO Auto-generated method stub
-               super.rollback(wc);
+               // prepare not impacting
        }
 
 }
index 845fefd13da483a6ee88c3c48690c0f45062ad0d..3a2aeca2ea5c2715a58ee84815d82b700b82819f 100644 (file)
@@ -9,7 +9,7 @@ import org.osgi.service.useradmin.Authorization;
 import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.User;
 
-public class LdifAuthorization implements Authorization, LdapNames {
+public class LdifAuthorization implements Authorization {
        private final String name;
        private final String displayName;
        private final List<String> allRoles;
@@ -21,16 +21,16 @@ public class LdifAuthorization implements Authorization, LdapNames {
                } else {
                        this.name = user.getName();
                        Dictionary<String, Object> props = user.getProperties();
-                       Object displayName = props.get(LDAP_DISPLAY_NAME);
+                       Object displayName = props.get(LdifName.displayName);
                        if (displayName == null)
-                               displayName = props.get(LDAP_CN);
+                               displayName = props.get(LdifName.cn);
                        if (displayName == null)
-                               displayName = props.get(LDAP_UID);
+                               displayName = props.get(LdifName.uid);
                        if (displayName == null)
                                displayName = user.getName();
                        if (displayName == null)
-                               throw new UserDirectoryException(
-                                               "Cannot set display name for " + user);
+                               throw new UserDirectoryException("Cannot set display name for "
+                                               + user);
                        this.displayName = displayName.toString();
                }
                // roles
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifName.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifName.java
new file mode 100644 (file)
index 0000000..2614b6f
--- /dev/null
@@ -0,0 +1,26 @@
+package org.argeo.osgi.useradmin;
+
+import javax.naming.ldap.LdapName;
+
+/**
+ * Standard LDAP attributes and object classes leveraged in this implementation
+ * of user admin. Named {@link LdifName} in order not to collide with
+ * {@link LdapName}.
+ */
+public enum LdifName {
+       // Attributes
+       cn, sn, uid, displayName, objectClass,userPassword,
+       // Object classes
+       inetOrgPerson, organizationalPerson, person, groupOfNames, top;
+
+       public final static String LDAP_PREFIX = "ldap:";
+
+       public String property() {
+               return LDAP_PREFIX + name();
+       }
+
+       public static LdifName local(String property) {
+               String local = property.substring(LDAP_PREFIX.length());
+               return LdifName.valueOf(local);
+       }
+}
index 608a1f7518edd88eae8450c6e3f2e8fccac51167..9bf558b313b274a035d272a4db62d0f87db01381 100644 (file)
@@ -5,10 +5,9 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Dictionary;
+import java.util.Hashtable;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -32,58 +31,35 @@ public class LdifUserAdmin extends AbstractUserDirectory {
 
        private Map<String, Map<String, DirectoryUser>> userIndexes = new LinkedHashMap<String, Map<String, DirectoryUser>>();
 
-       // private Map<LdapName, List<LdifGroup>> directMemberOf = new
-       // TreeMap<LdapName, List<LdifGroup>>();
-
-       public LdifUserAdmin(String uri) {
-               this(uri, readOnlyDefault(uri));
-       }
-
-       public LdifUserAdmin(String uri, boolean isReadOnly) {
-               setReadOnly(isReadOnly);
-               try {
-                       setUri(new URI(uri));
-               } catch (URISyntaxException e) {
-                       throw new UserDirectoryException("Invalid URI " + uri, e);
-               }
-
-               if (!isReadOnly && !getUri().getScheme().equals("file"))
-                       throw new UnsupportedOperationException(getUri().getScheme()
-                                       + " not supported read-write.");
-
+       public LdifUserAdmin(String uri, String baseDn) {
+               this(fromUri(uri, baseDn));
        }
 
-       public LdifUserAdmin(URI uri, boolean isReadOnly) {
-               setReadOnly(isReadOnly);
-               setUri(uri);
-               if (!isReadOnly && !getUri().getScheme().equals("file"))
-                       throw new UnsupportedOperationException(getUri().getScheme()
-                                       + " not supported read-write.");
-
+       public LdifUserAdmin(Dictionary<String, ?> properties) {
+               super(properties);
        }
 
        public LdifUserAdmin(InputStream in) {
+               super(new Hashtable<String, Object>());
                load(in);
                setReadOnly(true);
                setUri(null);
        }
 
-       private static boolean readOnlyDefault(String uriStr) {
-               URI uri;
-               try {
-                       uri = new URI(uriStr);
-               } catch (Exception e) {
-                       throw new UserDirectoryException("Invalid URI " + uriStr, e);
-               }
-               if (uri.getScheme().equals("file")) {
-                       File file = new File(uri);
-                       return !file.canWrite();
-               }
-               return true;
+       private static Dictionary<String, Object> fromUri(String uri, String baseDn) {
+               Hashtable<String, Object> res = new Hashtable<String, Object>();
+               res.put(LdapProperties.uri.getFullName(), uri);
+               res.put(LdapProperties.baseDn.getFullName(), baseDn);
+               return res;
        }
 
        public void init() {
                try {
+                       if (getUri().getScheme().equals("file")) {
+                               File file = new File(getUri());
+                               if (!file.exists())
+                                       return;
+                       }
                        load(getUri().toURL().openStream());
                } catch (Exception e) {
                        throw new UserDirectoryException("Cannot open URL " + getUri(), e);
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/cm/LdapUserAdminFactory.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/cm/LdapUserAdminFactory.java
deleted file mode 100644 (file)
index 42338b2..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.argeo.osgi.useradmin.cm;
-
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.argeo.osgi.useradmin.AbstractUserDirectory;
-import org.argeo.osgi.useradmin.UserDirectoryException;
-import org.argeo.osgi.useradmin.LdapUserAdmin;
-import org.argeo.osgi.useradmin.LdifUserAdmin;
-import org.argeo.osgi.useradmin.UserAdminAggregator;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedServiceFactory;
-
-public class LdapUserAdminFactory implements ManagedServiceFactory {
-       private final UserAdminAggregator userAdminAggregator;
-
-       private Map<String, String> index = new HashMap<String, String>();
-
-       public LdapUserAdminFactory(UserAdminAggregator userAdminAggregator) {
-               this.userAdminAggregator = userAdminAggregator;
-       }
-
-       @Override
-       public String getName() {
-               return "LDAP/LDIF User Source";
-       }
-
-       @Override
-       public synchronized void updated(String pid,
-                       Dictionary<String, ?> properties) throws ConfigurationException {
-               String baseDn = properties.get("baseDn").toString();
-               String userAdminUri = properties.get("uri").toString();
-               AbstractUserDirectory userAdmin;
-               if (userAdminUri.startsWith("ldap"))
-                       userAdmin = new LdapUserAdmin(userAdminUri);
-               else
-                       userAdmin = new LdifUserAdmin(userAdminUri);
-               userAdminAggregator.addUserAdmin(baseDn, userAdmin);
-               index.put(pid, baseDn);
-       }
-
-       @Override
-       public synchronized void deleted(String pid) {
-               if (index.containsKey(pid))
-                       userAdminAggregator.removeUserAdmin(index.get(pid));
-               else
-                       throw new UserDirectoryException("No user admin registered for "
-                                       + pid);
-               index.remove(pid);
-       }
-
-}
index 06e9bd5b91727aed86d6cff843eca10c9b48662d..f9c0ad9afef3da9cce2af73fafd1c259346b4691 100644 (file)
@@ -22,6 +22,7 @@ import org.osgi.framework.BundleContext;
 public class SecurityAdminPlugin extends AbstractUIPlugin {
        public static final String PLUGIN_ID = "org.argeo.security.ui.admin"; //$NON-NLS-1$
        private static SecurityAdminPlugin plugin;
+       private static BundleContext bundleContext;
 
        public SecurityAdminPlugin() {
        }
@@ -29,10 +30,12 @@ public class SecurityAdminPlugin extends AbstractUIPlugin {
        public void start(BundleContext context) throws Exception {
                super.start(context);
                plugin = this;
+               bundleContext = context;
        }
 
        public void stop(BundleContext context) throws Exception {
                plugin = null;
+               bundleContext = null;
                super.stop(context);
        }
 
@@ -40,6 +43,10 @@ public class SecurityAdminPlugin extends AbstractUIPlugin {
                return plugin;
        }
 
+       public static BundleContext getBundleContext() {
+               return bundleContext;
+       }
+
        public static ImageDescriptor getImageDescriptor(String path) {
                return imageDescriptorFromPlugin(PLUGIN_ID, path);
        }