// 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;
}
--- /dev/null
+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() {
+
+ }
+}
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
@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())
@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
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();
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");
+// }
}
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;
@Override
public boolean login() throws LoginException {
UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class));
- Authorization authorization = null;
if (isAnonymous) {
authorization = userAdmin.getAuthorization(null);
} else {
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;
}
}
}
}
- 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;
}
}
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 {
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;
/** 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;
protected abstract List<DirectoryUser> doGetRoles(Filter f);
+ protected abstract AbstractUserDirectory scope(User user);
+
public void init() {
}
@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
return properties;
}
+ public Dictionary<String, Object> cloneProperties() {
+ return new Hashtable<>(properties);
+ }
+
public void setExternalRoles(UserAdmin externalRoles) {
this.externalRoles = externalRoles;
}
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}
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;
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;
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
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);