/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the License). You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * https://opensso.dev.java.net/public/CDDLv1.0.html or * opensso/legal/CDDLv1.0.txt * See the License for the specific language governing * permission and limitations under the License. * * When distributing Covered Code, include this CDDL * Header Notice in each file and include the License file * at opensso/legal/CDDLv1.0.txt. * If applicable, add the following below the CDDL Header, * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * $Id: StaticGroup.java,v 1.4 2009/01/28 05:34:51 ww203982 Exp $ * * Portions Copyright 2015 ForgeRock AS. */ package com.iplanet.ums; import java.security.Principal; import java.util.Collections; import java.util.Iterator; import com.iplanet.services.ldap.Attr; import com.iplanet.services.ldap.AttrSet; import com.iplanet.services.util.I18n; import org.forgerock.opendj.ldap.Attribute; import org.forgerock.opendj.ldap.Attributes; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.DN; import org.forgerock.opendj.ldap.Modification; import org.forgerock.opendj.ldap.ModificationType; /** * Represents a static group entry. * @supported.api */ public class StaticGroup extends PersistentObject implements IAssignableMembership { /** * Level indicator for no nesting of group membership. Use this level * indicator for getting direct membership in a group. * * @supported.api */ public static final int LEVEL_DIRECT = 0; /** * Level indicator for expanding nested membership to the fullest. Use this * level indicator in getting all direct and indirect members through nested * group behavior. * * @supported.api */ public static final int LEVEL_ALL = -1; /** * Internal maximum level used if no default is found in configuration. */ static final int DEFAULT_MAX = 5; private static I18n i18n = I18n.getInstance(IUMSConstants.UMS_PKG); /** * Default constructor */ protected StaticGroup() { } /** * Constructs a group object from an ID by reading from persistent storage. * * @param session * Authenticated session * @param guid * Globally unique identifier for the group entry * @exception UMSException * on failure to instantiate from persistent storage * @deprecated */ StaticGroup(Principal principal, Guid guid) throws UMSException { super(principal, guid); verifyClass(); } /** * Constructs a group object in memory using the default registered template * for StaticGroup. This is an in-memory representation of a new StaticGroup * object; the save method must be called to save the new object to * persistent storage. * * @param attrSet * Attribute/value set * @exception UMSException * on failure to instantiate from persistent storage */ StaticGroup(AttrSet attrSet) throws UMSException { this(TemplateManager.getTemplateManager().getCreationTemplate(_class, null), attrSet); } /** * Constructs a StaticGroup object in memory with * a given template. This one simply creates a Group object in memory; the * save method must be called to save the new object to persistent storage. * * @param template * Template for creating a group * @param attrSet * Attribute/value set * @exception UMSException * on failure to instantiate from persistent storage * @supported.api */ public StaticGroup(CreationTemplate template, AttrSet attrSet) throws UMSException { super(template, attrSet); } /** * Adds a member to the group. The change is saved to * persistent storage. * * @param guid * Globally unique identifier for the member to be added * @exception UMSException * on failure to save to persistent storage * @supported.api */ public void addMember(Guid guid) throws UMSException { String id = guid.getDn(); PersistentObject entry = null; try { entry = UMSObject.getObject(getPrincipal(), guid); } catch (UMSException ignore) { } if (entry != null && entry instanceof StaticGroup) { StaticGroup g = (StaticGroup) entry; if (id.equalsIgnoreCase(getDN()) || g.hasMember(getGuid(), LEVEL_ALL)) { throw new UMSException(i18n .getString(IUMSConstants.NO_RECURSION_ALLOW)); } } modify(new Attr(MEMBER_ATTR_NAME, id), ModificationType.ADD); save(); } /** * Adds a member to the group. The change is saved to * persistent storage. * * @param member * Object to be added as member * @exception UMSException * on failure to save to persistent storage * @supported.api */ public void addMember(PersistentObject member) throws UMSException { addMember(member.getGuid()); } /** * Adds a list of members to the group. The change is * saved to persistent storage. * * @param guids * Array of member guids to be added as members to the group * @exception UMSException * on failure to save to persistent storage * @supported.api */ public void addMembers(Guid[] guids) throws UMSException { if (guids == null) { String msg = i18n.getString(IUMSConstants.BAD_GUID); throw new IllegalArgumentException(msg); } for (int i = 0; i < guids.length; i++) { addMember(guids[i]); } } /** * Gets the members of the group. * * @return SearchResults for members of the group * @exception Not * thrown by this class * @supported.api */ public SearchResults getMemberIDs() throws UMSException { return getMembers(LEVEL_DIRECT); } static int getMaxNestingLevel() { // PKB: Get it from the dsConfig manager // TO FIX return DEFAULT_MAX; } /** * Get members of the group. * * @param level * Nesting level * @return SearchResults for members of the group * @exception Not * thrown by this class * @supported.api * */ public SearchResults getMembers(int level) throws UMSException { Attr attr = getAttribute(MEMBER_ATTR_NAME); if (attr == null) { return null; } if (level == LEVEL_ALL) { level = getMaxNestingLevel(); } if (level == LEVEL_DIRECT) { return new SearchResults(getAttribute(MEMBER_ATTR_NAME)); } Attr nestedMembers = new Attr(MEMBER_ATTR_NAME); Attribute la = attr.toLDAPAttribute(); Iterator iterator = la.iterator(); while (iterator.hasNext()) { String memberdn = iterator.next().toString(); PersistentObject entry = null; try { // entry = getUMSSession().getObject(new Guid(memberdn)); entry = UMSObject.getObject(getPrincipal(), new Guid(memberdn)); } catch (UMSException ignore) { } if (entry != null && entry instanceof StaticGroup) { SearchResults r = ((StaticGroup) entry).getMembers(level - 1); while (r.hasMoreElements()) { PersistentObject member = null; try { member = r.next(); nestedMembers.addValue(member.getDN()); } catch (UMSException ignore) { } } } else { nestedMembers.addValue(memberdn); } entry = null; } return new SearchResults(nestedMembers); } /** * Gets the member count. * * @return Number of members of the group * @exception Not * thrown by this class * @supported.api */ public int getMemberCount() throws UMSException { return getMemberCount(LEVEL_DIRECT); } /** * Gets the member count. * * @param level * Nesting level * @return Number of members of the group * @exception Not * thrown by this class * @supported.api */ public int getMemberCount(int level) throws UMSException { if (level == LEVEL_ALL) { level = getMaxNestingLevel(); } if (level == LEVEL_DIRECT) { Attr attr = getAttribute(MEMBER_ATTR_NAME); return (attr != null) ? attr.size() : 0; } SearchResults allMembers = getMembers(level); if (allMembers == null) return 0; int count = 0; while (allMembers.hasMoreElements()) { allMembers.next(); count++; } return count; } /** * Gets a member given an index (zero-based). * * @param index * Zero-based index into the group container * @return The unique identifier for a member * @exception Not * thrown by this class * @supported.api */ public Guid getMemberIDAt(int index) throws UMSException { Attr attr = getAttribute(MEMBER_ATTR_NAME); String value = attr.getStringValues()[index]; return (value != null) ? new Guid(value) : null; } /** * Gets a member given an index (zero-based). * * @param index * Zero-based index into the group container * @param level * Nesting level * @return The unique identifier for a member * @exception Not * thrown by this class * @supported.api */ public Guid getMemberIDAt(int index, int level) throws UMSException { SearchResults allMembers = getMembers(level); if (allMembers == null) { return null; } int i = 0; while (allMembers.hasMoreElements()) { PersistentObject entry = allMembers.next(); if (i++ == index) { return new Guid(entry.getDN()); } } return null; } /** * Removes a member from the group. The change is saved to persistent * storage. * * @param guid * Unique identifier for the member to be removed * @exception UMSException * on failure to save to persistent storage * @supported.api */ public void removeMember(Guid guid) throws UMSException { String dn = guid.getDn(); super.modify(new Attr(MEMBER_ATTR_NAME, dn), ModificationType.DELETE); save(); } /** * Removes a member from the group. The change is saved to persistent * storage. * * @param member * Object to be removed * @exception UMSException * on failure to save to persistent storage * @supported.api */ public void removeMember(PersistentObject member) throws UMSException { removeMember(member.getGuid()); } /** * Removes all members of the group. * * @exception UMSException * on failure to save to persistent storage * @supported.api */ public void removeAllMembers() throws UMSException { if (getMemberCount() == 0) { return; } // TODO: this should probably be REPLACE instead of DELETE, so it works even if there are no members modify(Collections.singleton( new Modification(ModificationType.DELETE, Attributes.emptyAttribute(MEMBER_ATTR_NAME)))); save(); } /** * Checks if a given identifier is a member of the group. * * @param guid * Identity of member to be checked for membership * @return true if it is a member * @exception Not thrown by this class * @supported.api */ public boolean hasMember(Guid guid) throws UMSException { return isMemberAtLevel(guid.getDn(), LEVEL_DIRECT); } private boolean isMemberAtLevel(String normalizedID, int level) throws UMSException { if (level == LEVEL_ALL) { level = getMaxNestingLevel(); } SearchResults members = getMembers(level); while (members.hasMoreElements()) { PersistentObject entry = members.next(); String entryDN = entry.getDN(); if (Guid.equals(normalizedID, entryDN)) { return true; } } return false; } /** * Checks if a given identifier is a member of the group. * * @param guid * Identity of member to be checked for membership * @param level * Nesting level * @return true if it is a member * @exception Not * thrown by this class * @supported.api */ public boolean hasMember(Guid guid, int level) throws UMSException { if (level == LEVEL_ALL) { level = getMaxNestingLevel(); } String id = guid.getDn(); for (int i = LEVEL_DIRECT; i <= level; i++) { if (isMemberAtLevel(id, i)) { return true; } } return false; } private static final String MEMBER_ATTR_NAME = "uniquemember"; private static final Class _class = new StaticGroup().getClass(); }