]>
git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.enterprise/src/org/argeo/osgi/useradmin/UserAdminConf.java
1 package org
.argeo
.osgi
.useradmin
;
3 import java
.io
.IOException
;
4 import java
.net
.InetAddress
;
6 import java
.net
.URISyntaxException
;
7 import java
.net
.UnknownHostException
;
8 import java
.util
.Dictionary
;
9 import java
.util
.Enumeration
;
10 import java
.util
.Hashtable
;
11 import java
.util
.List
;
14 import javax
.naming
.Context
;
15 import javax
.naming
.NamingException
;
16 import javax
.naming
.ldap
.LdapName
;
18 import org
.apache
.commons
.logging
.Log
;
19 import org
.apache
.commons
.logging
.LogFactory
;
20 import org
.argeo
.naming
.DnsBrowser
;
21 import org
.argeo
.naming
.NamingUtils
;
22 import org
.osgi
.framework
.Constants
;
24 /** Properties used to configure user admins. */
25 public enum UserAdminConf
{
26 /** Base DN (cannot be configured externally) */
27 baseDn("dc=example,dc=com"),
29 /** URI of the underlying resource (cannot be configured externally) */
30 uri("ldap://localhost:10389"),
32 /** User objectClass */
33 userObjectClass("inetOrgPerson"),
35 /** Relative base DN for users */
36 userBase("ou=People"),
38 /** Groups objectClass */
39 groupObjectClass("groupOfNames"),
41 /** Relative base DN for users */
42 groupBase("ou=Groups"),
44 /** Read-only source */
47 /** Disabled source */
50 /** Authentication realm */
53 public final static String FACTORY_PID
= "org.argeo.osgi.useradmin.config";
54 private final static Log log
= LogFactory
.getLog(UserAdminConf
.class);
56 public final static String SCHEME_LDAP
= "ldap";
57 public final static String SCHEME_FILE
= "file";
58 public final static String SCHEME_OS
= "os";
59 public final static String SCHEME_IPA
= "ipa";
61 /** The default value. */
64 UserAdminConf(Object def
) {
68 public Object
getDefault() {
73 * For use as Java property.
75 * @deprecated use {@link #name()} instead
78 public String
property() {
82 public String
getValue(Dictionary
<String
, ?
> properties
) {
83 Object res
= getRawValue(properties
);
86 return res
.toString();
89 @SuppressWarnings("unchecked")
90 public <T
> T
getRawValue(Dictionary
<String
, ?
> properties
) {
91 Object res
= properties
.get(name());
97 /** @deprecated use {@link #valueOf(String)} instead */
99 public static UserAdminConf
local(String property
) {
100 return UserAdminConf
.valueOf(property
);
103 /** Hides host and credentials. */
104 public static URI
propertiesAsUri(Dictionary
<String
, ?
> properties
) {
105 StringBuilder query
= new StringBuilder();
107 boolean first
= true;
108 for (Enumeration
<String
> keys
= properties
.keys(); keys
.hasMoreElements();) {
109 String key
= keys
.nextElement();
110 // TODO clarify which keys are relevant (list only the enum?)
111 if (!key
.equals("service.factoryPid") && !key
.equals("cn") && !key
.equals("dn")
112 && !key
.equals(Constants
.SERVICE_PID
) && !key
.startsWith("java") && !key
.equals(baseDn
.name())
113 && !key
.equals(uri
.name())) {
118 query
.append(valueOf(key
).name());
119 query
.append('=').append(properties
.get(key
).toString());
123 String bDn
= (String
) properties
.get(baseDn
.name());
125 return new URI(null, null, bDn
!= null ?
'/' + bDn
: null, query
.length() != 0 ? query
.toString() : null,
127 } catch (URISyntaxException e
) {
128 throw new UserDirectoryException("Cannot create URI from properties", e
);
132 public static Dictionary
<String
, Object
> uriAsProperties(String uriStr
) {
134 Hashtable
<String
, Object
> res
= new Hashtable
<String
, Object
>();
135 URI u
= new URI(uriStr
);
136 String scheme
= u
.getScheme();
137 if (scheme
!= null && scheme
.equals(SCHEME_IPA
)) {
138 u
= convertIpaConfig(u
);
139 scheme
= u
.getScheme();
141 String path
= u
.getPath();
143 String bDn
= path
.substring(path
.lastIndexOf('/') + 1, path
.length());
144 if (bDn
.equals("") && SCHEME_OS
.equals(scheme
)) {
145 bDn
= getBaseDnFromHostname();
148 if (bDn
.endsWith(".ldif"))
149 bDn
= bDn
.substring(0, bDn
.length() - ".ldif".length());
151 // Normalize base DN as LDAP name
152 bDn
= new LdapName(bDn
).toString();
154 String principal
= null;
155 String credentials
= null;
157 if (scheme
.equals(SCHEME_LDAP
) || scheme
.equals("ldaps")) {
158 // TODO additional checks
159 if (u
.getUserInfo() != null) {
160 String
[] userInfo
= u
.getUserInfo().split(":");
161 principal
= userInfo
.length
> 0 ? userInfo
[0] : null;
162 credentials
= userInfo
.length
> 1 ? userInfo
[1] : null;
164 } else if (scheme
.equals(SCHEME_FILE
)) {
165 } else if (scheme
.equals(SCHEME_IPA
)) {
166 } else if (scheme
.equals(SCHEME_OS
)) {
168 throw new UserDirectoryException("Unsupported scheme " + scheme
);
169 Map
<String
, List
<String
>> query
= NamingUtils
.queryToMap(u
);
170 for (String key
: query
.keySet()) {
171 UserAdminConf ldapProp
= UserAdminConf
.valueOf(key
);
172 List
<String
> values
= query
.get(key
);
173 if (values
.size() == 1) {
174 res
.put(ldapProp
.name(), values
.get(0));
176 throw new UserDirectoryException("Only single values are supported");
179 res
.put(baseDn
.name(), bDn
);
180 if (SCHEME_OS
.equals(scheme
))
181 res
.put(readOnly
.name(), "true");
182 if (principal
!= null)
183 res
.put(Context
.SECURITY_PRINCIPAL
, principal
);
184 if (credentials
!= null)
185 res
.put(Context
.SECURITY_CREDENTIALS
, credentials
);
186 if (scheme
!= null) {// relative URIs are dealt with externally
187 if (SCHEME_OS
.equals(scheme
)) {
188 res
.put(uri
.name(), SCHEME_OS
+ ":///");
190 URI bareUri
= new URI(scheme
, null, u
.getHost(), u
.getPort(),
191 scheme
.equals(SCHEME_FILE
) ? u
.getPath() : null, null, null);
192 res
.put(uri
.name(), bareUri
.toString());
196 } catch (Exception e
) {
197 throw new UserDirectoryException("Cannot convert " + uri
+ " to properties", e
);
201 private static URI
convertIpaConfig(URI uri
) {
202 String path
= uri
.getPath();
203 String kerberosRealm
;
204 if (path
== null || path
.length() <= 1) {
205 kerberosRealm
= kerberosDomainFromDns();
207 kerberosRealm
= path
.substring(1);
210 if (kerberosRealm
== null)
211 throw new UserDirectoryException("No Kerberos domain available for " + uri
);
212 try (DnsBrowser dnsBrowser
= new DnsBrowser()) {
213 String ldapHostsStr
= uri
.getHost();
214 if (ldapHostsStr
== null || ldapHostsStr
.trim().equals("")) {
215 List
<String
> ldapHosts
= dnsBrowser
.getSrvRecordsAsHosts("_ldap._tcp." + kerberosRealm
.toLowerCase());
216 if (ldapHosts
== null || ldapHosts
.size() == 0) {
217 throw new UserDirectoryException("Cannot configure LDAP for IPA " + uri
);
219 ldapHostsStr
= ldapHosts
.get(0);
222 URI convertedUri
= new URI(
223 SCHEME_LDAP
+ "://" + ldapHostsStr
+ "/" + IpaUtils
.domainToUserDirectoryConfigPath(kerberosRealm
));
224 if (log
.isDebugEnabled())
225 log
.debug("Converted " + uri
+ " to " + convertedUri
);
227 } catch (NamingException
| IOException
| URISyntaxException e
) {
228 throw new UserDirectoryException("cannot convert IPA uri " + uri
, e
);
232 private static String
kerberosDomainFromDns() {
233 String kerberosDomain
;
234 try (DnsBrowser dnsBrowser
= new DnsBrowser()) {
235 InetAddress localhost
= InetAddress
.getLocalHost();
236 String hostname
= localhost
.getHostName();
237 String dnsZone
= hostname
.substring(hostname
.indexOf('.') + 1);
238 kerberosDomain
= dnsBrowser
.getRecord("_kerberos." + dnsZone
, "TXT");
239 return kerberosDomain
;
240 } catch (Exception e
) {
241 throw new UserDirectoryException("Cannot determine Kerberos domain from DNS", e
);
246 private static String
getBaseDnFromHostname() {
249 hostname
= InetAddress
.getLocalHost().getHostName();
250 } catch (UnknownHostException e
) {
251 log
.warn("Using localhost as hostname", e
);
252 hostname
= "localhost.localdomain";
254 int dotIdx
= hostname
.indexOf('.');
256 String domain
= hostname
.substring(dotIdx
+ 1, hostname
.length());
257 String bDn
= ("." + domain
).replaceAll("\\.", ",dc=");
258 bDn
= bDn
.substring(1, bDn
.length());
261 return "dc=" + hostname
;
266 * Hash the base DN in order to have a deterministic string to be used as a cn
267 * for the underlying user directory.
269 public static String
baseDnHash(Dictionary
<String
, Object
> properties
) {
270 String bDn
= (String
) properties
.get(baseDn
.name());
272 throw new UserDirectoryException("No baseDn in " + properties
);
273 return DigestUtils
.sha1str(bDn
);