]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/osgi/useradmin/UserAdminConf.java
Introduce system roles
[lgpl/argeo-commons.git] / org.argeo.util / src / org / argeo / osgi / useradmin / UserAdminConf.java
1 package org.argeo.osgi.useradmin;
2
3 import java.net.InetAddress;
4 import java.net.URI;
5 import java.net.URISyntaxException;
6 import java.net.UnknownHostException;
7 import java.util.Dictionary;
8 import java.util.Hashtable;
9 import java.util.List;
10 import java.util.Map;
11
12 import javax.naming.Context;
13 import javax.naming.ldap.LdapName;
14
15 import org.argeo.util.naming.NamingUtils;
16
17 /** Properties used to configure user admins. */
18 public enum UserAdminConf {
19 /** Base DN (cannot be configured externally) */
20 baseDn("dc=example,dc=com"),
21
22 /** URI of the underlying resource (cannot be configured externally) */
23 uri("ldap://localhost:10389"),
24
25 /** User objectClass */
26 userObjectClass("inetOrgPerson"),
27
28 /** Relative base DN for users */
29 userBase("ou=People"),
30
31 /** Groups objectClass */
32 groupObjectClass("groupOfNames"),
33
34 /** Relative base DN for users */
35 groupBase("ou=Groups"),
36
37 /** Relative base DN for users */
38 systemRoleBase("ou=Roles"),
39
40 /** Read-only source */
41 readOnly(null),
42
43 /** Disabled source */
44 disabled(null),
45
46 /** Authentication realm */
47 realm(null),
48
49 /** Override all passwords with this value (typically for testing purposes) */
50 forcedPassword(null);
51
52 public final static String FACTORY_PID = "org.argeo.osgi.useradmin.config";
53
54 public final static String SCHEME_LDAP = "ldap";
55 public final static String SCHEME_LDAPS = "ldaps";
56 public final static String SCHEME_FILE = "file";
57 public final static String SCHEME_OS = "os";
58 public final static String SCHEME_IPA = "ipa";
59
60 /** The default value. */
61 private Object def;
62
63 UserAdminConf(Object def) {
64 this.def = def;
65 }
66
67 public Object getDefault() {
68 return def;
69 }
70
71 /**
72 * For use as Java property.
73 *
74 * @deprecated use {@link #name()} instead
75 */
76 @Deprecated
77 public String property() {
78 return name();
79 }
80
81 public String getValue(Dictionary<String, ?> properties) {
82 Object res = getRawValue(properties);
83 if (res == null)
84 return null;
85 return res.toString();
86 }
87
88 @SuppressWarnings("unchecked")
89 public <T> T getRawValue(Dictionary<String, ?> properties) {
90 Object res = properties.get(name());
91 if (res == null)
92 res = getDefault();
93 return (T) res;
94 }
95
96 /** @deprecated use {@link #valueOf(String)} instead */
97 @Deprecated
98 public static UserAdminConf local(String property) {
99 return UserAdminConf.valueOf(property);
100 }
101
102 /** Hides host and credentials. */
103 public static URI propertiesAsUri(Dictionary<String, ?> properties) {
104 StringBuilder query = new StringBuilder();
105
106 boolean first = true;
107 // for (Enumeration<String> keys = properties.keys(); keys.hasMoreElements();) {
108 // String key = keys.nextElement();
109 // // TODO clarify which keys are relevant (list only the enum?)
110 // if (!key.equals("service.factoryPid") && !key.equals("cn") && !key.equals("dn")
111 // && !key.equals(Constants.SERVICE_PID) && !key.startsWith("java") && !key.equals(baseDn.name())
112 // && !key.equals(uri.name()) && !key.equals(Constants.OBJECTCLASS)
113 // && !key.equals(Constants.SERVICE_ID) && !key.equals("bundle.id")) {
114 // if (first)
115 // first = false;
116 // else
117 // query.append('&');
118 // query.append(valueOf(key).name());
119 // query.append('=').append(properties.get(key).toString());
120 // }
121 // }
122
123 keys: for (UserAdminConf key : UserAdminConf.values()) {
124 if (key.equals(baseDn) || key.equals(uri))
125 continue keys;
126 Object value = properties.get(key.name());
127 if (value == null)
128 continue keys;
129 if (first)
130 first = false;
131 else
132 query.append('&');
133 query.append(key.name());
134 query.append('=').append(value.toString());
135
136 }
137
138 Object bDnObj = properties.get(baseDn.name());
139 String bDn = bDnObj != null ? bDnObj.toString() : null;
140 try {
141 return new URI(null, null, bDn != null ? '/' + bDn : null, query.length() != 0 ? query.toString() : null,
142 null);
143 } catch (URISyntaxException e) {
144 throw new UserDirectoryException("Cannot create URI from properties", e);
145 }
146 }
147
148 public static Dictionary<String, Object> uriAsProperties(String uriStr) {
149 try {
150 Hashtable<String, Object> res = new Hashtable<String, Object>();
151 URI u = new URI(uriStr);
152 String scheme = u.getScheme();
153 if (scheme != null && scheme.equals(SCHEME_IPA)) {
154 return IpaUtils.convertIpaUri(u);
155 // scheme = u.getScheme();
156 }
157 String path = u.getPath();
158 // base DN
159 String bDn = path.substring(path.lastIndexOf('/') + 1, path.length());
160 if (bDn.equals("") && SCHEME_OS.equals(scheme)) {
161 bDn = getBaseDnFromHostname();
162 }
163
164 if (bDn.endsWith(".ldif"))
165 bDn = bDn.substring(0, bDn.length() - ".ldif".length());
166
167 // Normalize base DN as LDAP name
168 bDn = new LdapName(bDn).toString();
169
170 String principal = null;
171 String credentials = null;
172 if (scheme != null)
173 if (scheme.equals(SCHEME_LDAP) || scheme.equals(SCHEME_LDAPS)) {
174 // TODO additional checks
175 if (u.getUserInfo() != null) {
176 String[] userInfo = u.getUserInfo().split(":");
177 principal = userInfo.length > 0 ? userInfo[0] : null;
178 credentials = userInfo.length > 1 ? userInfo[1] : null;
179 }
180 } else if (scheme.equals(SCHEME_FILE)) {
181 } else if (scheme.equals(SCHEME_IPA)) {
182 } else if (scheme.equals(SCHEME_OS)) {
183 } else
184 throw new UserDirectoryException("Unsupported scheme " + scheme);
185 Map<String, List<String>> query = NamingUtils.queryToMap(u);
186 for (String key : query.keySet()) {
187 UserAdminConf ldapProp = UserAdminConf.valueOf(key);
188 List<String> values = query.get(key);
189 if (values.size() == 1) {
190 res.put(ldapProp.name(), values.get(0));
191 } else {
192 throw new UserDirectoryException("Only single values are supported");
193 }
194 }
195 res.put(baseDn.name(), bDn);
196 if (SCHEME_OS.equals(scheme))
197 res.put(readOnly.name(), "true");
198 if (principal != null)
199 res.put(Context.SECURITY_PRINCIPAL, principal);
200 if (credentials != null)
201 res.put(Context.SECURITY_CREDENTIALS, credentials);
202 if (scheme != null) {// relative URIs are dealt with externally
203 if (SCHEME_OS.equals(scheme)) {
204 res.put(uri.name(), SCHEME_OS + ":///");
205 } else {
206 URI bareUri = new URI(scheme, null, u.getHost(), u.getPort(),
207 scheme.equals(SCHEME_FILE) ? u.getPath() : null, null, null);
208 res.put(uri.name(), bareUri.toString());
209 }
210 }
211 return res;
212 } catch (Exception e) {
213 throw new UserDirectoryException("Cannot convert " + uri + " to properties", e);
214 }
215 }
216
217 private static String getBaseDnFromHostname() {
218 String hostname;
219 try {
220 hostname = InetAddress.getLocalHost().getHostName();
221 } catch (UnknownHostException e) {
222 hostname = "localhost.localdomain";
223 }
224 int dotIdx = hostname.indexOf('.');
225 if (dotIdx >= 0) {
226 String domain = hostname.substring(dotIdx + 1, hostname.length());
227 String bDn = ("." + domain).replaceAll("\\.", ",dc=");
228 bDn = bDn.substring(1, bDn.length());
229 return bDn;
230 } else {
231 return "dc=" + hostname;
232 }
233 }
234
235 /**
236 * Hash the base DN in order to have a deterministic string to be used as a cn
237 * for the underlying user directory.
238 */
239 public static String baseDnHash(Dictionary<String, Object> properties) {
240 String bDn = (String) properties.get(baseDn.name());
241 if (bDn == null)
242 throw new UserDirectoryException("No baseDn in " + properties);
243 return DigestUtils.sha1str(bDn);
244 }
245 }