]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdapUserAdmin.java
Add JGit to client.
[lgpl/argeo-commons.git] / org.argeo.enterprise / src / org / argeo / osgi / useradmin / LdapUserAdmin.java
1 package org.argeo.osgi.useradmin;
2
3 import static org.argeo.naming.LdapAttrs.objectClass;
4
5 import java.util.ArrayList;
6 import java.util.Dictionary;
7 import java.util.Hashtable;
8 import java.util.List;
9
10 import javax.naming.Binding;
11 import javax.naming.Context;
12 import javax.naming.InvalidNameException;
13 import javax.naming.NameNotFoundException;
14 import javax.naming.NamingEnumeration;
15 import javax.naming.NamingException;
16 import javax.naming.directory.Attribute;
17 import javax.naming.directory.Attributes;
18 import javax.naming.directory.DirContext;
19 import javax.naming.directory.SearchControls;
20 import javax.naming.directory.SearchResult;
21 import javax.naming.ldap.InitialLdapContext;
22 import javax.naming.ldap.LdapName;
23 import javax.transaction.TransactionManager;
24
25 import org.argeo.naming.LdapAttrs;
26 import org.osgi.framework.Filter;
27 import org.osgi.service.useradmin.Role;
28 import org.osgi.service.useradmin.User;
29
30 /**
31 * A user admin based on a LDAP server. Requires a {@link TransactionManager}
32 * and an open transaction for write access.
33 */
34 public class LdapUserAdmin extends AbstractUserDirectory {
35 private InitialLdapContext initialLdapContext = null;
36
37 public LdapUserAdmin(Dictionary<String, ?> properties) {
38 super(null, properties);
39 try {
40 Hashtable<String, Object> connEnv = new Hashtable<String, Object>();
41 connEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
42 connEnv.put(Context.PROVIDER_URL, getUri().toString());
43 connEnv.put("java.naming.ldap.attributes.binary", LdapAttrs.userPassword.name());
44
45 initialLdapContext = new InitialLdapContext(connEnv, null);
46 // StartTlsResponse tls = (StartTlsResponse) ctx
47 // .extendedOperation(new StartTlsRequest());
48 // tls.negotiate();
49 Object securityAuthentication = properties.get(Context.SECURITY_AUTHENTICATION);
50 if (securityAuthentication != null)
51 initialLdapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, securityAuthentication);
52 else
53 initialLdapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
54 Object principal = properties.get(Context.SECURITY_PRINCIPAL);
55 if (principal != null) {
56 initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, principal.toString());
57 Object creds = properties.get(Context.SECURITY_CREDENTIALS);
58 if (creds != null) {
59 initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, creds.toString());
60
61 }
62 }
63 } catch (Exception e) {
64 throw new UserDirectoryException("Cannot connect to LDAP", e);
65 }
66 }
67
68 public void destroy() {
69 try {
70 // tls.close();
71 initialLdapContext.close();
72 } catch (NamingException e) {
73 e.printStackTrace();
74 }
75 }
76
77 @Override
78 protected AbstractUserDirectory scope(User user) {
79 Dictionary<String, Object> credentials = user.getCredentials();
80 String username = (String) credentials.get(SHARED_STATE_USERNAME);
81 if (username == null)
82 username = user.getName();
83 Dictionary<String, Object> properties = cloneProperties();
84 properties.put(Context.SECURITY_PRINCIPAL, username.toString());
85 Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
86 byte[] pwd = (byte[]) pwdCred;
87 if (pwd != null) {
88 char[] password = DigestUtils.bytesToChars(pwd);
89 properties.put(Context.SECURITY_CREDENTIALS, new String(password));
90 } else {
91 properties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
92 }
93 return new LdapUserAdmin(properties);
94 }
95
96 protected InitialLdapContext getLdapContext() {
97 return initialLdapContext;
98 }
99
100 @Override
101 protected Boolean daoHasRole(LdapName dn) {
102 try {
103 return daoGetRole(dn) != null;
104 } catch (NameNotFoundException e) {
105 return false;
106 }
107 }
108
109 @Override
110 protected DirectoryUser daoGetRole(LdapName name) throws NameNotFoundException {
111 try {
112 Attributes attrs = getLdapContext().getAttributes(name);
113 if (attrs.size() == 0)
114 return null;
115 int roleType = roleType(name);
116 LdifUser res;
117 if (roleType == Role.GROUP)
118 res = new LdifGroup(this, name, attrs);
119 else if (roleType == Role.USER)
120 res = new LdifUser(this, name, attrs);
121 else
122 throw new UserDirectoryException("Unsupported LDAP type for " + name);
123 return res;
124 } catch (NameNotFoundException e) {
125 throw e;
126 } catch (NamingException e) {
127 return null;
128 }
129 }
130
131 @Override
132 protected List<DirectoryUser> doGetRoles(Filter f) {
133 try {
134 String searchFilter = f != null ? f.toString()
135 : "(|(" + objectClass + "=" + getUserObjectClass() + ")(" + objectClass + "="
136 + getGroupObjectClass() + "))";
137 SearchControls searchControls = new SearchControls();
138 searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
139
140 LdapName searchBase = getBaseDn();
141 NamingEnumeration<SearchResult> results = getLdapContext().search(searchBase, searchFilter, searchControls);
142
143 ArrayList<DirectoryUser> res = new ArrayList<DirectoryUser>();
144 results: while (results.hasMoreElements()) {
145 SearchResult searchResult = results.next();
146 Attributes attrs = searchResult.getAttributes();
147 Attribute objectClassAttr = attrs.get(objectClass.name());
148 LdapName dn = toDn(searchBase, searchResult);
149 LdifUser role;
150 if (objectClassAttr.contains(getGroupObjectClass())
151 || objectClassAttr.contains(getGroupObjectClass().toLowerCase()))
152 role = new LdifGroup(this, dn, attrs);
153 else if (objectClassAttr.contains(getUserObjectClass())
154 || objectClassAttr.contains(getUserObjectClass().toLowerCase()))
155 role = new LdifUser(this, dn, attrs);
156 else {
157 // log.warn("Unsupported LDAP type for " + searchResult.getName());
158 continue results;
159 }
160 res.add(role);
161 }
162 return res;
163 } catch (Exception e) {
164 throw new UserDirectoryException("Cannot get roles for filter " + f, e);
165 }
166 }
167
168 private LdapName toDn(LdapName baseDn, Binding binding) throws InvalidNameException {
169 return new LdapName(binding.isRelative() ? binding.getName() + "," + baseDn : binding.getName());
170 }
171
172 @Override
173 protected List<LdapName> getDirectGroups(LdapName dn) {
174 List<LdapName> directGroups = new ArrayList<LdapName>();
175 try {
176 String searchFilter = "(&(" + objectClass + "=" + getGroupObjectClass() + ")(" + getMemberAttributeId()
177 + "=" + dn + "))";
178
179 SearchControls searchControls = new SearchControls();
180 searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
181
182 LdapName searchBase = getBaseDn();
183 NamingEnumeration<SearchResult> results = getLdapContext().search(searchBase, searchFilter, searchControls);
184
185 while (results.hasMoreElements()) {
186 SearchResult searchResult = (SearchResult) results.nextElement();
187 directGroups.add(toDn(searchBase, searchResult));
188 }
189 return directGroups;
190 } catch (Exception e) {
191 throw new UserDirectoryException("Cannot populate direct members of " + dn, e);
192 }
193 }
194
195 @Override
196 protected void prepare(UserDirectoryWorkingCopy wc) {
197 try {
198 getLdapContext().reconnect(getLdapContext().getConnectControls());
199 // delete
200 for (LdapName dn : wc.getDeletedUsers().keySet()) {
201 if (!entryExists(dn))
202 throw new UserDirectoryException("User to delete no found " + dn);
203 }
204 // add
205 for (LdapName dn : wc.getNewUsers().keySet()) {
206 if (entryExists(dn))
207 throw new UserDirectoryException("User to create found " + dn);
208 }
209 // modify
210 for (LdapName dn : wc.getModifiedUsers().keySet()) {
211 if (!wc.getNewUsers().containsKey(dn) && !entryExists(dn))
212 throw new UserDirectoryException("User to modify not found " + dn);
213 }
214 } catch (NamingException e) {
215 throw new UserDirectoryException("Cannot prepare LDAP", e);
216 }
217 }
218
219 private boolean entryExists(LdapName dn) throws NamingException {
220 try {
221 return getLdapContext().getAttributes(dn).size() != 0;
222 } catch (NameNotFoundException e) {
223 return false;
224 }
225 }
226
227 @Override
228 protected void commit(UserDirectoryWorkingCopy wc) {
229 try {
230 // delete
231 for (LdapName dn : wc.getDeletedUsers().keySet()) {
232 getLdapContext().destroySubcontext(dn);
233 }
234 // add
235 for (LdapName dn : wc.getNewUsers().keySet()) {
236 DirectoryUser user = wc.getNewUsers().get(dn);
237 getLdapContext().createSubcontext(dn, user.getAttributes());
238 }
239 // modify
240 for (LdapName dn : wc.getModifiedUsers().keySet()) {
241 Attributes modifiedAttrs = wc.getModifiedUsers().get(dn);
242 getLdapContext().modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, modifiedAttrs);
243 }
244 } catch (NamingException e) {
245 throw new UserDirectoryException("Cannot commit LDAP", e);
246 }
247 }
248
249 @Override
250 protected void rollback(UserDirectoryWorkingCopy wc) {
251 // prepare not impacting
252 }
253
254 }