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<>(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 @Override 053 public boolean addMember(Principal user) { 054 if (groupMembers.contains(user)) { 055 return false; 056 } 057 058 // do not allow groups to be added to itself. 059 if (group.equals(user.toString())) { 060 throw new IllegalArgumentException(); 061 } 062 063 groupMembers.addElement(user); 064 return true; 065 } 066 067 /** 068 * Removes the specified member from the group. 069 * 070 * @param user The principal to remove from the group. 071 * @return true if the principal was removed false if the principal was not a member 072 */ 073 @Override 074 public boolean removeMember(Principal user) { 075 return groupMembers.removeElement(user); 076 } 077 078 /** 079 * returns the enumeration of the members in the group. 080 */ 081 @Override 082 public Enumeration<? extends Principal> members() { 083 return groupMembers.elements(); 084 } 085 086 /** 087 * This function returns true if the group passed matches the group represented in this interface. 088 * 089 * @param obj the group to compare this group to. 090 */ 091 @Override 092 public boolean equals(Object obj) { 093 if (this == obj) { 094 return true; 095 } 096 if (!(obj instanceof Group)) { 097 return false; 098 } 099 Group other = (Group) obj; 100 return group.equals(other.toString()); 101 } 102 103 // equals(Group) for compatibility 104 public boolean equals(Group other) { 105 return equals((Object) other); 106 } 107 108 /** 109 * Prints a stringified version of the group. 110 */ 111 @Override 112 public String toString() { 113 return group; 114 } 115 116 /** 117 * return a hashcode for the principal. 118 */ 119 @Override 120 public int hashCode() { 121 return group.hashCode(); 122 } 123 124 /** 125 * returns true if the passed principal is a member of the group. 126 * 127 * @param member The principal whose membership must be checked for. 128 * @return true if the principal is a member of this group, false otherwise 129 */ 130 @Override 131 public boolean isMember(Principal member) { 132 133 // 134 // if the member is part of the group (common case), return true. 135 // if not, recursively search depth first in the group looking for the 136 // principal. 137 // 138 if (groupMembers.contains(member)) { 139 return true; 140 } else { 141 Vector<Group> alreadySeen = new Vector<>(10); 142 return isMemberRecurse(member, alreadySeen); 143 } 144 } 145 146 /** 147 * return the name of the principal. 148 */ 149 @Override 150 public String getName() { 151 return group; 152 } 153 154 // 155 // This function is the recursive search of groups for this 156 // implementation of the Group. The search proceeds building up 157 // a vector of already seen groups. Only new groups are considered, 158 // thereby avoiding loops. 159 // 160 boolean isMemberRecurse(Principal member, Vector<Group> alreadySeen) { 161 Enumeration<? extends Principal> e = members(); 162 while (e.hasMoreElements()) { 163 boolean mem = false; 164 Principal p = e.nextElement(); 165 166 // if the member is in this collection, return true 167 if (p.equals(member)) { 168 return true; 169 } else if (p instanceof GroupImpl) { 170 // 171 // if not recurse if the group has not been checked already. 172 // Can call method in this package only if the object is an 173 // instance of this class. Otherwise call the method defined 174 // in the interface. (This can lead to a loop if a mixture of 175 // implementations form a loop, but we live with this improbable 176 // case rather than clutter the interface by forcing the 177 // implementation of this method.) 178 // 179 GroupImpl g = (GroupImpl) p; 180 alreadySeen.addElement(this); 181 if (!alreadySeen.contains(g)) { 182 mem = g.isMemberRecurse(member, alreadySeen); 183 } 184 } else if (p instanceof Group) { 185 Group g = (Group) p; 186 if (!alreadySeen.contains(g)) { 187 mem = g.isMember(member); 188 } 189 } 190 191 if (mem) { 192 return mem; 193 } 194 } 195 return false; 196 } 197}