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