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