Start finalizing security
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 7 Oct 2016 19:58:19 +0000 (19:58 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 7 Oct 2016 19:58:19 +0000 (19:58 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@9258 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

org.argeo.cms/src/org/argeo/cms/auth/AuthConstants.java
org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/auth/NodeUserLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg
org.argeo.enterprise/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java
org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdapUserAdmin.java
org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdifUserAdmin.java

index a0ceec0693f315249127a997c10a08d5c5690891..cd793332c9df769f7fcc40eaefc99a695a7dad8e 100644 (file)
@@ -51,8 +51,8 @@ public interface AuthConstants {
 
        // SHARED STATE KEYS
        // compatible with com.sun.security.auth.module.*LoginModule
-       public static final String SHARED_STATE_USERNAME = "javax.security.auth.login.name";
-       public static final String SHARED_STATE_PASSWORD = "javax.security.auth.login.password";
+//     public static final String SHARED_STATE_USERNAME = "javax.security.auth.login.name";
+//     public static final String SHARED_STATE_PASSWORD = "javax.security.auth.login.password";
        public static final String SHARED_STATE_AUTHORIZATION = HttpContext.AUTHORIZATION;
 
 }
diff --git a/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java b/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java
new file mode 100644 (file)
index 0000000..2e58523
--- /dev/null
@@ -0,0 +1,108 @@
+package org.argeo.cms.auth;
+
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.security.auth.Subject;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.jackrabbit.core.security.AnonymousPrincipal;
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.internal.auth.ImpliedByPrincipal;
+import org.argeo.node.NodeConstants;
+import org.osgi.service.useradmin.Authorization;
+
+class CmsAuthUtils {
+       final static LdapName ROLE_ADMIN_NAME, ROLE_ANONYMOUS_NAME, ROLE_USER_NAME;
+       final static List<LdapName> RESERVED_ROLES;
+       final static X500Principal ROLE_ANONYMOUS_PRINCIPAL;
+       static {
+               try {
+                       // ROLE_KERNEL_NAME = new LdapName(AuthConstants.ROLE_KERNEL);
+                       ROLE_ADMIN_NAME = new LdapName(NodeConstants.ROLE_ADMIN);
+                       ROLE_USER_NAME = new LdapName(NodeConstants.ROLE_USER);
+                       ROLE_ANONYMOUS_NAME = new LdapName(NodeConstants.ROLE_ANONYMOUS);
+                       RESERVED_ROLES = Collections.unmodifiableList(Arrays.asList(new LdapName[] { ROLE_ADMIN_NAME,
+                                       ROLE_ANONYMOUS_NAME, ROLE_USER_NAME, new LdapName(AuthConstants.ROLE_GROUP_ADMIN),
+                                       new LdapName(NodeConstants.ROLE_USER_ADMIN) }));
+                       ROLE_ANONYMOUS_PRINCIPAL = new X500Principal(ROLE_ANONYMOUS_NAME.toString());
+               } catch (InvalidNameException e) {
+                       throw new Error("Cannot initialize login module class", e);
+               }
+       }
+
+       static void addAuthentication(Subject subject, Authorization authorization) {
+               assert subject != null;
+               assert authorization != null;
+               
+               // required for display name:
+               subject.getPrivateCredentials().add(authorization);
+
+               Set<Principal> principals = subject.getPrincipals();
+               try {
+                       String authName = authorization.getName();
+
+                       // determine user's principal
+                       final LdapName name;
+                       final Principal userPrincipal;
+                       if (authName == null) {
+                               name = ROLE_ANONYMOUS_NAME;
+                               userPrincipal = ROLE_ANONYMOUS_PRINCIPAL;
+                               principals.add(userPrincipal);
+                               principals.add(new AnonymousPrincipal());
+                       } else {
+                               name = new LdapName(authName);
+                               checkUserName(name);
+                               userPrincipal = new X500Principal(name.toString());
+                               principals.add(userPrincipal);
+                               principals.add(new ImpliedByPrincipal(ROLE_USER_NAME, userPrincipal));
+                       }
+
+                       // Add roles provided by authorization
+                       for (String role : authorization.getRoles()) {
+                               LdapName roleName = new LdapName(role);
+                               if (roleName.equals(name)) {
+                                       // skip
+                               } else {
+                                       checkImpliedPrincipalName(roleName);
+                                       principals.add(new ImpliedByPrincipal(roleName.toString(), userPrincipal));
+                                       if (roleName.equals(ROLE_ADMIN_NAME))
+                                               principals.add(new AdminPrincipal(SecurityConstants.ADMIN_ID));
+                               }
+                       }
+
+               } catch (InvalidNameException e) {
+                       throw new CmsException("Cannot commit", e);
+               }
+       }
+
+       static void checkUserName(LdapName name) {
+               if (RESERVED_ROLES.contains(name))
+                       throw new CmsException(name + " is a reserved name");
+       }
+
+       static void checkImpliedPrincipalName(LdapName roleName) {
+               if (ROLE_USER_NAME.equals(roleName) || ROLE_ANONYMOUS_NAME.equals(roleName))
+                       throw new CmsException(roleName + " cannot be listed as role");
+       }
+       
+       static void cleanUp(Subject subject){
+               // Argeo
+               subject.getPrincipals().removeAll(subject.getPrincipals(X500Principal.class));
+               subject.getPrincipals().removeAll(subject.getPrincipals(ImpliedByPrincipal.class));
+               // Jackrabbit
+               subject.getPrincipals().removeAll(subject.getPrincipals(AdminPrincipal.class));
+               subject.getPrincipals().removeAll(subject.getPrincipals(AnonymousPrincipal.class));
+       }
+
+       private CmsAuthUtils() {
+
+       }
+}
index 956b4a65cd512ba70f6575cf9d9105c803a3a33a..0b638bc2f1249d8716ee6a0e7fc167cc84a4a06e 100644 (file)
@@ -1,52 +1,37 @@
 package org.argeo.cms.auth;
 
-import java.security.Principal;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
 import javax.security.auth.Subject;
 import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.FailedLoginException;
 import javax.security.auth.login.LoginException;
 import javax.security.auth.spi.LoginModule;
-import javax.security.auth.x500.X500Principal;
 
-import org.apache.jackrabbit.core.security.AnonymousPrincipal;
-import org.apache.jackrabbit.core.security.SecurityConstants;
-import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.internal.auth.ImpliedByPrincipal;
-import org.argeo.node.NodeConstants;
 import org.osgi.service.useradmin.Authorization;
 
 public class NodeUserLoginModule implements LoginModule, AuthConstants {
        private Subject subject;
        private Map<String, Object> sharedState = null;
 
-       private final static LdapName ROLE_ADMIN_NAME, ROLE_ANONYMOUS_NAME, ROLE_USER_NAME;
-       private final static List<LdapName> RESERVED_ROLES;
-       private final static X500Principal ROLE_ANONYMOUS_PRINCIPAL;
-       static {
-               try {
-                       // ROLE_KERNEL_NAME = new LdapName(AuthConstants.ROLE_KERNEL);
-                       ROLE_ADMIN_NAME = new LdapName(NodeConstants.ROLE_ADMIN);
-                       ROLE_USER_NAME = new LdapName(NodeConstants.ROLE_USER);
-                       ROLE_ANONYMOUS_NAME = new LdapName(NodeConstants.ROLE_ANONYMOUS);
-                       RESERVED_ROLES = Collections.unmodifiableList(Arrays.asList(new LdapName[] { ROLE_ADMIN_NAME,
-                                       ROLE_ANONYMOUS_NAME, ROLE_USER_NAME, new LdapName(AuthConstants.ROLE_GROUP_ADMIN),
-                                       new LdapName(NodeConstants.ROLE_USER_ADMIN) }));
-                       ROLE_ANONYMOUS_PRINCIPAL = new X500Principal(ROLE_ANONYMOUS_NAME.toString());
-               } catch (InvalidNameException e) {
-                       throw new Error("Cannot initialize login module class", e);
-               }
-       }
-
-       private Authorization authorization;
+//     private final static LdapName ROLE_ADMIN_NAME, ROLE_ANONYMOUS_NAME, ROLE_USER_NAME;
+//     private final static List<LdapName> RESERVED_ROLES;
+//     private final static X500Principal ROLE_ANONYMOUS_PRINCIPAL;
+//     static {
+//             try {
+//                     // ROLE_KERNEL_NAME = new LdapName(AuthConstants.ROLE_KERNEL);
+//                     ROLE_ADMIN_NAME = new LdapName(NodeConstants.ROLE_ADMIN);
+//                     ROLE_USER_NAME = new LdapName(NodeConstants.ROLE_USER);
+//                     ROLE_ANONYMOUS_NAME = new LdapName(NodeConstants.ROLE_ANONYMOUS);
+//                     RESERVED_ROLES = Collections.unmodifiableList(Arrays.asList(new LdapName[] { ROLE_ADMIN_NAME,
+//                                     ROLE_ANONYMOUS_NAME, ROLE_USER_NAME, new LdapName(AuthConstants.ROLE_GROUP_ADMIN),
+//                                     new LdapName(NodeConstants.ROLE_USER_ADMIN) }));
+//                     ROLE_ANONYMOUS_PRINCIPAL = new X500Principal(ROLE_ANONYMOUS_NAME.toString());
+//             } catch (InvalidNameException e) {
+//                     throw new Error("Cannot initialize login module class", e);
+//             }
+//     }
+
+       // private Authorization authorization;
 
        @SuppressWarnings("unchecked")
        @Override
@@ -58,9 +43,8 @@ public class NodeUserLoginModule implements LoginModule, AuthConstants {
 
        @Override
        public boolean login() throws LoginException {
-               authorization = (Authorization) sharedState.get(SHARED_STATE_AUTHORIZATION);
-               if (authorization == null)
-                       throw new FailedLoginException("No authorization available");
+               // if (authorization == null)
+               // throw new FailedLoginException("No authorization available");
                // Iterator<Authorization> auth = subject.getPrivateCredentials(
                // Authorization.class).iterator();
                // if (!auth.hasNext())
@@ -71,48 +55,53 @@ public class NodeUserLoginModule implements LoginModule, AuthConstants {
 
        @Override
        public boolean commit() throws LoginException {
+               Authorization authorization = (Authorization) sharedState.get(SHARED_STATE_AUTHORIZATION);
                if (authorization == null)
                        throw new LoginException("Authorization should not be null");
-               // required for display name:
-               subject.getPrivateCredentials().add(authorization);
-
-               Set<Principal> principals = subject.getPrincipals();
-               try {
-                       String authName = authorization.getName();
-
-                       // determine user's principal
-                       final LdapName name;
-                       final Principal userPrincipal;
-                       if (authName == null) {
-                               name = ROLE_ANONYMOUS_NAME;
-                               userPrincipal = ROLE_ANONYMOUS_PRINCIPAL;
-                               principals.add(userPrincipal);
-                               principals.add(new AnonymousPrincipal());
-                       } else {
-                               name = new LdapName(authName);
-                               checkUserName(name);
-                               userPrincipal = new X500Principal(name.toString());
-                               principals.add(userPrincipal);
-                               principals.add(new ImpliedByPrincipal(ROLE_USER_NAME, userPrincipal));
-                       }
-
-                       // Add roles provided by authorization
-                       for (String role : authorization.getRoles()) {
-                               LdapName roleName = new LdapName(role);
-                               if (roleName.equals(name)) {
-                                       // skip
-                               } else {
-                                       checkImpliedPrincipalName(roleName);
-                                       principals.add(new ImpliedByPrincipal(roleName.toString(), userPrincipal));
-                                       if (roleName.equals(ROLE_ADMIN_NAME))
-                                               principals.add(new AdminPrincipal(SecurityConstants.ADMIN_ID));
-                               }
-                       }
-
-                       return true;
-               } catch (InvalidNameException e) {
-                       throw new CmsException("Cannot commit", e);
-               }
+               CmsAuthUtils.addAuthentication(subject, authorization);
+               return true;
+               // // required for display name:
+               // subject.getPrivateCredentials().add(authorization);
+               //
+               // Set<Principal> principals = subject.getPrincipals();
+               // try {
+               // String authName = authorization.getName();
+               //
+               // // determine user's principal
+               // final LdapName name;
+               // final Principal userPrincipal;
+               // if (authName == null) {
+               // name = ROLE_ANONYMOUS_NAME;
+               // userPrincipal = ROLE_ANONYMOUS_PRINCIPAL;
+               // principals.add(userPrincipal);
+               // principals.add(new AnonymousPrincipal());
+               // } else {
+               // name = new LdapName(authName);
+               // checkUserName(name);
+               // userPrincipal = new X500Principal(name.toString());
+               // principals.add(userPrincipal);
+               // principals.add(new ImpliedByPrincipal(ROLE_USER_NAME,
+               // userPrincipal));
+               // }
+               //
+               // // Add roles provided by authorization
+               // for (String role : authorization.getRoles()) {
+               // LdapName roleName = new LdapName(role);
+               // if (roleName.equals(name)) {
+               // // skip
+               // } else {
+               // checkImpliedPrincipalName(roleName);
+               // principals.add(new ImpliedByPrincipal(roleName.toString(),
+               // userPrincipal));
+               // if (roleName.equals(ROLE_ADMIN_NAME))
+               // principals.add(new AdminPrincipal(SecurityConstants.ADMIN_ID));
+               // }
+               // }
+               //
+               // return true;
+               // } catch (InvalidNameException e) {
+               // throw new CmsException("Cannot commit", e);
+               // }
        }
 
        @Override
@@ -126,12 +115,7 @@ public class NodeUserLoginModule implements LoginModule, AuthConstants {
                if (subject == null)
                        throw new LoginException("Subject should not be null");
                // Clean up principals
-               // Argeo
-               subject.getPrincipals().removeAll(subject.getPrincipals(X500Principal.class));
-               subject.getPrincipals().removeAll(subject.getPrincipals(ImpliedByPrincipal.class));
-               // Jackrabbit
-               subject.getPrincipals().removeAll(subject.getPrincipals(AdminPrincipal.class));
-               subject.getPrincipals().removeAll(subject.getPrincipals(AnonymousPrincipal.class));
+               CmsAuthUtils.cleanUp(subject);
                // Clean up private credentials
                subject.getPrivateCredentials().clear();
                cleanUp();
@@ -140,16 +124,16 @@ public class NodeUserLoginModule implements LoginModule, AuthConstants {
 
        private void cleanUp() {
                subject = null;
-               authorization = null;
+               // authorization = null;
        }
 
-       private void checkUserName(LdapName name) {
-               if (RESERVED_ROLES.contains(name))
-                       throw new CmsException(name + " is a reserved name");
-       }
-
-       private void checkImpliedPrincipalName(LdapName roleName) {
-               if (ROLE_USER_NAME.equals(roleName) || ROLE_ANONYMOUS_NAME.equals(roleName))
-                       throw new CmsException(roleName + " cannot be listed as role");
-       }
+//     private void checkUserName(LdapName name) {
+//             if (RESERVED_ROLES.contains(name))
+//                     throw new CmsException(name + " is a reserved name");
+//     }
+//
+//     private void checkImpliedPrincipalName(LdapName roleName) {
+//             if (ROLE_USER_NAME.equals(roleName) || ROLE_ANONYMOUS_NAME.equals(roleName))
+//                     throw new CmsException(roleName + " cannot be listed as role");
+//     }
 }
index 3dfbc0ddb194e94bc879d44ba380c6a3f3f4e05a..52a90c7a5eed86bc2f2eb5b1827b9386721cc05d 100644 (file)
@@ -25,17 +25,21 @@ import org.osgi.service.useradmin.User;
 import org.osgi.service.useradmin.UserAdmin;
 
 public class UserAdminLoginModule implements LoginModule, AuthConstants {
+       private Subject subject;
        private CallbackHandler callbackHandler;
        private Map<String, Object> sharedState = null;
 
        private boolean isAnonymous = false;
 
+       // private state
        private BundleContext bc;
+       private Authorization authorization;
 
        @SuppressWarnings("unchecked")
        @Override
        public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
                        Map<String, ?> options) {
+               this.subject = subject;
                try {
                        bc = FrameworkUtil.getBundle(UserAdminLoginModule.class).getBundleContext();
                        assert bc != null;
@@ -52,7 +56,6 @@ public class UserAdminLoginModule implements LoginModule, AuthConstants {
        @Override
        public boolean login() throws LoginException {
                UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class));
-               Authorization authorization = null;
                if (isAnonymous) {
                        authorization = userAdmin.getAuthorization(null);
                } else {
@@ -64,8 +67,9 @@ public class UserAdminLoginModule implements LoginModule, AuthConstants {
                                callbackHandler.handle(new Callback[] { nameCallback, passwordCallback, langCallback });
                        } catch (IOException e) {
                                throw new LoginException("Cannot handle callback: " + e.getMessage());
-//                     } catch (ThreadDeath e) {
-//                             throw new ThreadDeathLoginException("Callbackhandler thread died", e);
+                               // } catch (ThreadDeath e) {
+                               // throw new ThreadDeathLoginException("Callbackhandler thread
+                               // died", e);
                        } catch (UnsupportedCallbackException e) {
                                return false;
                        }
@@ -107,23 +111,43 @@ public class UserAdminLoginModule implements LoginModule, AuthConstants {
                                }
                        }
                }
-               if (!sharedState.containsKey(SHARED_STATE_AUTHORIZATION))
-                       sharedState.put(SHARED_STATE_AUTHORIZATION, authorization);
-               return true;
+               // if (!sharedState.containsKey(SHARED_STATE_AUTHORIZATION))
+               // sharedState.put(SHARED_STATE_AUTHORIZATION, authorization);
+               return authorization != null;
        }
 
        @Override
        public boolean commit() throws LoginException {
-               return true;
+               // Set<KerberosPrincipal> kerberosPrincipals =
+               // subject.getPrincipals(KerberosPrincipal.class);
+               // if (kerberosPrincipals.size() != 0) {
+               // KerberosPrincipal kerberosPrincipal =
+               // kerberosPrincipals.iterator().next();
+               // System.out.println(kerberosPrincipal);
+               // UserAdmin userAdmin =
+               // bc.getService(bc.getServiceReference(UserAdmin.class));
+               // User user = userAdmin.getUser(null, kerberosPrincipal.getName());
+               // Authorization authorization = userAdmin.getAuthorization(user);
+               // sharedState.put(SHARED_STATE_AUTHORIZATION, authorization);
+               // }
+               if (authorization == null) {
+                       return false;
+                       // throw new LoginException("Authorization should not be null");
+               } else {
+                       CmsAuthUtils.addAuthentication(subject, authorization);
+                       return true;
+               }
        }
 
        @Override
        public boolean abort() throws LoginException {
+               authorization = null;
                return true;
        }
 
        @Override
        public boolean logout() throws LoginException {
+               CmsAuthUtils.cleanUp(subject);
                return true;
        }
 }
index 4c7ebb328c7b7f766e3278011629b1c5ce2744b8..7d900fbe610a77903b568431229f1af60492af02 100644 (file)
@@ -1,12 +1,10 @@
 USER {
     org.argeo.cms.auth.HttpLoginModule requisite;
     org.argeo.cms.auth.UserAdminLoginModule requisite;
-    org.argeo.cms.auth.NodeUserLoginModule requisite;
 };
 
 ANONYMOUS {
     org.argeo.cms.auth.UserAdminLoginModule requisite anonymous=true;
-    org.argeo.cms.auth.NodeUserLoginModule requisite;
 };
 
 DATA_ADMIN {
@@ -17,7 +15,6 @@ SYSTEM {
     org.argeo.cms.auth.DataAdminLoginModule requisite;
 };
 
-
 HARDENED_KERNEL {
     com.sun.security.auth.module.UnixLoginModule requisite;
     com.sun.security.auth.module.KeyStoreLoginModule requisite keyStoreURL="${osgi.instance.area}/node.p12" keyStoreType=PKCS12;
index e8dd6f2a6974af43f0b5dda922256c847c27f8b7..5e7cbc61cde708cdf832e96e1a4736874757a4ff 100644 (file)
@@ -40,6 +40,9 @@ import org.osgi.service.useradmin.UserAdmin;
 
 /** Base class for a {@link UserDirectory}. */
 public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
+       static final String SHARED_STATE_USERNAME = "javax.security.auth.login.name";
+       static final String SHARED_STATE_PASSWORD = "javax.security.auth.login.password";
+
        private final static Log log = LogFactory.getLog(AbstractUserDirectory.class);
 
        private final Hashtable<String, Object> properties;
@@ -104,6 +107,8 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
 
        protected abstract List<DirectoryUser> doGetRoles(Filter f);
 
+       protected abstract AbstractUserDirectory scope(User user);
+
        public void init() {
 
        }
@@ -245,7 +250,17 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
 
        @Override
        public Authorization getAuthorization(User user) {
-               return new LdifAuthorization((DirectoryUser) user, getAllRoles((DirectoryUser) user));
+               if (user == null || user instanceof DirectoryUser) {
+                       return new LdifAuthorization(user, getAllRoles((DirectoryUser) user));
+               } else {
+                       // bind
+                       AbstractUserDirectory scopedUserAdmin = scope(user);
+                       DirectoryUser directoryUser = (DirectoryUser) scopedUserAdmin.getRole(user.getName());
+                       LdifAuthorization authorization = new LdifAuthorization(directoryUser,
+                                       scopedUserAdmin.getAllRoles(directoryUser));
+                       scopedUserAdmin.destroy();
+                       return authorization;
+               }
        }
 
        @Override
@@ -412,6 +427,10 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
                return properties;
        }
 
+       public Dictionary<String, Object> cloneProperties() {
+               return new Hashtable<>(properties);
+       }
+
        public void setExternalRoles(UserAdmin externalRoles) {
                this.externalRoles = externalRoles;
        }
index f78da0af0d29aed943c3cda8831bb9d97bffef47..000cfab0c623e26aae86f5ffd81cc2bb6ae50e7c 100644 (file)
@@ -26,6 +26,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.naming.LdapAttrs;
 import org.osgi.framework.Filter;
+import org.osgi.service.useradmin.User;
 
 /**
  * A user admin based on a LDAP server. Requires a {@link TransactionManager}
@@ -75,6 +76,21 @@ public class LdapUserAdmin extends AbstractUserDirectory {
                        log.error("Cannot destroy LDAP user admin", e);
                }
        }
+       
+       
+
+       @SuppressWarnings("unchecked")
+       @Override
+       protected AbstractUserDirectory scope(User user) {
+               Dictionary<String, Object> credentials = user.getCredentials();
+               // FIXME use arrays
+               Object usernameObj =    credentials.get(SHARED_STATE_USERNAME);
+               Object passwordObj =    credentials.get(SHARED_STATE_PASSWORD);
+               Dictionary<String, Object> properties = cloneProperties();
+               properties.put(Context.SECURITY_PRINCIPAL, usernameObj.toString());
+               properties.put(Context.SECURITY_CREDENTIALS, passwordObj.toString());
+               return new LdapUserAdmin(properties);
+       }
 
        protected InitialLdapContext getLdapContext() {
                return initialLdapContext;
index 4ebca4fcff3a0c3b95ee27d5a16f107173ed8b14..8ec967b7007a73c8875e557b6e8ecee6c0305105 100644 (file)
@@ -1,7 +1,7 @@
 package org.argeo.osgi.useradmin;
 
-import static org.argeo.naming.LdapObjs.inetOrgPerson;
 import static org.argeo.naming.LdapAttrs.objectClass;
+import static org.argeo.naming.LdapObjs.inetOrgPerson;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -26,6 +26,7 @@ import org.argeo.naming.LdifParser;
 import org.argeo.naming.LdifWriter;
 import org.osgi.framework.Filter;
 import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
 
 /**
  * A user admin based on a LDIF files. Requires a {@link TransactionManager} and
@@ -48,6 +49,13 @@ public class LdifUserAdmin extends AbstractUserDirectory {
                load(in);
        }
 
+       @Override
+       protected AbstractUserDirectory scope(User user) {
+               Dictionary<String, Object> properties = cloneProperties();
+               properties.put(UserAdminConf.readOnly.name(), "true");
+               return new LdifUserAdmin(properties);
+       }
+
        private static Dictionary<String, Object> fromUri(String uri, String baseDn) {
                Hashtable<String, Object> res = new Hashtable<String, Object>();
                res.put(UserAdminConf.uri.name(), uri);