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 2018/07/07 02:57:51 UTC

directory-fortress-core git commit: FC-235 - Add support for runtime constraints to be placed on activated roles

Repository: directory-fortress-core
Updated Branches:
  refs/heads/master 53673c634 -> 4405c7216


FC-235 - Add support for runtime constraints to be placed on activated roles


Project: http://git-wip-us.apache.org/repos/asf/directory-fortress-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-fortress-core/commit/4405c721
Tree: http://git-wip-us.apache.org/repos/asf/directory-fortress-core/tree/4405c721
Diff: http://git-wip-us.apache.org/repos/asf/directory-fortress-core/diff/4405c721

Branch: refs/heads/master
Commit: 4405c7216494b7454705c0e98428cf8adfca9aec
Parents: 53673c6
Author: Shawn McKinney <sm...@apache.org>
Authored: Fri Jul 6 04:43:42 2018 -0500
Committer: Shawn McKinney <sm...@apache.org>
Committed: Fri Jul 6 04:43:42 2018 -0500

----------------------------------------------------------------------
 ldap/setup/ConfigNodeUpdate.xml                 |  7 ++
 ldap/setup/TestLocaleConstraints.xml            | 72 ++++++++++++++
 ldap/setup/demo-fortressproject-users.xml       |  6 +-
 ldap/setup/refreshLDAPData-src.xml              |  2 +
 .../directory/fortress/core/GlobalErrIds.java   |  4 +
 .../fortress/core/ant/FortressAntTask.java      | 75 ++++++++++++++-
 .../directory/fortress/core/ant/Updconfig.java  | 99 ++++++++++++++++++++
 .../directory/fortress/core/impl/ConfigDAO.java | 26 ++---
 .../directory/fortress/core/impl/UserP.java     |  7 ++
 .../fortress/core/util/time/Discrimant.java     | 85 +++++++++++++++++
 .../fortress/core/AccessMgrConsole.java         | 40 ++++++--
 .../fortress/core/AdminMgrConsole.java          |  6 +-
 12 files changed, 403 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/4405c721/ldap/setup/ConfigNodeUpdate.xml
----------------------------------------------------------------------
diff --git a/ldap/setup/ConfigNodeUpdate.xml b/ldap/setup/ConfigNodeUpdate.xml
index c050ba1..7a1a1a4 100644
--- a/ldap/setup/ConfigNodeUpdate.xml
+++ b/ldap/setup/ConfigNodeUpdate.xml
@@ -30,6 +30,13 @@
                 <config props="pwpolicy.root:ou=Policies,dc=example,dc=com"/>
             </addconfig>
 
+            <updconfig>
+                <!-- To update existing config node with new props specify config.realm name: -->
+                <config props="config.realm:DEFAULT"/>
+                <config props="newname:newvalue"/>
+            </updconfig>
+
+
             <addconfig>
                 <config props="config.realm:TOMCAT"/>
                 <config props="authn.type:realm"/>

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/4405c721/ldap/setup/TestLocaleConstraints.xml
----------------------------------------------------------------------
diff --git a/ldap/setup/TestLocaleConstraints.xml b/ldap/setup/TestLocaleConstraints.xml
new file mode 100644
index 0000000..a461483
--- /dev/null
+++ b/ldap/setup/TestLocaleConstraints.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+-->
+<project basedir="." default="all" name="Fortress Sample Data">
+    <taskdef classname="org.apache.directory.fortress.core.ant.FortressAntTask" name="FortressAdmin" >
+        <classpath path="${java.class.path}"/>
+    </taskdef>
+
+    <target name="all">
+        <FortressAdmin>
+
+            <updconfig>
+                <config props="config.realm:DEFAULT"/>
+                <!-- if role name matches this props's name, that role may only be activated
+                 when the user has a matching property.  That constraint will be passed in user.getPropName(value).
+                 constraint name must match user's property for that role -->
+                <config props="oamrole1:locale"/>
+                <config props="oamrole2:locale"/>
+                <config props="oamrole3:locale"/>
+            </updconfig>
+
+            <adduser>
+                <user userId="curly"
+                      description="Test Location Constraint on User Role Assignments"
+                      ou="foo"
+                      userProps="oamrole1:locale1$oamrole2:locale3$oamrole3:locale2" />
+
+                <user userId="moe"
+                      description="Test Location Constraint on User Role Assignments"
+                      ou="foo"
+                      userProps="oamrole2:locale1" />
+
+                <user userId="larry"
+                      description="Test Location Constraint on User Role Assignments"
+                      ou="foo"
+                      userProps="oamrole3:locale3" />
+            </adduser>
+
+            <adduserrole>
+                <userrole userId="curly" name="oamrole1"/>
+                <userrole userId="curly" name="oamrole2"/>
+                <userrole userId="curly" name="oamrole3"/>
+                <userrole userId="curly" name="oamrole4"/>
+                <userrole userId="curly" name="oamrole5"/>
+                <userrole userId="curly" name="oamrole6"/>
+                <userrole userId="moe"   name="oamrole2"/>
+                <userrole userId="larry" name="oamrole3"/>
+            </adduserrole>
+
+            <addorgunit>
+                <orgunit name="foo" typeName="USER" description="Test Locale Constraints"/>
+            </addorgunit>
+
+        </FortressAdmin>
+    </target>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/4405c721/ldap/setup/demo-fortressproject-users.xml
----------------------------------------------------------------------
diff --git a/ldap/setup/demo-fortressproject-users.xml b/ldap/setup/demo-fortressproject-users.xml
index 056fa64..6bf480a 100644
--- a/ldap/setup/demo-fortressproject-users.xml
+++ b/ldap/setup/demo-fortressproject-users.xml
@@ -43,9 +43,9 @@
             </deluser>
 
             <adduser>
-                <user userId="user1" password="password" description="Wicket Fortress Project Demo User1" ou="WicketUsers" cn="test1" sn="user1"  pwPolicy="Test1" beginTime="0000" endTime="0000" beginDate="20090101" endDate="20990101" beginLockDate="none" endLockDate="none" dayMask="1234567" timeout="0" userProps="fortressdemo1:ROLE_TEST1,ROLE_TEST_SUPER" photo="p27.jpeg" />
-                <user userId="user2" password="password" description="Wicket Fortress Project Demo User1" ou="WicketUsers" cn="test2" sn="user2"  pwPolicy="Test1" beginTime="0000" endTime="0000" beginDate="20090101" endDate="20990101" beginLockDate="none" endLockDate="none" dayMask="1234567" timeout="0" userProps="fortressdemo1:ROLE_TEST2,ROLE_TEST_USER" photo="p20.jpeg"/>
-                <user userId="user3" password="password" description="Wicket Fortress Project Demo User1" ou="WicketUsers" cn="test3" sn="user3"  pwPolicy="Test1" beginTime="0000" endTime="0000" beginDate="20090101" endDate="20990101" beginLockDate="none" endLockDate="none" dayMask="1234567" timeout="0" userProps="fortressdemo1:ROLE_TEST3,ROLE_TEST_USER" photo="p28.jpeg"/>
+                <user userId="user1" password="password" description="Wicket Fortress Project Demo User1" ou="WicketUsers" cn="test1" sn="user1"  pwPolicy="Test1" beginTime="0000" endTime="0000" beginDate="20090101" endDate="20990101" beginLockDate="none" endLockDate="none" dayMask="1234567" timeout="0" userProps="fortressdemo1:ROLE_TEST1$ROLE_TEST_SUPER" photo="p27.jpeg" />
+                <user userId="user2" password="password" description="Wicket Fortress Project Demo User1" ou="WicketUsers" cn="test2" sn="user2"  pwPolicy="Test1" beginTime="0000" endTime="0000" beginDate="20090101" endDate="20990101" beginLockDate="none" endLockDate="none" dayMask="1234567" timeout="0" userProps="fortressdemo1:ROLE_TEST2$ROLE_TEST_USER" photo="p20.jpeg"/>
+                <user userId="user3" password="password" description="Wicket Fortress Project Demo User1" ou="WicketUsers" cn="test3" sn="user3"  pwPolicy="Test1" beginTime="0000" endTime="0000" beginDate="20090101" endDate="20990101" beginLockDate="none" endLockDate="none" dayMask="1234567" timeout="0" userProps="fortressdemo1:ROLE_TEST3$ROLE_TEST_USER" photo="p28.jpeg"/>
             </adduser>
 
             <deluserrole>

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/4405c721/ldap/setup/refreshLDAPData-src.xml
----------------------------------------------------------------------
diff --git a/ldap/setup/refreshLDAPData-src.xml b/ldap/setup/refreshLDAPData-src.xml
index cdbfc89..6dc934d 100755
--- a/ldap/setup/refreshLDAPData-src.xml
+++ b/ldap/setup/refreshLDAPData-src.xml
@@ -95,6 +95,7 @@
                 <config props="temporal.validator.2:org.apache.directory.fortress.core.util.time.Timeout"/>
                 <config props="temporal.validator.3:org.apache.directory.fortress.core.util.time.ClockTime"/>
                 <config props="temporal.validator.4:org.apache.directory.fortress.core.util.time.Day"/>
+                <config props="temporal.validator.5:org.apache.directory.fortress.core.util.time.Discrimant"/>
                 <config props="temporal.validator.dsd:org.apache.directory.fortress.core.impl.DSDChecker"/>
                 <config props="user.objectclass:inetOrgPerson"/>
                 <config props="group.objectclass:@GROUP_OBJECT_CLASS@"/>
@@ -164,6 +165,7 @@
                 <config props="temporal.validator.2:org.apache.directory.fortress.core.util.time.Timeout"/>
                 <config props="temporal.validator.3:org.apache.directory.fortress.core.util.time.ClockTime"/>
                 <config props="temporal.validator.4:org.apache.directory.fortress.core.util.time.Day"/>
+                <config props="temporal.validator.5:org.apache.directory.fortress.core.util.time.Discrimant"/>
                 <config props="temporal.validator.dsd:org.apache.directory.fortress.core.impl.DSDChecker"/>
                 <config props="accessmgr.implementation:org.apache.directory.fortress.core.impl.AccessMgrImpl"/>
                 <config props="auditmgr.implementation:org.apache.directory.fortress.core.impl.AuditMgrImpl"/>

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/4405c721/src/main/java/org/apache/directory/fortress/core/GlobalErrIds.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/GlobalErrIds.java b/src/main/java/org/apache/directory/fortress/core/GlobalErrIds.java
index 8f5621c..84b5bfc 100755
--- a/src/main/java/org/apache/directory/fortress/core/GlobalErrIds.java
+++ b/src/main/java/org/apache/directory/fortress/core/GlobalErrIds.java
@@ -500,6 +500,10 @@ public final class GlobalErrIds
     public static final int ACTV_FAILED_AUTHN = 2056;
 
     /**
+     * Entity activation failed dynamic constraint.
+     */
+    public static final int ACTV_DYNAMIC_RUNTIME = 2057;
+    /**
      * 3000's - Permission Entity
      */
 

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/4405c721/src/main/java/org/apache/directory/fortress/core/ant/FortressAntTask.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/ant/FortressAntTask.java b/src/main/java/org/apache/directory/fortress/core/ant/FortressAntTask.java
index 49e7f13..86e232e 100755
--- a/src/main/java/org/apache/directory/fortress/core/ant/FortressAntTask.java
+++ b/src/main/java/org/apache/directory/fortress/core/ant/FortressAntTask.java
@@ -263,6 +263,7 @@ public class FortressAntTask extends Task implements InputHandler
         "debug.admin" ).equalsIgnoreCase( "true" ) ) );
     private static final String SEMICOLON = ";";
     private final List<Addconfig> addconfig = new ArrayList<>();
+    private final List<Updconfig> updconfig = new ArrayList<>();
     private final List<Delconfig> delconfig = new ArrayList<>();
     private final List<Adduser> addusers = new ArrayList<>();
     private final List<Deluser> delusers = new ArrayList<>();
@@ -414,6 +415,17 @@ public class FortressAntTask extends Task implements InputHandler
     /**
      * Load the entity with data.
      *
+     * @param updcfg contains the ant initialized data entities to be handed off for further processing.
+     */
+    public void addUpdconfig( Updconfig updcfg )
+    {
+        this.updconfig.add( updcfg );
+    }
+
+
+    /**
+     * Load the entity with data.
+     *
      * @param delcfg contains the ant initialized data entities to be handed off for further processing.
      */
     public void addDelconfig( Delconfig delcfg )
@@ -910,6 +922,7 @@ public class FortressAntTask extends Task implements InputHandler
         addSuffixes();
         addContainers();
         addConfig();
+        updConfig();
         addOrgunits();
         addUserOrgunitInheritances();
         addPermOrgunitInheritances();
@@ -2403,7 +2416,7 @@ public class FortressAntTask extends Task implements InputHandler
 
 
     /**
-     * @throws BuildException An error occurred while building
+     * Add a new configuration node and its associated property values into the directory.
      */
     private void addConfig() throws BuildException
     {
@@ -2461,6 +2474,66 @@ public class FortressAntTask extends Task implements InputHandler
 
 
     /**
+     * Update existing configuration node with new values.
+     */
+    private void updConfig() throws BuildException
+    {
+        if( updconfig == null )
+        {
+            return;
+        }
+
+        Properties props = new Properties();
+        String configNodeName = "";
+        // Loop through the entityclass elements
+        for ( Updconfig updcfg : updconfig )
+        {
+            List<ConfigAnt> cfgs = updcfg.getConfig();
+            for ( ConfigAnt cfg : cfgs )
+            {
+                LOG.info( "updateConfig" );
+                String val = cfg.getProps();
+                int indx = val.indexOf( GlobalIds.PROP_SEP );
+                if ( indx >= 1 )
+                {
+                    String name = val.substring( 0, indx );
+                    String value = val.substring( indx + 1 );
+
+                    // The config realm property is required on updconfig op and points to the existing node in ldap to update with these new props.
+                    if( name.equalsIgnoreCase( GlobalIds.CONFIG_REALM ))
+                    {
+                        configNodeName = value;
+                    }
+                    else
+                    {
+                        props.setProperty( name, value );
+                    }
+                }
+            }
+            // Can't go on w/out a name for the config node to update.
+            if ( StringUtils.isEmpty( configNodeName ))
+            {
+                LOG.warn( "updConfig realm name not specified, operation aborted." );
+                LOG.warn( "Add entry like this  to input xml: <config props=\"config.realm:DEFAULT\"/>" );
+            }
+            else
+            {
+                try
+                {
+                    LOG.info( "updateConfig realm name [{}]", configNodeName );
+                    cfgMgr.update( configNodeName, props );
+                }
+                catch ( SecurityException se )
+                {
+                    LOG.warn( "updConfig realm name={} failed SecurityException={}", configNodeName, se );
+                    LOG.warn( "Verify that config realm name={} exists", configNodeName);
+                }
+            }
+        }
+    }
+
+
+    /**
      * @throws BuildException An error occurred while building
      */
     private void deleteConfig() throws BuildException

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/4405c721/src/main/java/org/apache/directory/fortress/core/ant/Updconfig.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/ant/Updconfig.java b/src/main/java/org/apache/directory/fortress/core/ant/Updconfig.java
new file mode 100644
index 0000000..b964306
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/ant/Updconfig.java
@@ -0,0 +1,99 @@
+/*
+ *   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.ant;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The class is used by {@link FortressAntTask} to update an existing config node.
+ * It calls {@link org.apache.directory.fortress.core.ConfigMgr#update(String, java.util.Properties)}.
+ * It is not intended to be callable by programs outside of the Ant load utility.  The class name itself maps to the xml tag
+ * used by load utility.
+ * <p>
+ * This class name, 'Updconfig', is used for the xml tag in the load script.
+ * <pre>
+ * {@code
+ * <target name="all">
+ *     <FortressAdmin>
+ *         <updconfig>
+ *           ...
+ *         </updconfig>
+ *     </FortressAdmin>
+ * </target>
+ * }
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Updconfig
+{
+    final private List<ConfigAnt> config = new ArrayList<>();
+
+    /**
+     * All Ant data entities must have a default constructor.
+     */
+    public Updconfig()
+    {
+    }
+
+    /**
+     * This method name, 'addConfig', is used for derived xml tag 'config' in the load script.
+     * <pre>
+     * {@code
+     * <updconfig>
+     *     <config props="config.realm:DEFAULT"/>
+     *     <config props="enable.audit:true"/>
+     *     <config props="authn.type:default"/>
+     *     <config props="password.policy:openldap"/>
+     *     <config props="clientside.sorting:true"/>
+     *     <config props="suffix:dc=jts\,dc=com"/>
+     *     <config props="user.root:ou=People\,dc=jts\,dc=com"/>
+     *     <config props="pwpolicy.root:ou=Policies\,dc=jts\,dc=com"/>
+     *     <config props="role.root:ou=Roles\,ou=RBAC\,dc=jts\,dc=com"/>
+     *     <config props="perm.root:ou=Permissions\,ou=RBAC\,dc=jts\,dc=com"/>
+     *     <config props="sdconstraint.root:ou=Constraints\,ou=RBAC\,dc=jts\,dc=com"/>
+     *     <config props="userou.root:ou=OS-U\,ou=ARBAC\,dc=jts\,dc=com"/>
+     *     <config props="permou.root:ou=OS-P\,ou=ARBAC\,dc=jts\,dc=com"/>
+     *     <config props="adminrole.root:ou=AdminRoles\,ou=ARBAC\,dc=jts\,dc=com"/>
+     *     <config props="adminperm.root:ou=AdminPerms\,ou=ARBAC\,dc=jts\,dc=com"/>
+     *     ...
+     * </updconfig>
+     * }
+     * </pre>
+     *
+     * @param config contains reference to data element targeted for insertion..
+     */
+    public void addConfig(ConfigAnt config)
+    {
+        this.config.add(config);
+    }
+
+    /**
+     * Used by {@link FortressAntTask#addConfig()} to retrieve list of properties as defined in input xml file.
+     *
+     * @return collection containing {@link ConfigAnt}s targeted for insertion.
+     */
+    public List<ConfigAnt> getConfig()
+    {
+        return this.config;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/4405c721/src/main/java/org/apache/directory/fortress/core/impl/ConfigDAO.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/impl/ConfigDAO.java b/src/main/java/org/apache/directory/fortress/core/impl/ConfigDAO.java
index fec9d2a..275689e 100755
--- a/src/main/java/org/apache/directory/fortress/core/impl/ConfigDAO.java
+++ b/src/main/java/org/apache/directory/fortress/core/impl/ConfigDAO.java
@@ -98,8 +98,6 @@ final class ConfigDAO extends LdapDataProvider
             SchemaConstants.CN_AT, GlobalIds.PROPS
     };
 
-    public static final String GID_SEQ = "ftGidSequence";
-    public static final String UID_SEQ = "ftUidSequence";
 
     /**
      * Package private default constructor.
@@ -113,8 +111,9 @@ final class ConfigDAO extends LdapDataProvider
 
 
     /**
-     * @param name
-     * @param props
+     * Create a new configuration node and load it with properties.
+     * @param name of the new configuration node to be created in ldap.
+     * @param props each name/value pair becomes an ftprop in this entry.
      * @return
      * @throws org.apache.directory.fortress.core.CreateException
      */
@@ -131,8 +130,6 @@ final class ConfigDAO extends LdapDataProvider
             ld = getAdminConnection();
             myEntry.add( SchemaConstants.CN_AT, name );
             loadProperties( props, myEntry, GlobalIds.PROPS );
-            //myEntry.add( GID_SEQ, "" + 0 );
-            //myEntry.add( UID_SEQ, "" + 0 );
             add( ld, myEntry );
         }
         catch ( LdapEntryAlreadyExistsException e )
@@ -157,8 +154,9 @@ final class ConfigDAO extends LdapDataProvider
 
 
     /**
-     * @param name
-     * @param props
+     * Update existing node with new properties.
+     * @param name contains existing config node name
+     * @param props each property name value will loaded into an attribute (ftprops) under the config node.
      * @return
      * @throws org.apache.directory.fortress.core.UpdateException
      */
@@ -173,7 +171,7 @@ final class ConfigDAO extends LdapDataProvider
             List<Modification> mods = new ArrayList<Modification>();
             if ( PropUtil.isNotEmpty( props ) )
             {
-                loadProperties( props, mods, GlobalIds.PROPS, true );
+                loadProperties( props, mods, GlobalIds.PROPS, false );
             }
             ld = getAdminConnection();
             if ( mods.size() > 0 )
@@ -184,7 +182,7 @@ final class ConfigDAO extends LdapDataProvider
         }
         catch ( LdapException e )
         {
-            String error = "update dn [" + dn + "] caught LDAPException=" + e.getMessage();
+            String error = "update dn [" + dn + "] caught LDAPException=" + e;
             throw new UpdateException( GlobalErrIds.FT_CONFIG_UPDATE_FAILED, error, e );
         }
         finally
@@ -232,7 +230,8 @@ final class ConfigDAO extends LdapDataProvider
 
 
     /**
-     * @param name
+     * Remove the configuration node from the directory.
+     * @param name of the node to be removed.
      * @throws org.apache.directory.fortress.core.RemoveException
      */
     void remove( String name )
@@ -259,8 +258,9 @@ final class ConfigDAO extends LdapDataProvider
 
 
     /**
-     * @param name
-     * @param props
+     * A set of properties from a configuration node.
+     * @param name the name of config node.
+     * @param props each name/value will be a ftprop attribute to remove.
      * @return
      * @throws org.apache.directory.fortress.core.UpdateException
      */

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/4405c721/src/main/java/org/apache/directory/fortress/core/impl/UserP.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/impl/UserP.java b/src/main/java/org/apache/directory/fortress/core/impl/UserP.java
index de49972..175f44f 100755
--- a/src/main/java/org/apache/directory/fortress/core/impl/UserP.java
+++ b/src/main/java/org/apache/directory/fortress/core/impl/UserP.java
@@ -44,6 +44,7 @@ import org.apache.directory.fortress.core.model.Session;
 import org.apache.directory.fortress.core.model.User;
 import org.apache.directory.fortress.core.model.UserAdminRole;
 import org.apache.directory.fortress.core.model.UserRole;
+import org.apache.directory.fortress.core.util.Config;
 import org.apache.directory.fortress.core.util.VUtil;
 
 import org.slf4j.Logger;
@@ -512,6 +513,12 @@ final class UserP
                 }
             }
         }
+        // Did the caller pass in a set of dynamic constraints as properties?
+        if ( user.getProps() != null )
+        {
+            session.getUser().addProperties( user.getProperties() );
+        }
+
         // Check role temporal constraints + activate roles:
         VUtil.getInstance().validateConstraints( session, VUtil.ConstraintType.ROLE, true );
         return session;

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/4405c721/src/main/java/org/apache/directory/fortress/core/util/time/Discrimant.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/util/time/Discrimant.java b/src/main/java/org/apache/directory/fortress/core/util/time/Discrimant.java
new file mode 100644
index 0000000..c2f9f79
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/util/time/Discrimant.java
@@ -0,0 +1,85 @@
+/*
+ *   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.util.time;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.directory.fortress.core.GlobalErrIds;
+import org.apache.directory.fortress.core.model.Constraint;
+import org.apache.directory.fortress.core.model.Session;
+import org.apache.directory.fortress.core.util.Config;
+import org.apache.directory.fortress.core.util.VUtil;
+
+/**
+ * This class performs dynamic constraint validation on role per FC-235
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Discrimant
+    implements Validator
+{
+    /**
+     * This method is called during entity activation, {@link org.apache.directory.fortress.core.util.VUtil#validateConstraints} and ensures role has a
+     * matching constraint value.
+     *
+     * @param session    required for {@link Validator} interface but not used here.
+     * @param constraint only the name is used on this validator.
+     * @param time       contains the current time stamp which is not needed here.
+     * @param type       here it is used as this validator should not be applied to a user.
+     * @return '0' if validation succeeds else {@link org.apache.directory.fortress.core.GlobalErrIds#ACTV_DYNAMIC_RUNTIME} if failed.
+     */
+    @Override
+    public int validate(Session session, Constraint constraint, Time time, VUtil.ConstraintType type )
+    {
+        int rc = 0;
+
+        // Doesn't make sense to apply this constraint on a user:
+        if ( type != VUtil.ConstraintType.USER )
+        {
+            String constraintType = Config.getInstance().getProperty( constraint.getName() );
+            // Is there a runtime constraint placed on this role activation?
+            if ( StringUtils.isNotEmpty( constraintType ))
+            {
+                // Get the value for the constraint set by the caller:
+                String userProp = session.getUser().getProperty( constraint.getName() );
+
+                // Does the user object have a property that is associated with the runtime constraint set by the caller on this particular role?
+                if ( StringUtils.isNotEmpty( userProp ) )
+                {
+                    // The constraint is passed by caller in a property with keyName located in the constraintType for the role.
+                    //String constraintValue = user.getProperty( constraintType );
+                    String constraintValue = session.getUser().getProperty( constraintType );
+
+                    // Is the activated role's constraint valid per the constraint value passed in by the caller?  (Is the role allowed here)
+                    if ( !userProp.equalsIgnoreCase( constraintValue ) )
+                    {
+                        rc = GlobalErrIds.ACTV_DYNAMIC_RUNTIME;
+                    }
+                }
+                else
+                {
+                    // No, there is no constraint value on a role that requires one.
+                    rc = GlobalErrIds.ACTV_DYNAMIC_RUNTIME;
+                }
+            }
+        }
+        return rc;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/4405c721/src/test/java/org/apache/directory/fortress/core/AccessMgrConsole.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/directory/fortress/core/AccessMgrConsole.java b/src/test/java/org/apache/directory/fortress/core/AccessMgrConsole.java
index a2a9132..329b9a0 100755
--- a/src/test/java/org/apache/directory/fortress/core/AccessMgrConsole.java
+++ b/src/test/java/org/apache/directory/fortress/core/AccessMgrConsole.java
@@ -19,11 +19,17 @@
  */
 package org.apache.directory.fortress.core;
 
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+import org.apache.directory.fortress.core.model.Permission;
+import org.apache.directory.fortress.core.model.Session;
+import org.apache.directory.fortress.core.model.User;
+import org.apache.directory.fortress.core.model.UserAdminRole;
+import org.apache.directory.fortress.core.model.UserRole;
 import org.apache.directory.fortress.core.impl.TestUtils;
-import org.apache.directory.fortress.core.model.*;
-
-import java.util.*;
-
 import org.apache.directory.fortress.core.util.VUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -163,7 +169,9 @@ class AccessMgrConsole
             String userId = ReaderUtil.readLn();
             System.out.println("Enter password:");
             String password = ReaderUtil.readLn();
-            session = am.createSession(new User(userId, password), false);
+            User inUser = new User(userId, password);
+            getRuntimeConstraint( inUser );
+            session = am.createSession(inUser, false);
             System.out.println("Session created successfully for userId [" + userId + "]");
             System.out.println("session [" + session + "]");
             System.out.println("ENTER to continue");
@@ -175,6 +183,7 @@ class AccessMgrConsole
         ReaderUtil.readChar();
     }
 
+
     void createSessionTrusted()
     {
         try
@@ -182,7 +191,9 @@ class AccessMgrConsole
             ReaderUtil.clearScreen();
             System.out.println("Enter userId:");
             String userId = ReaderUtil.readLn();
-            session = am.createSession(new User(userId), true);
+            User inUser = new User(userId);
+            getRuntimeConstraint( inUser );
+            session = am.createSession(inUser, true);
             System.out.println("Trusted Session created successfully for userId [" + userId + "]");
             System.out.println("session [" + session + "]");
             System.out.println("ENTER to continue");
@@ -194,6 +205,23 @@ class AccessMgrConsole
         ReaderUtil.readChar();
     }
 
+
+    private void getRuntimeConstraint(User user)
+    {
+        System.out.println("Do you want to set a runtime constrait on user role activation? - Y or NULL to skip");
+        String choice = ReaderUtil.readLn();
+        if (choice != null && choice.equalsIgnoreCase("Y"))
+        {
+            System.out.println("Enter constraint type):");
+            String key = ReaderUtil.readLn();
+            System.out.println("Enter constraint value):");
+            String value = ReaderUtil.readLn();
+            Properties props = new Properties(  );
+            props.setProperty( key, value );
+            user.addProperties( props );
+        }
+    }
+
     /**
      *
      */

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/4405c721/src/test/java/org/apache/directory/fortress/core/AdminMgrConsole.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/directory/fortress/core/AdminMgrConsole.java b/src/test/java/org/apache/directory/fortress/core/AdminMgrConsole.java
index 63a7a4d..5b33658 100755
--- a/src/test/java/org/apache/directory/fortress/core/AdminMgrConsole.java
+++ b/src/test/java/org/apache/directory/fortress/core/AdminMgrConsole.java
@@ -343,14 +343,14 @@ class AdminMgrConsole
             System.out.println("Enter organization unit, blank for default");
             ue.setOu(ReaderUtil.readLn());
 
-            System.out.println("Do you want to set temporal constraints on User - Y or N");
+            System.out.println("Do you want to set temporal constraints on User - Y or NULL to skip");
             String choice = ReaderUtil.readLn();
             if (choice != null && choice.equalsIgnoreCase("Y"))
             {
                 enterTemporal(ue);
             }
 
-            System.out.println("Do you want to set posix account attributes on User - Y or N");
+            System.out.println("Do you want to set posix account attributes on User - Y or NULL to skip");
             choice = ReaderUtil.readLn();
             if (choice != null && choice.equalsIgnoreCase("Y"))
             {
@@ -365,7 +365,7 @@ class AdminMgrConsole
                 userRole.setName(val);
                 userRole.setUserId( ue.getUserId() );
                 ue.setRole(userRole);
-                System.out.println("Do you want to set temporal constraints on User - Y or N");
+                System.out.println("Do you want to set temporal constraints on User - Y or NULL to skip");
                 choice = ReaderUtil.readLn();
                 if (choice != null && choice.equalsIgnoreCase("Y"))
                 {