001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.security;
023:
024: import java.security.Principal;
025: import java.security.acl.Group;
026: import java.util.Enumeration;
027: import java.util.LinkedList;
028:
029: /** An implementation of Group that allows that acts as a stack of Groups
030: with a single Group member active at any time.
031: When one adds a Group to a NestableGroup the Group is pushed onto
032: the active Group stack and any of the Group methods operate as though the
033: NestableGroup contains only the Group. When removing the Group that
034: corresponds to the active Group, the active Group is popped from the stack and
035: the new active Group is set to the new top of the stack.
036:
037: The typical usage of this class is when doing a JAAS LoginContext login
038: to runAs a new Principal with a new set of roles that should be added
039: without destroying the current identity and roles.
040:
041: @author Scott.Stark@jboss.org
042: @version $Revision: 57203 $
043: */
044: public class NestableGroup extends SimplePrincipal implements Group,
045: Cloneable {
046: /** The serialVersionUID */
047: private static final long serialVersionUID = -1516580228749739423L;
048:
049: /** The stack of the Groups. Elements are pushed/poped by
050: inserting/removing element 0.
051: */
052: private LinkedList rolesStack;
053:
054: /** Creates new NestableGroup with the given name
055: */
056: public NestableGroup(String name) {
057: super (name);
058: rolesStack = new LinkedList();
059: }
060:
061: // --- Begin Group interface methods
062: /** Returns an enumeration that contains the single active Principal.
063: @return an Enumeration of the single active Principal.
064: */
065: public Enumeration members() {
066: return new IndexEnumeration();
067: }
068:
069: /** Removes the first occurence of user from the Principal stack.
070:
071: @param user the principal to remove from this group.
072: @return true if the principal was removed, or
073: * false if the principal was not a member.
074: */
075: public boolean removeMember(Principal user) {
076: return rolesStack.remove(user);
077: }
078:
079: /** Pushes the group onto the Group stack and makes it the active
080: Group.
081: @param group the instance of Group that contains the roles to set as the
082: active Group.
083: @exception IllegalArgumentException thrown if group is not an instance of Group.
084: @return true always.
085: */
086: public boolean addMember(Principal group)
087: throws IllegalArgumentException {
088: if ((group instanceof Group) == false)
089: throw new IllegalArgumentException(
090: "The addMember argument must be a Group");
091:
092: rolesStack.addFirst(group);
093: return true;
094: }
095:
096: /** Returns true if the passed principal is a member of the active group.
097: This method does a recursive search, so if a principal belongs to a
098: group which is a member of this group, true is returned.
099:
100: @param member the principal whose membership is to be checked.
101:
102: @return true if the principal is a member of this group, false otherwise.
103: */
104: public boolean isMember(Principal member) {
105: if (rolesStack.size() == 0)
106: return false;
107: Group activeGroup = (Group) rolesStack.getFirst();
108: boolean isMember = activeGroup.isMember(member);
109: return isMember;
110: }
111:
112: public String toString() {
113: StringBuffer tmp = new StringBuffer(getName());
114: tmp.append("(members:");
115: Enumeration iter = members();
116: while (iter.hasMoreElements()) {
117: tmp.append(iter.nextElement());
118: tmp.append(',');
119: }
120: tmp.setCharAt(tmp.length() - 1, ')');
121: return tmp.toString();
122: }
123:
124: public synchronized Object clone()
125: throws CloneNotSupportedException {
126: NestableGroup clone = (NestableGroup) super .clone();
127: if (clone != null)
128: clone.rolesStack = (LinkedList) this .rolesStack.clone();
129: return clone;
130: }
131:
132: // --- End Group interface methods
133:
134: private class IndexEnumeration implements Enumeration {
135: private Enumeration iter;
136:
137: IndexEnumeration() {
138: if (rolesStack.size() > 0) {
139: Group grp = (Group) rolesStack.get(0);
140: iter = grp.members();
141: }
142: }
143:
144: public boolean hasMoreElements() {
145: boolean hasMore = iter != null && iter.hasMoreElements();
146: return hasMore;
147: }
148:
149: public Object nextElement() {
150: Object next = null;
151: if (iter != null)
152: next = iter.nextElement();
153: return next;
154: }
155: }
156: }
|