001: /*
002: * $Id: LDAPTribe.java,v 1.10 2002/09/16 08:05:06 jkl Exp $
003: *
004: * Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
005: *
006: * Use is subject to license terms, as defined in
007: * Anvil Sofware License, Version 1.1. See LICENSE
008: * file, or http://njet.org/license-1.1.txt
009: */
010: package anvil.server.ldap;
011:
012: import java.security.Permission;
013: import java.security.Permissions;
014: import java.security.PermissionCollection;
015: import java.util.ArrayList;
016: import java.util.Iterator;
017: import java.util.Enumeration;
018:
019: import anvil.java.util.BindingEnumeration;
020: import anvil.java.util.EnumerationToIterator;
021: import anvil.java.security.PermissionCollectionCombiner;
022: import anvil.core.Any;
023: import anvil.server.Tribe;
024: import anvil.server.Citizen;
025: import anvil.server.Tribe;
026: import anvil.server.Realm;
027: import anvil.server.Citizen;
028: import anvil.server.CitizenNotFoundException;
029: import anvil.server.OperationFailedException;
030: import anvil.database.PooledConnection;
031: import anvil.Log;
032:
033: import javax.naming.directory.DirContext;
034: import javax.naming.directory.Attribute;
035: import javax.naming.directory.Attributes;
036: import javax.naming.directory.BasicAttribute;
037: import javax.naming.directory.BasicAttributes;
038: import javax.naming.NamingEnumeration;
039: import javax.naming.NameClassPair;
040: import javax.naming.NamingException;
041: import javax.naming.Name;
042: import javax.naming.NameParser;
043: import javax.naming.NameNotFoundException;
044:
045: /**
046: * class LDAPTribe
047: *
048: * @author: Simo Tuokko
049: */
050:
051: public class LDAPTribe implements Tribe {
052: private LDAPRealm realm;
053: private Log log;
054: private String name;
055: private String dn;
056: private String fullDN;
057: private boolean isRoot;
058: Tribe[] children = null;
059: Tribe[] parents = null;
060: Citizen[] citizens = null;
061: private PermissionCollection permissions = null;
062: private PermissionCollection combined = null;
063: private boolean hasPermissions = false;
064:
065: LDAPTribe(LDAPRealm realm, String name)
066: throws OperationFailedException {
067: this (realm, name, false);
068: }
069:
070: LDAPTribe(LDAPRealm realm, String name, boolean isRoot)
071: throws OperationFailedException {
072: this .realm = realm;
073: this .name = name;
074: this .dn = "cn=" + name + ",ou=groups";
075: this .fullDN = realm.createGroupDN(name);
076: this .isRoot = isRoot;
077: log = realm.getLog();
078:
079: if (!isRoot) {
080: PooledConnection connImpl = null;
081: DirContext ctx = null;
082: boolean tribeFound = false;
083:
084: try {
085: connImpl = realm.getConnection();
086: ctx = (DirContext) connImpl.getConnection();
087:
088: ctx.getAttributes(dn, new String[] { "cn" });
089: tribeFound = true;
090: } catch (NameNotFoundException nnfe) {
091: //not found
092:
093: } catch (Exception e) {
094: throw new OperationFailedException(
095: "Creating of tribe failed", e);
096:
097: } finally {
098: LDAPRealm.cleanupContext(connImpl);
099: }
100: if (!tribeFound) {
101: throw new CitizenNotFoundException(name);
102: }
103: }
104: }
105:
106: public Realm getRealm() {
107: return realm;
108: }
109:
110: public String getName() {
111: return name;
112: }
113:
114: public Tribe[] getParents() {
115: if (parents == null) {
116: synchronized (this ) {
117: if (parents == null) {
118: parents = realm.getMemberGroups(fullDN);
119: }
120: }
121: }
122: return parents;
123: }
124:
125: public boolean hasChilds() {
126: if (children == null) {
127: getChilds();
128: }
129: return (children.length > 0);
130: }
131:
132: public Tribe[] getChilds() {
133: if (children == null) {
134: synchronized (this ) {
135: if (children == null) {
136: children = (Tribe[]) fetchChildren(true);
137: }
138: }
139: }
140: return children;
141: }
142:
143: public Citizen[] getCitizens() {
144: if (citizens == null) {
145: synchronized (this ) {
146: if (citizens == null) {
147: citizens = (Citizen[]) fetchChildren(false);
148: }
149: }
150: }
151: return citizens;
152: }
153:
154: public PermissionCollection getPermissions() {
155: if (permissions == null) {
156: synchronized (this ) {
157: if (permissions == null) {
158: permissions = realm.loadPermissions(dn);
159: }
160: }
161: }
162: return permissions;
163: }
164:
165: public PermissionCollection getCombinedPermissions() {
166: if (!hasPermissions) {
167: synchronized (this ) {
168: if (!hasPermissions) {
169: hasPermissions = true;
170: getParents();
171: Permissions perms = new Permissions();
172: for (int i = 0; i < parents.length; i++) {
173: PermissionCollection parentCol = parents[i]
174: .getCombinedPermissions();
175: if (parentCol != null) {
176: for (Enumeration enu = parentCol.elements(); enu
177: .hasMoreElements();) {
178: perms.add((Permission) enu
179: .nextElement());
180: }
181: }
182: }
183: //combine own permissions
184: for (Enumeration enu = getPermissions().elements(); enu
185: .hasMoreElements();) {
186: perms.add((Permission) enu.nextElement());
187: }
188:
189: combined = perms;
190: }
191: }
192: }
193:
194: return combined;
195: }
196:
197: public void addPermission(Permission perm)
198: throws OperationFailedException {
199: if (isRoot) {
200: throw new OperationFailedException(
201: "addPermission operation isn't allowed for synthetic root tribe!");
202: }
203: permissions = realm.addPermission(perm, dn);
204: }
205:
206: public void removePermission(Permission perm)
207: throws OperationFailedException {
208: permissions = realm.removePermission(perm, dn);
209: }
210:
211: public Iterator listPermissions() {
212: if (permissions != null) {
213: return new EnumerationToIterator(permissions.elements());
214: } else {
215: return BindingEnumeration.EMPTY;
216: }
217: }
218:
219: public void commit() throws OperationFailedException {
220: }
221:
222: private Object fetchChildren(boolean isTribe) {
223: PooledConnection connImpl = null;
224: DirContext ctx = null;
225: ArrayList result = new ArrayList();
226:
227: try {
228: connImpl = realm.getConnection();
229: ctx = (DirContext) connImpl.getConnection();
230:
231: if (isRoot) {
232: NamingEnumeration enu = ctx.list(isTribe ? "ou=groups"
233: : "ou=users");
234:
235: while (enu.hasMore()) {
236: String name = ((NameClassPair) enu.next())
237: .getName();
238: name = name.substring(name.indexOf("=") + 1);
239: if (isTribe) {
240: result.add(realm.getTribe(name));
241: } else {
242: result.add(realm.getCitizen(name));
243: }
244:
245: }
246: } else {
247:
248: Attributes a = ctx.getAttributes(dn,
249: new String[] { "uniquemember" });
250: Attribute memberAttr = a.get("uniquemember");
251:
252: if (memberAttr != null) {
253: for (NamingEnumeration de = memberAttr.getAll(); de
254: .hasMore();) {
255: String val = (String) de.next();
256: String name = val.substring(
257: val.indexOf("=") + 1, val.indexOf(","))
258: .trim();
259:
260: if (isTribe) {
261: if (val.startsWith("cn")) {
262: result.add(realm.getTribe(name));
263: }
264: } else {
265: if (val.startsWith("uid")) {
266: result.add(realm.getCitizen(name));
267: }
268: }
269: } //for
270: }
271: } //if isRoot
272:
273: } catch (Exception e) {
274: log.error("LDAPTribe.fetchChildren() failed: " + e);
275:
276: } finally {
277: LDAPRealm.cleanupContext(connImpl);
278: }
279:
280: int l = result.size();
281: if (isTribe) {
282: return (Tribe[]) result.toArray(new Tribe[l]);
283: } else {
284: return (Citizen[]) result.toArray(new Citizen[l]);
285: }
286: }
287:
288: //Namespace stuff
289: public Any setVariable(String name, Any value) {
290: return null;
291: }
292:
293: public boolean deleteVariable(String name) {
294: return false;
295: }
296:
297: public Any getVariable(String name) {
298: return null;
299: }
300:
301: public Any checkVariable(String name) {
302: return null;
303: }
304:
305: public BindingEnumeration getVariables() {
306: return null;
307: }
308:
309: //Mutable stuff
310: public void attach(Tribe tribe) throws OperationFailedException {
311: LDAPTribe t = (LDAPTribe) tribe;
312: if (attach(t.getFullDN(), tribe)) {
313: //refresh
314: children = null;
315: t.refreshPermissions();
316: }
317: }
318:
319: public void attach(Citizen citizen) throws OperationFailedException {
320: LDAPCitizen c = (LDAPCitizen) citizen;
321: if (attach(c.getFullDN(), citizen)) {
322: //refresh
323: citizens = null;
324: c.refreshPermissions();
325: }
326: }
327:
328: private synchronized boolean attach(String dn, Object res)
329: throws OperationFailedException {
330: if (isRoot) {
331: throw new OperationFailedException(
332: "Attach operation isn't allowed for synthetic root tribe!");
333: }
334: PooledConnection connImpl = null;
335: DirContext ctx = null;
336:
337: try {
338: connImpl = realm.getConnection();
339: ctx = (DirContext) connImpl.getConnection();
340:
341: //check that this tribe isn't a member of the tribe being attached
342: if (res instanceof LDAPTribe) {
343: LDAPTribe parentCand = (LDAPTribe) res;
344: String parentFail = parentCand.containsName(ctx,
345: parentCand.fetchMembers(ctx), this .dn);
346: if (parentFail != null) {
347: throw new OperationFailedException(
348: "Loops not allowed, '" + dn
349: + "' is parent of of '" + this .dn
350: + "'");
351: }
352: }
353:
354: Attribute currMembers = fetchMembers(ctx);
355: String failer = containsName(ctx, currMembers, dn);
356: if (failer == null) {
357: currMembers.add(dn);
358: Attributes attrs = new BasicAttributes();
359: attrs.put(currMembers);
360:
361: ctx.modifyAttributes(this .dn,
362: DirContext.REPLACE_ATTRIBUTE, attrs);
363: return true;
364: }
365:
366: } catch (Exception e) {
367: throw new OperationFailedException(e);
368:
369: } finally {
370: LDAPRealm.cleanupContext(connImpl);
371: }
372: return false;
373: }
374:
375: public void detach(Tribe tribe) throws OperationFailedException {
376: LDAPTribe t = (LDAPTribe) tribe;
377: if (detach(t.getFullDN())) {
378: //refresh
379: children = null;
380: t.refreshPermissions();
381: }
382: }
383:
384: public void detach(Citizen citizen) throws OperationFailedException {
385: LDAPCitizen c = (LDAPCitizen) citizen;
386: if (detach(c.getFullDN())) {
387: //refresh
388: citizens = null;
389: c.refreshPermissions();
390: }
391: }
392:
393: private synchronized boolean detach(String dn)
394: throws OperationFailedException {
395: if (isRoot) {
396: throw new OperationFailedException(
397: "Detach operation isn't allowed for synthetic root tribe!");
398: }
399: PooledConnection connImpl = null;
400: DirContext ctx = null;
401:
402: try {
403: connImpl = realm.getConnection();
404: ctx = (DirContext) connImpl.getConnection();
405:
406: Attribute currMembers = fetchMembers(ctx);
407: String result = containsName(ctx, currMembers, dn);
408: if (result != null) {
409: currMembers.remove(result);
410: Attributes attrs = new BasicAttributes();
411: attrs.put(currMembers);
412:
413: ctx.modifyAttributes(this .dn,
414: DirContext.REPLACE_ATTRIBUTE, attrs);
415:
416: return true;
417: }
418:
419: } catch (Exception e) {
420: throw new OperationFailedException(e);
421:
422: } finally {
423: LDAPRealm.cleanupContext(connImpl);
424: }
425: return false;
426: }
427:
428: private Attribute fetchMembers(DirContext ctx)
429: throws NamingException {
430: return fetchMembers(ctx, dn);
431: }
432:
433: private Attribute fetchMembers(DirContext ctx, String fetchDN)
434: throws NamingException {
435: Attributes attrs = ctx.getAttributes(fetchDN,
436: new String[] { "uniquemember" });
437: Attribute members = attrs.get("uniquemember");
438: return (members == null) ? new BasicAttribute("uniquemember")
439: : members;
440: }
441:
442: private String containsName(DirContext ctx, Attribute attr,
443: String dn) throws NamingException, OperationFailedException {
444: NameParser parser = ctx.getNameParser(realm.getPrefix());
445: Name name = parser.parse(dn);
446:
447: for (NamingEnumeration e = attr.getAll(); e.hasMore();) {
448: String cand = (String) e.next();
449: Name candName = parser.parse(cand);
450:
451: if (name.equals(candName)) {
452: e.close();
453: return cand;
454: }
455:
456: //toimiiko jos prefixiä ei ole???
457: if (cand.toLowerCase().startsWith("cn")) {
458: String res = containsName(ctx, fetchMembers(ctx,
459: candName.getSuffix(candName.size() - 2)
460: .toString()), dn);
461: if (res != null) {
462: throw new OperationFailedException(
463: "Loops not allowed, '" + dn
464: + "' is already a member of '"
465: + cand + "'");
466: }
467: }
468: }
469: return null;
470: }
471:
472: public void remove() throws OperationFailedException {
473: PooledConnection connImpl = null;
474: DirContext ctx = null;
475:
476: try {
477: connImpl = realm.getConnection();
478: ctx = (DirContext) connImpl.getConnection();
479:
480: ctx.unbind(dn);
481:
482: } catch (NameNotFoundException e) {
483: throw new OperationFailedException("Tribe '" + name
484: + "' not found!");
485:
486: } catch (Exception e) {
487: throw new OperationFailedException(e.getMessage());
488:
489: } finally {
490: LDAPRealm.cleanupContext(connImpl);
491: }
492: }
493:
494: String getDN() {
495: return dn;
496: }
497:
498: String getFullDN() {
499: return fullDN;
500: }
501:
502: void refreshCitizens() {
503: citizens = null;
504: }
505:
506: void refreshPermissions() {
507: hasPermissions = false;
508: parents = null;
509:
510: if (citizens != null) {
511: for (int i = 0, l = citizens.length; i < l; i++) {
512: ((LDAPCitizen) citizens[i]).refreshPermissions();
513: }
514: }
515:
516: if (children != null) {
517: for (int i = 0, l = children.length; i < l; i++) {
518: ((LDAPTribe) children[i]).refreshPermissions();
519: }
520: }
521: }
522:
523: public boolean equals(Object o) {
524: if (o instanceof LDAPTribe) {
525: LDAPTribe c = (LDAPTribe) o;
526: return (c.name.equals(name) && c.realm.equals(realm));
527: }
528: return false;
529: }
530:
531: public String toString() {
532: return "LDAPTribe (" + name + ")";
533: }
534: }
|