1
2
3
4
5
6
7
8
9
10
11 package gov.bnl.gums.db;
12
13 import gov.bnl.gums.GUMS;
14 import gov.bnl.gums.GridUser;
15 import gov.bnl.gums.persistence.LDAPPersistenceFactory;
16
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.Hashtable;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23
24 import javax.naming.NameAlreadyBoundException;
25 import javax.naming.NamingEnumeration;
26 import javax.naming.directory.*;
27 import javax.naming.ldap.Control;
28 import javax.naming.ldap.LdapContext;
29 import javax.naming.ldap.PagedResultsControl;
30
31 import org.apache.log4j.Logger;
32
33
34
35
36
37 public class LDAPAccountMapperDB implements AccountPoolMapperDB, ManualAccountMapperDB {
38 private Logger log = Logger.getLogger(LDAPAccountMapperDB.class);
39 private LDAPPersistenceFactory factory;
40 private String map;
41 private String mapDN;
42 private String group;
43 private List secondaryGroups;
44 private static Map needsCacheRefresh = Collections.synchronizedMap(new HashMap());
45
46
47
48
49
50
51
52 public LDAPAccountMapperDB(LDAPPersistenceFactory factory, String map) {
53 this.factory = factory;
54 this.map = map;
55 this.mapDN = "map=" + map + "," + factory.getGumsObject();
56 createGroupIfNotExists();
57 log.trace("LDAPMapDB object create: map '" + map + "' factory "
58 + factory);
59 }
60
61
62
63
64
65
66
67
68
69
70
71 public LDAPAccountMapperDB(LDAPPersistenceFactory factory, String map, String group, List secondaryGroups) {
72 this(factory, map);
73 this.group = group;
74 this.secondaryGroups = secondaryGroups;
75 if (group==null)
76 log.info("No primary group: factory '" + factory + "'");
77 log.trace("LDAPMapDB object create: map '" + map + "' factory "
78 + factory + " primary group '" + group + "' secondary groups '"
79 + secondaryGroups + "'");
80 }
81
82 public void addAccount(String account) {
83 try {
84 factory.createAccountInMap(account, map, mapDN);
85 setNeedsCacheRefresh(true);
86 } catch (Exception e) {
87 if (e.getCause() instanceof NameAlreadyBoundException) {
88 throw new IllegalArgumentException("Account '" + account
89 + "' is already present in LDAP pool '" + map + "'");
90 }
91 }
92 }
93
94 public String assignAccount(GridUser user) {
95 DirContext context = factory.retrieveGumsDirContext();
96 String account = null;
97 Control[] controlsBackup = null;
98 String userDN = user.getCertificateDN();
99 String email = user.getEmail();
100 try {
101 LdapContext ldapContext = (LdapContext) context;
102 controlsBackup = ldapContext.getRequestControls();
103 ldapContext.setRequestControls(new Control[] { new PagedResultsControl( 100, Control.CRITICAL) });
104 SearchControls ctrls = new SearchControls();
105 ctrls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
106 NamingEnumeration result = context.search(mapDN, "(!(user=*))", null, ctrls);
107 while (result.hasMore()) {
108 SearchResult res = (SearchResult) result.next();
109 Attributes atts = res.getAttributes();
110 Attribute accounts = atts.get("account");
111 if (accounts != null) {
112 String newAccount = (String) accounts.get();
113 if (account == null) {
114 account = newAccount;
115 } else {
116 if (account.compareTo(newAccount) > 0) {
117 account = newAccount;
118 }
119 }
120 }
121 }
122 } catch (Exception e) {
123 log.error("Couldn't assign account from LDAP map '" + map
124 + "' to user '" + userDN + "'", e);
125 throw new RuntimeException(
126 "Couldn't assign account from LDAP map '" + map
127 + "' to user '" + userDN + "': " + e.getMessage(),
128 e);
129 } finally {
130 if (controlsBackup != null) {
131 try {
132 ((LdapContext) context).setRequestControls(controlsBackup);
133 } catch (Exception e) {
134 log.error("Couldn't reset controls", e);
135 }
136 }
137 factory.releaseContext(context);
138 }
139
140 if (account != null) {
141 if (group!=null) {
142 assignGroups(account, group, secondaryGroups);
143 log.trace("Assigned gids for user '" + userDN + "' account '" + account + "'");
144 }
145 if (email!=null) {
146 assignEmail(account, email);
147 log.trace("Assigned email for account '" + account + "' to email '" + email + "'");
148 }
149 factory.addMapEntry(userDN, account, map, mapDN);
150 log.trace("Assigned account for LDAP map '" + map + "' user '"
151 + userDN + "' account '" + account + "'");
152 } else {
153 log.trace("No account to assign for LDAP map '" + map + "' user '"
154 + userDN + "' account '" + account + "'");
155 }
156 setNeedsCacheRefresh(true);
157
158 return account;
159 }
160
161 public void createGroupIfNotExists() {
162 if (!doesMapExist()) {
163 factory.createMap(map, mapDN);
164 log.trace("LDAP group '" + map + "' didn't exist, and it was created");
165 setNeedsCacheRefresh(true);
166 }
167 }
168
169 public void createMapping(String userDN, String account) {
170 factory.addMapEntry(userDN, account, map, mapDN);
171 setNeedsCacheRefresh(true);
172 }
173
174 public boolean doesMapExist() {
175 DirContext context = factory.retrieveGumsDirContext();
176 try {
177 SearchControls ctrls = new SearchControls();
178 ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
179 log.trace("Checking if LDAP map '" + map + "' exists");
180 NamingEnumeration result = context.search(factory.getGumsObject(), "(map={0})", new Object[] { map },
181 ctrls);
182 return result.hasMore();
183 } catch (Exception e) {
184 log.error("Couldn't determine if LDAP map exists '" + map + "'", e);
185 throw new RuntimeException(
186 "Couldn't determine if LDAP map exists '" + map + "': "
187 + e.getMessage(), e);
188 } finally {
189 factory.releaseContext(context);
190 }
191 }
192
193 public String getMap() {
194 return map;
195 }
196
197 public boolean needsCacheRefresh() {
198 if (needsCacheRefresh.get(map) != null)
199 return ((Boolean)needsCacheRefresh.get(map)).booleanValue();
200 else
201 return true;
202 }
203
204 public boolean removeAccount(String account) {
205 try {
206 boolean retVal = factory.destroyAccountInMap(account, map, mapDN);
207 setNeedsCacheRefresh(true);
208 return retVal;
209 } catch (RuntimeException e) {
210 if (e.getCause() instanceof NameAlreadyBoundException)
211 throw new IllegalArgumentException("Cannot remove '" + account + "' from LDAP pool '" + map + "'");
212 throw e;
213 }
214 }
215
216 public boolean removeMapping(String userDN) {
217 try {
218 boolean retVal = factory.removeMapEntry(userDN, map, mapDN);
219 setNeedsCacheRefresh(true);
220 return retVal;
221 } catch (RuntimeException e) {
222 if (e.getCause() instanceof NoSuchAttributeException)
223 return false;
224 throw e;
225 }
226 }
227
228 public String retrieveAccount(GridUser user) {
229 String userDN = user.getCertificateDN();
230 String account = retrieveMapping(userDN);
231 log.trace("Retrieving account from LDAP map '" + map + "' for user '"
232 + userDN + "' account '" + account + "'");
233 if (account != null) {
234 reassignGroups(account, group, secondaryGroups);
235 reassignEmail(account, user.getEmail());
236 log.trace("Reassigned gids for user '" + userDN + "' account '"
237 + account + "'");
238 }
239 return account;
240 }
241
242 public java.util.Map retrieveAccountMap() {
243 DirContext context = factory.retrieveGumsDirContext();
244 Map map = new Hashtable();
245 try {
246 SearchControls ctrls = new SearchControls();
247 ctrls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
248 NamingEnumeration result = context.search(mapDN, "(user=*)", null,
249 ctrls);
250 while (result.hasMore()) {
251 SearchResult res = (SearchResult) result.next();
252 Attributes atts = res.getAttributes();
253 Attribute accounts = atts.get("account");
254 if (accounts != null) {
255 String account = (String) accounts.get();
256 Attribute users = atts.get("user");
257 String user = (String) users.get();
258 map.put(user, account);
259 }
260 }
261 log.trace("Retrieved LDAP map '" + map + "'");
262 return map;
263 } catch (Exception e) {
264 log.error("Couldn't retrieve LDAP map '" + map + "'", e);
265 throw new RuntimeException("Couldn't retrieve LDAP map '" + map
266 + "': " + e.getMessage(), e);
267 } finally {
268 factory.releaseContext(context);
269 }
270 }
271
272 public String retrieveMapping(String userDN) {
273 DirContext context = factory.retrieveGumsDirContext();
274 try {
275 SearchControls ctrls = new SearchControls();
276 ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
277 NamingEnumeration result = context.search(mapDN, "(user={0})",
278 new Object[] { userDN }, ctrls);
279 if (result.hasMore()) {
280 SearchResult res = (SearchResult) result.next();
281 Attributes atts = res.getAttributes();
282 Attribute map = atts.get("account");
283 if (map == null)
284 return null;
285 String account = (String) map.get();
286 log.trace("Retrieved map entry in map '" + map + "' for user '"
287 + userDN + "' to account '" + account + "'");
288 return account;
289 }
290 return null;
291 } catch (Exception e) {
292 log.error("Couldn't retrieve entry from LDAP map '" + map
293 + "' for user '" + userDN + "'", e);
294 throw new RuntimeException(
295 "Couldn't retrieve entry from LDAP map '" + map
296 + "' for user '" + userDN + "': " + e.getMessage(),
297 e);
298 } finally {
299 factory.releaseContext(context);
300 }
301 }
302
303 public java.util.Map retrieveReverseAccountMap() {
304 DirContext context = factory.retrieveGumsDirContext();
305 Map map = new Hashtable();
306 try {
307 SearchControls ctrls = new SearchControls();
308 ctrls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
309 NamingEnumeration result = context.search(mapDN, "(account=*)",
310 null, ctrls);
311 while (result.hasMore()) {
312 SearchResult res = (SearchResult) result.next();
313 Attributes atts = res.getAttributes();
314 Attribute accounts = atts.get("account");
315 String account = (String) accounts.get();
316 Attribute users = atts.get("user");
317 String user = users!=null ? (String) users.get() : "";
318 map.put(account, user);
319 }
320 log.trace("Retrieved LDAP map '" + map + "'");
321 return map;
322 } catch (Exception e) {
323 log.error("Couldn't retrieve LDAP map '" + map + "'", e);
324 throw new RuntimeException("Couldn't retrieve LDAP map '" + map
325 + "': " + e.getMessage(), e);
326 } finally {
327 factory.releaseContext(context);
328 }
329 }
330
331 public java.util.List retrieveUsersNotUsedSince(java.util.Date date) {
332 throw new UnsupportedOperationException(
333 "retrieveUsersNotUsedSince is not supported anymore");
334 }
335
336 public String retrieveEmail(String account) {
337 return factory.retrieveEmail(account);
338 }
339
340 public synchronized void setCacheRefreshed() {
341 needsCacheRefresh.put(map, new Boolean(false));
342 }
343
344 public void unassignAccount(String account) {
345 DirContext context = factory.retrieveGumsDirContext();
346 try {
347 SearchControls ctrls = new SearchControls();
348 ctrls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
349 NamingEnumeration result = context.search(mapDN, "(account={0})", new Object[] { account }, ctrls);
350 while (result.hasMore()) {
351 SearchResult res = (SearchResult) result.next();
352 Attributes atts = res.getAttributes();
353 Attribute users = atts.get("user");
354 if (users!=null) {
355 String user = (String) users.get();
356 factory.removeMapEntry(user, map, mapDN);
357 }
358 }
359 setNeedsCacheRefresh(true);
360 log.trace("Unassigned account '" + account + "' at LDAP map '" + map + "'");
361 } catch (Exception e) {
362 log.error("Unassigned account '" + account + "' at LDAP map '" + map + "'", e);
363 throw new RuntimeException("Couldn't retrieve LDAP map '" + map
364 + "': " + e.getMessage(), e);
365 } finally {
366 factory.releaseContext(context);
367 }
368 }
369
370
371 public void unassignUser(String userDN) {
372 factory.removeMapEntry(userDN, map, mapDN);
373 setNeedsCacheRefresh(true);
374 }
375
376
377
378
379
380
381
382
383 private void assignGroups(String account, String primaryGroup, List secondaryGroups) {
384 try {
385 factory.changeGroupID(account, primaryGroup);
386 log.trace("Assigned '" + primaryGroup + "' to '" + account + "'");
387 if (secondaryGroups == null) return;
388 Iterator iter = secondaryGroups.iterator();
389 while (iter.hasNext()) {
390 String group = (String) iter.next();
391 factory.addToSecondaryGroup(account, group);
392 log.trace("Assigned secondary group '" + group + "' to '" + account + "'");
393 }
394 } catch (Exception e) {
395 log.warn("Couldn't assign GIDs. account '" + account + "' - primary group '" + primaryGroup + "' - secondary '" + secondaryGroups + "'", e);
396 throw new RuntimeException("Couldn't assign GIDs: " + e.getMessage() + ". account '" + account + "' - primary group '" + primaryGroup + "' - secondary '" + secondaryGroups + "' - " + e.getMessage());
397 }
398 }
399
400
401
402
403
404
405
406 private void assignEmail(String account, String email) {
407 try {
408 factory.changeEmail(account, email);
409 log.trace("Assigned '" + email + "' to '" + account + "'");
410 } catch (Exception e) {
411 log.warn("Couldn't assign email. account '" + account + "' - email '" + email + "'", e);
412 throw new RuntimeException("Couldn't assign email: " + e.getMessage() + ". account '" + account + "' - email '" + email + "' - " + e.getMessage());
413 }
414 }
415
416
417
418
419
420
421
422
423
424
425 private void reassignGroups(String account, String primary, List secondary) {
426 if (factory.isSynch()) {
427 assignGroups(account, primary, secondary);
428 } else {
429 log.trace("Skip reassign groups for account '" + account + "' - primary group '" + primary + "' - secondary '" + secondary + "'");
430 }
431 }
432
433
434
435
436
437
438
439
440 private void reassignEmail(String account, String email) {
441 if (factory.isSynch()) {
442 assignEmail(account, email);
443 } else {
444 log.trace("Skip reassign email for account '" + account + "' - email '" + email + "'");
445 }
446 }
447
448 private void setNeedsCacheRefresh(boolean value) {
449 needsCacheRefresh.put(map, new Boolean(value));
450 }
451
452 }