package org.argeo.osgi.useradmin;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
-import java.net.URLDecoder;
+import java.net.UnknownHostException;
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;
-import javax.naming.NamingException;
+import javax.naming.ldap.LdapName;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.naming.DnsBrowser;
-import org.osgi.framework.Constants;
+import org.argeo.naming.NamingUtils;
/** Properties used to configure user admins. */
public enum UserAdminConf {
/** Read-only source */
readOnly(null),
+ /** Disabled source */
+ disabled(null),
+
/** Authentication realm */
realm(null);
public final static String FACTORY_PID = "org.argeo.osgi.useradmin.config";
- private final static Log log = LogFactory.getLog(UserAdminConf.class);
+
+ public final static String SCHEME_LDAP = "ldap";
+ public final static String SCHEME_LDAPS = "ldaps";
+ public final static String SCHEME_FILE = "file";
+ public final static String SCHEME_OS = "os";
+ public final static String SCHEME_IPA = "ipa";
/** The default value. */
private Object def;
StringBuilder query = new StringBuilder();
boolean first = true;
- for (Enumeration<String> keys = properties.keys(); keys.hasMoreElements();) {
- String key = keys.nextElement();
- // TODO clarify which keys are relevant (list only the enum?)
- if (!key.equals("service.factoryPid") && !key.equals("cn") && !key.equals("dn")
- && !key.equals(Constants.SERVICE_PID) && !key.startsWith("java") && !key.equals(baseDn.name())
- && !key.equals(uri.name())) {
- if (first)
- first = false;
- else
- query.append('&');
- query.append(valueOf(key).name());
- query.append('=').append(properties.get(key).toString());
- }
+// for (Enumeration<String> keys = properties.keys(); keys.hasMoreElements();) {
+// String key = keys.nextElement();
+// // TODO clarify which keys are relevant (list only the enum?)
+// if (!key.equals("service.factoryPid") && !key.equals("cn") && !key.equals("dn")
+// && !key.equals(Constants.SERVICE_PID) && !key.startsWith("java") && !key.equals(baseDn.name())
+// && !key.equals(uri.name()) && !key.equals(Constants.OBJECTCLASS)
+// && !key.equals(Constants.SERVICE_ID) && !key.equals("bundle.id")) {
+// if (first)
+// first = false;
+// else
+// query.append('&');
+// query.append(valueOf(key).name());
+// query.append('=').append(properties.get(key).toString());
+// }
+// }
+
+ keys: for (UserAdminConf key : UserAdminConf.values()) {
+ if (key.equals(baseDn) || key.equals(uri))
+ continue keys;
+ Object value = properties.get(key.name());
+ if (value == null)
+ continue keys;
+ if (first)
+ first = false;
+ else
+ query.append('&');
+ query.append(key.name());
+ query.append('=').append(value.toString());
+
}
- String bDn = (String) properties.get(baseDn.name());
+ Object bDnObj = properties.get(baseDn.name());
+ String bDn = bDnObj != null ? bDnObj.toString() : null;
try {
return new URI(null, null, bDn != null ? '/' + bDn : null, query.length() != 0 ? query.toString() : null,
null);
Hashtable<String, Object> res = new Hashtable<String, Object>();
URI u = new URI(uriStr);
String scheme = u.getScheme();
- if (scheme != null && scheme.equals("ipa")) {
- u = convertIpaConfig(u);
- scheme = u.getScheme();
+ if (scheme != null && scheme.equals(SCHEME_IPA)) {
+ return IpaUtils.convertIpaUri(u);
+// scheme = u.getScheme();
}
String path = u.getPath();
+ // base DN
String bDn = path.substring(path.lastIndexOf('/') + 1, path.length());
+ if (bDn.equals("") && SCHEME_OS.equals(scheme)) {
+ bDn = getBaseDnFromHostname();
+ }
+
if (bDn.endsWith(".ldif"))
bDn = bDn.substring(0, bDn.length() - ".ldif".length());
+ // Normalize base DN as LDAP name
+ bDn = new LdapName(bDn).toString();
+
String principal = null;
String credentials = null;
if (scheme != null)
- if (scheme.equals("ldap") || scheme.equals("ldaps")) {
+ if (scheme.equals(SCHEME_LDAP) || scheme.equals(SCHEME_LDAPS)) {
// TODO additional checks
if (u.getUserInfo() != null) {
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 if (scheme.equals("ipa")) {
+ } else if (scheme.equals(SCHEME_FILE)) {
+ } else if (scheme.equals(SCHEME_IPA)) {
+ } else if (scheme.equals(SCHEME_OS)) {
} else
throw new UserDirectoryException("Unsupported scheme " + scheme);
- Map<String, List<String>> query = splitQuery(u.getQuery());
+ Map<String, List<String>> query = NamingUtils.queryToMap(u);
for (String key : query.keySet()) {
UserAdminConf ldapProp = UserAdminConf.valueOf(key);
List<String> values = query.get(key);
}
}
res.put(baseDn.name(), bDn);
+ if (SCHEME_OS.equals(scheme))
+ res.put(readOnly.name(), "true");
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.name(), bareUri.toString());
+ if (scheme != null) {// relative URIs are dealt with externally
+ if (SCHEME_OS.equals(scheme)) {
+ res.put(uri.name(), SCHEME_OS + ":///");
+ } else {
+ URI bareUri = new URI(scheme, null, u.getHost(), u.getPort(),
+ scheme.equals(SCHEME_FILE) ? u.getPath() : null, null, null);
+ res.put(uri.name(), bareUri.toString());
+ }
}
return res;
} catch (Exception e) {
}
}
- private static URI convertIpaConfig(URI uri) {
- String path = uri.getPath();
- String kerberosRealm;
- if (path == null || path.length() <= 1) {
- kerberosRealm = kerberosDomainFromDns();
- } else {
- kerberosRealm = path.substring(1);
- }
-
- if (kerberosRealm == null)
- throw new UserDirectoryException("No Kerberos domain available for " + uri);
- try (DnsBrowser dnsBrowser = new DnsBrowser()) {
- String ldapHostsStr = uri.getHost();
- if (ldapHostsStr == null || ldapHostsStr.trim().equals("")) {
- List<String> ldapHosts = dnsBrowser.getSrvRecordsAsHosts("_ldap._tcp." + kerberosRealm.toLowerCase());
- if (ldapHosts == null || ldapHosts.size() == 0) {
- throw new UserDirectoryException("Cannot configure LDAP for IPA " + uri);
- } else {
- ldapHostsStr = ldapHosts.get(0);
- }
- }
- URI convertedUri = new URI(
- "ldap://" + ldapHostsStr + "/" + IpaUtils.domainToUserDirectoryConfigPath(kerberosRealm));
- if (log.isDebugEnabled())
- log.debug("Converted " + uri + " to " + convertedUri);
- return convertedUri;
- } catch (NamingException | IOException | URISyntaxException e) {
- throw new UserDirectoryException("cannot convert IPA uri " + uri, e);
- }
- }
-
- private static String kerberosDomainFromDns() {
- String kerberosDomain;
- try (DnsBrowser dnsBrowser = new DnsBrowser()) {
- InetAddress localhost = InetAddress.getLocalHost();
- String hostname = localhost.getHostName();
- String dnsZone = hostname.substring(hostname.indexOf('.') + 1);
- kerberosDomain = dnsBrowser.getRecord("_kerberos." + dnsZone, "TXT");
- return kerberosDomain;
- } catch (Exception e) {
- throw new UserDirectoryException("Cannot determine Kerberos domain from DNS", e);
+ private static String getBaseDnFromHostname() {
+ String hostname;
+ try {
+ hostname = InetAddress.getLocalHost().getHostName();
+ } catch (UnknownHostException e) {
+ hostname = "localhost.localdomain";
}
-
- }
-
- 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);
+ int dotIdx = hostname.indexOf('.');
+ if (dotIdx >= 0) {
+ String domain = hostname.substring(dotIdx + 1, hostname.length());
+ String bDn = ("." + domain).replaceAll("\\.", ",dc=");
+ bDn = bDn.substring(1, bDn.length());
+ return bDn;
+ } else {
+ return "dc=" + hostname;
}
- 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));
+ /**
+ * Hash the base DN in order to have a deterministic string to be used as a cn
+ * for the underlying user directory.
+ */
+ public static String baseDnHash(Dictionary<String, Object> properties) {
+ String bDn = (String) properties.get(baseDn.name());
+ if (bDn == null)
+ throw new UserDirectoryException("No baseDn in " + properties);
+ return DigestUtils.sha1str(bDn);
}
}