001/* 002 * (C) Copyright 2010 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 */ 017 018package org.nuxeo.ecm.platform.login; 019 020import java.security.Principal; 021import java.security.acl.Group; 022import java.util.Enumeration; 023import java.util.Vector; 024 025/** 026 * This class implements a group of principals. 027 * 028 * @author Satish Dharmaraj 029 */ 030public class GroupImpl implements Group { 031 private Vector<Principal> groupMembers = new Vector<Principal>(50, 100); 032 033 private String group; 034 035 /** 036 * Constructs a Group object with no members. 037 * 038 * @param groupName the name of the group 039 */ 040 public GroupImpl(String groupName) { 041 this.group = groupName; 042 } 043 044 /** 045 * adds the specified member to the group. 046 * 047 * @param user The principal to add to the group. 048 * @return true if the member was added - false if the member could not be added. 049 */ 050 public boolean addMember(Principal user) { 051 if (groupMembers.contains(user)) { 052 return false; 053 } 054 055 // do not allow groups to be added to itself. 056 if (group.equals(user.toString())) { 057 throw new IllegalArgumentException(); 058 } 059 060 groupMembers.addElement(user); 061 return true; 062 } 063 064 /** 065 * Removes the specified member from the group. 066 * 067 * @param user The principal to remove from the group. 068 * @return true if the principal was removed false if the principal was not a member 069 */ 070 public boolean removeMember(Principal user) { 071 return groupMembers.removeElement(user); 072 } 073 074 /** 075 * returns the enumeration of the members in the group. 076 */ 077 public Enumeration<? extends Principal> members() { 078 return groupMembers.elements(); 079 } 080 081 /** 082 * This function returns true if the group passed matches the group represented in this interface. 083 * 084 * @param obj the group to compare this group to. 085 */ 086 @Override 087 public boolean equals(Object obj) { 088 if (this == obj) { 089 return true; 090 } 091 if (!(obj instanceof Group)) { 092 return false; 093 } 094 Group other = (Group) obj; 095 return group.equals(other.toString()); 096 } 097 098 // equals(Group) for compatibility 099 public boolean equals(Group other) { 100 return equals((Object) other); 101 } 102 103 /** 104 * Prints a stringified version of the group. 105 */ 106 @Override 107 public String toString() { 108 return group; 109 } 110 111 /** 112 * return a hashcode for the principal. 113 */ 114 @Override 115 public int hashCode() { 116 return group.hashCode(); 117 } 118 119 /** 120 * returns true if the passed principal is a member of the group. 121 * 122 * @param member The principal whose membership must be checked for. 123 * @return true if the principal is a member of this group, false otherwise 124 */ 125 public boolean isMember(Principal member) { 126 127 // 128 // if the member is part of the group (common case), return true. 129 // if not, recursively search depth first in the group looking for the 130 // principal. 131 // 132 if (groupMembers.contains(member)) { 133 return true; 134 } else { 135 Vector<Group> alreadySeen = new Vector<Group>(10); 136 return isMemberRecurse(member, alreadySeen); 137 } 138 } 139 140 /** 141 * return the name of the principal. 142 */ 143 public String getName() { 144 return group; 145 } 146 147 // 148 // This function is the recursive search of groups for this 149 // implementation of the Group. The search proceeds building up 150 // a vector of already seen groups. Only new groups are considered, 151 // thereby avoiding loops. 152 // 153 boolean isMemberRecurse(Principal member, Vector<Group> alreadySeen) { 154 Enumeration<? extends Principal> e = members(); 155 while (e.hasMoreElements()) { 156 boolean mem = false; 157 Principal p = e.nextElement(); 158 159 // if the member is in this collection, return true 160 if (p.equals(member)) { 161 return true; 162 } else if (p instanceof GroupImpl) { 163 // 164 // if not recurse if the group has not been checked already. 165 // Can call method in this package only if the object is an 166 // instance of this class. Otherwise call the method defined 167 // in the interface. (This can lead to a loop if a mixture of 168 // implementations form a loop, but we live with this improbable 169 // case rather than clutter the interface by forcing the 170 // implementation of this method.) 171 // 172 GroupImpl g = (GroupImpl) p; 173 alreadySeen.addElement(this); 174 if (!alreadySeen.contains(g)) { 175 mem = g.isMemberRecurse(member, alreadySeen); 176 } 177 } else if (p instanceof Group) { 178 Group g = (Group) p; 179 if (!alreadySeen.contains(g)) { 180 mem = g.isMember(member); 181 } 182 } 183 184 if (mem) { 185 return mem; 186 } 187 } 188 return false; 189 } 190}