001: /*
002: * The contents of this file are subject to the Sapient Public License
003: * Version 1.0 (the "License"); you may not use this file except in compliance
004: * with the License. You may obtain a copy of the License at
005: * http://carbon.sf.net/License.html.
006: *
007: * Software distributed under the License is distributed on an "AS IS" basis,
008: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
009: * the specific language governing rights and limitations under the License.
010: *
011: * The Original Code is The Carbon Component Framework.
012: *
013: * The Initial Developer of the Original Code is Sapient Corporation
014: *
015: * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
016: */
017: package org.sape.carbon.services.security.management.jndi;
018:
019: import java.security.Principal;
020: import java.security.acl.Group;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.Map;
024: import java.util.Set;
025:
026: import javax.naming.Context;
027: import javax.naming.NameAlreadyBoundException;
028: import javax.naming.NameNotFoundException;
029: import javax.naming.NamingEnumeration;
030: import javax.naming.NamingException;
031: import javax.naming.directory.Attribute;
032: import javax.naming.directory.Attributes;
033: import javax.naming.directory.BasicAttribute;
034: import javax.naming.directory.BasicAttributes;
035: import javax.naming.directory.DirContext;
036: import javax.naming.directory.SearchResult;
037:
038: import org.sape.carbon.core.component.Component;
039: import org.sape.carbon.core.component.ComponentConfiguration;
040: import org.sape.carbon.core.component.lifecycle.Configurable;
041: import org.sape.carbon.core.component.lifecycle.Initializable;
042: import org.sape.carbon.core.config.InvalidConfigurationException;
043: import org.sape.carbon.services.security.management.DefaultGroupImpl;
044: import org.sape.carbon.services.security.management.DefaultUserImpl;
045: import org.sape.carbon.services.security.management.DuplicateGroupException;
046: import org.sape.carbon.services.security.management.DuplicatePrincipalException;
047: import org.sape.carbon.services.security.management.RuntimeSecurityManagementException;
048: import org.sape.carbon.services.security.management.UnknownGroupException;
049: import org.sape.carbon.services.security.management.UnknownPrincipalException;
050: import org.sape.carbon.services.security.management.UserManager;
051:
052: /**
053: * <p></p>
054: *
055: * Copyright 2003 Sapient
056: * @since carbon 2.1
057: * @author Douglas Voet, Jun 12, 2003
058: * @version $Revision: 1.2 $($Author: dvoet $ / $Date: 2003/11/03 19:48:31 $)
059: */
060: public class JNDIUserManagerImpl implements UserManager, Initializable,
061: Configurable {
062:
063: protected String serviceName;
064: protected JNDIUserManagerConfiguration config;
065:
066: /* (non-Javadoc)
067: * @see org.sape.carbon.services.security.management.UserManager#createUser(java.lang.String, java.lang.Object)
068: */
069: public Principal createUser(String userName, Map userInfo)
070: throws DuplicatePrincipalException {
071:
072: Principal newPrincipal = new DefaultUserImpl(userName);
073:
074: try {
075: Attributes userAttributes = new BasicAttributes();
076:
077: userAttributes.put(new BasicAttribute(this .config
078: .getUserNameAttribute(), userName));
079:
080: Iterator userInfoIterator = userInfo.entrySet().iterator();
081: while (userInfoIterator.hasNext()) {
082: Map.Entry attribute = (Map.Entry) userInfoIterator
083: .next();
084:
085: userAttributes.put(new BasicAttribute(attribute
086: .getKey().toString(), attribute.getValue()));
087: }
088:
089: getUserParentContext().createSubcontext(
090: getUserContextName(userName), userAttributes);
091:
092: } catch (NameAlreadyBoundException nabe) {
093: throw new DuplicatePrincipalException(this .getClass(),
094: newPrincipal, nabe);
095:
096: } catch (NamingException ne) {
097: throw new RuntimeSecurityManagementException(
098: this .getClass(),
099: "Caught NamingException adding Principal to directory",
100: ne);
101: }
102:
103: return newPrincipal;
104: }
105:
106: /* (non-Javadoc)
107: * @see org.sape.carbon.services.security.management.UserManager#authenticate(java.lang.String, java.lang.Object)
108: */
109: public boolean authenticate(String userName, Object credential) {
110: try {
111: Attributes userAttributes = new BasicAttributes();
112: userAttributes.put(this .config.getUserNameAttribute(),
113: userName);
114: userAttributes.put(this .config.getCredentialAttribute(),
115: credential);
116:
117: // if the query returns results, the user exists with the
118: // specified credentials and is authentic,
119: // otherwise, the user is either unknown or the credentials are
120: // invalid
121: return getUserParentContext().search("", userAttributes)
122: .hasMore();
123:
124: } catch (NamingException ne) {
125: throw new RuntimeSecurityManagementException(this
126: .getClass(),
127: "Caught NamingException authenticating user", ne);
128: }
129: }
130:
131: /* (non-Javadoc)
132: * @see org.sape.carbon.services.security.management.UserManager#removeUser(java.security.Principal)
133: */
134: public void removeUser(Principal user)
135: throws UnknownPrincipalException {
136: try {
137: // remove user
138: getUserParentContext().unbind(
139: getUserContextName(user.getName()));
140:
141: // remove user from groups
142: removeUserFromGroups(user);
143:
144: } catch (NameNotFoundException nfe) {
145: throw new UnknownPrincipalException(this .getClass(), user,
146: nfe);
147: } catch (NamingException ne) {
148: throw new RuntimeSecurityManagementException(this
149: .getClass(),
150: "Caught NamingException removing Principal", ne);
151: }
152: }
153:
154: protected void removeUserFromGroups(Principal user)
155: throws NamingException {
156: Attributes searchCriteria = new BasicAttributes(this .config
157: .getUserNameAttribute(), user.getName());
158:
159: NamingEnumeration groups = getGroupParentContext().search("",
160: searchCriteria);
161:
162: while (groups.hasMore()) {
163: SearchResult group = (SearchResult) groups.next();
164:
165: Attribute members = group.getAttributes().get(
166: this .config.getMembersAttribute());
167:
168: members.remove(user.getName());
169:
170: this .getGroupParentContext().modifyAttributes(
171: group.getName(), DirContext.REPLACE_ATTRIBUTE,
172: group.getAttributes());
173: }
174: }
175:
176: /* (non-Javadoc)
177: * @see org.sape.carbon.services.security.management.UserManager#updateCredential(java.security.Principal, java.lang.Object)
178: */
179: public void updateCredential(Principal user, Object credential)
180: throws UnknownPrincipalException {
181:
182: try {
183: Attributes newCredential = new BasicAttributes(this .config
184: .getCredentialAttribute(), credential);
185:
186: getUserParentContext().modifyAttributes(
187: getUserContextName(user.getName()),
188: DirContext.REPLACE_ATTRIBUTE, newCredential);
189:
190: } catch (NameNotFoundException nfe) {
191: throw new UnknownPrincipalException(this .getClass(), user,
192: nfe);
193:
194: } catch (NamingException ne) {
195: throw new RuntimeSecurityManagementException(this
196: .getClass(),
197: "Caught NamingException updating credentials", ne);
198: }
199: }
200:
201: /* (non-Javadoc)
202: * @see org.sape.carbon.services.security.management.UserManager#createGroup(java.lang.String)
203: */
204: public Group createGroup(String groupName)
205: throws DuplicateGroupException {
206:
207: Group newGroup = constructGroup(groupName);
208:
209: try {
210: Attributes groupAttributes = new BasicAttributes(
211: this .config.getGroupNameAttribute(), groupName);
212:
213: getGroupParentContext().createSubcontext(
214: getGroupContextName(groupName), groupAttributes);
215:
216: } catch (NameAlreadyBoundException nabe) {
217: throw new DuplicateGroupException(this .getClass(),
218: newGroup, nabe);
219:
220: } catch (NamingException ne) {
221: throw new RuntimeSecurityManagementException(this
222: .getClass(),
223: "Caught NamingException adding Group to directory",
224: ne);
225: }
226:
227: return newGroup;
228: }
229:
230: /* (non-Javadoc)
231: * @see org.sape.carbon.services.security.management.UserManager#removeGroup(java.security.acl.Group)
232: */
233: public void removeGroup(Group group) throws UnknownGroupException {
234: try {
235: getGroupParentContext().unbind(
236: getGroupContextName(group.getName()));
237:
238: } catch (NameNotFoundException nfe) {
239: throw new UnknownGroupException(this .getClass(), group
240: .getName(), nfe);
241: } catch (NamingException ne) {
242: throw new RuntimeSecurityManagementException(this
243: .getClass(),
244: "Caught NamingException removing Group, group name ["
245: + group.getName() + "]", ne);
246: }
247: }
248:
249: /* (non-Javadoc)
250: * @see org.sape.carbon.services.security.management.UserManager#retreiveUser(java.lang.String)
251: */
252: public Principal retreiveUser(String userName) {
253: try {
254: getUserParentContext().lookup(getUserContextName(userName));
255: // did not get an exception, so userName exists
256: // construct a new user Principal and return it
257: return constructUser(userName);
258: } catch (NameNotFoundException nfe) {
259: // null is the valid response if userName not found
260: return null;
261: } catch (NamingException ne) {
262: throw new RuntimeSecurityManagementException(this
263: .getClass(),
264: "Caught NamingException looking up user context, userName ["
265: + userName + "]", ne);
266: }
267: }
268:
269: /* (non-Javadoc)
270: * @see org.sape.carbon.services.security.management.UserManager#retreiveGroup(java.lang.String)
271: */
272: public Group retreiveGroup(String groupName) {
273: try {
274: getGroupParentContext().lookup(
275: getGroupContextName(groupName));
276: // did not get an exception, so groupName exists
277: // construct a new group Principal and return it
278: return constructGroup(groupName);
279: } catch (NameNotFoundException nfe) {
280: // null is the valid response if userName not found
281: return null;
282: } catch (NamingException ne) {
283: throw new RuntimeSecurityManagementException(this
284: .getClass(),
285: "Caught NamingException looking up group context, groupName ["
286: + groupName + "]", ne);
287: }
288: }
289:
290: /* (non-Javadoc)
291: * @see org.sape.carbon.services.security.management.UserManager#retreiveGroups(java.security.Principal)
292: */
293: public Set retreiveGroups(Principal principal)
294: throws UnknownPrincipalException {
295:
296: try {
297: Set groups = new HashSet();
298:
299: Attributes searchCriteria = new BasicAttributes(this .config
300: .getMembersAttribute(), principal.getName());
301:
302: NamingEnumeration groupResults = getGroupParentContext()
303: .search("", searchCriteria);
304:
305: while (groupResults.hasMore()) {
306: SearchResult group = (SearchResult) groupResults.next();
307: String groupName = group.getAttributes().get(
308: this .config.getGroupNameAttribute()).get()
309: .toString();
310: groups.add(constructGroup(groupName));
311: }
312:
313: return groups;
314:
315: } catch (NamingException ne) {
316: throw new RuntimeSecurityManagementException(this
317: .getClass(),
318: "Caught NamingException looking up groups for principal ["
319: + principal.getName() + "]", ne);
320: }
321: }
322:
323: /* (non-Javadoc)
324: * @see org.sape.carbon.services.security.management.UserManager#addPrincipalToGroup(java.security.Principal, java.security.acl.Group)
325: */
326: public boolean addPrincipalToGroup(Principal principal, Group group)
327: throws UnknownPrincipalException, UnknownGroupException {
328:
329: try {
330: Context principalContext = lookupPrincipalContext(principal);
331:
332: Attributes groupAttributes = getGroupParentContext()
333: .getAttributes(
334: getGroupContextName(group.getName()),
335: new String[] { this .config
336: .getGroupNameAttribute() });
337:
338: Attribute members = groupAttributes.get(this .config
339: .getGroupNameAttribute());
340:
341: // TODO DV does this affect groupAttributes?
342: boolean memberAdded = members.add(principalContext
343: .getNameInNamespace());
344:
345: if (memberAdded) {
346: getGroupParentContext().modifyAttributes(
347: getGroupContextName(group.getName()),
348: DirContext.REPLACE_ATTRIBUTE, groupAttributes);
349: }
350:
351: return memberAdded;
352:
353: } catch (NameNotFoundException nfe) {
354: throw new UnknownGroupException(this .getClass(), group
355: .getName(), nfe);
356: } catch (NamingException ne) {
357: throw new RuntimeSecurityManagementException(this
358: .getClass(),
359: "Caught NamingException adding Principal to group",
360: ne);
361: }
362: }
363:
364: /* (non-Javadoc)
365: * @see org.sape.carbon.services.security.management.UserManager#removePrincipalFromGroup(java.security.Principal, java.security.acl.Group)
366: */
367: public boolean removePrincipalFromGroup(Principal principal,
368: Group group) throws UnknownPrincipalException,
369: UnknownGroupException {
370:
371: try {
372: Context principalContext = lookupPrincipalContext(principal);
373:
374: Attributes groupAttributes = getGroupParentContext()
375: .getAttributes(
376: getGroupContextName(group.getName()),
377: new String[] { this .config
378: .getGroupNameAttribute() });
379:
380: Attribute members = groupAttributes.get(this .config
381: .getGroupNameAttribute());
382:
383: // TODO DV does this affect groupAttributes?
384: boolean memberRemoved = members.remove(principalContext
385: .getNameInNamespace());
386:
387: if (memberRemoved) {
388: getGroupParentContext().modifyAttributes(
389: getGroupContextName(group.getName()),
390: DirContext.REPLACE_ATTRIBUTE, groupAttributes);
391: }
392:
393: return memberRemoved;
394:
395: } catch (NameNotFoundException nfe) {
396: throw new UnknownGroupException(this .getClass(), group
397: .getName(), nfe);
398: } catch (NamingException ne) {
399: throw new RuntimeSecurityManagementException(this
400: .getClass(),
401: "Caught NamingException adding Principal to group",
402: ne);
403: }
404: }
405:
406: private Context lookupPrincipalContext(Principal principal)
407: throws UnknownPrincipalException, NamingException {
408:
409: Context principalContext;
410: // ensure that principal exists
411: try {
412: // is principal a user?
413: principalContext = (Context) getUserParentContext().lookup(
414: getUserContextName(principal.getName()));
415: } catch (NameNotFoundException nfe) {
416: try {
417: // principal is not a user, is it a group?
418: principalContext = (Context) getGroupParentContext()
419: .lookup(
420: getGroupContextName(principal.getName()));
421: } catch (NameNotFoundException nfe2) {
422: // principal was not found as a user or group
423: throw new UnknownPrincipalException(this .getClass(),
424: principal, nfe2);
425: }
426: }
427:
428: return principalContext;
429: }
430:
431: /* (non-Javadoc)
432: * @see org.sape.carbon.services.security.management.UserManager#retreiveAllUserNames()
433: */
434: public Set retreiveAllUserNames() {
435: try {
436: NamingEnumeration allUserContexts = getUserParentContext()
437: .search("", null);
438:
439: Set allUserNames = new HashSet();
440: while (allUserContexts.hasMore()) {
441: SearchResult user = (SearchResult) allUserContexts
442: .next();
443:
444: allUserNames.add(user.getAttributes().get(
445: this .config.getUserNameAttribute()).get());
446: }
447:
448: return allUserNames;
449: } catch (NamingException ne) {
450: throw new RuntimeSecurityManagementException(this
451: .getClass(),
452: "Caught NamingException retrieving all user names",
453: ne);
454: }
455: }
456:
457: /* (non-Javadoc)
458: * @see org.sape.carbon.services.security.management.UserManager#retreiveAllGroupNames()
459: */
460: public Set retreiveAllGroupNames() {
461: try {
462: NamingEnumeration allGroupContexts = getGroupParentContext()
463: .search("", null);
464:
465: Set allGroupNames = new HashSet();
466: while (allGroupContexts.hasMore()) {
467: SearchResult group = (SearchResult) allGroupContexts
468: .next();
469:
470: allGroupNames.add(group.getAttributes().get(
471: this .config.getGroupNameAttribute()).get());
472: }
473:
474: return allGroupNames;
475: } catch (NamingException ne) {
476: throw new RuntimeSecurityManagementException(
477: this .getClass(),
478: "Caught NamingException retrieving all group names",
479: ne);
480: }
481: }
482:
483: /* (non-Javadoc)
484: * @see org.sape.carbon.core.component.lifecycle.Configurable#configure(org.sape.carbon.core.component.ComponentConfiguration)
485: */
486: public void configure(ComponentConfiguration configuration)
487: throws Exception {
488:
489: // TODO validate config
490: try {
491: this .config = (JNDIUserManagerConfiguration) configuration;
492: } catch (ClassCastException cce) {
493: throw new InvalidConfigurationException(this .getClass(),
494: configuration.getConfigurationName(),
495: "ConfigurationInterface",
496: "Configuration object was not of type "
497: + JNDIUserManagerConfiguration.class
498: .getName(), cce);
499: }
500: }
501:
502: /**
503: * @return
504: */
505: protected DirContext getInitialContext() throws NamingException {
506: return (DirContext) this .config.getInitialContextFactory()
507: .getContext();
508: }
509:
510: protected DirContext getUserParentContext() throws NamingException {
511: return (DirContext) getInitialContext().lookup(
512: this .config.getUserParentContextName());
513: }
514:
515: protected DirContext getGroupParentContext() throws NamingException {
516: return (DirContext) getInitialContext().lookup(
517: this .config.getGroupParentContextName());
518: }
519:
520: protected String getUserContextName(String userName)
521: throws NamingException {
522: return this .config.getUserNameAttribute()
523: + this .config.getAttributeNameValueSeparator()
524: + userName;
525: }
526:
527: protected String getGroupContextName(String groupName)
528: throws NamingException {
529: return this .config.getGroupNameAttribute()
530: + this .config.getAttributeNameValueSeparator()
531: + groupName;
532: }
533:
534: protected Principal constructUser(String userName) {
535: return new DefaultUserImpl(userName);
536: }
537:
538: protected Group constructGroup(String groupName) {
539: return new DefaultGroupImpl(groupName, null, this .serviceName);
540: }
541:
542: public void initialize(Component thisComponent) throws Exception {
543: this.serviceName = thisComponent.getComponentName();
544: }
545:
546: }
|