final static String LOGIN_CONTEXT_SINGLE_USER = "SINGLE_USER";
// RESERVED ROLES
- final static String ROLES_BASEDN = "ou=roles,ou=node";
+ public final static String ROLE_KERNEL = "OU=node";
+ public final static String ROLES_BASEDN = "ou=roles,ou=node";
public final static String ROLE_ADMIN = "cn=admin," + ROLES_BASEDN;
public final static String ROLE_GROUP_ADMIN = "cn=groupAdmin,"
+ ROLES_BASEDN;
@Override
public String toString() {
- return name.toString() + " implied by " + causes;
+ // return name.toString() + " implied by " + causes;
+ return name.toString();
}
}
--- /dev/null
+package org.argeo.cms.internal.auth;
+
+import java.security.Principal;
+import java.security.cert.CertPath;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import javax.security.auth.x500.X500Principal;
+import javax.security.auth.x500.X500PrivateCredential;
+
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
+import org.argeo.cms.KernelHeader;
+
+public class KernelLoginModule implements LoginModule {
+ private Subject subject;
+
+ @Override
+ public void initialize(Subject subject, CallbackHandler callbackHandler,
+ Map<String, ?> sharedState, Map<String, ?> options) {
+ this.subject = subject;
+ }
+
+ @Override
+ public boolean login() throws LoginException {
+ // TODO check permission at code level
+ return true;
+ }
+
+ @Override
+ public boolean commit() throws LoginException {
+ // Check that kernel has been logged in w/ certificate
+ // Name
+ Set<X500Principal> names = subject.getPrincipals(X500Principal.class);
+ if (names.isEmpty() || names.size() > 1)
+ throw new LoginException("Kernel must have been named");
+ X500Principal name = names.iterator().next();
+ if (!KernelHeader.ROLE_KERNEL.equals(name.getName()))
+ throw new LoginException("Kernel must be named named "
+ + KernelHeader.ROLE_KERNEL);
+ // Private certificate
+ Set<X500PrivateCredential> privateCerts = subject
+ .getPrivateCredentials(X500PrivateCredential.class);
+ X500PrivateCredential privateCert = null;
+ for (X500PrivateCredential pCert : privateCerts) {
+ if (pCert.getCertificate().getSubjectX500Principal().equals(name)) {
+ privateCert = pCert;
+ }
+ }
+ if (privateCert == null)
+ throw new LoginException("Kernel must have a private certificate");
+ // Certificate path
+ Set<CertPath> certPaths = subject.getPublicCredentials(CertPath.class);
+ CertPath certPath = null;
+ for (CertPath cPath : certPaths) {
+ if (cPath.getCertificates().get(0)
+ .equals(privateCert.getCertificate())) {
+ certPath = cPath;
+ }
+ }
+ if (certPath == null)
+ throw new LoginException("Kernel must have a certificate path");
+
+ Set<Principal> principals = subject.getPrincipals();
+ // Add admin roles
+
+ // Add data access roles
+ principals.add(new AdminPrincipal(SecurityConstants.ADMIN_ID));
+
+ return true;
+ }
+
+ @Override
+ public boolean abort() throws LoginException {
+ return true;
+ }
+
+ @Override
+ public boolean logout() throws LoginException {
+ // clear everything
+ subject.getPrincipals().clear();
+ subject.getPublicCredentials().clear();
+ subject.getPrivateCredentials().clear();
+ return true;
+ }
+
+}
private CallbackHandler callbackHandler;
private boolean isAnonymous = false;
- private final static LdapName ROLE_ADMIN_NAME, ROLE_USER_NAME,
- ROLE_ANONYMOUS_NAME;
+ private final static LdapName ROLE_KERNEL_NAME, 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(KernelHeader.ROLE_KERNEL);
ROLE_ADMIN_NAME = new LdapName(KernelHeader.ROLE_ADMIN);
ROLE_USER_NAME = new LdapName(KernelHeader.ROLE_USER);
ROLE_ANONYMOUS_NAME = new LdapName(KernelHeader.ROLE_ANONYMOUS);
RESERVED_ROLES = Collections.unmodifiableList(Arrays
- .asList(new LdapName[] { ROLE_ANONYMOUS_NAME,
- ROLE_USER_NAME, ROLE_ADMIN_NAME,
+ .asList(new LdapName[] { ROLE_KERNEL_NAME, ROLE_ADMIN_NAME,
+ ROLE_ANONYMOUS_NAME, ROLE_USER_NAME,
new LdapName(KernelHeader.ROLE_GROUP_ADMIN),
new LdapName(KernelHeader.ROLE_USER_ADMIN) }));
ROLE_ANONYMOUS_PRINCIPAL = new X500Principal(
private void checkImpliedPrincipalName(LdapName roleName) {
if (ROLE_USER_NAME.equals(roleName)
- || ROLE_ANONYMOUS_NAME.equals(roleName))
+ || ROLE_ANONYMOUS_NAME.equals(roleName)
+ || ROLE_KERNEL_NAME.equals(roleName))
throw new CmsException(roleName + " cannot be listed as role");
}
}
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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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;
* </ul>
*/
final class Kernel implements ServiceListener {
+
private final static Log log = LogFactory.getLog(Kernel.class);
private final BundleContext bundleContext = Activator.getBundleContext();
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(
- KernelHeader.LOGIN_CONTEXT_SYSTEM, kernelSubject);
+ KernelConstants.LOGIN_CONTEXT_KERNEL, kernelSubject,
+ cbHandler);
kernelLc.login();
} catch (LoginException e) {
throw new CmsException("Cannot log in kernel", e);
try {
LoginContext kernelLc = new LoginContext(
- KernelHeader.LOGIN_CONTEXT_SYSTEM, kernelSubject);
+ KernelConstants.LOGIN_CONTEXT_KERNEL, kernelSubject);
kernelLc.logout();
} catch (LoginException e) {
throw new CmsException("Cannot log in kernel", e);
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;
// Security
final static String DEFAULT_SECURITY_KEY = "argeo";
final static String JAAS_CONFIG = "/org/argeo/cms/internal/kernel/jaas.cfg";
+ final static String LOGIN_CONTEXT_KERNEL = "KERNEL";
// DAV
final static String WEBDAV_CONFIG = "/org/argeo/cms/internal/kernel/webdav-config.xml";
import java.io.File;
import java.io.IOException;
+import java.net.URI;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
/** Package utilities */
class KernelUtils implements KernelConstants {
private final static String OSGI_INSTANCE_AREA = "osgi.instance.area";
+ private final static String OSGI_CONFIGURATION_AREA = "osgi.configuration.area";
static Dictionary<String, ?> asDictionary(Properties props) {
Hashtable<String, Object> hashtable = new Hashtable<String, Object>();
.getAbsoluteFile();
}
+ static File getOsgiConfigurationFile(String relativePath) {
+ try {
+ return new File(new URI(Activator.getBundleContext().getProperty(
+ OSGI_CONFIGURATION_AREA)
+ + relativePath)).getCanonicalFile();
+ } catch (Exception e) {
+ throw new CmsException("Cannot get configuration file for "
+ + relativePath, e);
+ }
+ }
+
static String getFrameworkProp(String key, String def) {
String value = Activator.getBundleContext().getProperty(key);
if (value == null)
--- /dev/null
+package org.argeo.cms.internal.kernel;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.osgi.service.useradmin.Authorization;
+
+class NodeAuthorization implements Authorization {
+ private final String name;
+ private final String displayName;
+ private final List<String> systemRoles;
+ private final List<String> roles;
+
+ public NodeAuthorization(String name, String displayName,
+ Collection<String> systemRoles, String[] roles) {
+ this.name = name;
+ this.displayName = displayName;
+ this.systemRoles = Collections.unmodifiableList(new ArrayList<String>(
+ systemRoles));
+ this.roles = Collections.unmodifiableList(Arrays.asList(roles));
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean hasRole(String name) {
+ if (systemRoles.contains(name))
+ return true;
+ if (roles.contains(name))
+ return true;
+ return false;
+ }
+
+ @Override
+ public String[] getRoles() {
+ int size = systemRoles.size() + roles.size();
+ List<String> res = new ArrayList<String>(size);
+ res.addAll(systemRoles);
+ res.addAll(roles);
+ return res.toArray(new String[size]);
+ }
+
+ @Override
+ public int hashCode() {
+ if (name == null)
+ return super.hashCode();
+ return name.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Authorization))
+ return false;
+ Authorization that = (Authorization) obj;
+ if (name == null)
+ return that.getName() == null;
+ return name.equals(that.getName());
+ }
+
+ @Override
+ public String toString() {
+ return displayName;
+ }
+
+}
@Override
public Authorization getAuthorization(User user) {
UserAdmin userAdmin = findUserAdmin(user.getName());
- // FIXME clarify assumptions
- return userAdmin.getAuthorization(user);
- // String[] roles = auth.getRoles();
- // // Gather system roles
- // Set<String> systemRoles = new HashSet<String>();
- // for(String businessRole:roles){
- //
- // }
- // return null;
+ Authorization rawAuthorization = userAdmin.getAuthorization(user);
+ // gather system roles
+ Set<String> systemRoles = new HashSet<String>();
+ for (String role : rawAuthorization.getRoles()) {
+ Authorization auth = nodeRoles.getAuthorization((User) userAdmin
+ .getRole(role));
+ systemRoles.addAll(Arrays.asList(auth.getRoles()));
+ }
+ return new NodeAuthorization(rawAuthorization.getName(),
+ rawAuthorization.toString(), systemRoles,
+ rawAuthorization.getRoles());
}
//
org.argeo.security.core.SystemLoginModule requisite;
};
+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;
+ org.argeo.cms.internal.auth.KernelLoginModule requisite;
+};
+
OLD_SYSTEM {
org.argeo.cms.internal.auth.SystemLoginModule requisite;
org.springframework.security.authentication.jaas.SecurityContextLoginModule requisite;
+++ /dev/null
-package org.argeo.osgi.auth;
-
-import java.io.IOException;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.UnsupportedCallbackException;
-
-import org.osgi.framework.BundleContext;
-
-public class BuncleContextCallbackHander implements CallbackHandler {
- private final BundleContext bundleContext;
-
- public BuncleContextCallbackHander(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
- @Override
- public void handle(Callback[] callbacks) throws IOException,
- UnsupportedCallbackException {
- for (Callback callback : callbacks) {
- if (!(callback instanceof BundleContextCallback))
- throw new UnsupportedCallbackException(callback);
- ((BundleContextCallback) callback).setBundleContext(bundleContext);
- }
-
- }
-
-}
--- /dev/null
+package org.argeo.osgi.auth;
+
+import java.io.IOException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.osgi.framework.BundleContext;
+
+public class BundleContextCallbackHander implements CallbackHandler {
+ private final BundleContext bundleContext;
+
+ public BundleContextCallbackHander(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException,
+ UnsupportedCallbackException {
+ for (Callback callback : callbacks) {
+ if (!(callback instanceof BundleContextCallback))
+ throw new UnsupportedCallbackException(callback);
+ ((BundleContextCallback) callback).setBundleContext(bundleContext);
+ }
+
+ }
+
+}
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 URI uri;
private UserAdmin externalRoles;
+ private List<String> indexedUserProperties = Arrays.asList(new String[] {
+ "uid", "mail", "cn" });
public AbstractLdapUserAdmin() {
}
this.isReadOnly = isReadOnly;
}
- private List<String> indexedUserProperties = Arrays.asList(new String[] {
- "uid", "mail", "cn" });
+ 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;
return isReadOnly;
}
- public void init() {
-
- }
-
- public void destroy() {
-
- }
-
UserAdmin getExternalRoles() {
return externalRoles;
}
--- /dev/null
+package org.argeo.osgi.useradmin;
+
+/**
+ * Standard LDAP attributes and object classes leverages in ths implementation
+ * of user admin.
+ */
+public interface LdapNames {
+ public final static String LDAP_PREFIX = "ldap:";
+
+ // Attributes
+ public final static String LDAP_CN = LDAP_PREFIX + "cn";
+ public final static String LDAP_UID = LDAP_PREFIX + "uid";
+ public final static String LDAP_DISPLAY_NAME = LDAP_PREFIX + "displayName";
+}
import org.argeo.ArgeoException;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.useradmin.Authorization;
+import org.osgi.service.useradmin.Group;
import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.User;
Attributes attrs = initialLdapContext.getAttributes(name);
LdifUser res;
if (attrs.get("objectClass").contains("groupOfNames"))
- res = new LdifGroup(new LdapName(name), attrs);
+ res = new LdifGroup(this, new LdapName(name), attrs);
else if (attrs.get("objectClass").contains("inetOrgPerson"))
res = new LdifUser(new LdapName(name), attrs);
else
public Role[] getRoles(String filter) throws InvalidSyntaxException {
try {
String searchFilter = filter;
+ if (searchFilter == null)
+ searchFilter = "(|(objectClass=inetOrgPerson)(objectClass=groupOfNames))";
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
while (results.hasMoreElements()) {
SearchResult searchResult = results.next();
Attributes attrs = searchResult.getAttributes();
- String name = searchResult.getName();
LdifUser role;
if (attrs.get("objectClass").contains("groupOfNames"))
- role = new LdifGroup(new LdapName(name), attrs);
+ role = new LdifGroup(this, toDn(searchBase, searchResult),
+ attrs);
else if (attrs.get("objectClass").contains("inetOrgPerson"))
- role = new LdifUser(new LdapName(name), attrs);
+ role = new LdifUser(toDn(searchBase, searchResult), attrs);
else
throw new ArgeoUserAdminException(
- "Unsupported LDAP type for " + name);
+ "Unsupported LDAP type for "
+ + searchResult.getName());
res.add(role);
}
return res.toArray(new Role[res.size()]);
@Override
public Authorization getAuthorization(User user) {
LdifUser u = (LdifUser) user;
- populateDirectMemberOf(u);
- return new LdifAuthorization(u);
+ // populateDirectMemberOf(u);
+ return new LdifAuthorization(u, getAllRoles(u));
}
private LdapName toDn(String baseDn, Binding binding)
+ baseDn : binding.getName());
}
- void populateDirectMemberOf(LdifUser user) {
+ // void populateDirectMemberOf(LdifUser user) {
+ //
+ // try {
+ // String searchFilter = "(&(objectClass=groupOfNames)(member="
+ // + user.getName() + "))";
+ //
+ // SearchControls searchControls = new SearchControls();
+ // searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+ //
+ // String searchBase = "ou=node";
+ // NamingEnumeration<SearchResult> results = initialLdapContext
+ // .search(searchBase, searchFilter, searchControls);
+ //
+ // // TODO synchro
+ // //user.directMemberOf.clear();
+ // while (results.hasMoreElements()) {
+ // SearchResult searchResult = (SearchResult) results
+ // .nextElement();
+ // LdifGroup group = new LdifGroup(toDn(searchBase, searchResult),
+ // searchResult.getAttributes());
+ // populateDirectMemberOf(group);
+ // //user.directMemberOf.add(group);
+ // }
+ // } catch (Exception e) {
+ // throw new ArgeoException("Cannot populate direct members of "
+ // + user, e);
+ // }
+ // }
+ @Override
+ protected List<? extends Group> getDirectGroups(User user) {
+ List<Group> directGroups = new ArrayList<Group>();
try {
String searchFilter = "(&(objectClass=groupOfNames)(member="
+ user.getName() + "))";
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
- String searchBase = "ou=node";
+ String searchBase = getGroupsSearchBase();
NamingEnumeration<SearchResult> results = initialLdapContext
.search(searchBase, searchFilter, searchControls);
- // TODO synchro
- user.directMemberOf.clear();
while (results.hasMoreElements()) {
SearchResult searchResult = (SearchResult) results
.nextElement();
- LdifGroup group = new LdifGroup(toDn(searchBase, searchResult),
- searchResult.getAttributes());
- populateDirectMemberOf(group);
- user.directMemberOf.add(group);
+ LdifGroup group = new LdifGroup(this, toDn(searchBase,
+ searchResult), searchResult.getAttributes());
+ directGroups.add(group);
}
+ return directGroups;
} catch (Exception e) {
throw new ArgeoException("Cannot populate direct members of "
+ user, e);
}
}
+ protected String getGroupsSearchBase() {
+ // TODO configure group search base
+ return baseDn;
+ }
}
package org.argeo.osgi.useradmin;
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Dictionary;
import java.util.List;
import org.osgi.service.useradmin.Authorization;
import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
-public class LdifAuthorization implements Authorization {
- private final LdifUser user;
+public class LdifAuthorization implements Authorization, LdapNames {
+ private final String name;
+ private final String displayName;
+ private final List<String> allRoles;
- public LdifAuthorization(LdifUser user) {
- this.user = user;
+ public LdifAuthorization(User user, List<Role> allRoles) {
+ if (user == null) {
+ this.name = null;
+ this.displayName = "anonymous";
+ } else {
+ this.name = user.getName();
+ Dictionary<String, Object> props = user.getProperties();
+ Object displayName = props.get(LDAP_DISPLAY_NAME);
+ if (displayName == null)
+ displayName = props.get(LDAP_CN);
+ if (displayName == null)
+ displayName = props.get(LDAP_UID);
+ if (displayName == null)
+ displayName = user.getName();
+ if (displayName == null)
+ throw new ArgeoUserAdminException(
+ "Cannot set display name for " + user);
+ this.displayName = displayName.toString();
+ }
+ // roles
+ String[] roles = new String[allRoles.size()];
+ for (int i = 0; i < allRoles.size(); i++) {
+ roles[i] = allRoles.get(i).getName();
+ }
+ this.allRoles = Collections.unmodifiableList(Arrays.asList(roles));
}
@Override
public String getName() {
- if (user == null)
- return null;
- return user.getName();
+ return name;
}
@Override
public boolean hasRole(String name) {
- for (Role role : getAllRoles()) {
- if (role.getName().equals(name))
- return true;
- }
- return false;
+ return allRoles.contains(name);
}
@Override
public String[] getRoles() {
- List<Role> allRoles = getAllRoles();
- if (user != null)
- allRoles.add(0, user);
- String[] res = new String[allRoles.size()];
- for (int i = 0; i < allRoles.size(); i++)
- res[i] = allRoles.get(i).getName();
- return res;
+ return allRoles.toArray(new String[allRoles.size()]);
}
- List<Role> getAllRoles() {
- List<Role> allRoles = new ArrayList<Role>();
- if (user != null)
- collectRoles(user, allRoles);
- else
- collectAnonymousRoles(allRoles);
- return allRoles;
+ @Override
+ public int hashCode() {
+ if (name == null)
+ return super.hashCode();
+ return name.hashCode();
}
- private void collectRoles(LdifUser user, List<Role> allRoles) {
- for (LdifGroup group : user.directMemberOf) {
- // TODO check for loops
- allRoles.add(group);
- collectRoles(group, allRoles);
- }
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Authorization))
+ return false;
+ Authorization that = (Authorization) obj;
+ if (name == null)
+ return that.getName() == null;
+ return name.equals(that.getName());
}
- private void collectAnonymousRoles(List<Role> allRoles) {
- // TODO gather anonymous roles
+ @Override
+ public String toString() {
+ return displayName;
}
-
}
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;
+ // List<Role> directMembers = null;
+ private final UserAdmin userAdmin;
private String memberAttrName = "member";
- public LdifGroup(LdapName dn, Attributes attributes) {
+ public LdifGroup(UserAdmin userAdmin, LdapName dn, Attributes attributes) {
super(dn, attributes);
+ this.userAdmin = userAdmin;
}
@Override
return false;
} else
getAttributes().put(memberAttrName, role.getName());
- directMembers.add(role);
- if (role instanceof LdifUser)
- ((LdifUser) role).directMemberOf.add(this);
+ // directMembers.add(role);
+ // if (role instanceof LdifUser)
+ // ((LdifUser) role).directMemberOf.add(this);
return true;
}
if (!member.contains(role.getName()))
return false;
member.remove(role.getName());
- directMembers.remove(role);
- if (role instanceof LdifUser)
- ((LdifUser) role).directMemberOf.remove(this);
+ // directMembers.remove(role);
+ // if (role instanceof LdifUser)
+ // ((LdifUser) role).directMemberOf.remove(this);
return true;
} else
return false;
@Override
public Role[] getMembers() {
- if (directMembers != null)
- return directMembers.toArray(new Role[directMembers.size()]);
- else
- throw new ArgeoUserAdminException("Members have not been loaded.");
+ 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());
+ }
+ 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);
+ 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)
// }
}
-// 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);
-// }
-// }
+ // 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);
public String getMemberAttrName() {
return memberAttrName;
}
-
-
+
}
class LdifUser implements User {
// optimisation
- List<LdifGroup> directMemberOf = new ArrayList<LdifGroup>();
+ //List<LdifGroup> directMemberOf = new ArrayList<LdifGroup>();
private final LdapName dn;
private Attributes attributes;
private Map<String, Map<String, LdifUser>> userIndexes = new LinkedHashMap<String, Map<String, LdifUser>>();
+ // private Map<LdapName, List<LdifGroup>> directMemberOf = new
+ // TreeMap<LdapName, List<LdifGroup>>();
+
public LdifUserAdmin(String uri) {
this(uri, true);
}
users.put(key, new LdifUser(key, attributes));
break objectClasses;
} else if (objectClass.equals("groupOfNames")) {
- groups.put(key, new LdifGroup(key, attributes));
+ groups.put(key, new LdifGroup(this, key, attributes));
break objectClasses;
}
}
}
// optimise
- for (LdifGroup group : groups.values())
- loadMembers(group);
+// for (LdifGroup group : groups.values())
+// loadMembers(group);
// indexes
for (String attr : getIndexedUserProperties())
@Override
public Authorization getAuthorization(User user) {
- return new LdifAuthorization((LdifUser) user);
+ return new LdifAuthorization((LdifUser) user,
+ getAllRoles((LdifUser) user));
}
@Override
newRole = new LdifUser(dn, attrs);
users.put(dn, newRole);
} else if (type == Role.GROUP) {
- newRole = new LdifGroup(dn, attrs);
+ newRole = new LdifGroup(this, dn, attrs);
groups.put(dn, (LdifGroup) newRole);
} else
throw new ArgeoUserAdminException("Unsupported type " + type);
throw new ArgeoUserAdminException("There is no role " + name);
if (role == null)
return false;
- for (LdifGroup group : role.directMemberOf) {
- group.directMembers.remove(role);
+ for (LdifGroup group : getDirectGroups(role)) {
+// group.directMembers.remove(role);
group.getAttributes().get(group.getMemberAttrName())
.remove(dn.toString());
}
if (role instanceof LdifGroup) {
LdifGroup group = (LdifGroup) role;
- for (Role user : group.directMembers) {
- if (user instanceof LdifUser)
- ((LdifUser) user).directMemberOf.remove(group);
- }
+ // for (Role user : group.directMembers) {
+ // if (user instanceof LdifUser)
+ // directMemberOf.get(((LdifUser) user).getDn()).remove(
+ // group);
+ // }
}
return true;
} catch (InvalidNameException e) {
// 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);
+// 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) {
+ LdapName dn;
+ if (user instanceof LdifUser)
+ dn = ((LdifUser) user).getDn();
+ else
+ try {
+ dn = new LdapName(user.getName());
+ } catch (InvalidNameException e) {
+ throw new ArgeoUserAdminException("Badly formatted user name "
+ + user.getName(), e);
}
- role.directMemberOf.add(group);
- group.directMembers.add(role);
+
+ List<LdifGroup> directGroups = new ArrayList<LdifGroup>();
+ for (LdapName name : groups.keySet()) {
+ LdifGroup group = groups.get(name);
+ if (group.getMemberNames().contains(dn))
+ directGroups.add(group);
}
+ return directGroups;
+ // if (directMemberOf.containsKey(dn))
+ // return Collections.unmodifiableList(directMemberOf.get(dn));
+ // else
+ // return Collections.EMPTY_LIST;
}
}
--- /dev/null
+package org.argeo.security.crypto;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.math.BigInteger;
+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;
+
+import javax.security.auth.x500.X500Principal;
+
+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;
+
+/**
+ * Utilities around private keys and certificate, mostly wrapping BouncyCastle
+ * implementations.
+ */
+public class PkiUtils {
+ private final static String SECURITY_PROVIDER;
+ static {
+ Security.addProvider(new BouncyCastleProvider());
+ SECURITY_PROVIDER = "BC";
+ }
+
+ public static X509Certificate generateSelfSignedCertificate(
+ KeyStore keyStore, X500Principal x500Principal, char[] keyPassword) {
+ try {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA",
+ SECURITY_PROVIDER);
+ kpGen.initialize(1024, new SecureRandom());
+ KeyPair pair = kpGen.generateKeyPair();
+ Date notBefore = new Date(System.currentTimeMillis() - 10000);
+ Date notAfter = new Date(
+ System.currentTimeMillis() + 24L * 3600 * 1000);
+ BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
+ x500Principal, serial, notBefore, notAfter, x500Principal,
+ pair.getPublic());
+ ContentSigner sigGen = new JcaContentSignerBuilder(
+ "SHA256WithRSAEncryption").setProvider(SECURITY_PROVIDER)
+ .build(pair.getPrivate());
+ X509Certificate cert = new JcaX509CertificateConverter()
+ .setProvider(SECURITY_PROVIDER).getCertificate(
+ certGen.build(sigGen));
+ cert.checkValidity(new Date());
+ cert.verify(cert.getPublicKey());
+
+ keyStore.setKeyEntry(x500Principal.getName(), pair.getPrivate(),
+ keyPassword, new Certificate[] { cert });
+ return cert;
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot generate self-signed certificate",
+ e);
+ }
+ }
+
+ public static KeyStore getKeyStore(File keyStoreFile,
+ char[] keyStorePassword) {
+ try {
+ KeyStore store = KeyStore.getInstance("PKCS12", SECURITY_PROVIDER);
+ if (keyStoreFile.exists()) {
+ try (FileInputStream fis = new FileInputStream(keyStoreFile)) {
+ store.load(fis, keyStorePassword);
+ }
+ } else {
+ store.load(null);
+ }
+ return store;
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot load keystore " + keyStoreFile, e);
+ }
+ }
+
+ public static void saveKeyStore(File keyStoreFile, char[] keyStorePassword,
+ KeyStore keyStore) {
+ try {
+ try (FileOutputStream fis = new FileOutputStream(keyStoreFile)) {
+ keyStore.store(fis, keyStorePassword);
+ }
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot save keystore " + keyStoreFile, e);
+ }
+ }
+
+}