argeo.osgi.start.4.workbench=\
org.eclipse.equinox.http.registry,\
-#argeo.node.useradmin.uri="\
+org.osgi.framework.security=osgi
+java.security.policy=file:../../all.policy
+
+argeo.node.useradmin.uris=ldap://uid=admin,ou=system:secret@localhost:10389\
+/dc=example,dc=com?userBase=ou=users&groupBase=ou=groups
+#argeo.node.useradmin.uris="\
#ldap://uid=admin,ou=system:secret\
#@localhost:10389\
#/dc=example,dc=com\
#&userObjectClass=inetOrgPerson \
#dc=example,dc=org.ldif"
-org.osgi.framework.security=osgi
-java.security.policy=file:../../all.policy
-
# HTTP
org.osgi.service.http.port=7070
org.eclipse.equinox.http.jetty.log.stderr.threshold=info
// Node Security
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 USERADMIN_URIS = "argeo.node.useradmin.uris";
final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd",
"/org/argeo/cms/cms.cnd" };
}
public void publish() {
+ userAdminReg = bundleContext.registerService(UserAdmin.class,
+ userAdmin, userAdmin.currentState());
+ // dummy auth manager, in order to smooth transition from Argeo 1
authenticationManagerReg = bundleContext.registerService(
AuthenticationManager.class, this, null);
- Hashtable<String, Object> properties = new Hashtable<String, Object>();
- // properties.put(KernelConstants.USERADMIN_URI,
- // userAdmin.asConfigUris());
- userAdminReg = bundleContext.registerService(UserAdmin.class,
- userAdmin, properties);
}
void destroy() {
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.UserDirectory;
+import org.argeo.osgi.useradmin.UserAdminProps;
import org.argeo.osgi.useradmin.LdapUserAdmin;
import org.argeo.osgi.useradmin.LdifUserAdmin;
import org.argeo.osgi.useradmin.UserDirectoryException;
nodeBaseDir.mkdirs();
String userAdminUri = KernelUtils
- .getFrameworkProp(KernelConstants.USERADMIN_URI);
+ .getFrameworkProp(KernelConstants.USERADMIN_URIS);
if (userAdminUri == null) {
String demoBaseDn = "dc=example,dc=com";
File businessRolesFile = new File(nodeBaseDir, demoBaseDn + ".ldif");
throw new CmsException(
"Cannot interpret " + uri + " as an uri", e);
}
- Dictionary<String, ?> properties = LdapProperties.uriAsProperties(u
+ Dictionary<String, ?> properties = UserAdminProps.uriAsProperties(u
.toString());
- AbstractUserDirectory businessRoles;
+ UserDirectory businessRoles;
if (u.getScheme().startsWith("ldap")) {
businessRoles = new LdapUserAdmin(properties);
} else {
businessRoles = new LdifUserAdmin(properties);
}
businessRoles.init();
- addUserAdmin(businessRoles.getBaseDn(), businessRoles);
+ addUserAdmin(businessRoles.getBaseDn(), (UserAdmin) businessRoles);
if (log.isDebugEnabled())
log.debug("User directory " + businessRoles.getBaseDn() + " ["
+ u.getScheme() + "] enabled.");
nodeRolesUri = nodeRolesFile.toURI().toString();
}
- Dictionary<String, ?> nodeRolesProperties = LdapProperties
+ Dictionary<String, ?> nodeRolesProperties = UserAdminProps
.uriAsProperties(nodeRolesUri);
- if (!nodeRolesProperties.get(LdapProperties.baseDn.getFullName())
+ if (!nodeRolesProperties.get(UserAdminProps.baseDn.getFullName())
.equals(baseNodeRoleDn)) {
throw new CmsException("Invalid base dn for node roles");
// TODO deal with "mounted" roles with a different baseDN
}
- AbstractUserDirectory nodeRoles;
+ UserDirectory nodeRoles;
if (nodeRolesUri.startsWith("ldap")) {
nodeRoles = new LdapUserAdmin(nodeRolesProperties);
} else {
}
nodeRoles.setExternalRoles(this);
nodeRoles.init();
- addUserAdmin(baseNodeRoleDn, nodeRoles);
+ addUserAdmin(baseNodeRoleDn, (UserAdmin)nodeRoles);
if (log.isTraceEnabled())
log.trace("Node roles enabled.");
}
- String asConfigUris() {
- StringBuilder buf = new StringBuilder();
+ Dictionary<String, ?> currentState() {
+ Dictionary<String, Object> res = new Hashtable<String, Object>();
for (LdapName name : userAdmins.keySet()) {
- buf.append('/').append(name.toString());
- if (userAdmins.get(name) instanceof AbstractUserDirectory) {
- AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins
+ StringBuilder buf = new StringBuilder();
+ if (userAdmins.get(name) instanceof UserDirectory) {
+ UserDirectory userDirectory = (UserDirectory) userAdmins
.get(name);
- if (userDirectory.isReadOnly())
- buf.append('?').append(LdapProperties.readOnly.name())
- .append("=true");
+ String uri = UserAdminProps.propertiesAsUri(
+ userDirectory.getProperties()).toString();
+ res.put(uri, "");
+ } else {
+ buf.append('/').append(name.toString())
+ .append("?readOnly=true");
}
- buf.append(' ');
}
- return buf.toString();
+ return res;
}
public void destroy() {
for (LdapName name : userAdmins.keySet()) {
- if (userAdmins.get(name) instanceof AbstractUserDirectory) {
- AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins
+ if (userAdmins.get(name) instanceof UserDirectory) {
+ UserDirectory userDirectory = (UserDirectory) userAdmins
.get(name);
userDirectory.destroy();
}
}
public void setTransactionManager(TransactionManager transactionManager) {
- if (nodeRoles instanceof AbstractUserDirectory)
- ((AbstractUserDirectory) nodeRoles)
+ if (nodeRoles instanceof UserDirectory)
+ ((UserDirectory) nodeRoles)
.setTransactionManager(transactionManager);
for (UserAdmin userAdmin : userAdmins.values()) {
- if (userAdmin instanceof AbstractUserDirectory)
- ((AbstractUserDirectory) userAdmin)
+ if (userAdmin instanceof UserDirectory)
+ ((UserDirectory) userAdmin)
.setTransactionManager(transactionManager);
}
}
import org.osgi.service.useradmin.User;
import org.osgi.service.useradmin.UserAdmin;
-public abstract class AbstractUserDirectory implements UserAdmin {
+abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
private final static Log log = LogFactory
.getLog(AbstractUserDirectory.class);
// TODO make a copy?
this.properties = properties;
- String uriStr = LdapProperties.uri.getValue(properties);
+ String uriStr = UserAdminProps.uri.getValue(properties);
if (uriStr == null)
uri = null;
else
throw new UserDirectoryException("Badly formatted URI", e);
}
- baseDn = LdapProperties.baseDn.getValue(properties).toString();
- String isReadOnly = LdapProperties.readOnly.getValue(properties);
+ baseDn = UserAdminProps.baseDn.getValue(properties).toString();
+ String isReadOnly = UserAdminProps.readOnly.getValue(properties);
if (isReadOnly == null)
this.isReadOnly = readOnlyDefault(uri);
else
this.isReadOnly = new Boolean(isReadOnly);
- this.userObjectClass = LdapProperties.userObjectClass
+ this.userObjectClass = UserAdminProps.userObjectClass
.getValue(properties);
- this.groupObjectClass = LdapProperties.groupObjectClass
+ this.groupObjectClass = UserAdminProps.groupObjectClass
.getValue(properties);
}
return groupObjectClass;
}
- protected Dictionary<String, ?> getProperties() {
+ public Dictionary<String, ?> getProperties() {
return properties;
}
+++ /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"));
- }
-}
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);
+ res.put(UserAdminProps.uri.getFullName(), uri);
+ res.put(UserAdminProps.baseDn.getFullName(), baseDn);
return res;
}
--- /dev/null
+package org.argeo.osgi.useradmin;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLDecoder;
+import java.util.Dictionary;
+import java.util.Enumeration;
+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 UserAdminProps {
+ /** Base DN */
+ baseDn("dc=example,dc=com"),
+
+ /** URI of the underlying resource */
+ uri("ldap://localhost:10389"),
+
+ /** User objectClass */
+ userObjectClass("inetOrgPerson"),
+
+ /** Relative base DN for users */
+ userBase("ou=users"),
+
+ /** Groups objectClass */
+ groupObjectClass("groupOfNames"),
+
+ /** Relative base DN for users */
+ groupBase("ou=groups"),
+
+ /** Read-only source */
+ readOnly(null);
+
+ private static String PREFIX = "argeo.useradmin";
+
+ /** The default value. */
+ private Object def;
+
+ UserAdminProps(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;
+ }
+
+ /** Hides host and credentials. */
+ public static URI propertiesAsUri(Dictionary<String, ?> properties) {
+ StringBuilder query = new StringBuilder();
+
+ boolean first = true;
+ for (Enumeration<String> keys = properties.keys(); keys
+ .hasMoreElements();) {
+ String key = keys.nextElement();
+ if (key.startsWith(PREFIX) && !key.equals(baseDn.getFullName())
+ && !key.equals(uri.getFullName())) {
+ if (first)
+ first = false;
+ else
+ query.append('&');
+ query.append(key.substring(PREFIX.length()));
+ query.append('=').append(properties.get(key).toString());
+ }
+ }
+
+ String bDn = (String) properties.get(baseDn.getFullName());
+ try {
+ return new URI(null, null, bDn != null ? '/' + bDn : null,
+ query.length() != 0 ? query.toString() : null, null);
+ } catch (URISyntaxException e) {
+ throw new UserDirectoryException(
+ "Cannot create URI from properties", e);
+ }
+ }
+
+ 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());
+ if (bDn.endsWith(".ldif"))
+ bDn = bDn.substring(0, bDn.length() - ".ldif".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")) {
+ } else
+ throw new UserDirectoryException("Unsupported scheme "
+ + scheme);
+ Map<String, List<String>> query = splitQuery(u.getQuery());
+ for (String key : query.keySet()) {
+ UserAdminProps ldapProp = UserAdminProps.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);
+ }
+ }
+
+ private 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) {
+ Dictionary<String, ?> props = uriAsProperties("ldap://"
+ + "uid=admin,ou=system:secret@localhost:10389"
+ + "/dc=example,dc=com"
+ + "?readOnly=false&userObjectClass=person");
+ System.out.println(props);
+ System.out.println(propertiesAsUri(props));
+
+ System.out
+ .println(uriAsProperties("file://some/dir/dc=example,dc=com.ldif"));
+
+ props = uriAsProperties("/dc=example,dc=com.ldif?readOnly=true"
+ + "&userBase=ou=CoWorkers,ou=People&groupBase=ou=Roles");
+ System.out.println(props);
+ System.out.println(propertiesAsUri(props));
+ }
+}
--- /dev/null
+package org.argeo.osgi.useradmin;
+
+import java.util.Dictionary;
+
+import javax.transaction.TransactionManager;
+
+import org.osgi.service.useradmin.UserAdmin;
+
+/** Information about a user directory. */
+public interface UserDirectory {
+ public String getBaseDn();
+
+ public void setExternalRoles(UserAdmin externalRoles);
+
+ public Dictionary<String, ?> getProperties();
+
+ // Transitional. In the future, more will be managed in OSGi.
+ public void setTransactionManager(TransactionManager transactionManager);
+
+ public void init();
+
+ public void destroy();
+}