You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by sm...@apache.org on 2014/10/22 17:44:43 UTC

[24/51] [partial] Rename packages from org.openldap.fortress to org.apache.directory.fortress.core. Change default suffix to org.apache. Switch default ldap api from unbound to apache ldap.

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/rbac/Permission.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/rbac/Permission.java b/src/main/java/org/apache/directory/fortress/core/rbac/Permission.java
new file mode 100755
index 0000000..d8ed919
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/rbac/Permission.java
@@ -0,0 +1,750 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.fortress.core.rbac;
+
+
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.directory.fortress.core.rbac.dao.RoleDAO;
+import org.apache.directory.fortress.core.rbac.dao.UserDAO;
+
+/*
+## OC2: Fortress Permission Structural Object Class
+    objectclass	( 1.3.6.1.4.1.38088.2.2
+    NAME 'ftObject'
+    DESC 'Fortress Permission Object Class'
+    SUP organizationalunit
+    STRUCTURAL
+    MUST (
+    ftId $
+    ftObjNm
+    )
+    MAY (
+    ftType
+    )
+    )
+*/
+/**
+ * All entities ({@link org.apache.directory.fortress.core.rbac.User}, {@link org.apache.directory.fortress.core.rbac.Role}, {@link Permission},
+ * {@link org.apache.directory.fortress.core.rbac.PwPolicy} {@link org.apache.directory.fortress.core.rbac.SDSet} etc...) are used to carry data between three Fortress
+ * layers.starting with the (1) Manager layer down thru middle (2) Process layer and it's processing rules into
+ * (3) DAO layer where persistence with the OpenLDAP server occurs.
+ * <h4>Fortress Processing Layers</h4>
+ * <ol>
+ * <li>Manager layer:  {@link AdminMgrImpl}, {@link AccessMgrImpl}, {@link ReviewMgrImpl},...</li>
+ * <li>Process layer:  {@link org.apache.directory.fortress.core.rbac.UserP}, {@link org.apache.directory.fortress.core.rbac.RoleP}, {@link org.apache.directory.fortress.core.rbac.PermP},...</li>
+ * <li>DAO layer: {@link UserDAO}, {@link RoleDAO}, {@link org.apache.directory.fortress.core.rbac.dao.PermDAO},...</li>
+ * </ol>
+ * Fortress clients first instantiate and populate a data entity before invoking any of the Manager APIs.  The caller must
+ * provide enough information to uniquely identity the entity target within ldap.<br />
+ * For example, this entity requires {@link #setObjName} and {@link #setOpName} attributes set before passing into {@link AccessMgrImpl} APIs.
+ * Create methods usually require more attributes (than Read) due to constraints enforced between entities.
+ * <p/>
+ * <h4>Permission entity attribute usages include</h4>
+ * <ul>
+ * <li>{@link #setObjName} and {@link #setOpName} attributes set before calling {@link AccessMgrImpl#checkAccess(org.apache.directory.fortress.core.rbac.Session, Permission)}.
+ * <li>{@link #getRoles} may be set after calling {@link ReviewMgrImpl#readPermission(Permission)} or {@link AccessMgrImpl#sessionPermissions(org.apache.directory.fortress.core.rbac.Session)}.
+ * <li>{@link #getUsers} may be set after calling {@link ReviewMgrImpl#readPermission(Permission)} or {@link AccessMgrImpl#sessionPermissions(org.apache.directory.fortress.core.rbac.Session)}.
+ *
+ * </ul>
+ * <p/>
+ * <h4>More Permission entity notes</h4>
+ * <ul>
+ * <li>The unique key to locate a Permission entity (which is required for all authZ requests) is {@link Permission#objName} and {@link Permission#opName}.<br />
+ * <li>The Permission entity is used to target function points within computer programs needing authorization. This permission model allows a one-to-many relationship between the objects {@link org.apache.directory.fortress.core.rbac.PermObj} and operations {@link Permission}.
+ * <p/>
+ * <img src="../doc-files/RbacCore.png">
+ * <li>The object to operation pairings enable application resources to be mapped to Fortress permissions in a way that is natural for object oriented programming.
+ * <li>Permissions = Object {@link org.apache.directory.fortress.core.rbac.PermObj} 1<->* Operations {@link Permission}
+ * <li>Permissions in Fortress may also be assigned directly to {@link #users}.
+ * <li>Objects {@link #objName}, Operations {@link #opName}, Roles {@link #roles}, Users {@link #users} are not case sensitive for reads or searches.
+ * </ul>
+ * <p/>
+ * The application entity that requires authorization will be mapped to the {@link org.apache.directory.fortress.core.rbac.PermObj} entity and the application's methods or operation names
+ * will be mapped to {@link Permission} entities.
+ * For example, the application entity 'ShoppingCart' has 5 operations - 'create', 'read', 'update', 'delete' and 'checkout'.
+ * The following code will create the permissions and perform the necessary grants.
+ * <pre>
+ * try
+ * {
+ *  // Instantiate the AdminMgr first
+ *  AdminMgr adminMgr = AdminMgrFactory.createInstance();
+ *
+ *  // Now Instantiate the Object
+ *  PermObj shoppingCart = new PermObj("ShoppingCart", "KillerBikes.com");
+ *
+ *  // Add it to the directory
+ *  adminMgr.addPermObj(shoppingCart);
+ *
+ *  // Now create the permission operations and grant to applicable roles:
+ *  Permission create = new Permission(shoppingCart.getObjName(), "create");
+ *  adminMgr.addPermission(create);
+ *  adminMgr.grantPermission(create, new Role("Customer"));
+ *
+ *  Permission read = new Permission(shoppingCart.getObjName(), "read");
+ *  adminMgr.addPermission(read);
+ *  adminMgr.grantPermission(read, new Role("Customer"));
+ *
+ *  Permission update = new Permission(shoppingCart.getObjName(), "update");
+ *  adminMgr.addPermission(update);
+ *  adminMgr.grantPermission(update, new Role("Admin"));
+ *
+ *  Permission delete = new Permission(shoppingCart.getObjName(), "delete");
+ *  adminMgr.addPermission(delete);
+ *  adminMgr.grantPermission(delete, new Role("Manager"));
+ *
+ *  Permission checkout = new Permission(shoppingCart.getObjName(), "checkout");
+ *  adminMgr.addPermission(checkout);
+ *  adminMgr.grantPermission(delete, new Role("Customer"));
+ * }
+ * catch (SecurityException ex)
+ * {
+ *  // log or throw
+ * }
+ * </pre>
+ * <p/>
+ * <h4>Notes on the shopping cart example</h4>
+ * <ul>
+ * <li> {@link org.apache.directory.fortress.core.rbac.User} that activate 'Manager' role into their Sessions will be allowed access to 'ShoppingCart.delete' permission.
+ * <li> {@link org.apache.directory.fortress.core.rbac.User} that activate 'Admin' role may perform 'ShoppingCart.update'.
+ * <li> {@link org.apache.directory.fortress.core.rbac.User} with 'Customer' role may perform the 'ShoppingCart.create'  'ShoppingCart.read and 'ShoppingCart.checkout'.
+ * <li> {@link org.apache.directory.fortress.core.rbac.Role}s must exist in ldap before assignment here, see javadoc {@link org.apache.directory.fortress.core.rbac.Role} for details.
+ * <p/>
+ * </ul>
+ * <p/>
+ * <h4>Permission Schema</h4>
+ * This Permission entity extends a single standard ldap structural object class, {@code organizationalRole} with
+ * one extension structural class, {@code ftOperation}, and two auxiliary object classes, {@code ftProperties}, {@code ftMods}.
+ * The following 3 LDAP object classes will be mapped into this entity:
+ * <p/>
+ * 1. {@code ftOperation} STRUCTURAL Object Class is assigned roles and/or users which grants permissions which can be later checked
+ * using either 'checkAccess' or 'sessionPermissions APIs both methods that reside in the 'AccessMgrImpl' class.
+ * <pre>
+ * ------------------------------------------
+ * Fortress Operation Structural Object Class
+ * objectclass	( 1.3.6.1.4.1.38088.2.3
+ *  NAME 'ftOperation'
+ *  DESC 'Fortress Permission Operation Structural Object Class'
+ *  SUP organizationalrole
+ *  STRUCTURAL
+ *  MUST (
+ *      ftId $
+ *      ftPermName $
+ *      ftObjNm $
+ *      ftOpNm
+ *  )
+ *  MAY (
+ *      ftObjId $
+ *      ftRoles $
+ *      ftUsers $
+ *      ftType
+ *  )
+ *  )
+ * 2. {@code ftProperties} AUXILIARY Object Class is used to store optional client or otherwise custom name/value pairs on target entity.<br />
+ * <code># This aux object class can be used to store custom attributes.</code><br />
+ * <code># The properties collections consist of name/value pairs and are not constrainted by Fortress.</code><br />
+ * <pre>
+ * ------------------------------------------
+ * AC2: Fortress Properties Auxiliary Object Class
+ * objectclass ( 1.3.6.1.4.1.38088.3.2
+ *  NAME 'ftProperties'
+ *  DESC 'Fortress Properties AUX Object Class'
+ *  AUXILIARY
+ *  MAY (
+ *      ftProps
+ *  )
+ * )
+ * ------------------------------------------
+ * </pre>
+ * <p/>
+ * 3. {@code ftMods} AUXILIARY Object Class is used to store Fortress audit variables on target entity.
+ * <pre>
+ * ------------------------------------------
+ * Fortress Audit Modification Auxiliary Object Class
+ * objectclass ( 1.3.6.1.4.1.38088.3.4
+ *  NAME 'ftMods'
+ *  DESC 'Fortress Modifiers AUX Object Class'
+ *  AUXILIARY
+ *  MAY (
+ *      ftModifier $
+ *      ftModCode $
+ *      ftModId
+ *  )
+ * )
+ * ------------------------------------------
+ * </pre>
+ * <p/>
+ *
+ * @author Shawn McKinney
+ */
+@XmlRootElement(name = "fortPermission")
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "permission", propOrder =
+    {
+        "objName",
+        "opName",
+        "objId",
+        "description",
+        "abstractName",
+        "internalId",
+        "type",
+        "users",
+        "roles",
+        "props",
+        "dn",
+        "admin"
+})
+public class Permission extends FortEntity
+    implements java.io.Serializable
+{
+    private boolean admin;
+    private String internalId;
+    private String opName;
+    private String objName;
+    private String objId;
+    private String abstractName;
+    private String type;
+    private String dn;
+    private String description;
+    @XmlElement(nillable = true)
+    private Props props = new Props();
+    //private Properties props;
+    @XmlElement(nillable = true)
+    private Set<String> roles;
+    @XmlElement(nillable = true)
+    private Set<String> users;
+
+
+    /**
+     * This constructor is commonly used to create Permission that is a target for authorization API.
+     *
+     * @param objName maps to 'ftObjNm' attribute in 'ftOperation' object class.
+     * @param opName     maps to 'ftOpNm' attribute in 'ftOperation' object class.
+     */
+    public Permission( String objName, String opName )
+    {
+        this.objName = objName;
+        this.opName = opName;
+    }
+
+
+    /**
+     * Default constructor is used by internal Fortress classes and not intended for external use.
+     */
+    public Permission()
+    {
+    }
+
+
+    /**
+     * Constructor is used for APIs that do not require opName for example ARBAC canGrant/canRevoke.
+     *
+     * @param objName maps to 'ftObjNm' attribute in 'ftOperation' object class.
+     */
+    public Permission( String objName )
+    {
+        this.objName = objName;
+    }
+
+
+    /**
+     * This constructor adds the objId which is used for creating Permissions that have an identity.
+     *
+     * @param objName maps to 'ftObjNm' attribute in 'ftOperation' object class.
+     * @param opName     maps to 'ftOpNm' attribute in 'ftOperation' object class.
+     * @param objId   maps to 'ftObjId' attribute in 'ftOperation' object class.
+     */
+    public Permission( String objName, String opName, String objId )
+    {
+        this.objName = objName;
+        this.opName = opName;
+        this.objId = objId;
+    }
+
+
+    /**
+     * This constructor adds the admin flag which is used to process as Administrative permission.
+     *
+     * @param objName maps to 'ftObjNm' attribute in 'ftOperation' object class.
+     * @param opName     maps to 'ftOpNm' attribute in 'ftOperation' object class.
+     * @param admin      attribute is used to specify the Permission is to be stored and processed in the Administrative RBAC data sets.
+     */
+    public Permission( String objName, String opName, boolean admin )
+    {
+        this.objName = objName;
+        this.opName = opName;
+        this.admin = admin;
+    }
+
+
+    /**
+     * Determine if this Permission is for RBAC or ARBAC processing.
+     *
+     * @return 'true' indicates administrative permission.
+     */
+    public boolean isAdmin()
+    {
+        return admin;
+    }
+
+
+    /**
+     * Set will determine if this Permission is for RBAC or ARBAC processing.
+     *
+     * @param admin contains is 'true' if ARBAC permission..
+     */
+    public void setAdmin( boolean admin )
+    {
+        this.admin = admin;
+    }
+
+
+    /**
+     * This attribute is required but is set automatically by Fortress DAO class before object is persisted to ldap.
+     * This generated internal id is associated with Permission.  This method is used by DAO class and
+     * is not available to outside classes.   The generated attribute maps to 'ftId' in 'ftOperation' object class.
+     */
+    public void setInternalId()
+    {
+        // generate a unique id that will be used as the rDn for this entry:
+        UUID uuid = UUID.randomUUID();
+        this.internalId = uuid.toString();
+    }
+
+
+    /**
+     * Set the internal id that is associated with Permission.  This method is used by DAO class and
+     * is generated automatically by Fortress.  Attribute stored in LDAP cannot be changed by external caller.
+     * This method can be used by client for search purposes only.
+     *
+     * @param internalId maps to 'ftId' in 'ftObject' object class.
+     */
+    public void setInternalId( String internalId )
+    {
+        this.internalId = internalId;
+    }
+
+
+    /**
+     * Return the internal id that is associated with Permission.  This attribute is generated automatically
+     * by Fortress when new PermObj is added to directory and is not known or changeable by external client.
+     *
+     * @return attribute maps to 'ftId' in 'ftOperation' object class.
+     */
+    public String getInternalId()
+    {
+        return internalId;
+    }
+
+
+    /**
+     * Get the Permission operation name.  This is used to specify method name - i.e. Create, Read, Update, Delete, ...
+     *
+     * @return opName maps to 'ftOpNm' attribute in 'ftOperation' object class.
+     */
+    public String getOpName()
+    {
+        return opName;
+    }
+
+
+    /**
+     * Set the Permission operation name.  This is used to specify method name - i.e. Create, Read, Update, Delete, ...
+     *
+     * @param opName maps to 'ftOpNm' attribute in 'ftOperation' object class.
+     */
+    public void setOpName( String opName )
+    {
+        this.opName = opName;
+    }
+
+
+    /**
+     * Get the authorization target's object name.  This is typically mapped to the class name for component
+     * that is the target for Fortress authorization check. For example 'PatientRelationshipInquire'.
+     *
+     * @return the name of the object which maps to 'ftObjNm' attribute in 'ftOperation' object class.
+     */
+    public String getObjName()
+    {
+        return this.objName;
+    }
+
+
+    /**
+     * This attribute is required and sets the authorization target object name.  This name is typically derived from the class name
+     * for component that is the target for Fortress authorization check. For example 'CustomerCheckOutPage'.
+     *
+     */
+    public void setObjName( String objName )
+    {
+        this.objName = objName;
+    }
+
+
+    /**
+     * Return the Permission's abstract name which is the value of objName concatenated with OpName, i.e. 'Patient.checkin'
+     * This value is automatically generated by the Fortress DAO class.
+     *
+     * @return abstractName maps to 'ftPermName' attribute in 'ftOperation' object class.
+     */
+    public String getAbstractName()
+    {
+        return abstractName;
+    }
+
+
+    /**
+     * Set the Permission's abstract name which is the value of objName concatenated with OpName, i.e. 'Patient.checkin'
+     * This value is automatically generated by the Fortress DAO class and value will be ignored if set by external client.
+     *
+     * @param abstractName maps to 'ftPermName' attribute in 'ftOperation' object class.
+     */
+    public void setAbstractName( String abstractName )
+    {
+        this.abstractName = abstractName;
+    }
+
+
+    /**
+     * Get the optional type name which is an unconstrained attribute on Permission entity.
+     *
+     * @return type maps to 'ftType' attribute in 'ftOperation' object class.
+     */
+    public String getType()
+    {
+        return type;
+    }
+
+
+    /**
+     * Set the optional type name which is an unconstrained attribute on Permission entity.
+     *
+     * @param type maps to 'ftType' attribute in 'ftOperation' object class.
+     */
+    public void setType( String type )
+    {
+        this.type = type;
+    }
+
+
+    /**
+     * Get optional objId attribute which can be used to tag a Permission object with an identity, i.e. objName='Customer', objId='12345'.
+     * This value is not constrained by any other object.
+     *
+     * @return maps to 'ftObjectId' attribute in 'ftOperation' object class.
+     */
+    public String getObjId()
+    {
+        return objId;
+    }
+
+
+    /**
+     * Set optional objId which can be used to tag a Permission object with an identity, i.e. objName='Account', objId='09876543'.
+     * This value is not constrained by any other object.
+     *
+     * @param objId maps to 'ftObjectId' attribute in 'ftOperation' object class.
+     */
+    public void setObjId( String objId )
+    {
+        this.objId = objId;
+    }
+
+
+    /**
+     * Add a Role name to list of Roles that are valid for this Permission.  This is optional attribute.
+     *
+     * @param role maps to 'ftRoles' attribute in 'ftOperation' object class.
+     */
+    public void setRole( String role )
+    {
+        if ( roles == null )
+        {
+            roles = new TreeSet<>( String.CASE_INSENSITIVE_ORDER );
+        }
+
+        this.roles.add( role );
+    }
+
+
+    /**
+     * Delete a Role name from list of Roles that are valid for this Permission.
+     *
+     * @param role maps to 'ftRoles' attribute in 'ftOperation' object class.
+     */
+    public void delRole( String role )
+    {
+        if ( this.roles != null )
+        {
+            this.roles.remove( role );
+        }
+    }
+
+
+    /**
+     * Return the collection of optional Roles that have been loaded into this entity.  This is stored as a multi-occurring
+     * attribute of Role names on the 'ftOperation' object class.
+     *
+     * @return Set containing the roles which maps to 'ftRoles' attribute in 'ftOperation' object class.
+     */
+    public Set<String> getRoles()
+    {
+        return this.roles;
+    }
+
+
+    /**
+     * Set the collection of optional Roles that have been loaded into this entity.  This is stored as a multi-occurring
+     * attribute of Role names on the 'ftOperation' object class.
+     *
+     * @param roles maps to 'ftRoles' attribute in 'ftOperation' object class.
+     */
+    public void setRoles( Set<String> roles )
+    {
+        this.roles = roles;
+    }
+
+
+    /**
+     * Add a UserId to list of Users that are valid for this Permission.  This is optional attribute.
+     *
+     * @param user maps to 'ftUsers' attribute in 'ftOperation' object class.
+     */
+    public void setUser( String user )
+    {
+        if ( users == null )
+        {
+            users = new TreeSet<>( String.CASE_INSENSITIVE_ORDER );
+        }
+
+        this.users.add( user );
+    }
+
+
+    /**
+     * Return the collection of optional Users that have been loaded into this entity.  This is stored as a multi-occurring
+     * attribute of ftUsers on the 'ftOperation' object class.
+     *
+     * @return Set containing the Users which maps to 'ftUsers' attribute in 'ftOperation' object class.
+     */
+    public Set<String> getUsers()
+    {
+        return this.users;
+    }
+
+
+    /**
+     * Set the collection of optional Users that have been loaded into this entity.  This is stored as a multi-occurring
+     * attribute of userIds on the 'ftOperation' object class.
+     *
+     * @param users maps to 'ftUsers' attribute in 'ftOperation' object class.
+     */
+    public void setUsers( Set<String> users )
+    {
+        this.users = users;
+    }
+
+
+    public String getDn()
+    {
+        return dn;
+    }
+
+    public void setDn( String dn )
+    {
+        this.dn = dn;
+    }
+
+    /**
+     * Return the description field on this entity.  The description is often used as a human readable label for the permission.
+     * @return String containing the description.
+     */
+    public String getDescription()
+    {
+        return description;
+    }
+
+    /**
+     * Set the optional description field on this entity.  The description is used as a human readable label for the permission.
+     *
+     * @param description String contains the description.
+     */
+    public void setDescription( String description )
+    {
+        this.description = description;
+    }
+
+    /**
+      * Gets the value of the Props property.  This method is used by Fortress and En Masse and should not be called by external programs.
+      *
+      * @return
+      *     possible object is
+      *     {@link Props }
+      *
+      */
+    public Props getProps()
+    {
+        return props;
+    }
+
+
+    /**
+     * Sets the value of the Props property.  This method is used by Fortress and En Masse and should not be called by external programs.
+     *
+     * @param value
+     *     allowed object is
+     *     {@link Props }
+     *
+     */
+    public void setProps( Props value )
+    {
+        this.props = value;
+    }
+
+
+    /**
+     * Add name/value pair to list of properties associated with Permission.  These values are not constrained by Fortress.
+     * Properties are optional.
+     *
+     * @param key   contains property name and maps to 'ftProps' attribute in 'ftProperties' aux object class.
+     * @param value
+     */
+    public void addProperty( String key, String value )
+    {
+        Props.Entry entry = new Props.Entry();
+        entry.setKey( key );
+        entry.setValue( value );
+        this.props.getEntry().add( entry );
+    }
+
+
+    /**
+     * Get a name/value pair attribute from list of properties associated with Permission.  These values are not constrained by Fortress.
+     * Properties are optional.
+     *
+     * @param key contains property name and maps to 'ftProps' attribute in 'ftProperties' aux object class.
+     * @return value containing name/value pair that maps to 'ftProps' attribute in 'ftProperties' aux object class.
+     */
+    public String getProperty( String key )
+    {
+        List<Props.Entry> props = this.props.getEntry();
+        Props.Entry keyObj = new Props.Entry();
+        keyObj.setKey( key );
+
+        String value = null;
+        int indx = props.indexOf( keyObj );
+        if ( indx != -1 )
+        {
+            Props.Entry entry = props.get( props.indexOf( keyObj ) );
+            value = entry.getValue();
+        }
+
+        return value;
+    }
+
+
+    /**
+     * Add new collection of name/value pairs to attributes associated with Permission.  These values are not constrained by Fortress.
+     * Properties are optional.
+     *
+     * @param props contains collection of name/value pairs and maps to 'ftProps' attribute in 'ftProperties' aux object class.
+     */
+    public void addProperties( Properties props )
+    {
+        if ( props != null )
+        {
+            for ( Enumeration e = props.propertyNames(); e.hasMoreElements(); )
+            {
+                // This LDAP attr is stored as a name-value pair separated by a ':'.
+                String key = ( String ) e.nextElement();
+                String val = props.getProperty( key );
+                addProperty( key, val );
+            }
+        }
+    }
+
+
+    /**
+     * Return the collection of name/value pairs to attributes associated with Permission.  These values are not constrained by Fortress.
+     * Properties are optional.
+     *
+     * @return Properties contains collection of name/value pairs and maps to 'ftProps' attribute in 'ftProperties' aux object class.
+     */
+    public Properties getProperties()
+    {
+        Properties properties = null;
+        List<Props.Entry> props = this.props.getEntry();
+        if ( props.size() > 0 )
+        {
+            properties = new Properties();
+            //int size = props.size();
+            for ( Props.Entry entry : props )
+            {
+                String key = entry.getKey();
+                String val = entry.getValue();
+                properties.setProperty( key, val );
+            }
+        }
+        return properties;
+    }
+
+
+    /**
+     * Matches the objName and opName from two Permission entities.
+     *
+     * @param thatOp contains a Permission entity.
+     * @return boolean indicating both Permissions contain matching objName and opName attributes.
+     */
+    public boolean equals( Object thatOp )
+    {
+        if ( this == thatOp )
+            return true;
+        if ( this.getObjName() == null )
+            return false;
+        if ( !( thatOp instanceof Permission ) )
+            return false;
+        Permission thatPermission = ( Permission ) thatOp;
+        if ( thatPermission.getObjName() == null )
+            return false;
+        return ( ( thatPermission.getObjName().equalsIgnoreCase( this.getObjName() ) ) && ( thatPermission
+            .getOpName().equalsIgnoreCase( this.getOpName() ) ) );
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Permission{" +
+            "objName='" + objName + '\'' +
+            ", opName='" + opName + '\'' +
+            '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/rbac/PolicyP.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/rbac/PolicyP.java b/src/main/java/org/apache/directory/fortress/core/rbac/PolicyP.java
new file mode 100755
index 0000000..e6f935f
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/rbac/PolicyP.java
@@ -0,0 +1,378 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.fortress.core.rbac;
+
+
+import java.util.List;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.directory.fortress.core.GlobalErrIds;
+import org.apache.directory.fortress.core.GlobalIds;
+import org.apache.directory.fortress.core.SecurityException;
+import org.apache.directory.fortress.core.ValidationException;
+import org.apache.directory.fortress.core.rbac.dao.unboundid.PolicyDAO;
+import org.apache.directory.fortress.core.util.attr.VUtil;
+import org.apache.directory.fortress.core.util.cache.Cache;
+import org.apache.directory.fortress.core.util.cache.CacheMgr;
+
+
+/**
+ * Process module for the OpenLDAP Password Policy entity.  This class performs data validations and error mapping.
+ * It is typically called by internal Fortress manager class {@link PwPolicyMgrImpl} but also
+ * needed by {@link org.apache.directory.fortress.core.rbac.UserP#validate(org.apache.directory.fortress.core.rbac.User, boolean)}
+ * This class is not intended to be used by external programs.  This class will accept Fortress entity, {@link PwPolicy}, on its
+ * methods, validate contents and forward on to it's corresponding DAO class {@link PolicyDAO}.
+ * <p/>
+ * Class will throw {@link SecurityException} to caller in the event of security policy, data constraint violation or system
+ * error internal to DAO object. This class will forward DAO exceptions ({@link org.apache.directory.fortress.core.FinderException},
+ *
+ * {@link org.apache.directory.fortress.core.CreateException},{@link org.apache.directory.fortress.core.UpdateException},{@link org.apache.directory.fortress.core.RemoveException}),
+ * or {@link org.apache.directory.fortress.core.ValidationException} as {@link SecurityException}s with appropriate
+ * error id from {@link org.apache.directory.fortress.core.GlobalErrIds}.
+ * <p/>
+ * This class uses one reference to synchronized data set {@link #policyCache} but is thread safe.
+ * <p/>
+
+ *
+ * @author Shawn McKinney
+ */
+public final class PolicyP
+{
+
+    private static final String CLS_NM = PolicyP.class.getName();
+    private static final Logger LOG = LoggerFactory.getLogger( CLS_NM );
+    // This is 5 years duration in seconds:
+    private static final int MAX_AGE = 157680000;
+
+    // DAO class for ol pw policy data sets must be initialized before the other statics:
+    private static final PolicyDAO olDao = new PolicyDAO();
+    // this field is used to synchronize access to the above static data set:
+    private static final Object policySetSynchLock = new Object();
+    // static field holds the list of names for all valid pw policies in effect:
+    private static Cache policyCache;
+    private static final int MIN_PW_LEN = 20;
+    private static final int MAX_FAILURE = 100;
+    private static final int MAX_GRACE_COUNT = 10;
+    private static final int MAX_HISTORY = 100;
+    private static final String POLICIES = "policies";
+    private static final String FORTRESS_POLICIES = "fortress.policies";
+
+    static
+    {
+        CacheMgr cacheMgr = CacheMgr.getInstance();
+        PolicyP.policyCache = cacheMgr.getCache( FORTRESS_POLICIES );
+    }
+
+
+    /**
+     * Package private constructor.
+     */
+    PolicyP()
+    {
+    }
+
+
+    /**
+     * This function uses a case insensitive search.
+     *
+     * @param policy
+     * @return
+     */
+    final boolean isValid( PwPolicy policy )
+    {
+        boolean result = false;
+        Set<String> policySet = getPolicySet( policy.getContextId() );
+        if ( policySet != null )
+            result = policySet.contains( policy.getName() );
+        return result;
+    }
+
+
+    /**
+     * This method will return the password policy entity to the caller.  This command is valid
+     * if and only if the policy entry is present in the POLICIES data set.
+     *
+     * @param policy contains the name of the policy entity.
+     * @return PswdPolicy entity returns fully populated with attributes.
+     * @throws SecurityException In the event policy entry not found, data validation or system error.
+     */
+    final PwPolicy read( PwPolicy policy ) throws SecurityException
+    {
+        // Call the finder method for the primary key.
+        return olDao.getPolicy( policy );
+    }
+
+
+    /**
+     * This method will add a new policy entry to the POLICIES data set.  This command is valid
+     * if and only if the policy entry is not already present in the POLICIES data set.
+     *
+     * @param policy Object contains the password policy attributes.
+     * @throws SecurityException In the event of data validation or system error.
+     */
+    final void add( PwPolicy policy ) throws SecurityException
+    {
+        validate( policy );
+        olDao.create( policy );
+        synchronized ( policySetSynchLock )
+        {
+            Set<String> policySet = getPolicySet( policy.getContextId() );
+            if ( policySet != null )
+                policySet.add( policy.getName() );
+        }
+    }
+
+
+    /**
+     * This method will update an exiting policy entry to the POLICIES data set.  This command is valid
+     * if and only if the policy entry is already present in the POLICIES data set.
+     *
+     * @param policy Object must contain the name of the policy entity.  All non-null attributes will
+     *               be updated.  null attributes will be ignored.
+     * @throws SecurityException In the event policy not found , data validation or system error.
+     */
+    final void update( PwPolicy policy ) throws SecurityException
+    {
+        validate( policy );
+        olDao.update( policy );
+    }
+
+
+    /**
+     * This method will delete exiting policy entry from the POLICIES data set.  This command is valid
+     * if and only if the policy entry is already present in the POLICIES data set.  Existing users that
+     * are assigned this policy will be removed from association.
+     *
+     * @param policy Object must contain the name of the policy entity.
+     * @throws SecurityException In the event policy entity not found or system error.
+     */
+    final void delete( PwPolicy policy ) throws SecurityException
+    {
+        olDao.remove( policy );
+        synchronized ( policySetSynchLock )
+        {
+            Set<String> policySet = getPolicySet( policy.getContextId() );
+            if ( policySet != null )
+                policySet.remove( policy.getName() );
+        }
+    }
+
+
+    /**
+     * This method will return a list of all password policy entities that match a particular search string.
+     * This command will return an empty list of no matching entries are found.
+     *
+     * @param policy contains the leading chars of a policy entity.  This search is not case sensitive.
+     * @return List<PswdPolicy> contains all matching password policy entities. If no records found this will be empty.
+     * @throws SecurityException In the event of data validation or system error.
+     */
+    final List<PwPolicy> search( PwPolicy policy ) throws SecurityException
+    {
+        return olDao.findPolicy( policy );
+    }
+
+
+    /**
+     * Method will perform simple validations to ensure the integrity of the OpenLDAP Password Policy entity targeted for insertion
+     * or updating in directory.  Data reasonability checks will be performed on all non-null attributes.
+     *
+     * @param policy contains data targeted for insertion or update.
+     * @throws ValidationException in the event of data validation error or DAO error on Org validation.
+     */
+    private void validate( PwPolicy policy ) throws ValidationException
+    {
+        int length = policy.getName().length();
+        if ( length < 1 || length > GlobalIds.PWPOLICY_NAME_LEN )
+        {
+            String error = "validate policy name [" + policy.getName() + "] INVALID LENGTH [" + length + "]";
+            LOG.error( error );
+            throw new ValidationException( GlobalErrIds.PSWD_NAME_INVLD_LEN, error );
+        }
+        if ( policy.getCheckQuality() != null )
+        {
+            try
+            {
+                if ( policy.getCheckQuality() < 0 || policy.getCheckQuality() > 2 )
+                {
+                    String error = "validate policy name [" + policy.getName() + "] value checkQuality ["
+                        + policy.getCheckQuality() + "] INVALID INT VALUE";
+                    LOG.error( error );
+                    throw new ValidationException( GlobalErrIds.PSWD_QLTY_INVLD, error );
+                }
+            }
+            catch ( java.lang.NumberFormatException nfe )
+            {
+                String error = "validate policy name [" + policy.getName() + "] value checkQuality ["
+                    + policy.getCheckQuality() + "] INVALID INT VALUE";
+                LOG.error( error );
+                throw new ValidationException( GlobalErrIds.PSWD_QLTY_INVLD, error );
+            }
+        }
+        if ( policy.getMaxAge() != null )
+        {
+            if ( policy.getMaxAge() > MAX_AGE )
+            {
+                String error = "validate policy name [" + policy.getName() + "] value maxAge [" + policy.getMaxAge()
+                    + "] INVALID INT VALUE";
+                LOG.error( error );
+                throw new ValidationException( GlobalErrIds.PSWD_MAXAGE_INVLD, error );
+            }
+        }
+        if ( policy.getMinAge() != null )
+        {
+            // policy.minAge
+            if ( policy.getMinAge() > MAX_AGE )
+            {
+                String error = "validate policy name [" + policy.getName() + "] value minAge [" + policy.getMinAge()
+                    + "] INVALID INT VALUE";
+                LOG.error( error );
+                throw new ValidationException( GlobalErrIds.PSWD_MINAGE_INVLD, error );
+            }
+        }
+        if ( policy.getMinLength() != null )
+        {
+            if ( policy.getMinLength() > MIN_PW_LEN )
+            {
+                String error = "validate policy name [" + policy.getName() + "] value minLength ["
+                    + policy.getMinLength() + "] INVALID INT VALUE";
+                LOG.error( error );
+                throw new ValidationException( GlobalErrIds.PSWD_MINLEN_INVLD, error );
+            }
+        }
+        if ( policy.getFailureCountInterval() != null )
+        {
+            if ( policy.getFailureCountInterval() > MAX_AGE )
+            {
+                String error = "validate policy name [" + policy.getName() + "] value failureCountInterval ["
+                    + policy.getFailureCountInterval() + "] INVALID INT VALUE";
+                LOG.error( error );
+                throw new ValidationException( GlobalErrIds.PSWD_INTERVAL_INVLD, error );
+            }
+        }
+        if ( policy.getMaxFailure() != null )
+        {
+            if ( policy.getMaxFailure() > MAX_FAILURE )
+            {
+                String error = "validate policy name [" + policy.getName() + "] value maxFailure ["
+                    + policy.getMaxFailure() + "] INVALID INT VALUE";
+                LOG.error( error );
+                throw new ValidationException( GlobalErrIds.PSWD_MAXFAIL_INVLD, error );
+            }
+        }
+        if ( policy.getInHistory() != null )
+        {
+            if ( policy.getInHistory() > MAX_HISTORY )
+            {
+                String error = "validate policy name [" + policy.getName() + "] value inHistory ["
+                    + policy.getInHistory() + "] INVALID VALUE";
+                LOG.error( error );
+                throw new ValidationException( GlobalErrIds.PSWD_HISTORY_INVLD, error );
+            }
+        }
+        if ( policy.getGraceLoginLimit() != null )
+        {
+            if ( policy.getGraceLoginLimit() > MAX_GRACE_COUNT )
+            {
+                String error = "validate policy name [" + policy.getName() + "] value graceLoginLimit ["
+                    + policy.getGraceLoginLimit() + "] INVALID VALUE";
+                LOG.error( error );
+                throw new ValidationException( GlobalErrIds.PSWD_GRACE_INVLD, error );
+            }
+        }
+        if ( policy.getLockoutDuration() != null )
+        {
+            if ( policy.getLockoutDuration() > MAX_AGE )
+            {
+                String error = "validate policy name [" + policy.getName() + "] value lockoutDuration ["
+                    + policy.getLockoutDuration() + "] INVALID VALUE";
+                LOG.error( error );
+                throw new ValidationException( GlobalErrIds.PSWD_LOCKOUTDUR_INVLD, error );
+            }
+        }
+        if ( policy.getExpireWarning() != null )
+        {
+            if ( policy.getExpireWarning() > MAX_AGE )
+            {
+                String error = "validate policy name [" + policy.getName() + "] value expireWarning ["
+                    + policy.getExpireWarning() + "] INVALID VALUE";
+                LOG.error( error );
+                throw new ValidationException( GlobalErrIds.PSWD_EXPWARN_INVLD, error );
+            }
+        }
+    }
+
+
+    /**
+     * Load the cache with read only list of valid openldap policy names.
+     *
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return Set of unique names.
+     */
+    private static Set<String> loadPolicySet( String contextId )
+    {
+        Set<String> policySet = null;
+        try
+        {
+            policySet = olDao.getPolicies( contextId );
+        }
+        catch ( SecurityException se )
+        {
+            String warning = "loadPolicySet static initializer caught SecurityException=" + se;
+            LOG.info( warning );
+        }
+        policyCache.put( getKey( contextId ), policySet );
+        return policySet;
+    }
+
+
+    /**
+     *
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return
+     */
+    private static Set<String> getPolicySet( String contextId )
+    {
+        Set<String> policySet = ( Set<String> ) policyCache.get( getKey( contextId ) );
+        if ( policySet == null )
+        {
+            policySet = loadPolicySet( contextId );
+        }
+        return policySet;
+    }
+
+
+    /**
+     *
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return
+     */
+    private static String getKey( String contextId )
+    {
+        String key = POLICIES;
+        if ( VUtil.isNotNullOrEmpty( contextId ) && !contextId.equalsIgnoreCase( GlobalIds.NULL ) )
+        {
+            key += ":" + contextId;
+        }
+        return key;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/rbac/Props.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/rbac/Props.java b/src/main/java/org/apache/directory/fortress/core/rbac/Props.java
new file mode 100755
index 0000000..8ea082e
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/rbac/Props.java
@@ -0,0 +1,200 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.fortress.core.rbac;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class is used as a container for {@code java.util.Properties} for passing to En Masse server.
+ * </p>
+ * This class is thread safe.
+ *
+ * @author Shawn McKinney
+ *         <p/>
+ *         <p>The following schema fragment specifies the expected content contained within this class.
+ *         <p/>
+ *         <pre>
+ *                 &lt;complexType>
+ *                   &lt;complexContent>
+ *                     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                       &lt;sequence>
+ *                         &lt;element name="entry" maxOccurs="unbounded" minOccurs="0">
+ *                           &lt;complexType>
+ *                             &lt;complexContent>
+ *                               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                 &lt;sequence>
+ *                                   &lt;element name="key" type="{http://www.w3.org/2001/XMLSchema}anyType" minOccurs="0"/>
+ *                                   &lt;element name="value" type="{http://www.w3.org/2001/XMLSchema}anyType" minOccurs="0"/>
+ *                                 &lt;/sequence>
+ *                               &lt;/restriction>
+ *                             &lt;/complexContent>
+ *                           &lt;/complexType>
+ *                         &lt;/element>
+ *                       &lt;/sequence>
+ *                     &lt;/restriction>
+ *                   &lt;/complexContent>
+ *                 &lt;/complexType>
+ *                 </pre>
+ */
+@XmlRootElement(name = "fortProps")
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "props", propOrder = {
+    "entry"
+})
+public class Props extends FortEntity implements Serializable
+{
+    private List<Props.Entry> entry;
+
+    /**
+     * Gets the value of the entry property.
+     *
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the entry property.
+     *
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getEntry().add(newItem);
+     * </pre>
+     *
+     *
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Props.Entry }
+     *
+     *
+     */
+    public List<Props.Entry> getEntry()
+    {
+        if (entry == null)
+        {
+            entry = new ArrayList<>();
+        }
+        return this.entry;
+    }
+
+    /**
+     * <p>Java class for anonymous complex type.
+     *
+     * <p>The following schema fragment specifies the expected content contained within this class.
+     *
+     * <pre>
+     * &lt;complexType>
+     *   &lt;complexContent>
+     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       &lt;sequence>
+     *         &lt;element name="key" type="{http://www.w3.org/2001/XMLSchema}anyType" minOccurs="0"/>
+     *         &lt;element name="value" type="{http://www.w3.org/2001/XMLSchema}anyType" minOccurs="0"/>
+     *       &lt;/sequence>
+     *     &lt;/restriction>
+     *   &lt;/complexContent>
+     * &lt;/complexType>
+     * </pre>
+     *
+     *
+     */
+    @XmlAccessorType(XmlAccessType.FIELD)
+    @XmlType(name = "", propOrder = {
+        "key",
+        "value"
+    })
+    public static class Entry implements Serializable
+    {
+
+        protected String key;
+        protected String value;
+
+        /**
+         * Gets the value of the key property.
+         *
+         * @return
+         *     possible object is
+         *     {@link Object }
+         *
+         */
+        public String getKey()
+        {
+            return key;
+        }
+
+        /**
+         * Sets the value of the key property.
+         *
+         * @param value
+         *     allowed object is
+         *     {@link Object }
+         *
+         */
+        public void setKey(String value)
+        {
+            this.key = value;
+        }
+
+        /**
+         * Gets the value of the value property.
+         *
+         * @return
+         *     possible object is
+         *     {@link Object }
+         *
+         */
+        public String getValue()
+        {
+            return value;
+        }
+
+        /**
+         * Sets the value of the value property.
+         *
+         * @param value
+         *     allowed object is
+         *     {@link Object }
+         *
+         */
+        public void setValue(String value)
+        {
+            this.value = value;
+        }
+
+        /**
+         *
+         * @param obj
+         * @return boolean value
+         */
+        public boolean equals(Object obj)
+        {
+            if (obj != null && obj instanceof Props.Entry)
+            {
+                Props.Entry inObj = (Props.Entry) obj;
+                return key.equals(inObj.getKey());
+            }
+            return false;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/rbac/PsoUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/rbac/PsoUtil.java b/src/main/java/org/apache/directory/fortress/core/rbac/PsoUtil.java
new file mode 100755
index 0000000..2e2b937
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/rbac/PsoUtil.java
@@ -0,0 +1,274 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.fortress.core.rbac;
+
+
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.jgrapht.graph.SimpleDirectedGraph;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.directory.fortress.core.GlobalIds;
+import org.apache.directory.fortress.core.SecurityException;
+import org.apache.directory.fortress.core.ValidationException;
+import org.apache.directory.fortress.core.util.attr.VUtil;
+import org.apache.directory.fortress.core.util.cache.Cache;
+import org.apache.directory.fortress.core.util.cache.CacheMgr;
+
+
+/**
+ * This utility wraps {@link HierUtil} methods to provide hierarchical functionality using the {@link org.apache.directory.fortress.core.rbac.OrgUnit} data set
+ * for Permissions, {@link org.apache.directory.fortress.core.rbac.OrgUnit.Type#PERM}.
+ * The {@code cn=Hierarchies, ou=OS-P} data contains Permission OU pools and within a data cache, {@link #psoCache}, contained within this class.  The parent-child edges are contained in LDAP,
+ * in {@code ftParents} attribute.  The ldap data is retrieved {@link OrgUnitP#getAllDescendants(org.apache.directory.fortress.core.rbac.OrgUnit)} and loaded into {@code org.jgrapht.graph.SimpleDirectedGraph}.
+ * The graph...
+ * <ol>
+ * <li>is stored as singleton in this class with vertices of {@code String}, and edges, as {@link Relationship}s</li>
+ * <li>utilizes open source library, see <a href="http://www.jgrapht.org/">JGraphT</a>.</li>
+ * <li>contains a general hierarchical data structure i.e. allows multiple inheritance with parents.</li>
+ * <li>is a simple directed graph thus does not allow cycles.</li>
+ * </ol>
+ * After update is performed to ldap, the singleton is refreshed with latest info.
+ * <p/>
+ * Static methods on this class are intended for use by other Fortress classes, i.e. {@link DelAdminMgrImpl}.
+ * and cannot be directly invoked by outside programs.
+ * <p/>
+ * This class contains singleton that can be updated but is thread safe.
+ * <p/>
+ *
+ * @author Shawn McKinney
+ */
+public final class PsoUtil
+{
+    private static final Cache psoCache;
+    private static OrgUnitP orgUnitP = new OrgUnitP();
+    private static final String CLS_NM = PsoUtil.class.getName();
+    private static final Logger LOG = LoggerFactory.getLogger( CLS_NM );
+
+    /**
+     * Initialize the Perm OU hierarchies.  This will read the {@link org.apache.directory.fortress.core.rbac.Hier} data set from ldap and load into
+     * the JGraphT simple digraph that referenced statically within this class.
+     */
+    static
+    {
+        CacheMgr cacheMgr = CacheMgr.getInstance();
+        psoCache = cacheMgr.getCache( "fortress.pso" );
+    }
+
+
+    /**
+     * Recursively traverse the {@link org.apache.directory.fortress.core.rbac.OrgUnit} graph and return all of the descendants of a given parent {@link org.apache.directory.fortress.core.rbac.OrgUnit#name}.
+     *
+     * @param name      {@link org.apache.directory.fortress.core.rbac.OrgUnit#name} maps on 'ftOrgUnit' object class.
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return Set of names of descendants {@link org.apache.directory.fortress.core.rbac.OrgUnit}s of given parent.
+     */
+    static Set<String> getDescendants( String name, String contextId )
+    {
+        return HierUtil.getDescendants( name, getGraph( contextId ) );
+    }
+
+
+    /**
+     * Recursively traverse the {@link org.apache.directory.fortress.core.rbac.OrgUnit.Type#USER} graph and return all of the ascendants of a given child ou.
+     *
+     * @param name      maps to logical {@link org.apache.directory.fortress.core.rbac.OrgUnit#name} on 'ftOrgUnit' object class.
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return Set of ou names that are ascendants of given child.
+     */
+    static Set<String> getAscendants( String name, String contextId )
+    {
+        return HierUtil.getAscendants( name, getGraph( contextId ) );
+    }
+
+
+    /**
+     * Traverse one level of the {@link org.apache.directory.fortress.core.rbac.OrgUnit} graph and return all of the children (direct descendants) of a given parent {@link org.apache.directory.fortress.core.rbac.OrgUnit#name}.
+     *
+     * @param name      {@link org.apache.directory.fortress.core.rbac.OrgUnit#name} maps on 'ftOrgUnit' object class.
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return Set of names of children {@link org.apache.directory.fortress.core.rbac.OrgUnit}s of given parent.
+     */
+    public static Set<String> getChildren( String name, String contextId )
+    {
+        return HierUtil.getChildren( name, getGraph( contextId ) );
+    }
+
+
+    /**
+     * Traverse one level of the {@link org.apache.directory.fortress.core.rbac.OrgUnit.Type#USER} graph and return all of the parents (direct ascendants) of a given child ou.
+     *
+     * @param name      maps to logical {@link org.apache.directory.fortress.core.rbac.OrgUnit#name} on 'ftOrgUnit' object class.
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return Set of ou names that are parents of given child.
+     */
+    static Set<String> getParents( String name, String contextId )
+    {
+        return HierUtil.getParents( name, getGraph( contextId ) );
+    }
+
+
+    /**
+     * Recursively traverse the {@link org.apache.directory.fortress.core.rbac.OrgUnit.Type#PERM} graph and return number of children a given parent ou has.
+     *
+     * @param name      maps to logical {@link org.apache.directory.fortress.core.rbac.OrgUnit#name} on 'ftOrgUnit' object class.
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return int value contains the number of children of a given parent ou.
+     */
+    static int numChildren( String name, String contextId )
+    {
+        return HierUtil.numChildren( name, getGraph( contextId ) );
+    }
+
+
+    /**
+     * Return Set of {@link org.apache.directory.fortress.core.rbac.OrgUnit#name}s ascendants contained within {@link org.apache.directory.fortress.core.rbac.OrgUnit.Type#PERM}.
+     *
+     * @param ous       contains list of {@link org.apache.directory.fortress.core.rbac.OrgUnit}s.
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return contains Set of all descendants.
+     */
+    static Set<String> getInherited( List<OrgUnit> ous, String contextId )
+    {
+        // create Set with case insensitive comparator:
+        Set<String> iOUs = new TreeSet<>( String.CASE_INSENSITIVE_ORDER );
+        if ( VUtil.isNotNullOrEmpty( ous ) )
+        {
+            for ( OrgUnit ou : ous )
+            {
+                String name = ou.getName();
+                iOUs.add( name );
+                Set<String> parents = HierUtil.getAscendants( name, getGraph( contextId ) );
+                if ( VUtil.isNotNullOrEmpty( parents ) )
+                    iOUs.addAll( parents );
+            }
+        }
+        return iOUs;
+    }
+
+
+    /**
+     * This api is used by {@link DelAdminMgrImpl} to determine parentage for Permission OU processing.
+     * It calls {@link HierUtil#validateRelationship(org.jgrapht.graph.SimpleDirectedGraph, String, String, boolean)} to evaluate three OU relationship expressions:
+     * <ol>
+     * <li>If child equals parent</li>
+     * <li>If mustExist true and parent-child relationship exists</li>
+     * <li>If mustExist false and parent-child relationship does not exist</li>
+     * </ol>
+     * Method will throw {@link org.apache.directory.fortress.core.ValidationException} if rule check fails meaning caller failed validation
+     * attempt to add/remove hierarchical relationship failed.
+     *
+     * @param child     contains {@link org.apache.directory.fortress.core.rbac.OrgUnit#name} of child.
+     * @param parent    contains {@link org.apache.directory.fortress.core.rbac.OrgUnit#name} of parent.
+     * @param mustExist boolean is used to specify if relationship must be true.
+     * @throws org.apache.directory.fortress.core.ValidationException
+     *          in the event it fails one of the 3 checks.
+     */
+    static void validateRelationship( OrgUnit child, OrgUnit parent, boolean mustExist )
+        throws ValidationException
+    {
+        HierUtil.validateRelationship( getGraph( child.getContextId() ), child.getName(), parent.getName(), mustExist );
+    }
+
+
+    /**
+     * This api allows synchronized access to allow updates to hierarchical relationships.
+     * Method will update the hierarchical data set and reload the JGraphT simple digraph with latest.
+     *
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @param relationship contains parent-child relationship targeted for addition.
+     * @param op   used to pass the ldap op {@link org.apache.directory.fortress.core.rbac.Hier.Op#ADD}, {@link org.apache.directory.fortress.core.rbac.Hier.Op#MOD}, {@link org.apache.directory.fortress.core.rbac.Hier.Op#REM}
+     * @throws org.apache.directory.fortress.core.SecurityException in the event of a system error.
+     */
+    static void updateHier( String contextId, Relationship relationship, Hier.Op op ) throws SecurityException
+    {
+        HierUtil.updateHier( getGraph( contextId ), relationship, op );
+    }
+
+
+    /**
+     * Read this ldap record,{@code cn=Hierarchies, ou=OS-P} into this entity, {@link Hier}, before loading into this collection class,{@code org.jgrapht.graph.SimpleDirectedGraph}
+     * using 3rd party lib, <a href="http://www.jgrapht.org/">JGraphT</a>.
+     *
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return
+     */
+    private static SimpleDirectedGraph<String, Relationship> loadGraph( String contextId )
+    {
+        Hier inHier = new Hier( Hier.Type.ROLE );
+        inHier.setContextId( contextId );
+        LOG.info( "loadGraph initializing PSO context [" + inHier.getContextId() + "]" );
+        List<Graphable> descendants = null;
+        try
+        {
+            OrgUnit orgUnit = new OrgUnit();
+            orgUnit.setType( OrgUnit.Type.PERM );
+            orgUnit.setContextId( contextId );
+            descendants = orgUnitP.getAllDescendants( orgUnit );
+        }
+        catch ( SecurityException se )
+        {
+            LOG.info( "loadGraph caught SecurityException=" + se );
+        }
+        Hier hier = HierUtil.loadHier( contextId, descendants );
+        SimpleDirectedGraph<String, Relationship> graph;
+        synchronized ( HierUtil.getLock( contextId, HierUtil.Type.PSO ) )
+        {
+            graph = HierUtil.buildGraph( hier );
+        }
+        psoCache.put( getKey( contextId ), graph );
+        return graph;
+    }
+
+
+    /**
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return
+     */
+    private static SimpleDirectedGraph<String, Relationship> getGraph( String contextId )
+    {
+        SimpleDirectedGraph<String, Relationship> graph = ( SimpleDirectedGraph<String, Relationship> ) psoCache
+            .get( getKey( contextId ) );
+        if ( graph == null )
+        {
+            graph = loadGraph( contextId );
+        }
+        return graph;
+    }
+
+
+    /**
+     *
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return
+     */
+    private static String getKey( String contextId )
+    {
+        String key = HierUtil.Type.PSO.toString();
+        if ( VUtil.isNotNullOrEmpty( contextId ) && !contextId.equalsIgnoreCase( GlobalIds.NULL ) )
+        {
+            key += ":" + contextId;
+        }
+        return key;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/rbac/PwMessage.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/rbac/PwMessage.java b/src/main/java/org/apache/directory/fortress/core/rbac/PwMessage.java
new file mode 100755
index 0000000..e866749
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/rbac/PwMessage.java
@@ -0,0 +1,136 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.fortress.core.rbac;
+
+import java.util.List;
+
+/**
+ * Interface is implemented by {@link org.apache.directory.fortress.core.rbac.Session} and prescribes methods used to return Fortress
+ * password messages to the caller.
+ * <p/>
+
+ *
+ * @author Shawn McKinney
+ */
+public interface PwMessage
+{
+    /**
+     * Return the {@link org.apache.directory.fortress.core.rbac.User#userId} from entity.
+     *
+     * @param userId maps to {@code uid} attribute on inetOrgPerson object class.
+     */
+    public void setUserId(String userId);
+
+    /**
+     * Set the {@link org.apache.directory.fortress.core.rbac.User#userId} in entity.
+     *
+     * @return userId maps to {@code uid} attribute on inetOrgPerson object class.
+     */
+    public String getUserId();
+
+    /**
+     * Contains the message that corresponds to password.  These messages map to {@link GlobalPwMsgIds#pwMsgs}
+     *
+     * @param message
+     */
+    public void setMsg(String message);
+
+    /**
+     * Return the message that corresponds to last password check.
+     *
+     * @return message maps to {@link GlobalPwMsgIds#pwMsgs}
+     */
+    public String getMsg();
+
+    /**
+     * If set to true the user's password check out good.
+     *
+     * @param isAuthenticated
+     */
+    public void setAuthenticated(boolean isAuthenticated);
+
+    /**
+     * If set to true the user's password check out good.
+     *
+     * @return param isAuthenticated
+     */
+    public boolean isAuthenticated();
+
+    /**
+     * Return the warning id that pertain to User's password. This attribute maps to values between 0 and 100 contained within here {@link GlobalPwMsgIds}
+     *
+     * @param warning contains warning id.
+     */
+    public void setWarning(Warning warning);
+    public void setWarnings(List<Warning> warnings);
+    //public void setWarningId(int warning);
+
+
+    /**
+     * Set the warning id that pertain to User's password. This attribute maps to values between 0 and 100 contained within here {@link GlobalPwMsgIds}
+     *
+     * @return warning contains warning id.
+     */
+    public List<Warning> getWarnings();
+    //public int getWarningId();
+
+    /**
+     * Set the error id that pertain to User's password. This attribute maps to values greater than or equal to 100 contained within here {@link GlobalPwMsgIds}
+     *
+     * @param error contains error id that maps to {@link GlobalPwMsgIds#pwIds}
+     */
+    public void setErrorId(int error);
+
+    /**
+     * Return the error id that pertain to User's password. This attribute maps to values greater than or equal to 100 contained within here {@link GlobalPwMsgIds}
+     *
+     * @return error contains error id that maps to {@link GlobalPwMsgIds#pwIds}
+     */
+    public int getErrorId();
+
+    /**
+     * Grace count indicates how many binds User can perform before password slips into expired state.
+     *
+     * @param grace integer containing number of binds allowed for user.
+     */
+    public void setGraceLogins(int grace);
+
+    /**
+     * Get the grace count which indicates how many binds User can perform before password slips into expired state.
+     *
+     * @return grace integer containing number of binds allowed for user.
+     */
+    public int getGraceLogins();
+
+    /**
+     * The number of seconds until the User's password expires.
+     *
+     * @param expire value is computed by ldap server and contains the number of seconds until password will expire.
+     */
+    public void setExpirationSeconds(int expire);
+
+    /**
+     * Get the number of seconds until the User's password expires.
+     *
+     * @return expire value is computed by ldap server and contains the number of seconds until password will expire.
+     */
+    public int getExpirationSeconds();
+}
+