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