001/** 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: StaticGroup.java,v 1.4 2009/01/28 05:34:51 ww203982 Exp $ 026 * 027 */ 028 029package com.iplanet.ums; 030 031import java.security.Principal; 032import java.util.Enumeration; 033 034import com.sun.identity.shared.ldap.LDAPAttribute; 035import com.sun.identity.shared.ldap.LDAPDN; 036 037import com.iplanet.services.ldap.Attr; 038import com.iplanet.services.ldap.AttrSet; 039import com.iplanet.services.ldap.ModSet; 040import com.iplanet.services.util.I18n; 041 042/** 043 * Represents a static group entry. 044 * @supported.api 045 */ 046public class StaticGroup extends PersistentObject implements 047 IAssignableMembership { 048 049 /** 050 * Level indicator for no nesting of group membership. Use this level 051 * indicator for getting direct membership in a group. 052 * 053 * @supported.api 054 */ 055 public static final int LEVEL_DIRECT = 0; 056 057 /** 058 * Level indicator for expanding nested membership to the fullest. Use this 059 * level indicator in getting all direct and indirect members through nested 060 * group behavior. 061 * 062 * @supported.api 063 */ 064 public static final int LEVEL_ALL = -1; 065 066 /** 067 * Internal maximum level used if no default is found in configuration. 068 */ 069 static final int DEFAULT_MAX = 5; 070 071 private static I18n i18n = I18n.getInstance(IUMSConstants.UMS_PKG); 072 073 /** 074 * Default constructor 075 */ 076 protected StaticGroup() { 077 } 078 079 /** 080 * Constructs a group object from an ID by reading from persistent storage. 081 * 082 * @param session 083 * Authenticated session 084 * @param guid 085 * Globally unique identifier for the group entry 086 * @exception UMSException 087 * on failure to instantiate from persistent storage 088 * @deprecated 089 */ 090 StaticGroup(Principal principal, Guid guid) throws UMSException { 091 super(principal, guid); 092 verifyClass(); 093 } 094 095 /** 096 * Constructs a group object in memory using the default registered template 097 * for StaticGroup. This is an in-memory representation of a new StaticGroup 098 * object; the save method must be called to save the new object to 099 * persistent storage. 100 * 101 * @param attrSet 102 * Attribute/value set 103 * @exception UMSException 104 * on failure to instantiate from persistent storage 105 */ 106 StaticGroup(AttrSet attrSet) throws UMSException { 107 this(TemplateManager.getTemplateManager().getCreationTemplate(_class, 108 null), attrSet); 109 } 110 111 /** 112 * Constructs a StaticGroup object in memory with 113 * a given template. This one simply creates a Group object in memory; the 114 * save method must be called to save the new object to persistent storage. 115 * 116 * @param template 117 * Template for creating a group 118 * @param attrSet 119 * Attribute/value set 120 * @exception UMSException 121 * on failure to instantiate from persistent storage 122 * @supported.api 123 */ 124 public StaticGroup(CreationTemplate template, AttrSet attrSet) 125 throws UMSException { 126 super(template, attrSet); 127 } 128 129 /** 130 * Adds a member to the group. The change is saved to 131 * persistent storage. 132 * 133 * @param guid 134 * Globally unique identifier for the member to be added 135 * @exception UMSException 136 * on failure to save to persistent storage 137 * @supported.api 138 */ 139 public void addMember(Guid guid) throws UMSException { 140 141 String id = LDAPDN.normalize(guid.getDn()); 142 143 PersistentObject entry = null; 144 145 try { 146 // entry = getUMSSession().getObject(guid); 147 entry = UMSObject.getObject(getPrincipal(), guid); 148 } catch (UMSException ignore) { 149 } 150 151 if (entry != null && entry instanceof StaticGroup) { 152 StaticGroup g = (StaticGroup) entry; 153 if (id.equalsIgnoreCase(getDN()) 154 || g.hasMember(getGuid(), LEVEL_ALL)) { 155 throw new UMSException(i18n 156 .getString(IUMSConstants.NO_RECURSION_ALLOW)); 157 } 158 } 159 160 modify(new Attr(MEMBER_ATTR_NAME, id), ModSet.ADD); 161 save(); 162 } 163 164 /** 165 * Adds a member to the group. The change is saved to 166 * persistent storage. 167 * 168 * @param member 169 * Object to be added as member 170 * @exception UMSException 171 * on failure to save to persistent storage 172 * @supported.api 173 */ 174 public void addMember(PersistentObject member) throws UMSException { 175 addMember(member.getGuid()); 176 } 177 178 /** 179 * Adds a list of members to the group. The change is 180 * saved to persistent storage. 181 * 182 * @param guids 183 * Array of member guids to be added as members to the group 184 * @exception UMSException 185 * on failure to save to persistent storage 186 * @supported.api 187 */ 188 public void addMembers(Guid[] guids) throws UMSException { 189 if (guids == null) { 190 String msg = i18n.getString(IUMSConstants.BAD_GUID); 191 throw new IllegalArgumentException(msg); 192 } 193 194 for (int i = 0; i < guids.length; i++) { 195 addMember(guids[i]); 196 } 197 } 198 199 /** 200 * Gets the members of the group. 201 * 202 * @return SearchResults for members of the group 203 * @exception Not 204 * thrown by this class 205 * @supported.api 206 */ 207 public SearchResults getMemberIDs() throws UMSException { 208 return getMembers(LEVEL_DIRECT); 209 } 210 211 static int getMaxNestingLevel() { 212 // PKB: Get it from the dsConfig manager 213 // TO FIX 214 return DEFAULT_MAX; 215 } 216 217 /** 218 * Get members of the group. 219 * 220 * @param level 221 * Nesting level 222 * @return SearchResults for members of the group 223 * @exception Not 224 * thrown by this class 225 * @supported.api 226 * 227 */ 228 public SearchResults getMembers(int level) throws UMSException { 229 Attr attr = getAttribute(MEMBER_ATTR_NAME); 230 if (attr == null) { 231 return null; 232 } 233 234 if (level == LEVEL_ALL) { 235 level = getMaxNestingLevel(); 236 } 237 238 if (level == LEVEL_DIRECT) { 239 return new SearchResults(getAttribute(MEMBER_ATTR_NAME)); 240 } 241 242 Attr nestedMembers = new Attr(MEMBER_ATTR_NAME); 243 LDAPAttribute la = attr.toLDAPAttribute(); 244 Enumeration en = la.getStringValues(); 245 246 while (en.hasMoreElements()) { 247 String memberdn = (String) en.nextElement(); 248 PersistentObject entry = null; 249 250 try { 251 // entry = getUMSSession().getObject(new Guid(memberdn)); 252 entry = UMSObject.getObject(getPrincipal(), new Guid(memberdn)); 253 } catch (UMSException ignore) { 254 } 255 256 if (entry != null && entry instanceof StaticGroup) { 257 SearchResults r = ((StaticGroup) entry).getMembers(level - 1); 258 259 while (r.hasMoreElements()) { 260 PersistentObject member = null; 261 262 try { 263 member = r.next(); 264 nestedMembers.addValue(member.getDN()); 265 } catch (UMSException ignore) { 266 } 267 } 268 } else { 269 nestedMembers.addValue(memberdn); 270 } 271 272 entry = null; 273 } 274 275 return new SearchResults(nestedMembers); 276 } 277 278 /** 279 * Gets the member count. 280 * 281 * @return Number of members of the group 282 * @exception Not 283 * thrown by this class 284 * @supported.api 285 */ 286 public int getMemberCount() throws UMSException { 287 return getMemberCount(LEVEL_DIRECT); 288 } 289 290 /** 291 * Gets the member count. 292 * 293 * @param level 294 * Nesting level 295 * @return Number of members of the group 296 * @exception Not 297 * thrown by this class 298 * @supported.api 299 */ 300 public int getMemberCount(int level) throws UMSException { 301 302 if (level == LEVEL_ALL) { 303 level = getMaxNestingLevel(); 304 } 305 306 if (level == LEVEL_DIRECT) { 307 Attr attr = getAttribute(MEMBER_ATTR_NAME); 308 return (attr != null) ? attr.size() : 0; 309 } 310 311 SearchResults allMembers = getMembers(level); 312 313 if (allMembers == null) 314 return 0; 315 int count = 0; 316 while (allMembers.hasMoreElements()) { 317 allMembers.next(); 318 count++; 319 } 320 return count; 321 } 322 323 /** 324 * Gets a member given an index (zero-based). 325 * 326 * @param index 327 * Zero-based index into the group container 328 * @return The unique identifier for a member 329 * @exception Not 330 * thrown by this class 331 * @supported.api 332 */ 333 public Guid getMemberIDAt(int index) throws UMSException { 334 Attr attr = getAttribute(MEMBER_ATTR_NAME); 335 String value = attr.getStringValues()[index]; 336 return (value != null) ? new Guid(value) : null; 337 } 338 339 /** 340 * Gets a member given an index (zero-based). 341 * 342 * @param index 343 * Zero-based index into the group container 344 * @param level 345 * Nesting level 346 * @return The unique identifier for a member 347 * @exception Not 348 * thrown by this class 349 * @supported.api 350 */ 351 public Guid getMemberIDAt(int index, int level) throws UMSException { 352 SearchResults allMembers = getMembers(level); 353 if (allMembers == null) { 354 return null; 355 } 356 357 int i = 0; 358 while (allMembers.hasMoreElements()) { 359 PersistentObject entry = allMembers.next(); 360 if (i++ == index) { 361 return new Guid(entry.getDN()); 362 } 363 } 364 return null; 365 } 366 367 /** 368 * Removes a member from the group. The change is saved to persistent 369 * storage. 370 * 371 * @param guid 372 * Unique identifier for the member to be removed 373 * @exception UMSException 374 * on failure to save to persistent storage 375 * @supported.api 376 */ 377 public void removeMember(Guid guid) throws UMSException { 378 String dn = guid.getDn(); 379 super.modify(new Attr(MEMBER_ATTR_NAME, LDAPDN.normalize(dn)), 380 ModSet.DELETE); 381 save(); 382 } 383 384 /** 385 * Removes a member from the group. The change is saved to persistent 386 * storage. 387 * 388 * @param member 389 * Object to be removed 390 * @exception UMSException 391 * on failure to save to persistent storage 392 * @supported.api 393 */ 394 public void removeMember(PersistentObject member) throws UMSException { 395 removeMember(member.getGuid()); 396 } 397 398 /** 399 * Removes all members of the group. 400 * 401 * @exception UMSException 402 * on failure to save to persistent storage 403 * @supported.api 404 */ 405 public void removeAllMembers() throws UMSException { 406 407 if (getMemberCount() == 0) { 408 return; 409 } 410 411 ModSet modSet = new ModSet(); 412 413 // TODO: this should probably be REPLACE instead of DELETE, so it 414 // works even if there are no members 415 modSet.add(ModSet.DELETE, new LDAPAttribute(MEMBER_ATTR_NAME)); 416 417 modify(modSet); 418 save(); 419 } 420 421 /** 422 * Checks if a given identifier is a member of the group. 423 * 424 * @param guid 425 * Identity of member to be checked for membership 426 * @return <code>true if it is a member 427 * @exception Not thrown by this class 428 * @supported.api 429 */ 430 public boolean hasMember(Guid guid) throws UMSException { 431 return isMemberAtLevel(guid.getDn(), LEVEL_DIRECT); 432 } 433 434 private boolean isMemberAtLevel(String normalizedID, int level) 435 throws UMSException { 436 437 if (level == LEVEL_ALL) { 438 level = getMaxNestingLevel(); 439 } 440 441 SearchResults members = getMembers(level); 442 443 while (members.hasMoreElements()) { 444 PersistentObject entry = members.next(); 445 String entryDN = entry.getDN(); 446 if (Guid.equals(normalizedID, entryDN)) { 447 return true; 448 } 449 } 450 451 return false; 452 } 453 454 /** 455 * Checks if a given identifier is a member of the group. 456 * 457 * @param guid 458 * Identity of member to be checked for membership 459 * @param level 460 * Nesting level 461 * @return <code>true</code> if it is a member 462 * @exception Not 463 * thrown by this class 464 * @supported.api 465 */ 466 public boolean hasMember(Guid guid, int level) throws UMSException { 467 468 if (level == LEVEL_ALL) { 469 level = getMaxNestingLevel(); 470 } 471 472 String id = guid.getDn(); 473 474 for (int i = LEVEL_DIRECT; i <= level; i++) { 475 if (isMemberAtLevel(id, i)) { 476 return true; 477 } 478 } 479 return false; 480 } 481 482 private static final String MEMBER_ATTR_NAME = "uniquemember"; 483 484 private static final Class _class = new StaticGroup().getClass(); 485}