From db7aecc7170c024e0e39135cf6b8aa6ce7569ccb Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Fri, 7 Oct 2016 19:58:19 +0000 Subject: [PATCH] Start finalizing security git-svn-id: https://svn.argeo.org/commons/trunk@9258 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../src/org/argeo/cms/auth/AuthConstants.java | 4 +- .../src/org/argeo/cms/auth/CmsAuthUtils.java | 108 +++++++++++ .../argeo/cms/auth/NodeUserLoginModule.java | 170 ++++++++---------- .../argeo/cms/auth/UserAdminLoginModule.java | 38 +++- .../org/argeo/cms/internal/kernel/jaas.cfg | 3 - .../osgi/useradmin/AbstractUserDirectory.java | 21 ++- .../argeo/osgi/useradmin/LdapUserAdmin.java | 16 ++ .../argeo/osgi/useradmin/LdifUserAdmin.java | 10 +- 8 files changed, 263 insertions(+), 107 deletions(-) create mode 100644 org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java diff --git a/org.argeo.cms/src/org/argeo/cms/auth/AuthConstants.java b/org.argeo.cms/src/org/argeo/cms/auth/AuthConstants.java index a0ceec069..cd793332c 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/AuthConstants.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/AuthConstants.java @@ -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 index 000000000..2e585237d --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java @@ -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 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 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() { + + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/auth/NodeUserLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/NodeUserLoginModule.java index 956b4a65c..0b638bc2f 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/NodeUserLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/NodeUserLoginModule.java @@ -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 sharedState = null; - private final static LdapName ROLE_ADMIN_NAME, ROLE_ANONYMOUS_NAME, ROLE_USER_NAME; - private final static List 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 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 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 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 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"); +// } } diff --git a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java index 3dfbc0ddb..52a90c7a5 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java @@ -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 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 sharedState, Map 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 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; } } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg b/org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg index 4c7ebb328..7d900fbe6 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg @@ -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; diff --git a/org.argeo.enterprise/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java b/org.argeo.enterprise/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java index e8dd6f2a6..5e7cbc61c 100644 --- a/org.argeo.enterprise/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java +++ b/org.argeo.enterprise/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java @@ -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 properties; @@ -104,6 +107,8 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory protected abstract List 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 cloneProperties() { + return new Hashtable<>(properties); + } + public void setExternalRoles(UserAdmin externalRoles) { this.externalRoles = externalRoles; } diff --git a/org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdapUserAdmin.java b/org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdapUserAdmin.java index f78da0af0..000cfab0c 100644 --- a/org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdapUserAdmin.java +++ b/org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdapUserAdmin.java @@ -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 credentials = user.getCredentials(); + // FIXME use arrays + Object usernameObj = credentials.get(SHARED_STATE_USERNAME); + Object passwordObj = credentials.get(SHARED_STATE_PASSWORD); + Dictionary 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; diff --git a/org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdifUserAdmin.java b/org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdifUserAdmin.java index 4ebca4fcf..8ec967b70 100644 --- a/org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdifUserAdmin.java +++ b/org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdifUserAdmin.java @@ -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 properties = cloneProperties(); + properties.put(UserAdminConf.readOnly.name(), "true"); + return new LdifUserAdmin(properties); + } + private static Dictionary fromUri(String uri, String baseDn) { Hashtable res = new Hashtable(); res.put(UserAdminConf.uri.name(), uri); -- 2.30.2