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>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="entry" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="key" type="{http://www.w3.org/2001/XMLSchema}anyType" minOccurs="0"/>
+ * <element name="value" type="{http://www.w3.org/2001/XMLSchema}anyType" minOccurs="0"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </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>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="key" type="{http://www.w3.org/2001/XMLSchema}anyType" minOccurs="0"/>
+ * <element name="value" type="{http://www.w3.org/2001/XMLSchema}anyType" minOccurs="0"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </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();
+}
+