argeo.osgi.start.4.workbench=\
org.eclipse.equinox.http.registry,\
-#argeo.node.useradmin.uri=ldap://localhost:10389/
+#argeo.node.useradmin.uri="\
+#ldap://uid=admin,ou=system:secret\
+#@localhost:10389\
+#/dc=example,dc=com\
+#?readOnly=false\
+#&userObjectClass=inetOrgPerson \
+#dc=example,dc=org.ldif"
org.osgi.framework.security=osgi
java.security.policy=file:../../all.policy
repositoryFactory = new OsgiJackrabbitRepositoryFactory();
// Authentication
- nodeSecurity.getUserAdmin().setSyncRegistry(
- transactionManager.getTransactionSynchronizationRegistry());
nodeSecurity.getUserAdmin().setTransactionManager(
transactionManager);
final static String REPO_MAX_VOLATILE_INDEX_SIZE = "argeo.node.repo.maxVolatileIndexSize";
// Node Security
- /** URI to an LDIF file used as initialization or backend */
+ final static String ROLES_URI = "argeo.node.roles.uri";
+ /** URI to an LDIF file or LDAP server used as initialization or backend */
final static String USERADMIN_URI = "argeo.node.useradmin.uri";
final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd",
"/org/argeo/cms/cms.cnd" };
}
// Security
+ @Deprecated
static void anonymousLogin(AuthenticationManager authenticationManager) {
try {
List<GrantedAuthorityPrincipal> anonAuthorities = Collections
import java.security.Provider;
import java.security.Security;
import java.util.Arrays;
+import java.util.Hashtable;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.login.LoginException;
import javax.security.auth.x500.X500Principal;
-import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.cms.CmsException;
import org.argeo.cms.KernelHeader;
-import org.argeo.osgi.useradmin.AbstractUserDirectory;
-import org.argeo.osgi.useradmin.LdapUserAdmin;
-import org.argeo.osgi.useradmin.LdifUserAdmin;
import org.argeo.security.crypto.PkiUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.osgi.framework.BundleContext;
private final NodeUserAdmin userAdmin;
private final Subject kernelSubject;
- // private final OsAuthenticationProvider osAuth;
- // private final InternalAuthenticationProvider internalAuth;
- // private final AnonymousAuthenticationProvider anonymousAuth;
- // private final JackrabbitUserAdminService userAdminService;
-
private ServiceRegistration<AuthenticationManager> authenticationManagerReg;
- // private ServiceRegistration<UserAdminService> userAdminServiceReg;
- // private ServiceRegistration<UserDetailsManager> userDetailsManagerReg;
private ServiceRegistration<UserAdmin> userAdminReg;
this.bundleContext = bundleContext;
this.kernelSubject = logKernel();
-
- // osAuth = new OsAuthenticationProvider();
- // internalAuth = new InternalAuthenticationProvider(
- // Activator.getSystemKey());
- // anonymousAuth = new AnonymousAuthenticationProvider(
- // Activator.getSystemKey());
-
- // user admin
- // userAdminService = new JackrabbitUserAdminService();
- // userAdminService.setRepository(node);
- // userAdminService.setSecurityModel(new SimpleJcrSecurityModel());
- // userAdminService.init();
-
userAdmin = new NodeUserAdmin();
-
- File osgiInstanceDir = KernelUtils.getOsgiInstanceDir();
- File homeDir = new File(osgiInstanceDir, "node");
- homeDir.mkdirs();
-
- String userAdminUri = KernelUtils
- .getFrameworkProp(KernelConstants.USERADMIN_URI);
- String baseDn = "dc=example,dc=com";
- if (userAdminUri == null) {
- File businessRolesFile = new File(homeDir, baseDn + ".ldif");
- // userAdminUri = getClass().getResource(baseDn +
- // ".ldif").toString();
- if (!businessRolesFile.exists())
- try {
- FileUtils.copyInputStreamToFile(getClass()
- .getResourceAsStream(baseDn + ".ldif"),
- businessRolesFile);
- } catch (IOException e) {
- throw new CmsException("Cannot copy demo resource", e);
- }
- userAdminUri = businessRolesFile.toURI().toString();
- }
-
- AbstractUserDirectory businessRoles;
- if (userAdminUri.startsWith("ldap"))
- businessRoles = new LdapUserAdmin(userAdminUri);
- else {
- businessRoles = new LdifUserAdmin(userAdminUri);
- }
- businessRoles.init();
- userAdmin.addUserAdmin(baseDn, businessRoles);
-
- String baseNodeRoleDn = KernelHeader.ROLES_BASEDN;
- File nodeRolesFile = new File(homeDir, baseNodeRoleDn + ".ldif");
- if (!nodeRolesFile.exists())
- try {
- FileUtils.copyInputStreamToFile(
- getClass().getResourceAsStream("demo.ldif"),
- nodeRolesFile);
- } catch (IOException e) {
- throw new CmsException("Cannot copy demo resource", e);
- }
- LdifUserAdmin nodeRoles = new LdifUserAdmin(nodeRolesFile.toURI()
- .toString(), false);
- nodeRoles.setExternalRoles(userAdmin);
- nodeRoles.init();
- // nodeRoles.createRole(KernelHeader.ROLE_ADMIN, Role.GROUP);
- userAdmin.addUserAdmin(baseNodeRoleDn, nodeRoles);
-
}
private Subject logKernel() {
public void publish() {
authenticationManagerReg = bundleContext.registerService(
AuthenticationManager.class, this, null);
- // userAdminServiceReg = bundleContext.registerService(
- // UserAdminService.class, userAdminService, null);
- // userDetailsManagerReg = bundleContext.registerService(
- // UserDetailsManager.class, userAdminService, null);
+ Hashtable<String, Object> properties = new Hashtable<String, Object>();
+ // properties.put(KernelConstants.USERADMIN_URI,
+ // userAdmin.asConfigUris());
userAdminReg = bundleContext.registerService(UserAdmin.class,
- userAdmin, null);
+ userAdmin, properties);
}
void destroy() {
- // try {
- // userAdminService.destroy();
- // } catch (RepositoryException e) {
- // log.error("Error while destroying Jackrabbit useradmin");
- // }
- // userDetailsManagerReg.unregister();
- // userAdminServiceReg.unregister();
authenticationManagerReg.unregister();
- // userAdmin.destroy();
+ userAdmin.destroy();
userAdminReg.unregister();
// Logout kernel
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
- log.error("Authentication manager is deprectaed and should not be used.");
- // Authentication auth = null;
- // if (authentication instanceof InternalAuthentication)
- // auth = internalAuth.authenticate(authentication);
- // else if (authentication instanceof AnonymousAuthenticationToken)
- // auth = anonymousAuth.authenticate(authentication);
- // else if (authentication instanceof
- // UsernamePasswordAuthenticationToken)
- // auth = userAdminService.authenticate(authentication);
- // else if (authentication instanceof OsAuthenticationToken)
- // auth = osAuth.authenticate(authentication);
- // if (auth == null)
- // throw new CmsException("Could not authenticate " + authentication);
+ log.error("Authentication manager is deprecated and should not be used.");
throw new ProviderNotFoundException(
- "Authentication manager is deprectaed and should not be used.");
+ "Authentication manager is deprecated and should not be used.");
}
private void createKeyStoreIfNeeded() {
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);
}
}
}
-
}
package org.argeo.cms.internal.kernel;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
-import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
-import javax.transaction.TransactionSynchronizationRegistry;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
import org.argeo.cms.KernelHeader;
import org.argeo.osgi.useradmin.AbstractUserDirectory;
+import org.argeo.osgi.useradmin.LdapProperties;
+import org.argeo.osgi.useradmin.LdapUserAdmin;
+import org.argeo.osgi.useradmin.LdifUserAdmin;
import org.argeo.osgi.useradmin.UserAdminAggregator;
import org.argeo.osgi.useradmin.UserDirectoryException;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.useradmin.UserAdmin;
public class NodeUserAdmin implements UserAdmin, UserAdminAggregator {
+ private final static Log log = LogFactory.getLog(NodeUserAdmin.class);
final static LdapName ROLES_BASE;
static {
try {
private UserAdmin nodeRoles = null;
private Map<LdapName, UserAdmin> userAdmins = new HashMap<LdapName, UserAdmin>();
- private TransactionSynchronizationRegistry syncRegistry;
private TransactionManager transactionManager;
+ public NodeUserAdmin() {
+ File osgiInstanceDir = KernelUtils.getOsgiInstanceDir();
+ File nodeBaseDir = new File(osgiInstanceDir, "node");
+ nodeBaseDir.mkdirs();
+
+ String userAdminUri = KernelUtils
+ .getFrameworkProp(KernelConstants.USERADMIN_URI);
+ if (userAdminUri == null) {
+ String demoBaseDn = "dc=example,dc=com";
+ File businessRolesFile = new File(nodeBaseDir, demoBaseDn + ".ldif");
+ if (!businessRolesFile.exists())
+ try {
+ FileUtils.copyInputStreamToFile(getClass()
+ .getResourceAsStream(demoBaseDn + ".ldif"),
+ businessRolesFile);
+ } catch (IOException e) {
+ throw new CmsException("Cannot copy demo resource", e);
+ }
+ userAdminUri = businessRolesFile.toURI().toString();
+ }
+
+ String[] uris = userAdminUri.split(" ");
+ for (String uri : uris) {
+ URI u;
+ try {
+ u = new URI(uri);
+ if (u.getScheme() == null) {
+ if (uri.startsWith("/"))
+ u = new File(uri).getAbsoluteFile().toURI();
+ else if (!uri.contains("/"))
+ u = new File(nodeBaseDir, uri).getAbsoluteFile()
+ .toURI();
+ else
+ throw new CmsException("Cannot interpret " + uri
+ + " as an uri");
+ }
+ } catch (URISyntaxException e) {
+ throw new CmsException(
+ "Cannot interpret " + uri + " as an uri", e);
+ }
+ Dictionary<String, ?> properties = LdapProperties.uriAsProperties(u
+ .toString());
+ AbstractUserDirectory businessRoles;
+ if (u.getScheme().startsWith("ldap")) {
+ businessRoles = new LdapUserAdmin(properties);
+ } else {
+ businessRoles = new LdifUserAdmin(properties);
+ }
+ businessRoles.init();
+ addUserAdmin(businessRoles.getBaseDn(), businessRoles);
+ if (log.isDebugEnabled())
+ log.debug("User directory " + businessRoles.getBaseDn() + " ["
+ + u.getScheme() + "] enabled.");
+ }
+
+ // NOde roles
+ String nodeRolesUri = KernelUtils
+ .getFrameworkProp(KernelConstants.ROLES_URI);
+ String baseNodeRoleDn = KernelHeader.ROLES_BASEDN;
+ if (nodeRolesUri == null) {
+ File nodeRolesFile = new File(nodeBaseDir, baseNodeRoleDn + ".ldif");
+ if (!nodeRolesFile.exists())
+ try {
+ FileUtils.copyInputStreamToFile(getClass()
+ .getResourceAsStream("demo.ldif"), nodeRolesFile);
+ } catch (IOException e) {
+ throw new CmsException("Cannot copy demo resource", e);
+ }
+ nodeRolesUri = nodeRolesFile.toURI().toString();
+ }
+
+ Dictionary<String, ?> nodeRolesProperties = LdapProperties
+ .uriAsProperties(nodeRolesUri);
+ if (!nodeRolesProperties.get(LdapProperties.baseDn.getFullName())
+ .equals(baseNodeRoleDn)) {
+ throw new CmsException("Invalid base dn for node roles");
+ // TODO deal with "mounted" roles with a different baseDN
+ }
+ AbstractUserDirectory nodeRoles;
+ if (nodeRolesUri.startsWith("ldap")) {
+ nodeRoles = new LdapUserAdmin(nodeRolesProperties);
+ } else {
+ nodeRoles = new LdifUserAdmin(nodeRolesProperties);
+ }
+ nodeRoles.setExternalRoles(this);
+ nodeRoles.init();
+ addUserAdmin(baseNodeRoleDn, nodeRoles);
+ if (log.isTraceEnabled())
+ log.trace("Node roles enabled.");
+ }
+
+ String asConfigUris() {
+ StringBuilder buf = new StringBuilder();
+ for (LdapName name : userAdmins.keySet()) {
+ buf.append('/').append(name.toString());
+ if (userAdmins.get(name) instanceof AbstractUserDirectory) {
+ AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins
+ .get(name);
+ if (userDirectory.isReadOnly())
+ buf.append('?').append(LdapProperties.readOnly.name())
+ .append("=true");
+ }
+ buf.append(' ');
+ }
+ return buf.toString();
+ }
+
+ public void destroy() {
+ for (LdapName name : userAdmins.keySet()) {
+ if (userAdmins.get(name) instanceof AbstractUserDirectory) {
+ AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins
+ .get(name);
+ userDirectory.destroy();
+ }
+ }
+ }
+
@Override
public Role createRole(String name, int type) {
return findUserAdmin(name).createRole(name, type);
//
@Override
public synchronized void addUserAdmin(String baseDn, UserAdmin userAdmin) {
- if (userAdmin instanceof AbstractUserDirectory)
- ((AbstractUserDirectory) userAdmin).setSyncRegistry(syncRegistry);
-
if (baseDn.equals(KernelHeader.ROLES_BASEDN)) {
nodeRoles = userAdmin;
return;
if (!userAdmins.containsKey(base))
throw new UserDirectoryException("There is no user admin for "
+ base);
- UserAdmin userAdmin = userAdmins.remove(base);
- if (userAdmin instanceof AbstractUserDirectory)
- ((AbstractUserDirectory) userAdmin).setSyncRegistry(null);
+ userAdmins.remove(base);
}
private UserAdmin findUserAdmin(String name) {
.setTransactionManager(transactionManager);
}
}
-
- public void setSyncRegistry(TransactionSynchronizationRegistry syncRegistry) {
- this.syncRegistry = syncRegistry;
- if (nodeRoles instanceof AbstractUserDirectory)
- ((AbstractUserDirectory) nodeRoles).setSyncRegistry(syncRegistry);
- for (UserAdmin userAdmin : userAdmins.values()) {
- if (userAdmin instanceof AbstractUserDirectory)
- ((AbstractUserDirectory) userAdmin)
- .setSyncRegistry(syncRegistry);
- }
- }
-
}
package org.argeo.osgi.useradmin;
+import static org.argeo.osgi.useradmin.LdifName.inetOrgPerson;
+import static org.argeo.osgi.useradmin.LdifName.objectClass;
+import static org.argeo.osgi.useradmin.LdifName.organizationalPerson;
+import static org.argeo.osgi.useradmin.LdifName.person;
+import static org.argeo.osgi.useradmin.LdifName.top;
+
+import java.io.File;
import java.net.URI;
+import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Dictionary;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
public abstract class AbstractUserDirectory implements UserAdmin {
private final static Log log = LogFactory
.getLog(AbstractUserDirectory.class);
+
+ private Dictionary<String, ?> properties;
+ private String baseDn = "dc=example,dc=com";
+ private String userObjectClass;
+ private String groupObjectClass;
+
private boolean isReadOnly;
private URI uri;
private ThreadLocal<WorkingCopy> workingCopy = new ThreadLocal<AbstractUserDirectory.WorkingCopy>();
private Xid editingTransactionXid = null;
- public AbstractUserDirectory() {
- }
+ public AbstractUserDirectory(Dictionary<String, ?> properties) {
+ // TODO make a copy?
+ this.properties = properties;
- public AbstractUserDirectory(URI uri, boolean isReadOnly) {
- this.uri = uri;
- this.isReadOnly = isReadOnly;
+ String uriStr = LdapProperties.uri.getValue(properties);
+ if (uriStr == null)
+ uri = null;
+ else
+ try {
+ uri = new URI(uriStr);
+ } catch (URISyntaxException e) {
+ throw new UserDirectoryException("Badly formatted URI", e);
+ }
+
+ baseDn = LdapProperties.baseDn.getValue(properties).toString();
+ String isReadOnly = LdapProperties.readOnly.getValue(properties);
+ if (isReadOnly == null)
+ this.isReadOnly = readOnlyDefault(uri);
+ else
+ this.isReadOnly = new Boolean(isReadOnly);
+
+ this.userObjectClass = LdapProperties.userObjectClass
+ .getValue(properties);
+ this.groupObjectClass = LdapProperties.groupObjectClass
+ .getValue(properties);
}
+ // public AbstractUserDirectory(URI uri, boolean isReadOnly) {
+ // this.uri = uri;
+ // this.isReadOnly = isReadOnly;
+ // }
+
/** Returns the {@link Group}s this user is a direct member of. */
protected abstract List<? extends DirectoryGroup> getDirectGroups(User user);
protected DirectoryUser newRole(LdapName dn, int type, Attributes attrs) {
LdifUser newRole;
- BasicAttribute objectClass = new BasicAttribute("objectClass");
+ BasicAttribute objClass = new BasicAttribute(objectClass.name());
if (type == Role.USER) {
- objectClass.add("inetOrgPerson");
- objectClass.add("organizationalPerson");
- objectClass.add("person");
- objectClass.add("top");
- attrs.put(objectClass);
+ String userObjClass = getUserObjectClass();
+ objClass.add(userObjClass);
+ if (inetOrgPerson.name().equals(userObjClass)) {
+ objClass.add(organizationalPerson.name());
+ objClass.add(person.name());
+ } else if (organizationalPerson.name().equals(userObjClass)) {
+ objClass.add(person.name());
+ }
+ objClass.add(top);
+ attrs.put(objClass);
newRole = new LdifUser(this, dn, attrs);
} else if (type == Role.GROUP) {
- objectClass.add("groupOfNames");
- objectClass.add("top");
- attrs.put(objectClass);
+ objClass.add(getGroupObjectClass());
+ objClass.add(top);
+ attrs.put(objClass);
newRole = new LdifGroup(this, dn, attrs);
} else
throw new UserDirectoryException("Unsupported type " + type);
this.isReadOnly = isReadOnly;
}
+ private static boolean readOnlyDefault(URI uri) {
+ if (uri == null)
+ return true;
+ if (uri.getScheme().equals("file")) {
+ File file = new File(uri);
+ return !file.canWrite();
+ }
+ return true;
+ }
+
public boolean isReadOnly() {
return isReadOnly;
}
return externalRoles;
}
- public void setExternalRoles(UserAdmin externalRoles) {
- this.externalRoles = externalRoles;
+ public String getBaseDn() {
+ return baseDn;
}
- public void setSyncRegistry(TransactionSynchronizationRegistry syncRegistry) {
- // this.syncRegistry = syncRegistry;
+ protected String getUserObjectClass() {
+ return userObjectClass;
+ }
+
+ protected String getGroupObjectClass() {
+ return groupObjectClass;
+ }
+
+ public void setExternalRoles(UserAdmin externalRoles) {
+ this.externalRoles = externalRoles;
}
public void setTransactionManager(TransactionManager transactionManager) {
+++ /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_SN = LDAP_PREFIX + "sn";
- public final static String LDAP_UID = LDAP_PREFIX + "uid";
- public final static String LDAP_DISPLAY_NAME = LDAP_PREFIX + "displayName";
-
-}
--- /dev/null
+package org.argeo.osgi.useradmin;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLDecoder;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.naming.Context;
+
+public enum LdapProperties {
+ /** Base DN */
+ baseDn("dc=example,dc=com"),
+
+ /** URI of the underlying resource */
+ uri("ldap://localhost:10389"),
+
+ /** User objectClass */
+ userObjectClass("inetOrgPerson"),
+
+ /** Groups objectClass */
+ groupObjectClass("groupOfNames"),
+
+ /** Read-only source */
+ readOnly(null);
+
+ private static String PREFIX = "argeo.ldap.";
+
+ /** The default value. */
+ private Object def;
+
+ LdapProperties(Object def) {
+ this.def = def;
+ }
+
+ public Object getDefault() {
+ return def;
+ }
+
+ public String getFullName() {
+ return getPrefix() + name();
+ }
+
+ public String getPrefix() {
+ return PREFIX;
+ }
+
+ public String getValue(Dictionary<String, ?> properties) {
+ Object res = getRawValue(properties);
+ if (res == null)
+ return null;
+ return res.toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T getRawValue(Dictionary<String, ?> properties) {
+ Object res = properties.get(getFullName());
+ if (res == null)
+ res = getDefault();
+ return (T) res;
+ }
+
+ public static Dictionary<String, ?> uriAsProperties(String uriStr) {
+ try {
+ Hashtable<String, Object> res = new Hashtable<String, Object>();
+ URI u = new URI(uriStr);
+ String scheme = u.getScheme();
+ String path = u.getPath();
+ String bDn = path.substring(path.lastIndexOf('/') + 1,
+ path.length());
+ String principal = null;
+ String credentials = null;
+ if (scheme != null)
+ if (scheme.equals("ldap") || scheme.equals("ldaps")) {
+ // TODO additional checks
+ String[] userInfo = u.getUserInfo().split(":");
+ principal = userInfo.length > 0 ? userInfo[0] : null;
+ credentials = userInfo.length > 1 ? userInfo[1] : null;
+ } else if (scheme.equals("file")) {
+ if (bDn.endsWith(".ldif")) {
+ bDn = bDn.substring(0, bDn.length() - ".ldif".length());
+ }
+ } else
+ throw new UserDirectoryException("Unsupported scheme "
+ + scheme);
+ Map<String, List<String>> query = splitQuery(u.getQuery());
+ for (String key : query.keySet()) {
+ LdapProperties ldapProp = LdapProperties.valueOf(key);
+ List<String> values = query.get(key);
+ if (values.size() == 1) {
+ res.put(ldapProp.getFullName(), values.get(0));
+ } else {
+ throw new UserDirectoryException(
+ "Only single values are supported");
+ }
+ }
+ res.put(baseDn.getFullName(), bDn);
+ if (principal != null)
+ res.put(Context.SECURITY_PRINCIPAL, principal);
+ if (credentials != null)
+ res.put(Context.SECURITY_CREDENTIALS, credentials);
+ if (scheme != null) {
+ URI bareUri = new URI(scheme, null, u.getHost(), u.getPort(),
+ scheme.equals("file") ? u.getPath() : null, null, null);
+ res.put(uri.getFullName(), bareUri.toString());
+ }
+ return res;
+ } catch (Exception e) {
+ throw new UserDirectoryException("Cannot convert " + uri
+ + " to properties", e);
+ }
+ }
+
+ public static Map<String, List<String>> splitQuery(String query)
+ throws UnsupportedEncodingException {
+ final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
+ if (query == null)
+ return query_pairs;
+ final String[] pairs = query.split("&");
+ for (String pair : pairs) {
+ final int idx = pair.indexOf("=");
+ final String key = idx > 0 ? URLDecoder.decode(
+ pair.substring(0, idx), "UTF-8") : pair;
+ if (!query_pairs.containsKey(key)) {
+ query_pairs.put(key, new LinkedList<String>());
+ }
+ final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder
+ .decode(pair.substring(idx + 1), "UTF-8") : null;
+ query_pairs.get(key).add(value);
+ }
+ return query_pairs;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(uriAsProperties("ldap://"
+ + "uid=admin,ou=system:secret@localhost:10389"
+ + "/dc=example,dc=com"
+ + "?readOnly=false&userObjectClass=person"));
+ System.out
+ .println(uriAsProperties("file://some/dir/dc=example,dc=com.ldif"));
+ System.out
+ .println(uriAsProperties("/dc=example,dc=com.ldif?readOnly=true"));
+ }
+}
package org.argeo.osgi.useradmin;
-import java.net.URI;
+import static org.argeo.osgi.useradmin.LdifName.objectClass;
+
import java.util.ArrayList;
+import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
-import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
-import javax.naming.ldap.LdapContext;
import javax.naming.ldap.LdapName;
-import javax.transaction.xa.XAException;
-import javax.transaction.xa.Xid;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.ArgeoException;
import org.osgi.framework.Filter;
-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;
public class LdapUserAdmin extends AbstractUserDirectory {
private final static Log log = LogFactory.getLog(LdapUserAdmin.class);
- private String baseDn = "dc=example,dc=com";
private InitialLdapContext initialLdapContext = null;
- public LdapUserAdmin(String uri) {
+ public LdapUserAdmin(Dictionary<String, ?> properties) {
+ super(properties);
try {
- setUri(new URI(uri));
Hashtable<String, Object> connEnv = new Hashtable<String, Object>();
connEnv.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
connEnv.put(Context.PROVIDER_URL, getUri().toString());
- connEnv.put("java.naming.ldap.attributes.binary", "userPassword");
- // connEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
- // connEnv.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
- // connEnv.put(Context.SECURITY_CREDENTIALS, "secret");
+ connEnv.put("java.naming.ldap.attributes.binary",
+ LdifName.userPassword.name());
initialLdapContext = new InitialLdapContext(connEnv, null);
// StartTlsResponse tls = (StartTlsResponse) ctx
// tls.negotiate();
initialLdapContext.addToEnvironment(
Context.SECURITY_AUTHENTICATION, "simple");
- initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL,
- "uid=admin,ou=system");
- initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS,
- "secret");
- LdapContext ldapContext = (LdapContext) initialLdapContext
- .lookup("uid=root,ou=users,dc=example,dc=com");
- log.debug(initialLdapContext.getAttributes(
- "uid=root,ou=users,dc=example,dc=com").get("cn"));
+ Object principal = properties.get(Context.SECURITY_PRINCIPAL);
+ if (principal != null) {
+ initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL,
+ principal.toString());
+ Object creds = properties.get(Context.SECURITY_CREDENTIALS);
+ if (creds != null) {
+ initialLdapContext.addToEnvironment(
+ Context.SECURITY_CREDENTIALS, creds.toString());
+
+ }
+ }
+ // initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL,
+ // "uid=admin,ou=system");
+ // initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS,
+ // "secret");
} catch (Exception e) {
throw new UserDirectoryException("Cannot connect to LDAP", e);
}
}
}
+ protected InitialLdapContext getLdapContext() {
+ return initialLdapContext;
+ }
+
@Override
protected Boolean daoHasRole(LdapName dn) {
return daoGetRole(dn) != null;
@Override
protected DirectoryUser daoGetRole(LdapName name) {
try {
- Attributes attrs = initialLdapContext.getAttributes(name);
+ Attributes attrs = getLdapContext().getAttributes(name);
if (attrs.size() == 0)
return null;
LdifUser res;
- if (attrs.get("objectClass").contains("groupOfNames"))
+ if (attrs.get(objectClass.name()).contains(getGroupObjectClass()))
res = new LdifGroup(this, name, attrs);
- else if (attrs.get("objectClass").contains("inetOrgPerson"))
+ else if (attrs.get(objectClass.name()).contains(
+ getUserObjectClass()))
res = new LdifUser(this, name, attrs);
else
throw new UserDirectoryException("Unsupported LDAP type for "
protected List<DirectoryUser> doGetRoles(Filter f) {
// TODO Auto-generated method stub
try {
- String searchFilter = f != null ? f.toString()
- : "(|(objectClass=inetOrgPerson)(objectClass=groupOfNames))";
+ String searchFilter = f != null ? f.toString() : "(|("
+ + objectClass + "=" + getUserObjectClass() + ")("
+ + objectClass + "=" + getGroupObjectClass() + "))";
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
- String searchBase = baseDn;
- NamingEnumeration<SearchResult> results = initialLdapContext
- .search(searchBase, searchFilter, searchControls);
+ String searchBase = getBaseDn();
+ NamingEnumeration<SearchResult> results = getLdapContext().search(
+ searchBase, searchFilter, searchControls);
ArrayList<DirectoryUser> res = new ArrayList<DirectoryUser>();
while (results.hasMoreElements()) {
SearchResult searchResult = results.next();
Attributes attrs = searchResult.getAttributes();
LdifUser role;
- if (attrs.get("objectClass").contains("groupOfNames"))
+ if (attrs.get(objectClass.name()).contains(
+ getGroupObjectClass()))
role = new LdifGroup(this, toDn(searchBase, searchResult),
attrs);
- else if (attrs.get("objectClass").contains("inetOrgPerson"))
+ else if (attrs.get(objectClass.name()).contains(
+ getUserObjectClass()))
role = new LdifUser(this, toDn(searchBase, searchResult),
attrs);
else
protected void doGetUser(String key, String value,
List<DirectoryUser> collectedUsers) {
try {
- String searchFilter = "(&(objectClass=inetOrgPerson)(" + key + "="
- + value + "))";
+ String searchFilter = "(&(" + objectClass + "="
+ + getUserObjectClass() + ")(" + key + "=" + value + "))";
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
- String searchBase = baseDn;
- NamingEnumeration<SearchResult> results = initialLdapContext
- .search(searchBase, searchFilter, searchControls);
+ String searchBase = getBaseDn();
+ NamingEnumeration<SearchResult> results = getLdapContext().search(
+ searchBase, searchFilter, searchControls);
SearchResult searchResult = null;
if (results.hasMoreElements()) {
}
- @Override
- public User getUser(String key, String value) {
- if (key == null) {
- List<User> users = new ArrayList<User>();
- for (String prop : getIndexedUserProperties()) {
- User user = getUser(prop, value);
- if (user != null)
- users.add(user);
- }
- if (users.size() == 1)
- return users.get(0);
- else
- return null;
- }
-
- try {
- String searchFilter = "(&(objectClass=inetOrgPerson)(" + key + "="
- + value + "))";
-
- SearchControls searchControls = new SearchControls();
- searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-
- String searchBase = baseDn;
- NamingEnumeration<SearchResult> results = initialLdapContext
- .search(searchBase, searchFilter, searchControls);
-
- SearchResult searchResult = null;
- if (results.hasMoreElements()) {
- searchResult = (SearchResult) results.nextElement();
- if (results.hasMoreElements())
- searchResult = null;
- }
- if (searchResult == null)
- return null;
- return new LdifUser(this, toDn(searchBase, searchResult),
- searchResult.getAttributes());
- } catch (Exception e) {
- throw new UserDirectoryException("Cannot get user with " + key
- + "=" + value, e);
- }
- }
-
private LdapName toDn(String baseDn, Binding binding)
throws InvalidNameException {
return new LdapName(binding.isRelative() ? binding.getName() + ","
+ baseDn : binding.getName());
}
- // 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<DirectoryGroup> getDirectGroups(User user) {
List<DirectoryGroup> directGroups = new ArrayList<DirectoryGroup>();
try {
- String searchFilter = "(&(objectClass=groupOfNames)(member="
- + user.getName() + "))";
+ String searchFilter = "(&(" + objectClass + "="
+ + getGroupObjectClass() + ")(" + getMemberAttributeId()
+ + "=" + user.getName() + "))";
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
- String searchBase = getGroupsSearchBase();
- NamingEnumeration<SearchResult> results = initialLdapContext
- .search(searchBase, searchFilter, searchControls);
+ String searchBase = getBaseDn();
+ NamingEnumeration<SearchResult> results = getLdapContext().search(
+ searchBase, searchFilter, searchControls);
while (results.hasMoreElements()) {
SearchResult searchResult = (SearchResult) results
}
}
- protected String getGroupsSearchBase() {
- // TODO configure group search base
- return baseDn;
- }
-
@Override
protected void prepare(WorkingCopy wc) {
try {
- initialLdapContext.reconnect(initialLdapContext
- .getConnectControls());
+ getLdapContext().reconnect(getLdapContext().getConnectControls());
// delete
for (LdapName dn : wc.getDeletedUsers().keySet()) {
if (!entryExists(dn))
}
private boolean entryExists(LdapName dn) throws NamingException {
- return initialLdapContext.getAttributes(dn).size() != 0;
+ return getLdapContext().getAttributes(dn).size() != 0;
}
@Override
try {
// delete
for (LdapName dn : wc.getDeletedUsers().keySet()) {
- initialLdapContext.destroySubcontext(dn);
+ getLdapContext().destroySubcontext(dn);
}
// add
for (LdapName dn : wc.getNewUsers().keySet()) {
DirectoryUser user = wc.getNewUsers().get(dn);
- initialLdapContext.createSubcontext(dn, user.getAttributes());
+ getLdapContext().createSubcontext(dn, user.getAttributes());
}
// modify
for (LdapName dn : wc.getModifiedUsers().keySet()) {
Attributes modifiedAttrs = wc.getModifiedUsers().get(dn);
- initialLdapContext.modifyAttributes(dn,
+ getLdapContext().modifyAttributes(dn,
DirContext.REPLACE_ATTRIBUTE, modifiedAttrs);
}
} catch (NamingException e) {
@Override
protected void rollback(WorkingCopy wc) {
- // TODO Auto-generated method stub
- super.rollback(wc);
+ // prepare not impacting
}
}
import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.User;
-public class LdifAuthorization implements Authorization, LdapNames {
+public class LdifAuthorization implements Authorization {
private final String name;
private final String displayName;
private final List<String> allRoles;
} else {
this.name = user.getName();
Dictionary<String, Object> props = user.getProperties();
- Object displayName = props.get(LDAP_DISPLAY_NAME);
+ Object displayName = props.get(LdifName.displayName);
if (displayName == null)
- displayName = props.get(LDAP_CN);
+ displayName = props.get(LdifName.cn);
if (displayName == null)
- displayName = props.get(LDAP_UID);
+ displayName = props.get(LdifName.uid);
if (displayName == null)
displayName = user.getName();
if (displayName == null)
- throw new UserDirectoryException(
- "Cannot set display name for " + user);
+ throw new UserDirectoryException("Cannot set display name for "
+ + user);
this.displayName = displayName.toString();
}
// roles
--- /dev/null
+package org.argeo.osgi.useradmin;
+
+import javax.naming.ldap.LdapName;
+
+/**
+ * Standard LDAP attributes and object classes leveraged in this implementation
+ * of user admin. Named {@link LdifName} in order not to collide with
+ * {@link LdapName}.
+ */
+public enum LdifName {
+ // Attributes
+ cn, sn, uid, displayName, objectClass,userPassword,
+ // Object classes
+ inetOrgPerson, organizationalPerson, person, groupOfNames, top;
+
+ public final static String LDAP_PREFIX = "ldap:";
+
+ public String property() {
+ return LDAP_PREFIX + name();
+ }
+
+ public static LdifName local(String property) {
+ String local = property.substring(LDAP_PREFIX.length());
+ return LdifName.valueOf(local);
+ }
+}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Dictionary;
+import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
private Map<String, Map<String, DirectoryUser>> userIndexes = new LinkedHashMap<String, Map<String, DirectoryUser>>();
- // private Map<LdapName, List<LdifGroup>> directMemberOf = new
- // TreeMap<LdapName, List<LdifGroup>>();
-
- public LdifUserAdmin(String uri) {
- this(uri, readOnlyDefault(uri));
- }
-
- public LdifUserAdmin(String uri, boolean isReadOnly) {
- setReadOnly(isReadOnly);
- try {
- setUri(new URI(uri));
- } catch (URISyntaxException e) {
- throw new UserDirectoryException("Invalid URI " + uri, e);
- }
-
- if (!isReadOnly && !getUri().getScheme().equals("file"))
- throw new UnsupportedOperationException(getUri().getScheme()
- + " not supported read-write.");
-
+ public LdifUserAdmin(String uri, String baseDn) {
+ this(fromUri(uri, baseDn));
}
- public LdifUserAdmin(URI uri, boolean isReadOnly) {
- setReadOnly(isReadOnly);
- setUri(uri);
- if (!isReadOnly && !getUri().getScheme().equals("file"))
- throw new UnsupportedOperationException(getUri().getScheme()
- + " not supported read-write.");
-
+ public LdifUserAdmin(Dictionary<String, ?> properties) {
+ super(properties);
}
public LdifUserAdmin(InputStream in) {
+ super(new Hashtable<String, Object>());
load(in);
setReadOnly(true);
setUri(null);
}
- private static boolean readOnlyDefault(String uriStr) {
- URI uri;
- try {
- uri = new URI(uriStr);
- } catch (Exception e) {
- throw new UserDirectoryException("Invalid URI " + uriStr, e);
- }
- if (uri.getScheme().equals("file")) {
- File file = new File(uri);
- return !file.canWrite();
- }
- return true;
+ private static Dictionary<String, Object> fromUri(String uri, String baseDn) {
+ Hashtable<String, Object> res = new Hashtable<String, Object>();
+ res.put(LdapProperties.uri.getFullName(), uri);
+ res.put(LdapProperties.baseDn.getFullName(), baseDn);
+ return res;
}
public void init() {
try {
+ if (getUri().getScheme().equals("file")) {
+ File file = new File(getUri());
+ if (!file.exists())
+ return;
+ }
load(getUri().toURL().openStream());
} catch (Exception e) {
throw new UserDirectoryException("Cannot open URL " + getUri(), e);
+++ /dev/null
-package org.argeo.osgi.useradmin.cm;
-
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.argeo.osgi.useradmin.AbstractUserDirectory;
-import org.argeo.osgi.useradmin.UserDirectoryException;
-import org.argeo.osgi.useradmin.LdapUserAdmin;
-import org.argeo.osgi.useradmin.LdifUserAdmin;
-import org.argeo.osgi.useradmin.UserAdminAggregator;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedServiceFactory;
-
-public class LdapUserAdminFactory implements ManagedServiceFactory {
- private final UserAdminAggregator userAdminAggregator;
-
- private Map<String, String> index = new HashMap<String, String>();
-
- public LdapUserAdminFactory(UserAdminAggregator userAdminAggregator) {
- this.userAdminAggregator = userAdminAggregator;
- }
-
- @Override
- public String getName() {
- return "LDAP/LDIF User Source";
- }
-
- @Override
- public synchronized void updated(String pid,
- Dictionary<String, ?> properties) throws ConfigurationException {
- String baseDn = properties.get("baseDn").toString();
- String userAdminUri = properties.get("uri").toString();
- AbstractUserDirectory userAdmin;
- if (userAdminUri.startsWith("ldap"))
- userAdmin = new LdapUserAdmin(userAdminUri);
- else
- userAdmin = new LdifUserAdmin(userAdminUri);
- userAdminAggregator.addUserAdmin(baseDn, userAdmin);
- index.put(pid, baseDn);
- }
-
- @Override
- public synchronized void deleted(String pid) {
- if (index.containsKey(pid))
- userAdminAggregator.removeUserAdmin(index.get(pid));
- else
- throw new UserDirectoryException("No user admin registered for "
- + pid);
- index.remove(pid);
- }
-
-}
public class SecurityAdminPlugin extends AbstractUIPlugin {
public static final String PLUGIN_ID = "org.argeo.security.ui.admin"; //$NON-NLS-1$
private static SecurityAdminPlugin plugin;
+ private static BundleContext bundleContext;
public SecurityAdminPlugin() {
}
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
+ bundleContext = context;
}
public void stop(BundleContext context) throws Exception {
plugin = null;
+ bundleContext = null;
super.stop(context);
}
return plugin;
}
+ public static BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
public static ImageDescriptor getImageDescriptor(String path) {
return imageDescriptorFromPlugin(PLUGIN_ID, path);
}