LDIF user admin persistence based on transactions.
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 12 Sep 2015 11:25:51 +0000 (11:25 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 12 Sep 2015 11:25:51 +0000 (11:25 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@8388 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

29 files changed:
org.argeo.cms/bnd.bnd
org.argeo.cms/src/org/argeo/cms/KernelHeader.java
org.argeo.cms/src/org/argeo/cms/internal/auth/KernelLoginModule.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.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.cms/src/org/argeo/cms/internal/kernel/jaas.cfg
org.argeo.cms/src/org/argeo/cms/internal/transaction/SimpleTransaction.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/transaction/SimpleTransactionManager.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/transaction/UuidXid.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractLdapUserAdmin.java [deleted file]
org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/ArgeoUserAdminException.java [deleted file]
org.argeo.security.core/src/org/argeo/osgi/useradmin/AttributeDictionary.java [deleted file]
org.argeo.security.core/src/org/argeo/osgi/useradmin/DirectoryGroup.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/DirectoryUser.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/EditorRole.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapNames.java
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/LdifGroup.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUser.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifWriter.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminWorkingCopy.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/UserDirectoryException.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/UserDirectoryTransaction.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/cm/LdapUserAdminFactory.java
org.argeo.security.core/src/org/argeo/security/crypto/PkiUtils.java

index 1034b39fab694b32351624790f0a5a6ea9629ea6..6eecc6b85ce1dd6b4c73aeb72a5f1d1d6788399c 100644 (file)
@@ -21,5 +21,6 @@ org.apache.commons.vfs2.*;resolution:=optional,\
 org.apache.jackrabbit.*;resolution:=optional,\
 org.springframework.ldap.*;resolution:=optional,\
 org.springframework.security.ldap.*;resolution:=optional,\
+org.springframework.security.provisioning;resolution:=optional,\
 org.joda.time.*;resolution:=optional,\
 *
index f0e738a60988c899ebe457db62fd69bb7a86afee..8f817df791c73514c3ba0474bbeebad13c84113a 100644 (file)
@@ -2,6 +2,8 @@ package org.argeo.cms;
 
 /** Public properties of the CMS Kernel */
 public interface KernelHeader {
+       final static String SECURITY_PROVIDER = "BC";// Bouncy Castle
+
        // LOGIN CONTEXTS
        final static String LOGIN_CONTEXT_USER = "USER";
        final static String LOGIN_CONTEXT_ANONYMOUS = "ANONYMOUS";
index ee36d3534c8e005bfd9b2adf42db42e501680afc..f96bc88808b76e39a51331d1c622f7ca5a6ec3ad 100644 (file)
@@ -27,7 +27,7 @@ public class KernelLoginModule implements LoginModule {
 
        @Override
        public boolean login() throws LoginException {
-               // TODO check permission at code level
+               // TODO check permission at code level ?
                return true;
        }
 
index 08697503916bfca8c38f154d76d65915c3970e0a..6246a1b1b7f9cafb1070878656564ce5fb3cbda4 100644 (file)
@@ -1,38 +1,26 @@
 package org.argeo.cms.internal.kernel;
 
-import java.io.File;
-import java.io.IOException;
 import java.lang.management.ManagementFactory;
-import java.net.URL;
-import java.security.KeyStore;
 import java.security.PrivilegedAction;
-import java.security.cert.X509Certificate;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
 import javax.jcr.Repository;
 import javax.jcr.RepositoryFactory;
 import javax.security.auth.Subject;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-import javax.security.auth.x500.X500Principal;
+import javax.transaction.TransactionManager;
+import javax.transaction.TransactionSynchronizationRegistry;
+import javax.transaction.UserTransaction;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.jackrabbit.util.TransientFileFactory;
 import org.argeo.ArgeoException;
 import org.argeo.cms.CmsException;
-import org.argeo.cms.KernelHeader;
+import org.argeo.cms.internal.transaction.SimpleTransactionManager;
 import org.argeo.jackrabbit.OsgiJackrabbitRepositoryFactory;
 import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.security.core.InternalAuthentication;
-import org.argeo.security.crypto.PkiUtils;
 import org.eclipse.equinox.http.servlet.ExtendedHttpService;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceEvent;
@@ -53,62 +41,34 @@ import org.springframework.security.core.context.SecurityContextHolder;
  * </ul>
  */
 final class Kernel implements ServiceListener {
-
        private final static Log log = LogFactory.getLog(Kernel.class);
 
        private final BundleContext bundleContext = Activator.getBundleContext();
+       private final NodeSecurity nodeSecurity;
 
        ThreadGroup threadGroup = new ThreadGroup(Kernel.class.getSimpleName());
        JackrabbitNode node;
-       OsgiJackrabbitRepositoryFactory repositoryFactory;
-       NodeSecurity nodeSecurity;
-       NodeHttp nodeHttp;
-       private KernelThread kernelThread;
 
-       private final Subject kernelSubject = new Subject();
+       private SimpleTransactionManager transactionManager;
+       private OsgiJackrabbitRepositoryFactory repositoryFactory;
+       private NodeHttp nodeHttp;
+       private KernelThread kernelThread;
 
        public Kernel() {
-               URL url = getClass().getClassLoader().getResource(
-                               KernelConstants.JAAS_CONFIG);
-               System.setProperty("java.security.auth.login.config",
-                               url.toExternalForm());
-               createKeyStoreIfNeeded();
-
-               CallbackHandler cbHandler = new CallbackHandler() {
-
-                       @Override
-                       public void handle(Callback[] callbacks) throws IOException,
-                                       UnsupportedCallbackException {
-                               // alias
-                               ((NameCallback) callbacks[1]).setName(KernelHeader.ROLE_KERNEL);
-                               // store pwd
-                               ((PasswordCallback) callbacks[2]).setPassword("changeit"
-                                               .toCharArray());
-                               // key pwd
-                               ((PasswordCallback) callbacks[3]).setPassword("changeit"
-                                               .toCharArray());
-                       }
-               };
-               try {
-                       LoginContext kernelLc = new LoginContext(
-                                       KernelConstants.LOGIN_CONTEXT_KERNEL, kernelSubject,
-                                       cbHandler);
-                       kernelLc.login();
-               } catch (LoginException e) {
-                       throw new CmsException("Cannot log in kernel", e);
-               }
+               nodeSecurity = new NodeSecurity(bundleContext);
        }
 
        final void init() {
-               Subject.doAs(kernelSubject, new PrivilegedAction<Void>() {
+               Subject.doAs(nodeSecurity.getKernelSubject(),
+                               new PrivilegedAction<Void>() {
 
-                       @Override
-                       public Void run() {
-                               doInit();
-                               return null;
-                       }
+                                       @Override
+                                       public Void run() {
+                                               doInit();
+                                               return null;
+                                       }
 
-               });
+                               });
        }
 
        private void doInit() {
@@ -122,6 +82,17 @@ final class Kernel implements ServiceListener {
                SecurityContextHolder.getContext().setAuthentication(initAuth);
 
                try {
+                       // Transaction
+                       transactionManager = new SimpleTransactionManager();
+                       bundleContext.registerService(TransactionManager.class,
+                                       transactionManager, null);
+                       bundleContext.registerService(UserTransaction.class,
+                                       transactionManager, null);
+                       bundleContext.registerService(
+                                       TransactionSynchronizationRegistry.class,
+                                       transactionManager.getTransactionSynchronizationRegistry(),
+                                       null);
+
                        // Jackrabbit node
                        node = new JackrabbitNode(bundleContext);
 
@@ -129,7 +100,10 @@ final class Kernel implements ServiceListener {
                        repositoryFactory = new OsgiJackrabbitRepositoryFactory();
 
                        // Authentication
-                       nodeSecurity = new NodeSecurity(bundleContext, node);
+                       nodeSecurity.getUserAdmin().setSyncRegistry(
+                                       transactionManager.getTransactionSynchronizationRegistry());
+                       nodeSecurity.getUserAdmin().setTransactionManager(
+                                       transactionManager);
 
                        // Equinox dependency
                        ExtendedHttpService httpService = waitForHttpService();
@@ -170,8 +144,8 @@ final class Kernel implements ServiceListener {
 
                if (nodeHttp != null)
                        nodeHttp.destroy();
-               if (nodeSecurity != null)
-                       nodeSecurity.destroy();
+               // if (nodeSecurity != null)
+               // nodeSecurity.destroy();
                if (node != null)
                        node.destroy();
 
@@ -180,14 +154,10 @@ final class Kernel implements ServiceListener {
                // Clean hanging threads from Jackrabbit
                TransientFileFactory.shutdown();
 
-               try {
-                       LoginContext kernelLc = new LoginContext(
-                                       KernelConstants.LOGIN_CONTEXT_KERNEL, kernelSubject);
-                       kernelLc.logout();
-               } catch (LoginException e) {
-                       throw new CmsException("Cannot log in kernel", e);
-               }
+               // Clean hanging Gogo shell thread
+               new GogoShellKiller().start();
 
+               nodeSecurity.destroy();
                long duration = System.currentTimeMillis() - begin;
                log.info("## ARGEO CMS DOWN in " + (duration / 1000) + "."
                                + (duration % 1000) + "s ##");
@@ -237,25 +207,6 @@ final class Kernel implements ServiceListener {
                return httpService;
        }
 
-       private void createKeyStoreIfNeeded() {
-               char[] ksPwd = "changeit".toCharArray();
-               char[] keyPwd = Arrays.copyOf(ksPwd, ksPwd.length);
-               File keyStoreFile = KernelUtils.getOsgiConfigurationFile("node.p12");
-               if (!keyStoreFile.exists()) {
-                       try {
-                               KeyStore keyStore = PkiUtils.getKeyStore(keyStoreFile, ksPwd);
-                               X509Certificate cert = 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);
-                       }
-               }
-       }
-
        final private static void directorsCut(long initDuration) {
                // final long ms = 128l + (long) (Math.random() * 128d);
                long ms = initDuration / 100;
@@ -276,4 +227,62 @@ final class Kernel implements ServiceListener {
                                        + String.format("%.2f", 100 - (sleepAccuracy * 100 - 100))
                                        + " %");
        }
+
+       /** Workaround for blocking Gogo shell by system shutdown. */
+       private class GogoShellKiller extends Thread {
+
+               public GogoShellKiller() {
+                       super("Gogo shell killer");
+                       setDaemon(true);
+               }
+
+               @Override
+               public void run() {
+                       ThreadGroup rootTg = getRootThreadGroup(null);
+                       Thread gogoShellThread = findGogoShellThread(rootTg);
+                       if (gogoShellThread == null)
+                               return;
+                       while (getNonDaemonCount(rootTg) > 2) {
+                               try {
+                                       Thread.sleep(100);
+                               } catch (InterruptedException e) {
+                                       // silent
+                               }
+                       }
+                       gogoShellThread = findGogoShellThread(rootTg);
+                       if (gogoShellThread == null)
+                               return;
+                       System.exit(0);
+               }
+       }
+
+       private static ThreadGroup getRootThreadGroup(ThreadGroup tg) {
+               if (tg == null)
+                       tg = Thread.currentThread().getThreadGroup();
+               if (tg.getParent() == null)
+                       return tg;
+               else
+                       return getRootThreadGroup(tg.getParent());
+       }
+
+       private static int getNonDaemonCount(ThreadGroup rootThreadGroup) {
+               Thread[] threads = new Thread[rootThreadGroup.activeCount()];
+               rootThreadGroup.enumerate(threads);
+               int nonDameonCount = 0;
+               for (Thread t : threads)
+                       if (!t.isDaemon())
+                               nonDameonCount++;
+               return nonDameonCount;
+       }
+
+       private static Thread findGogoShellThread(ThreadGroup rootThreadGroup) {
+               Thread[] threads = new Thread[rootThreadGroup.activeCount()];
+               rootThreadGroup.enumerate(threads, true);
+               for (Thread thread : threads) {
+                       if (thread.getName().equals("Gogo shell"))
+                               return thread;
+               }
+               return null;
+       }
+
 }
\ No newline at end of file
index 13ecac4b09c1c599248420b2df2699114b1b3330..f2cffb3ad8d479220c7e0485d93a6699ca6a1e6c 100644 (file)
@@ -2,79 +2,119 @@ package org.argeo.cms.internal.kernel;
 
 import java.io.File;
 import java.io.IOException;
+import java.net.URL;
+import java.nio.file.ProviderNotFoundException;
+import java.security.KeyStore;
+import java.security.Provider;
+import java.security.Security;
+import java.util.Arrays;
 
-import javax.jcr.RepositoryException;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+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.cms.internal.useradmin.SimpleJcrSecurityModel;
-import org.argeo.cms.internal.useradmin.jackrabbit.JackrabbitUserAdminService;
-import org.argeo.osgi.useradmin.AbstractLdapUserAdmin;
+import org.argeo.osgi.useradmin.AbstractUserDirectory;
 import org.argeo.osgi.useradmin.LdapUserAdmin;
 import org.argeo.osgi.useradmin.LdifUserAdmin;
-import org.argeo.security.OsAuthenticationToken;
-import org.argeo.security.UserAdminService;
-import org.argeo.security.core.InternalAuthentication;
-import org.argeo.security.core.InternalAuthenticationProvider;
-import org.argeo.security.core.OsAuthenticationProvider;
+import org.argeo.security.crypto.PkiUtils;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.UserAdmin;
-import org.springframework.security.authentication.AnonymousAuthenticationProvider;
-import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.provisioning.UserDetailsManager;
 
 /** Authentication and user management. */
 class NodeSecurity implements AuthenticationManager {
-       private final static Log log = LogFactory.getLog(NodeSecurity.class);
+       private final static Log log;
+       static {
+               log = LogFactory.getLog(NodeSecurity.class);
+               // Make Bouncy Castle the default provider
+               Provider provider = new BouncyCastleProvider();
+               int position = Security.insertProviderAt(provider, 1);
+               if (position == -1)
+                       log.error("Provider " + provider.getName()
+                                       + " already installed and could not be set as default");
+               Provider defaultProvider = Security.getProviders()[0];
+               if (!defaultProvider.getName().equals(KernelHeader.SECURITY_PROVIDER))
+                       log.error("Provider name is " + defaultProvider.getName()
+                                       + " but it should be " + KernelHeader.SECURITY_PROVIDER);
+       }
 
        private final BundleContext bundleContext;
-
-       private final OsAuthenticationProvider osAuth;
-       private final InternalAuthenticationProvider internalAuth;
-       private final AnonymousAuthenticationProvider anonymousAuth;
-       private final JackrabbitUserAdminService userAdminService;
        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<UserAdminService> userAdminServiceReg;
+       // private ServiceRegistration<UserDetailsManager> userDetailsManagerReg;
 
        private ServiceRegistration<UserAdmin> userAdminReg;
 
-       public NodeSecurity(BundleContext bundleContext, JackrabbitNode node)
-                       throws RepositoryException {
+       public NodeSecurity(BundleContext bundleContext) {
+               // Configure JAAS first
+               URL url = getClass().getClassLoader().getResource(
+                               KernelConstants.JAAS_CONFIG);
+               System.setProperty("java.security.auth.login.config",
+                               url.toExternalForm());
+
                this.bundleContext = bundleContext;
+               this.kernelSubject = logKernel();
 
-               osAuth = new OsAuthenticationProvider();
-               internalAuth = new InternalAuthenticationProvider(
-                               Activator.getSystemKey());
-               anonymousAuth = new AnonymousAuthenticationProvider(
-                               Activator.getSystemKey());
+               // 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();
+               // userAdminService = new JackrabbitUserAdminService();
+               // userAdminService.setRepository(node);
+               // userAdminService.setSecurityModel(new SimpleJcrSecurityModel());
+               // userAdminService.init();
 
                userAdmin = new NodeUserAdmin();
 
-               String baseDn = "dc=example,dc=com";
+               File osgiInstanceDir = KernelUtils.getOsgiInstanceDir();
+               File homeDir = new File(osgiInstanceDir, "node");
+               homeDir.mkdirs();
+
                String userAdminUri = KernelUtils
                                .getFrameworkProp(KernelConstants.USERADMIN_URI);
-               if (userAdminUri == null)
-                       userAdminUri = getClass().getResource(baseDn + ".ldif").toString();
+               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();
+               }
 
-               AbstractLdapUserAdmin businessRoles;
+               AbstractUserDirectory businessRoles;
                if (userAdminUri.startsWith("ldap"))
                        businessRoles = new LdapUserAdmin(userAdminUri);
                else {
@@ -83,19 +123,18 @@ class NodeSecurity implements AuthenticationManager {
                businessRoles.init();
                userAdmin.addUserAdmin(baseDn, businessRoles);
 
-               File osgiInstanceDir = KernelUtils.getOsgiInstanceDir();
-               File homeDir = new File(osgiInstanceDir, "node");
-
                String baseNodeRoleDn = KernelHeader.ROLES_BASEDN;
                File nodeRolesFile = new File(homeDir, baseNodeRoleDn + ".ldif");
-               try {
-                       FileUtils.copyInputStreamToFile(
-                                       getClass().getResourceAsStream("demo.ldif"), nodeRolesFile);
-               } catch (IOException e) {
-                       throw new CmsException("Cannot copy demo resource", e);
-               }
+               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());
+                               .toString(), false);
                nodeRoles.setExternalRoles(userAdmin);
                nodeRoles.init();
                // nodeRoles.createRole(KernelHeader.ROLE_ADMIN, Role.GROUP);
@@ -103,47 +142,118 @@ class NodeSecurity implements AuthenticationManager {
 
        }
 
+       private Subject logKernel() {
+               final Subject kernelSubject = new Subject();
+               createKeyStoreIfNeeded();
+
+               CallbackHandler cbHandler = new CallbackHandler() {
+
+                       @Override
+                       public void handle(Callback[] callbacks) throws IOException,
+                                       UnsupportedCallbackException {
+                               // alias
+                               ((NameCallback) callbacks[1]).setName(KernelHeader.ROLE_KERNEL);
+                               // store pwd
+                               ((PasswordCallback) callbacks[2]).setPassword("changeit"
+                                               .toCharArray());
+                               // key pwd
+                               ((PasswordCallback) callbacks[3]).setPassword("changeit"
+                                               .toCharArray());
+                       }
+               };
+               try {
+                       LoginContext kernelLc = new LoginContext(
+                                       KernelConstants.LOGIN_CONTEXT_KERNEL, kernelSubject,
+                                       cbHandler);
+                       kernelLc.login();
+               } catch (LoginException e) {
+                       throw new CmsException("Cannot log in kernel", e);
+               }
+               return kernelSubject;
+       }
+
        public void publish() {
                authenticationManagerReg = bundleContext.registerService(
                                AuthenticationManager.class, this, null);
-               userAdminServiceReg = bundleContext.registerService(
-                               UserAdminService.class, userAdminService, null);
-               userDetailsManagerReg = bundleContext.registerService(
-                               UserDetailsManager.class, userAdminService, null);
+               // userAdminServiceReg = bundleContext.registerService(
+               // UserAdminService.class, userAdminService, null);
+               // userDetailsManagerReg = bundleContext.registerService(
+               // UserDetailsManager.class, userAdminService, null);
                userAdminReg = bundleContext.registerService(UserAdmin.class,
                                userAdmin, null);
        }
 
        void destroy() {
-               try {
-                       userAdminService.destroy();
-               } catch (RepositoryException e) {
-                       log.error("Error while destroying Jackrabbit useradmin");
-               }
-               userDetailsManagerReg.unregister();
-               userAdminServiceReg.unregister();
+               // try {
+               // userAdminService.destroy();
+               // } catch (RepositoryException e) {
+               // log.error("Error while destroying Jackrabbit useradmin");
+               // }
+               // userDetailsManagerReg.unregister();
+               // userAdminServiceReg.unregister();
                authenticationManagerReg.unregister();
 
                // userAdmin.destroy();
                userAdminReg.unregister();
+
+               // Logout kernel
+               try {
+                       LoginContext kernelLc = new LoginContext(
+                                       KernelConstants.LOGIN_CONTEXT_KERNEL, kernelSubject);
+                       kernelLc.logout();
+               } catch (LoginException e) {
+                       throw new CmsException("Cannot log in kernel", e);
+               }
+
+               Security.removeProvider(KernelHeader.SECURITY_PROVIDER);
+       }
+
+       public NodeUserAdmin getUserAdmin() {
+               return userAdmin;
+       }
+
+       public Subject getKernelSubject() {
+               return kernelSubject;
        }
 
        @Override
        public Authentication authenticate(Authentication authentication)
                        throws AuthenticationException {
-//             throw new UnsupportedOperationException(
-//                             "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);
-               return auth;
+               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);
+               throw new ProviderNotFoundException(
+                               "Authentication manager is deprectaed and should not be used.");
        }
+
+       private void createKeyStoreIfNeeded() {
+               char[] ksPwd = "changeit".toCharArray();
+               char[] keyPwd = Arrays.copyOf(ksPwd, ksPwd.length);
+               File keyStoreFile = new File(KernelUtils.getOsgiInstanceDir(),
+                               "node.p12");
+               if (!keyStoreFile.exists()) {
+                       try {
+                               keyStoreFile.getParentFile().mkdirs();
+                               KeyStore keyStore = PkiUtils.getKeyStore(keyStoreFile, ksPwd);
+                               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 19e52937eed8f1dc401578b9ebc11ee3403e7ce3..9dd516137ebe72e268689df709c625132e290e22 100644 (file)
@@ -10,10 +10,14 @@ 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.argeo.cms.KernelHeader;
-import org.argeo.osgi.useradmin.ArgeoUserAdminException;
+import org.argeo.osgi.useradmin.AbstractUserDirectory;
 import org.argeo.osgi.useradmin.UserAdminAggregator;
+import org.argeo.osgi.useradmin.UserDirectoryException;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.service.useradmin.Authorization;
 import org.osgi.service.useradmin.Role;
@@ -26,7 +30,7 @@ public class NodeUserAdmin implements UserAdmin, UserAdminAggregator {
                try {
                        ROLES_BASE = new LdapName(KernelHeader.ROLES_BASEDN);
                } catch (InvalidNameException e) {
-                       throw new ArgeoUserAdminException("Cannot initialize "
+                       throw new UserDirectoryException("Cannot initialize "
                                        + NodeUserAdmin.class, e);
                }
        }
@@ -34,6 +38,9 @@ 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;
+
        @Override
        public Role createRole(String name, int type) {
                return findUserAdmin(name).createRole(name, type);
@@ -92,18 +99,21 @@ 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;
                }
 
                if (userAdmins.containsKey(baseDn))
-                       throw new ArgeoUserAdminException(
+                       throw new UserDirectoryException(
                                        "There is already a user admin for " + baseDn);
                try {
                        userAdmins.put(new LdapName(baseDn), userAdmin);
                } catch (InvalidNameException e) {
-                       throw new ArgeoUserAdminException("Badly formatted base DN "
+                       throw new UserDirectoryException("Badly formatted base DN "
                                        + baseDn, e);
                }
        }
@@ -111,25 +121,27 @@ public class NodeUserAdmin implements UserAdmin, UserAdminAggregator {
        @Override
        public synchronized void removeUserAdmin(String baseDn) {
                if (baseDn.equals(KernelHeader.ROLES_BASEDN))
-                       throw new ArgeoUserAdminException("Node roles cannot be removed.");
+                       throw new UserDirectoryException("Node roles cannot be removed.");
                LdapName base;
                try {
                        base = new LdapName(baseDn);
                } catch (InvalidNameException e) {
-                       throw new ArgeoUserAdminException("Badly formatted base DN "
+                       throw new UserDirectoryException("Badly formatted base DN "
                                        + baseDn, e);
                }
                if (!userAdmins.containsKey(base))
-                       throw new ArgeoUserAdminException("There is no user admin for "
+                       throw new UserDirectoryException("There is no user admin for "
                                        + base);
-               userAdmins.remove(base);
+               UserAdmin userAdmin = userAdmins.remove(base);
+               if (userAdmin instanceof AbstractUserDirectory)
+                       ((AbstractUserDirectory) userAdmin).setSyncRegistry(null);
        }
 
        private UserAdmin findUserAdmin(String name) {
                try {
                        return findUserAdmin(new LdapName(name));
                } catch (InvalidNameException e) {
-                       throw new ArgeoUserAdminException("Badly formatted name " + name, e);
+                       throw new UserDirectoryException("Badly formatted name " + name, e);
                }
        }
 
@@ -142,11 +154,35 @@ public class NodeUserAdmin implements UserAdmin, UserAdminAggregator {
                                res.add(userAdmins.get(baseDn));
                }
                if (res.size() == 0)
-                       throw new ArgeoUserAdminException("Cannot find user admin for "
+                       throw new UserDirectoryException("Cannot find user admin for "
                                        + name);
                if (res.size() > 1)
-                       throw new ArgeoUserAdminException("Multiple user admin found for "
+                       throw new UserDirectoryException("Multiple user admin found for "
                                        + name);
                return res.get(0);
        }
+
+       public void setTransactionManager(TransactionManager transactionManager) {
+               this.transactionManager = transactionManager;
+               if (nodeRoles instanceof AbstractUserDirectory)
+                       ((AbstractUserDirectory) nodeRoles)
+                                       .setTransactionManager(transactionManager);
+               for (UserAdmin userAdmin : userAdmins.values()) {
+                       if (userAdmin instanceof AbstractUserDirectory)
+                               ((AbstractUserDirectory) userAdmin)
+                                               .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 8cd11ba447cc481dbbca80d776db1c3ebd2d85f4..f97cf9113b9b2a9e4f9d8372491d20d69b6e0182 100644 (file)
@@ -22,7 +22,7 @@ SYSTEM {
 
 KERNEL {
     com.sun.security.auth.module.UnixLoginModule requisite;
-    com.sun.security.auth.module.KeyStoreLoginModule requisite keyStoreURL="${osgi.configuration.area}/node.p12" keyStoreType=PKCS12 keyStoreProvider=BC;
+    com.sun.security.auth.module.KeyStoreLoginModule requisite keyStoreURL="${osgi.instance.area}/node.p12" keyStoreType=PKCS12 keyStoreProvider=BC;
     org.argeo.cms.internal.auth.KernelLoginModule requisite;
 };
 
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/transaction/SimpleTransaction.java b/org.argeo.cms/src/org/argeo/cms/internal/transaction/SimpleTransaction.java
new file mode 100644 (file)
index 0000000..a07645f
--- /dev/null
@@ -0,0 +1,121 @@
+package org.argeo.cms.internal.transaction;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+class SimpleTransaction implements Transaction, Status {
+       private final static Log log = LogFactory.getLog(SimpleTransaction.class);
+
+       private final Xid xid;
+       private int status = Status.STATUS_ACTIVE;
+       private final List<XAResource> xaResources = new ArrayList<XAResource>();
+
+       public SimpleTransaction() {
+               xid = new UuidXid();
+       }
+
+       @Override
+       public synchronized void commit() throws RollbackException,
+                       HeuristicMixedException, HeuristicRollbackException,
+                       SecurityException, IllegalStateException, SystemException {
+               status = STATUS_PREPARING;
+               for (XAResource xaRes : xaResources) {
+                       if (status == STATUS_MARKED_ROLLBACK)
+                               break;
+                       try {
+                               xaRes.prepare(xid);
+                       } catch (XAException e) {
+                               status = STATUS_MARKED_ROLLBACK;
+                               log.error("Cannot prepare " + xaRes + " for " + xid, e);
+                       }
+               }
+               if (status == STATUS_MARKED_ROLLBACK) {
+                       rollback();
+                       throw new RollbackException();
+               }
+               status = STATUS_PREPARED;
+
+               status = STATUS_COMMITTING;
+               for (XAResource xaRes : xaResources) {
+                       if (status == STATUS_MARKED_ROLLBACK)
+                               break;
+                       try {
+                               xaRes.commit(xid, false);
+                       } catch (XAException e) {
+                               status = STATUS_MARKED_ROLLBACK;
+                               log.error("Cannot prepare " + xaRes + " for " + xid, e);
+                       }
+               }
+               if (status == STATUS_MARKED_ROLLBACK) {
+                       rollback();
+                       throw new RollbackException();
+               }
+               status = STATUS_COMMITTED;
+       }
+
+       @Override
+       public synchronized boolean delistResource(XAResource xaRes, int flag)
+                       throws IllegalStateException, SystemException {
+               return xaResources.remove(xaRes);
+       }
+
+       @Override
+       public synchronized boolean enlistResource(XAResource xaRes)
+                       throws RollbackException, IllegalStateException, SystemException {
+               return xaResources.add(xaRes);
+       }
+
+       @Override
+       public synchronized int getStatus() throws SystemException {
+               return status;
+       }
+
+       @Override
+       public void registerSynchronization(Synchronization sync)
+                       throws RollbackException, IllegalStateException, SystemException {
+               throw new UnsupportedOperationException();
+       }
+
+       @Override
+       public synchronized void rollback() throws IllegalStateException,
+                       SystemException {
+               status = STATUS_ROLLING_BACK;
+               for (XAResource xaRes : xaResources) {
+                       try {
+                               xaRes.rollback(xid);
+                       } catch (XAException e) {
+                               log.error("Cannot rollback " + xaRes + " for " + xid, e);
+                       }
+               }
+               status = STATUS_ROLLEDBACK;
+       }
+
+       @Override
+       public void setRollbackOnly() throws IllegalStateException, SystemException {
+               status = STATUS_MARKED_ROLLBACK;
+       }
+
+       @Override
+       public int hashCode() {
+               return xid.hashCode();
+       }
+
+       public Xid getXid() {
+               return xid;
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/transaction/SimpleTransactionManager.java b/org.argeo.cms/src/org/argeo/cms/internal/transaction/SimpleTransactionManager.java
new file mode 100644 (file)
index 0000000..6261a02
--- /dev/null
@@ -0,0 +1,188 @@
+package org.argeo.cms.internal.transaction;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.InvalidTransactionException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.TransactionSynchronizationRegistry;
+import javax.transaction.UserTransaction;
+import javax.transaction.xa.Xid;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+
+public class SimpleTransactionManager implements TransactionManager,
+               UserTransaction {
+       private final static Log log = LogFactory
+                       .getLog(SimpleTransactionManager.class);
+
+       private ThreadLocal<SimpleTransaction> current = new ThreadLocal<SimpleTransaction>();
+
+       private Map<Xid, SimpleTransaction> knownTransactions = Collections
+                       .synchronizedMap(new HashMap<Xid, SimpleTransaction>());
+       private SyncRegistry syncRegistry = new SyncRegistry();
+
+       @Override
+       public void begin() throws NotSupportedException, SystemException {
+               if (getCurrent() != null)
+                       throw new NotSupportedException(
+                                       "Nested transactions are not supported");
+               SimpleTransaction transaction = new SimpleTransaction();
+               knownTransactions.put(transaction.getXid(), transaction);
+               current.set(transaction);
+               if (log.isDebugEnabled())
+                       log.debug("Started transaction " + transaction.getXid());
+       }
+
+       @Override
+       public void commit() throws RollbackException, HeuristicMixedException,
+                       HeuristicRollbackException, SecurityException,
+                       IllegalStateException, SystemException {
+               if (getCurrent() == null)
+                       throw new IllegalStateException(
+                                       "No transaction registered with the current thread.");
+               getCurrent().commit();
+       }
+
+       @Override
+       public int getStatus() throws SystemException {
+               if (getCurrent() == null)
+                       return Status.STATUS_NO_TRANSACTION;
+               return getTransaction().getStatus();
+       }
+
+       @Override
+       public Transaction getTransaction() throws SystemException {
+               return getCurrent();
+       }
+
+       protected SimpleTransaction getCurrent() throws SystemException {
+               SimpleTransaction transaction = current.get();
+               if (transaction == null)
+                       return null;
+               int status = transaction.getStatus();
+               if (Status.STATUS_COMMITTED == status
+                               || Status.STATUS_ROLLEDBACK == status) {
+                       current.remove();
+                       knownTransactions.remove(transaction.getXid());
+                       if (log.isDebugEnabled())
+                               log.debug("Completed transaction "
+                                               + transaction.getXid()
+                                               + " ["
+                                               + (status == Status.STATUS_ROLLEDBACK ? "FAILED" : "OK")
+                                               + "]");
+                       return null;
+               }
+               return transaction;
+       }
+
+       @Override
+       public void resume(Transaction tobj) throws InvalidTransactionException,
+                       IllegalStateException, SystemException {
+               if (getCurrent() != null)
+                       throw new IllegalStateException("Transaction " + current.get()
+                                       + " already registered");
+               current.set((SimpleTransaction) tobj);
+       }
+
+       @Override
+       public void rollback() throws IllegalStateException, SecurityException,
+                       SystemException {
+               if (getCurrent() == null)
+                       throw new IllegalStateException(
+                                       "No transaction registered with the current thread.");
+               getCurrent().rollback();
+       }
+
+       @Override
+       public void setRollbackOnly() throws IllegalStateException, SystemException {
+               if (getCurrent() == null)
+                       throw new IllegalStateException(
+                                       "No transaction registered with the current thread.");
+               getCurrent().setRollbackOnly();
+       }
+
+       @Override
+       public void setTransactionTimeout(int seconds) throws SystemException {
+               throw new UnsupportedOperationException();
+       }
+
+       @Override
+       public Transaction suspend() throws SystemException {
+               Transaction transaction = getCurrent();
+               current.remove();
+               return transaction;
+       }
+
+       public TransactionSynchronizationRegistry getTransactionSynchronizationRegistry() {
+               return syncRegistry;
+       }
+
+       private class SyncRegistry implements TransactionSynchronizationRegistry {
+               @Override
+               public Object getTransactionKey() {
+                       try {
+                               SimpleTransaction transaction = getCurrent();
+                               if (transaction == null)
+                                       return null;
+                               return getCurrent().getXid();
+                       } catch (SystemException e) {
+                               throw new CmsException("Cannot get transaction key", e);
+                       }
+               }
+
+               @Override
+               public void putResource(Object key, Object value) {
+                       throw new UnsupportedOperationException();
+               }
+
+               @Override
+               public Object getResource(Object key) {
+                       throw new UnsupportedOperationException();
+               }
+
+               @Override
+               public void registerInterposedSynchronization(Synchronization sync) {
+                       throw new UnsupportedOperationException();
+               }
+
+               @Override
+               public int getTransactionStatus() {
+                       try {
+                               return getStatus();
+                       } catch (SystemException e) {
+                               throw new CmsException("Cannot get status", e);
+                       }
+               }
+
+               @Override
+               public boolean getRollbackOnly() {
+                       try {
+                               return getStatus() == Status.STATUS_MARKED_ROLLBACK;
+                       } catch (SystemException e) {
+                               throw new CmsException("Cannot get status", e);
+                       }
+               }
+
+               @Override
+               public void setRollbackOnly() {
+                       try {
+                               getCurrent().setRollbackOnly();
+                       } catch (Exception e) {
+                               throw new CmsException("Cannot set rollback only", e);
+                       }
+               }
+
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/transaction/UuidXid.java b/org.argeo.cms/src/org/argeo/cms/internal/transaction/UuidXid.java
new file mode 100644 (file)
index 0000000..18975ea
--- /dev/null
@@ -0,0 +1,132 @@
+package org.argeo.cms.internal.transaction;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.UUID;
+
+import javax.transaction.xa.Xid;
+
+/**
+ * Implementation of {@link Xid} based on {@link UUID}, using max significant
+ * bits as global transaction id, and least significant bits as branch
+ * qualifier.
+ */
+public class UuidXid implements Xid, Serializable {
+       private static final long serialVersionUID = -5380531989917886819L;
+       public final static int FORMAT = (int) serialVersionUID;
+
+       private final static int BYTES_PER_LONG = Long.SIZE / Byte.SIZE;
+
+       private final int format;
+       private final byte[] globalTransactionId;
+       private final byte[] branchQualifier;
+       private final String uuid;
+       private final int hashCode;
+
+       public UuidXid() {
+               this(UUID.randomUUID());
+       }
+
+       public UuidXid(UUID uuid) {
+               this.format = FORMAT;
+               this.globalTransactionId = uuidToBytes(uuid.getMostSignificantBits());
+               this.branchQualifier = uuidToBytes(uuid.getLeastSignificantBits());
+               this.uuid = uuid.toString();
+               this.hashCode = uuid.hashCode();
+       }
+
+       public UuidXid(Xid xid) {
+               this(xid.getFormatId(), xid.getGlobalTransactionId(), xid
+                               .getBranchQualifier());
+       }
+
+       private UuidXid(int format, byte[] globalTransactionId,
+                       byte[] branchQualifier) {
+               this.format = format;
+               this.globalTransactionId = globalTransactionId;
+               this.branchQualifier = branchQualifier;
+               this.uuid = bytesToUUID(globalTransactionId, branchQualifier)
+                               .toString();
+               this.hashCode = uuid.hashCode();
+       }
+
+       @Override
+       public int getFormatId() {
+               return format;
+       }
+
+       @Override
+       public byte[] getGlobalTransactionId() {
+               return Arrays.copyOf(globalTransactionId, globalTransactionId.length);
+       }
+
+       @Override
+       public byte[] getBranchQualifier() {
+               return Arrays.copyOf(branchQualifier, branchQualifier.length);
+       }
+
+       @Override
+       public int hashCode() {
+               return hashCode;
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj instanceof UuidXid) {
+                       UuidXid that = (UuidXid) obj;
+                       return Arrays.equals(globalTransactionId, that.globalTransactionId)
+                                       && Arrays.equals(branchQualifier, that.branchQualifier);
+               }
+               if (obj instanceof Xid) {
+                       Xid that = (Xid) obj;
+                       return Arrays.equals(globalTransactionId,
+                                       that.getGlobalTransactionId())
+                                       && Arrays
+                                                       .equals(branchQualifier, that.getBranchQualifier());
+               }
+               return uuid.equals(obj.toString());
+       }
+
+       @Override
+       protected Object clone() throws CloneNotSupportedException {
+               return new UuidXid(format, globalTransactionId, branchQualifier);
+       }
+
+       @Override
+       public String toString() {
+               return uuid;
+       }
+
+       public UUID asUuid() {
+               return bytesToUUID(globalTransactionId, branchQualifier);
+       }
+
+       public static byte[] uuidToBytes(long bits) {
+               ByteBuffer buffer = ByteBuffer.allocate(BYTES_PER_LONG);
+               buffer.putLong(0, bits);
+               return buffer.array();
+       }
+
+       public static UUID bytesToUUID(byte[] most, byte[] least) {
+               if (most.length < BYTES_PER_LONG)
+                       most = Arrays.copyOf(most, BYTES_PER_LONG);
+               if (least.length < BYTES_PER_LONG)
+                       least = Arrays.copyOf(least, BYTES_PER_LONG);
+               ByteBuffer buffer = ByteBuffer.allocate(2 * BYTES_PER_LONG);
+               buffer.put(most, 0, BYTES_PER_LONG);
+               buffer.put(least, 0, BYTES_PER_LONG);
+               buffer.flip();
+               return new UUID(buffer.getLong(), buffer.getLong());
+       }
+
+       // public static void main(String[] args) {
+       // UUID uuid = UUID.randomUUID();
+       // System.out.println(uuid);
+       // uuid = bytesToUUID(uuidToBytes(uuid.getMostSignificantBits()),
+       // uuidToBytes(uuid.getLeastSignificantBits()));
+       // System.out.println(uuid);
+       // }
+}
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractLdapUserAdmin.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractLdapUserAdmin.java
deleted file mode 100644 (file)
index 8dcd6c2..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.osgi.service.useradmin.Group;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-
-public abstract class AbstractLdapUserAdmin implements UserAdmin {
-       private boolean isReadOnly;
-       private URI uri;
-
-       private UserAdmin externalRoles;
-       private List<String> indexedUserProperties = Arrays.asList(new String[] {
-                       "uid", "mail", "cn" });
-
-       public AbstractLdapUserAdmin() {
-       }
-
-       public AbstractLdapUserAdmin(URI uri, boolean isReadOnly) {
-               this.uri = uri;
-               this.isReadOnly = isReadOnly;
-       }
-
-       public void init() {
-
-       }
-
-       public void destroy() {
-
-       }
-
-       /** Returns the {@link Group}s this user is a direct member of. */
-       protected abstract List<? extends Group> getDirectGroups(User user);
-
-       List<Role> getAllRoles(User user) {
-               List<Role> allRoles = new ArrayList<Role>();
-               if (user != null) {
-                       collectRoles(user, allRoles);
-                       allRoles.add(user);
-               } else
-                       collectAnonymousRoles(allRoles);
-               return allRoles;
-       }
-
-       private void collectRoles(User user, List<Role> allRoles) {
-               for (Group group : getDirectGroups(user)) {
-                       // TODO check for loops
-                       allRoles.add(group);
-                       collectRoles(group, allRoles);
-               }
-       }
-
-       private void collectAnonymousRoles(List<Role> allRoles) {
-               // TODO gather anonymous roles
-       }
-
-       protected URI getUri() {
-               return uri;
-       }
-
-       protected void setUri(URI uri) {
-               this.uri = uri;
-       }
-
-       protected List<String> getIndexedUserProperties() {
-               return indexedUserProperties;
-       }
-
-       protected void setIndexedUserProperties(List<String> indexedUserProperties) {
-               this.indexedUserProperties = indexedUserProperties;
-       }
-
-       protected void setReadOnly(boolean isReadOnly) {
-               this.isReadOnly = isReadOnly;
-       }
-
-       public boolean isReadOnly() {
-               return isReadOnly;
-       }
-
-       UserAdmin getExternalRoles() {
-               return externalRoles;
-       }
-
-       public void setExternalRoles(UserAdmin externalRoles) {
-               this.externalRoles = externalRoles;
-       }
-
-}
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java
new file mode 100644 (file)
index 0000000..4f20dc3
--- /dev/null
@@ -0,0 +1,162 @@
+package org.argeo.osgi.useradmin;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.transaction.RollbackException;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.TransactionSynchronizationRegistry;
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+public abstract class AbstractUserDirectory implements UserAdmin {
+       private boolean isReadOnly;
+       private URI uri;
+
+       private UserAdmin externalRoles;
+       private List<String> indexedUserProperties = Arrays.asList(new String[] {
+                       "uid", "mail", "cn" });
+
+       private String memberAttributeId = "member";
+       private List<String> credentialAttributeIds = Arrays
+                       .asList(new String[] { "userpassword" });
+
+       private TransactionSynchronizationRegistry syncRegistry;
+       private Object editingTransactionKey = null;
+       private TransactionManager transactionManager;
+       private Transaction editingTransaction;
+
+       public AbstractUserDirectory() {
+       }
+
+       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 Group> getDirectGroups(User user);
+
+       public void init() {
+
+       }
+
+       public void destroy() {
+
+       }
+
+       boolean isEditing() {
+               if (editingTransactionKey == null)
+                       return false;
+               Object currentTrKey = syncRegistry.getTransactionKey();
+               if (currentTrKey == null)
+                       return false;
+               return editingTransactionKey.equals(currentTrKey);
+       }
+
+       void checkEdit() {
+               Object currentTrKey = syncRegistry.getTransactionKey();
+               if (currentTrKey == null)
+                       throw new UserDirectoryException(
+                                       "A transaction needs to be active in order to edit");
+               if (editingTransactionKey == null) {
+                       editingTransactionKey = currentTrKey;
+                       XAResource xaRes = getXAResource();
+                       if (xaRes != null)
+                               try {
+                                       transactionManager.getTransaction().enlistResource(xaRes);
+                               } catch (Exception e) {
+                                       throw new UserDirectoryException("Cannot enlist " + this, e);
+                               }
+               } else {
+                       if (!editingTransactionKey.equals(currentTrKey))
+                               throw new UserDirectoryException("Transaction "
+                                               + editingTransactionKey + " already editing");
+               }
+       }
+
+       List<Role> getAllRoles(User user) {
+               List<Role> allRoles = new ArrayList<Role>();
+               if (user != null) {
+                       collectRoles(user, allRoles);
+                       allRoles.add(user);
+               } else
+                       collectAnonymousRoles(allRoles);
+               return allRoles;
+       }
+
+       private void collectRoles(User user, List<Role> allRoles) {
+               for (Group group : getDirectGroups(user)) {
+                       // TODO check for loops
+                       allRoles.add(group);
+                       collectRoles(group, allRoles);
+               }
+       }
+
+       private void collectAnonymousRoles(List<Role> allRoles) {
+               // TODO gather anonymous roles
+       }
+
+       public XAResource getXAResource() {
+               return null;
+       }
+
+       String getMemberAttributeId() {
+               return memberAttributeId;
+       }
+
+       List<String> getCredentialAttributeIds() {
+               return credentialAttributeIds;
+       }
+
+       protected URI getUri() {
+               return uri;
+       }
+
+       protected void setUri(URI uri) {
+               this.uri = uri;
+       }
+
+       protected List<String> getIndexedUserProperties() {
+               return indexedUserProperties;
+       }
+
+       protected void setIndexedUserProperties(List<String> indexedUserProperties) {
+               this.indexedUserProperties = indexedUserProperties;
+       }
+
+       protected void setReadOnly(boolean isReadOnly) {
+               this.isReadOnly = isReadOnly;
+       }
+
+       public boolean isReadOnly() {
+               return isReadOnly;
+       }
+
+       UserAdmin getExternalRoles() {
+               return externalRoles;
+       }
+
+       public void setExternalRoles(UserAdmin externalRoles) {
+               this.externalRoles = externalRoles;
+       }
+
+       public void setSyncRegistry(TransactionSynchronizationRegistry syncRegistry) {
+               this.syncRegistry = syncRegistry;
+       }
+
+       public void setTransactionManager(TransactionManager transactionManager) {
+               this.transactionManager = transactionManager;
+       }
+
+}
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/ArgeoUserAdminException.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/ArgeoUserAdminException.java
deleted file mode 100644 (file)
index 70724a7..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import org.osgi.service.useradmin.UserAdmin;
-
-/**
- * Exceptions related to Argeo's implementation of OSGi {@link UserAdmin}
- * service.
- */
-public class ArgeoUserAdminException extends RuntimeException {
-       private static final long serialVersionUID = 1419352360062048603L;
-
-       public ArgeoUserAdminException(String message) {
-               super(message);
-       }
-
-       public ArgeoUserAdminException(String message, Throwable e) {
-               super(message, e);
-       }
-}
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/AttributeDictionary.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/AttributeDictionary.java
deleted file mode 100644 (file)
index 99e5edb..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttribute;
-
-class AttributeDictionary extends Dictionary<String,Object> {
-       private final Attributes attributes;
-       private final List<String> effectiveKeys = new ArrayList<String>();
-       private final List<String> attrFilter;
-       private final Boolean includeFilter;
-
-       public AttributeDictionary(Attributes attributes, List<String> attrFilter,
-                       Boolean includeFilter) {
-               this.attributes = attributes;
-               this.attrFilter = attrFilter;
-               this.includeFilter = includeFilter;
-               try {
-                       NamingEnumeration<String> ids = attributes.getIDs();
-                       while (ids.hasMore()) {
-                               String id = ids.next();
-                               if (includeFilter && attrFilter.contains(id))
-                                       effectiveKeys.add(id);
-                               else if (!includeFilter && !attrFilter.contains(id))
-                                       effectiveKeys.add(id);
-                       }
-               } catch (NamingException e) {
-                       throw new ArgeoUserAdminException(
-                                       "Cannot initialise attribute dictionary", e);
-               }
-       }
-
-       @Override
-       public int size() {
-               return effectiveKeys.size();
-       }
-
-       @Override
-       public boolean isEmpty() {
-               return effectiveKeys.size() == 0;
-       }
-
-       @Override
-       public Enumeration<String> keys() {
-               return Collections.enumeration(effectiveKeys);
-       }
-
-       @Override
-       public Enumeration<Object> elements() {
-               final Iterator<String> it = effectiveKeys.iterator();
-               return new Enumeration<Object>() {
-
-                       @Override
-                       public boolean hasMoreElements() {
-                               return it.hasNext();
-                       }
-
-                       @Override
-                       public Object nextElement() {
-                               String key = it.next();
-                               try {
-                                       return attributes.get(key).get();
-                               } catch (NamingException e) {
-                                       throw new ArgeoUserAdminException(
-                                                       "Cannot get value for key " + key, e);
-                               }
-                       }
-
-               };
-       }
-
-       @Override
-       public Object get(Object key) {
-               try {
-                       Attribute attr = attributes.get(key.toString());
-                       if (attr == null)
-                               return null;
-                       return attr.get();
-               } catch (NamingException e) {
-                       throw new ArgeoUserAdminException("Cannot get value for attribute "
-                                       + key, e);
-               }
-       }
-
-       @Override
-       public Object put(String key, Object value) {
-               if (!(value instanceof String || value instanceof byte[]))
-                       throw new IllegalArgumentException("Value must be String or byte[]");
-
-               if (includeFilter && !attrFilter.contains(key))
-                       throw new IllegalArgumentException("Key " + key + " not included");
-               else if (!includeFilter && attrFilter.contains(key))
-                       throw new IllegalArgumentException("Key " + key + " excluded");
-
-               try {
-                       Attribute attribute = attributes.get(key.toString());
-                       attribute = new BasicAttribute(key.toString());
-                       attribute.add(value);
-                       Attribute previousAttribute = attributes.put(attribute);
-                       if (previousAttribute != null)
-                               return previousAttribute.get();
-                       else
-                               return null;
-               } catch (NamingException e) {
-                       throw new ArgeoUserAdminException("Cannot get value for attribute "
-                                       + key, e);
-               }
-       }
-
-       @Override
-       public Object remove(Object key) {
-               if (includeFilter && !attrFilter.contains(key))
-                       throw new IllegalArgumentException("Key " + key + " not included");
-               else if (!includeFilter && attrFilter.contains(key))
-                       throw new IllegalArgumentException("Key " + key + " excluded");
-
-               try {
-                       Attribute attr = attributes.remove(key.toString());
-                       if (attr != null)
-                               return attr.get();
-                       else
-                               return null;
-               } catch (NamingException e) {
-                       throw new ArgeoUserAdminException("Cannot remove attribute " + key,
-                                       e);
-               }
-       }
-}
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/DirectoryGroup.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/DirectoryGroup.java
new file mode 100644 (file)
index 0000000..bb64c26
--- /dev/null
@@ -0,0 +1,11 @@
+package org.argeo.osgi.useradmin;
+
+import java.util.List;
+
+import javax.naming.ldap.LdapName;
+
+import org.osgi.service.useradmin.Group;
+
+public interface DirectoryGroup extends Group, DirectoryUser {
+       List<LdapName> getMemberNames();
+}
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/DirectoryUser.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/DirectoryUser.java
new file mode 100644 (file)
index 0000000..05107ab
--- /dev/null
@@ -0,0 +1,12 @@
+package org.argeo.osgi.useradmin;
+
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+
+import org.osgi.service.useradmin.User;
+
+interface DirectoryUser extends User {
+       LdapName getDn();
+
+       Attributes getAttributes();
+}
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/EditorRole.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/EditorRole.java
new file mode 100644 (file)
index 0000000..d99fc33
--- /dev/null
@@ -0,0 +1,9 @@
+package org.argeo.osgi.useradmin;
+
+import org.osgi.service.useradmin.Role;
+
+public interface EditorRole extends Role {
+       public static final int EDITOR = -1;
+
+       
+}
index 0b9c3ad7a4e9df74b9825e1d4151a7fcf10bfce9..62f4b2b3708231415d58d4bffac774c3f04a215a 100644 (file)
@@ -6,9 +6,11 @@ package org.argeo.osgi.useradmin;
  */
 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";
+
 }
index dabae718c2f1c9f71124d7f9ee4400086f2683e7..9bb8fbc7d44eadc5f0facbc8bb16a210bae0c74d 100644 (file)
@@ -26,7 +26,7 @@ import org.osgi.service.useradmin.Group;
 import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.User;
 
-public class LdapUserAdmin extends AbstractLdapUserAdmin {
+public class LdapUserAdmin extends AbstractUserDirectory {
        private final static Log log = LogFactory.getLog(LdapUserAdmin.class);
 
        private String baseDn = "dc=example,dc=com";
@@ -59,7 +59,7 @@ public class LdapUserAdmin extends AbstractLdapUserAdmin {
                        log.debug(initialLdapContext.getAttributes(
                                        "uid=root,ou=users,dc=example,dc=com").get("cn"));
                } catch (Exception e) {
-                       throw new ArgeoUserAdminException("Cannot connect to LDAP", e);
+                       throw new UserDirectoryException("Cannot connect to LDAP", e);
                }
        }
 
@@ -92,13 +92,13 @@ public class LdapUserAdmin extends AbstractLdapUserAdmin {
                        if (attrs.get("objectClass").contains("groupOfNames"))
                                res = new LdifGroup(this, new LdapName(name), attrs);
                        else if (attrs.get("objectClass").contains("inetOrgPerson"))
-                               res = new LdifUser(new LdapName(name), attrs);
+                               res = new LdifUser(this, new LdapName(name), attrs);
                        else
-                               throw new ArgeoUserAdminException("Unsupported LDAP type for "
+                               throw new UserDirectoryException("Unsupported LDAP type for "
                                                + name);
                        return res;
                } catch (NamingException e) {
-                       throw new ArgeoUserAdminException("Cannot get role for " + name, e);
+                       throw new UserDirectoryException("Cannot get role for " + name, e);
                }
        }
 
@@ -124,16 +124,17 @@ public class LdapUserAdmin extends AbstractLdapUserAdmin {
                                        role = new LdifGroup(this, toDn(searchBase, searchResult),
                                                        attrs);
                                else if (attrs.get("objectClass").contains("inetOrgPerson"))
-                                       role = new LdifUser(toDn(searchBase, searchResult), attrs);
+                                       role = new LdifUser(this, toDn(searchBase, searchResult),
+                                                       attrs);
                                else
-                                       throw new ArgeoUserAdminException(
+                                       throw new UserDirectoryException(
                                                        "Unsupported LDAP type for "
                                                                        + searchResult.getName());
                                res.add(role);
                        }
                        return res.toArray(new Role[res.size()]);
                } catch (Exception e) {
-                       throw new ArgeoUserAdminException("Cannot get roles for filter "
+                       throw new UserDirectoryException("Cannot get roles for filter "
                                        + filter, e);
                }
        }
@@ -172,10 +173,10 @@ public class LdapUserAdmin extends AbstractLdapUserAdmin {
                        }
                        if (searchResult == null)
                                return null;
-                       return new LdifUser(toDn(searchBase, searchResult),
+                       return new LdifUser(this, toDn(searchBase, searchResult),
                                        searchResult.getAttributes());
                } catch (Exception e) {
-                       throw new ArgeoUserAdminException("Cannot get user with " + key
+                       throw new UserDirectoryException("Cannot get user with " + key
                                        + "=" + value, e);
                }
        }
index 3600866af77aa8e8d32f74ff5525bce9fdf4c1e3..845fefd13da483a6ee88c3c48690c0f45062ad0d 100644 (file)
@@ -29,7 +29,7 @@ public class LdifAuthorization implements Authorization, LdapNames {
                        if (displayName == null)
                                displayName = user.getName();
                        if (displayName == null)
-                               throw new ArgeoUserAdminException(
+                               throw new UserDirectoryException(
                                                "Cannot set display name for " + user);
                        this.displayName = displayName.toString();
                }
index a19052425491759a9c2c55687522fa9532a49397..3e9d44750b2ef333326d36cf2a971483c74b61e4 100644 (file)
@@ -8,33 +8,25 @@ import javax.naming.directory.Attribute;
 import javax.naming.directory.Attributes;
 import javax.naming.ldap.LdapName;
 
-import org.osgi.service.useradmin.Group;
 import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.UserAdmin;
 
-public class LdifGroup extends LdifUser implements Group {
-       // optimisation
-       // List<Role> directMembers = null;
+public class LdifGroup extends LdifUser implements DirectoryGroup {
+       private final String memberAttributeId;
 
-       private final UserAdmin userAdmin;
-       private String memberAttrName = "member";
-
-       public LdifGroup(UserAdmin userAdmin, LdapName dn, Attributes attributes) {
-               super(dn, attributes);
-               this.userAdmin = userAdmin;
+       public LdifGroup(AbstractUserDirectory userAdmin, LdapName dn,
+                       Attributes attributes) {
+               super(userAdmin, dn, attributes);
+               memberAttributeId = userAdmin.getMemberAttributeId();
        }
 
        @Override
        public boolean addMember(Role role) {
-               Attribute member = getAttributes().get(memberAttrName);
+               Attribute member = getAttributes().get(memberAttributeId);
                if (member != null) {
                        if (member.contains(role.getName()))
                                return false;
                } else
-                       getAttributes().put(memberAttrName, role.getName());
-               // directMembers.add(role);
-               // if (role instanceof LdifUser)
-               // ((LdifUser) role).directMemberOf.add(this);
+                       getAttributes().put(memberAttributeId, role.getName());
                return true;
        }
 
@@ -45,14 +37,11 @@ public class LdifGroup extends LdifUser implements Group {
 
        @Override
        public boolean removeMember(Role role) {
-               Attribute member = getAttributes().get(memberAttrName);
+               Attribute member = getAttributes().get(memberAttributeId);
                if (member != null) {
                        if (!member.contains(role.getName()))
                                return false;
                        member.remove(role.getName());
-                       // directMembers.remove(role);
-                       // if (role instanceof LdifUser)
-                       // ((LdifUser) role).directMemberOf.remove(this);
                        return true;
                } else
                        return false;
@@ -62,62 +51,23 @@ public class LdifGroup extends LdifUser implements Group {
        public Role[] getMembers() {
                List<Role> directMembers = new ArrayList<Role>();
                for (LdapName ldapName : getMemberNames()) {
-                       Role role = userAdmin.getRole(ldapName.toString());
-                       if (role == null && userAdmin instanceof AbstractLdapUserAdmin) {
-                               AbstractLdapUserAdmin ua = (AbstractLdapUserAdmin) userAdmin;
-                               if (ua.getExternalRoles() != null)
-                                       role = ua.getExternalRoles().getRole(ldapName.toString());
+                       Role role = getUserAdmin().getRole(ldapName.toString());
+                       if (role == null) {
+                               if (getUserAdmin().getExternalRoles() != null)
+                                       role = getUserAdmin().getExternalRoles().getRole(
+                                                       ldapName.toString());
                        }
                        if (role == null)
-                               throw new ArgeoUserAdminException("No role found for "
+                               throw new UserDirectoryException("No role found for "
                                                + ldapName);
-
-                       // role.directMemberOf.add(group);
-                       // if (!directMemberOf.containsKey(role.getDn()))
-                       // directMemberOf.put(role.getDn(), new ArrayList<LdifGroup>());
-                       // directMemberOf.get(role.getDn()).add(group);
                        directMembers.add(role);
                }
                return directMembers.toArray(new Role[directMembers.size()]);
-               // if (directMembers != null)
-               // return directMembers.toArray(new Role[directMembers.size()]);
-               // else
-               // throw new ArgeoUserAdminException("Members have not been loaded.");
-
-               // Attribute memberAttribute = getAttributes().get(memberAttrName);
-               // if (memberAttribute == null)
-               // return new Role[0];
-               // try {
-               // List<Role> roles = new ArrayList<Role>();
-               // NamingEnumeration values = memberAttribute.getAll();
-               // while (values.hasMore()) {
-               // LdapName dn = new LdapName(values.next().toString());
-               // roles.add(new LdifUser(dn, null));
-               // }
-               // return roles.toArray(new Role[roles.size()]);
-               // } catch (Exception e) {
-               // throw new ArgeoUserAdminException("Cannot get members", e);
-               // }
        }
 
-       // void loadMembers(LdifUserAdmin userAdmin) {
-       // directMembers = new ArrayList<Role>();
-       // for (LdapName ldapName : getMemberNames()) {
-       // LdifUser role;
-       // if (userAdmin.groups.containsKey(ldapName))
-       // role = userAdmin.groups.get(ldapName);
-       // else if (userAdmin.users.containsKey(ldapName))
-       // role = userAdmin.users.get(ldapName);
-       // else
-       // throw new ArgeoUserAdminException("No role found for "
-       // + ldapName);
-       // role.directMemberOf.add(this);
-       // directMembers.add(role);
-       // }
-       // }
-
-       List<LdapName> getMemberNames() {
-               Attribute memberAttribute = getAttributes().get(memberAttrName);
+       @Override
+       public List<LdapName> getMemberNames() {
+               Attribute memberAttribute = getAttributes().get(memberAttributeId);
                if (memberAttribute == null)
                        return new ArrayList<LdapName>();
                try {
@@ -129,7 +79,7 @@ public class LdifGroup extends LdifUser implements Group {
                        }
                        return roles;
                } catch (Exception e) {
-                       throw new ArgeoUserAdminException("Cannot get members", e);
+                       throw new UserDirectoryException("Cannot get members", e);
                }
        }
 
@@ -142,9 +92,4 @@ public class LdifGroup extends LdifUser implements Group {
        public int getType() {
                return GROUP;
        }
-
-       public String getMemberAttrName() {
-               return memberAttrName;
-       }
-
 }
index 85d18c082b1d5ad93bd8e78d1740a9f29bd60759..cd5401a55794273ffd350c9e341d025d4bd6425c 100644 (file)
@@ -2,34 +2,43 @@ package org.argeo.osgi.useradmin;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
 import java.util.List;
 
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
 import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
 import javax.naming.ldap.LdapName;
 
-import org.osgi.service.useradmin.User;
-
-class LdifUser implements User {
-       // optimisation
-       //List<LdifGroup> directMemberOf = new ArrayList<LdifGroup>();
+class LdifUser implements DirectoryUser {
+       private final AbstractUserDirectory userAdmin;
 
        private final LdapName dn;
-       private Attributes attributes;
+
+       private final boolean frozen;
+       private Attributes publishedAttributes;
+       private Attributes modifiedAttributes = null;
 
        private final AttributeDictionary properties;
        private final AttributeDictionary credentials;
 
-       private List<String> credentialAttributes = Arrays
-                       .asList(new String[] { "userpassword" });
+       LdifUser(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
+               this(userAdmin, dn, attributes, false);
+       }
 
-       LdifUser(LdapName dn, Attributes attributes) {
+       private LdifUser(AbstractUserDirectory userAdmin, LdapName dn,
+                       Attributes attributes, boolean frozen) {
+               this.userAdmin = userAdmin;
                this.dn = dn;
-               this.attributes = attributes;
-               properties = new AttributeDictionary(attributes, credentialAttributes,
-                               false);
-               credentials = new AttributeDictionary(attributes, credentialAttributes,
-                               true);
+               this.publishedAttributes = attributes;
+               properties = new AttributeDictionary(false);
+               credentials = new AttributeDictionary(true);
+               this.frozen = frozen;
        }
 
        @Override
@@ -66,12 +75,38 @@ class LdifUser implements User {
                return false;
        }
 
-       protected LdapName getDn() {
+       @Override
+       public LdapName getDn() {
                return dn;
        }
 
-       protected Attributes getAttributes() {
-               return attributes;
+       @Override
+       public synchronized Attributes getAttributes() {
+               return isEditing() ? modifiedAttributes : publishedAttributes;
+       }
+
+       protected synchronized boolean isEditing() {
+               return userAdmin.isEditing() && modifiedAttributes != null;
+       }
+
+       protected synchronized void startEditing() {
+               if (frozen)
+                       throw new UserDirectoryException("Cannot edit frozen view");
+               if (getUserAdmin().isReadOnly())
+                       throw new UserDirectoryException("User directory is read-only");
+               assert modifiedAttributes == null;
+               modifiedAttributes = (Attributes) publishedAttributes.clone();
+       }
+
+       protected synchronized void stopEditing(boolean apply) {
+               assert modifiedAttributes != null;
+               if (apply)
+                       publishedAttributes = modifiedAttributes;
+               modifiedAttributes = null;
+       }
+
+       public DirectoryUser getPublished() {
+               return new LdifUser(userAdmin, dn, publishedAttributes, true);
        }
 
        @Override
@@ -94,4 +129,140 @@ class LdifUser implements User {
        public String toString() {
                return dn.toString();
        }
+
+       protected AbstractUserDirectory getUserAdmin() {
+               return userAdmin;
+       }
+
+       private class AttributeDictionary extends Dictionary<String, Object> {
+               private final List<String> effectiveKeys = new ArrayList<String>();
+               private final List<String> attrFilter;
+               private final Boolean includeFilter;
+
+               public AttributeDictionary(Boolean includeFilter) {
+                       this.attrFilter = userAdmin.getCredentialAttributeIds();
+                       this.includeFilter = includeFilter;
+                       try {
+                               NamingEnumeration<String> ids = getAttributes().getIDs();
+                               while (ids.hasMore()) {
+                                       String id = ids.next();
+                                       if (includeFilter && attrFilter.contains(id))
+                                               effectiveKeys.add(id);
+                                       else if (!includeFilter && !attrFilter.contains(id))
+                                               effectiveKeys.add(id);
+                               }
+                       } catch (NamingException e) {
+                               throw new UserDirectoryException(
+                                               "Cannot initialise attribute dictionary", e);
+                       }
+               }
+
+               @Override
+               public int size() {
+                       return effectiveKeys.size();
+               }
+
+               @Override
+               public boolean isEmpty() {
+                       return effectiveKeys.size() == 0;
+               }
+
+               @Override
+               public Enumeration<String> keys() {
+                       return Collections.enumeration(effectiveKeys);
+               }
+
+               @Override
+               public Enumeration<Object> elements() {
+                       final Iterator<String> it = effectiveKeys.iterator();
+                       return new Enumeration<Object>() {
+
+                               @Override
+                               public boolean hasMoreElements() {
+                                       return it.hasNext();
+                               }
+
+                               @Override
+                               public Object nextElement() {
+                                       String key = it.next();
+                                       try {
+                                               return getAttributes().get(key).get();
+                                       } catch (NamingException e) {
+                                               throw new UserDirectoryException(
+                                                               "Cannot get value for key " + key, e);
+                                       }
+                               }
+
+                       };
+               }
+
+               @Override
+               public Object get(Object key) {
+                       try {
+                               Attribute attr = getAttributes().get(key.toString());
+                               if (attr == null)
+                                       return null;
+                               return attr.get();
+                       } catch (NamingException e) {
+                               throw new UserDirectoryException(
+                                               "Cannot get value for attribute " + key, e);
+                       }
+               }
+
+               @Override
+               public Object put(String key, Object value) {
+                       userAdmin.checkEdit();
+                       if (!isEditing())
+                               startEditing();
+
+                       if (!(value instanceof String || value instanceof byte[]))
+                               throw new IllegalArgumentException(
+                                               "Value must be String or byte[]");
+
+                       if (includeFilter && !attrFilter.contains(key))
+                               throw new IllegalArgumentException("Key " + key
+                                               + " not included");
+                       else if (!includeFilter && attrFilter.contains(key))
+                               throw new IllegalArgumentException("Key " + key + " excluded");
+
+                       try {
+                               Attribute attribute = modifiedAttributes.get(key.toString());
+                               attribute = new BasicAttribute(key.toString());
+                               attribute.add(value);
+                               Attribute previousAttribute = modifiedAttributes.put(attribute);
+                               if (previousAttribute != null)
+                                       return previousAttribute.get();
+                               else
+                                       return null;
+                       } catch (NamingException e) {
+                               throw new UserDirectoryException(
+                                               "Cannot get value for attribute " + key, e);
+                       }
+               }
+
+               @Override
+               public Object remove(Object key) {
+                       userAdmin.checkEdit();
+                       if (!isEditing())
+                               startEditing();
+
+                       if (includeFilter && !attrFilter.contains(key))
+                               throw new IllegalArgumentException("Key " + key
+                                               + " not included");
+                       else if (!includeFilter && attrFilter.contains(key))
+                               throw new IllegalArgumentException("Key " + key + " excluded");
+
+                       try {
+                               Attribute attr = modifiedAttributes.remove(key.toString());
+                               if (attr != null)
+                                       return attr.get();
+                               else
+                                       return null;
+                       } catch (NamingException e) {
+                               throw new UserDirectoryException("Cannot remove attribute "
+                                               + key, e);
+                       }
+               }
+       }
+
 }
index c5ca49300425ad2910d361b2253c9e5728d7de35..098243638a9cdba82c8f9f2bf2ede3e2988024e3 100644 (file)
@@ -21,6 +21,9 @@ import javax.naming.directory.Attributes;
 import javax.naming.directory.BasicAttributes;
 import javax.naming.ldap.LdapName;
 import javax.naming.ldap.Rdn;
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
 
 import org.apache.commons.io.IOUtils;
 import org.osgi.framework.Filter;
@@ -31,7 +34,7 @@ import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.User;
 
 /** User admin implementation using LDIF file(s) as backend. */
-public class LdifUserAdmin extends AbstractLdapUserAdmin {
+public class LdifUserAdmin extends AbstractUserDirectory {
        SortedMap<LdapName, LdifUser> users = new TreeMap<LdapName, LdifUser>();
        SortedMap<LdapName, LdifGroup> groups = new TreeMap<LdapName, LdifGroup>();
 
@@ -39,9 +42,10 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
 
        // private Map<LdapName, List<LdifGroup>> directMemberOf = new
        // TreeMap<LdapName, List<LdifGroup>>();
+       private XaRes xaRes = new XaRes();
 
        public LdifUserAdmin(String uri) {
-               this(uri, true);
+               this(uri, readOnlyDefault(uri));
        }
 
        public LdifUserAdmin(String uri, boolean isReadOnly) {
@@ -49,12 +53,21 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                try {
                        setUri(new URI(uri));
                } catch (URISyntaxException e) {
-                       throw new ArgeoUserAdminException("Invalid URI " + uri, e);
+                       throw new UserDirectoryException("Invalid URI " + uri, e);
                }
 
-               if (!isReadOnly && !getUri().getScheme().equals("file:"))
+               if (!isReadOnly && !getUri().getScheme().equals("file"))
                        throw new UnsupportedOperationException(getUri().getScheme()
-                                       + "not supported read-write.");
+                                       + " not supported read-write.");
+
+       }
+
+       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.");
 
        }
 
@@ -64,21 +77,35 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                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;
+       }
+
        public void init() {
                try {
                        load(getUri().toURL().openStream());
                } catch (Exception e) {
-                       throw new ArgeoUserAdminException("Cannot open URL " + getUri(), e);
+                       throw new UserDirectoryException("Cannot open URL " + getUri(), e);
                }
        }
 
        public void save() {
                if (getUri() == null || isReadOnly())
-                       throw new ArgeoUserAdminException("Cannot save LDIF user admin");
+                       throw new UserDirectoryException("Cannot save LDIF user admin");
                try (FileOutputStream out = new FileOutputStream(new File(getUri()))) {
                        save(out);
                } catch (IOException e) {
-                       throw new ArgeoUserAdminException("Cannot save user admin to "
+                       throw new UserDirectoryException("Cannot save user admin to "
                                        + getUri(), e);
                }
        }
@@ -106,7 +133,7 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                                objectClasses: while (objectClasses.hasMore()) {
                                        String objectClass = objectClasses.next().toString();
                                        if (objectClass.equals("inetOrgPerson")) {
-                                               users.put(key, new LdifUser(key, attributes));
+                                               users.put(key, new LdifUser(this, key, attributes));
                                                break objectClasses;
                                        } else if (objectClass.equals("groupOfNames")) {
                                                groups.put(key, new LdifGroup(this, key, attributes));
@@ -116,8 +143,8 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                        }
 
                        // optimise
-//                     for (LdifGroup group : groups.values())
-//                             loadMembers(group);
+                       // for (LdifGroup group : groups.values())
+                       // loadMembers(group);
 
                        // indexes
                        for (String attr : getIndexedUserProperties())
@@ -131,7 +158,7 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                                                LdifUser otherUser = userIndexes.get(attr).put(
                                                                value.toString(), user);
                                                if (otherUser != null)
-                                                       throw new ArgeoUserAdminException("User " + user
+                                                       throw new UserDirectoryException("User " + user
                                                                        + " and user " + otherUser
                                                                        + " both have property " + attr
                                                                        + " set to " + value);
@@ -139,7 +166,7 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                                }
                        }
                } catch (Exception e) {
-                       throw new ArgeoUserAdminException(
+                       throw new UserDirectoryException(
                                        "Cannot load user admin service from LDIF", e);
                }
        }
@@ -180,7 +207,7 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                try {
                        LdapName dn = new LdapName(name);
                        if (users.containsKey(dn) || groups.containsKey(dn))
-                               throw new ArgeoUserAdminException("Already a role " + name);
+                               throw new UserDirectoryException("Already a role " + name);
 
                        BasicAttributes attrs = new BasicAttributes();
                        attrs.put("dn", dn.toString());
@@ -189,16 +216,16 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                        attrs.put(nameRdn.getType(), nameRdn.getValue());
                        LdifUser newRole;
                        if (type == Role.USER) {
-                               newRole = new LdifUser(dn, attrs);
+                               newRole = new LdifUser(this, dn, attrs);
                                users.put(dn, newRole);
                        } else if (type == Role.GROUP) {
                                newRole = new LdifGroup(this, dn, attrs);
                                groups.put(dn, (LdifGroup) newRole);
                        } else
-                               throw new ArgeoUserAdminException("Unsupported type " + type);
+                               throw new UserDirectoryException("Unsupported type " + type);
                        return newRole;
                } catch (InvalidNameException e) {
-                       throw new ArgeoUserAdminException("Cannot create role " + name, e);
+                       throw new UserDirectoryException("Cannot create role " + name, e);
                }
        }
 
@@ -212,12 +239,12 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                        else if (groups.containsKey(dn))
                                role = groups.remove(dn);
                        else
-                               throw new ArgeoUserAdminException("There is no role " + name);
+                               throw new UserDirectoryException("There is no role " + name);
                        if (role == null)
                                return false;
                        for (LdifGroup group : getDirectGroups(role)) {
-//                             group.directMembers.remove(role);
-                               group.getAttributes().get(group.getMemberAttrName())
+                               // group.directMembers.remove(role);
+                               group.getAttributes().get(getMemberAttributeId())
                                                .remove(dn.toString());
                        }
                        if (role instanceof LdifGroup) {
@@ -230,7 +257,7 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                        }
                        return true;
                } catch (InvalidNameException e) {
-                       throw new ArgeoUserAdminException("Cannot create role " + name, e);
+                       throw new UserDirectoryException("Cannot create role " + name, e);
                }
        }
 
@@ -285,29 +312,29 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                // throw new UnsupportedOperationException();
        }
 
-//     protected void loadMembers(LdifGroup group) {
-//             group.directMembers = new ArrayList<Role>();
-//             for (LdapName ldapName : group.getMemberNames()) {
-//                     LdifUser role = null;
-//                     if (groups.containsKey(ldapName))
-//                             role = groups.get(ldapName);
-//                     else if (users.containsKey(ldapName))
-//                             role = users.get(ldapName);
-//                     else {
-//                             if (getExternalRoles() != null)
-//                                     role = (LdifUser) getExternalRoles().getRole(
-//                                                     ldapName.toString());
-//                             if (role == null)
-//                                     throw new ArgeoUserAdminException("No role found for "
-//                                                     + ldapName);
-//                     }
-//                     // role.directMemberOf.add(group);
-//                     // if (!directMemberOf.containsKey(role.getDn()))
-//                     // directMemberOf.put(role.getDn(), new ArrayList<LdifGroup>());
-//                     // directMemberOf.get(role.getDn()).add(group);
-//                     group.directMembers.add(role);
-//             }
-//     }
+       // protected void loadMembers(LdifGroup group) {
+       // group.directMembers = new ArrayList<Role>();
+       // for (LdapName ldapName : group.getMemberNames()) {
+       // LdifUser role = null;
+       // if (groups.containsKey(ldapName))
+       // role = groups.get(ldapName);
+       // else if (users.containsKey(ldapName))
+       // role = users.get(ldapName);
+       // else {
+       // if (getExternalRoles() != null)
+       // role = (LdifUser) getExternalRoles().getRole(
+       // ldapName.toString());
+       // if (role == null)
+       // throw new ArgeoUserAdminException("No role found for "
+       // + ldapName);
+       // }
+       // // role.directMemberOf.add(group);
+       // // if (!directMemberOf.containsKey(role.getDn()))
+       // // directMemberOf.put(role.getDn(), new ArrayList<LdifGroup>());
+       // // directMemberOf.get(role.getDn()).add(group);
+       // group.directMembers.add(role);
+       // }
+       // }
 
        @Override
        protected List<LdifGroup> getDirectGroups(User user) {
@@ -318,7 +345,7 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                        try {
                                dn = new LdapName(user.getName());
                        } catch (InvalidNameException e) {
-                               throw new ArgeoUserAdminException("Badly formatted user name "
+                               throw new UserDirectoryException("Badly formatted user name "
                                                + user.getName(), e);
                        }
 
@@ -335,4 +362,72 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin {
                // return Collections.EMPTY_LIST;
        }
 
+       @Override
+       public XAResource getXAResource() {
+               return xaRes;
+       }
+
+       private class XaRes implements XAResource {
+
+               @Override
+               public void commit(Xid xid, boolean onePhase) throws XAException {
+                       save();
+               }
+
+               @Override
+               public void end(Xid xid, int flags) throws XAException {
+                       // TODO Auto-generated method stub
+
+               }
+
+               @Override
+               public void forget(Xid xid) throws XAException {
+                       // TODO Auto-generated method stub
+
+               }
+
+               @Override
+               public int getTransactionTimeout() throws XAException {
+                       // TODO Auto-generated method stub
+                       return 0;
+               }
+
+               @Override
+               public boolean isSameRM(XAResource xares) throws XAException {
+                       // TODO Auto-generated method stub
+                       return false;
+               }
+
+               @Override
+               public int prepare(Xid xid) throws XAException {
+                       // TODO Auto-generated method stub
+                       return 0;
+               }
+
+               @Override
+               public Xid[] recover(int flag) throws XAException {
+                       // TODO Auto-generated method stub
+                       return null;
+               }
+
+               @Override
+               public void rollback(Xid xid) throws XAException {
+                       // TODO Auto-generated method stub
+
+               }
+
+               @Override
+               public boolean setTransactionTimeout(int seconds) throws XAException {
+                       // TODO Auto-generated method stub
+                       return false;
+               }
+
+               @Override
+               public void start(Xid xid, int flags) throws XAException {
+                       // TODO Auto-generated method stub
+
+               }
+
+       }
+
 }
index 25793c923e97bc3c9199cb6a3ed0c41263d0a839..7aad5c488d78afca3f3121e99d5d7717d6f66d0f 100644 (file)
@@ -39,7 +39,7 @@ public class LdifWriter {
                        writer.append('\n');
                        writer.flush();
                } catch (NamingException e) {
-                       throw new ArgeoUserAdminException("Cannot write LDIF", e);
+                       throw new UserDirectoryException("Cannot write LDIF", e);
                }
        }
 
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminWorkingCopy.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminWorkingCopy.java
new file mode 100644 (file)
index 0000000..7103d7a
--- /dev/null
@@ -0,0 +1,14 @@
+package org.argeo.osgi.useradmin;
+
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.UserAdmin;
+
+public interface UserAdminWorkingCopy extends UserAdmin {
+       public void commit();
+
+       public void rollback();
+
+       public Boolean isEditable(Role role);
+
+       public <T extends Role> T getPublished(T role);
+}
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserDirectoryException.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserDirectoryException.java
new file mode 100644 (file)
index 0000000..613d0fd
--- /dev/null
@@ -0,0 +1,19 @@
+package org.argeo.osgi.useradmin;
+
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Exceptions related to Argeo's implementation of OSGi {@link UserAdmin}
+ * service.
+ */
+public class UserDirectoryException extends RuntimeException {
+       private static final long serialVersionUID = 1419352360062048603L;
+
+       public UserDirectoryException(String message) {
+               super(message);
+       }
+
+       public UserDirectoryException(String message, Throwable e) {
+               super(message, e);
+       }
+}
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserDirectoryTransaction.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserDirectoryTransaction.java
new file mode 100644 (file)
index 0000000..24e3cbe
--- /dev/null
@@ -0,0 +1,26 @@
+package org.argeo.osgi.useradmin;
+
+import javax.transaction.UserTransaction;
+
+import org.osgi.service.useradmin.UserAdmin;
+
+class UserDirectoryTransaction {
+       static ThreadLocal<UserDirectoryTransaction> current = new ThreadLocal<UserDirectoryTransaction>();
+
+       private UserAdmin userAdmin;
+
+       private UserTransaction userTransaction;
+
+       public UserDirectoryTransaction(UserAdmin userAdmin) {
+               this.userAdmin = userAdmin;
+               if (current.get() != null)
+                       throw new UserDirectoryException("Transaction " + current.get()
+                                       + " already active.");
+               current.set(this);
+       }
+
+       public void setUserTransaction(UserTransaction userTransaction) {
+               this.userTransaction = userTransaction;
+       }
+
+}
index 64fdea0b051afad187ef0f768cbd804153e24653..42338b2af99d0a665a208017f6120cab89c0af7d 100644 (file)
@@ -4,8 +4,8 @@ import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.argeo.osgi.useradmin.AbstractLdapUserAdmin;
-import org.argeo.osgi.useradmin.ArgeoUserAdminException;
+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;
@@ -31,7 +31,7 @@ public class LdapUserAdminFactory implements ManagedServiceFactory {
                        Dictionary<String, ?> properties) throws ConfigurationException {
                String baseDn = properties.get("baseDn").toString();
                String userAdminUri = properties.get("uri").toString();
-               AbstractLdapUserAdmin userAdmin;
+               AbstractUserDirectory userAdmin;
                if (userAdminUri.startsWith("ldap"))
                        userAdmin = new LdapUserAdmin(userAdminUri);
                else
@@ -45,7 +45,7 @@ public class LdapUserAdminFactory implements ManagedServiceFactory {
                if (index.containsKey(pid))
                        userAdminAggregator.removeUserAdmin(index.get(pid));
                else
-                       throw new ArgeoUserAdminException("No user admin registered for "
+                       throw new UserDirectoryException("No user admin registered for "
                                        + pid);
                index.remove(pid);
        }
index ed6640f36993ef06ddff5049d1c886ba782906d7..f66d3f99cf9ca9f42cb37d0e975c81accb280c18 100644 (file)
@@ -8,7 +8,6 @@ import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.KeyStore;
 import java.security.SecureRandom;
-import java.security.Security;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.util.Date;
@@ -19,7 +18,6 @@ import org.argeo.ArgeoException;
 import org.bouncycastle.cert.X509v3CertificateBuilder;
 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
 import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.operator.ContentSigner;
 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
 
@@ -30,7 +28,7 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
 public class PkiUtils {
        private final static String SECURITY_PROVIDER;
        static {
-               Security.addProvider(new BouncyCastleProvider());
+               // Security.addProvider(new BouncyCastleProvider());
                SECURITY_PROVIDER = "BC";
        }