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