Using the py-fortress Command Line Interpreter

The Command Line Interpreter (CLI) drives the admin and review APIs,  allowing ad-hoc RBAC setup and interrogation.  More info in the README.

This document also resides here: README-CLI.


Completed the setup described: README-QUICKSTART

Getting Started

The command syntax:

cli entity operation --arg1 --arg2 ... 

Where cli executes a package script that maps to this module:


The entity is (pick one)

(These are source pointers to their locations in github)

The operation is (pick one):

  • add
  • mod
  • del
  • assign
  • deassign
  • grant
  • revoke
  • read
  • search

(These are just meta tags)

Argument Format

Consists of two dashes ‘- -‘ plus the attribute name and value pair, with a space between them.

--attribute_name value

if an attribute value contains white space,  enclose in single ‘ ‘ or double tics ” “.

--attribute_name 'some value' --attribute_name2 "still more values"

For example, a perm grant:

$ cli perm grant --obj_name myobj --op_name add --role 'my role'

This command invokes Python’s runtime with the program name,, followed by an entity type, operation name and multiple name-value pairs.

The above used –role is the only argument that isn’t an entity attribute name.  It’s used on user assign, deassign, perm grant, revoke operations.

Arguments as Lists

For multi-occurring attributes, pass in as a list of string values, separated by whitespace

The following arguments are lists


--phones '+33 401 851 4679' '1-212-251-1111' '(028) 9024 6609'


--mobiles ' 017x-1234567' '+44 020 7234 3456' '1-212-650-9632'


--emails '' '' ''


--props 'name1:value1', 'name2:value2', 'name3:value3'

each value contains a name:value pair

Arguments as Constraint

Both the user and role entity support adding temporal constraint.

The following arguments comprise a single constraint

-name :  label for user, i.e uid

--name foo3

For users, this can be any safe text. For role, it must already be passed in, with the role’s name.

–timeout : 99 – set the integer timeout that contains max time (in minutes) that entity may remain inactive.

--timeout 30

30 minutes
–begin_time :  HHMM – determines begin hour entity may be activated.

--begin_time 0900

9:00 am
— end_time :  HHMM – determines end hour when entity is no longer allowed to activate.

--end_time 2359

11:59 pm
–begin_date : YYYYMMDD – determines date when entity may be activated.

--begin_date 20150101

Jan 1, 2015
–end_date :  YYMMDD – indicates latest date entity may be activated.

--end_date 20191231

Dec 31, 2019
–begin_lock_date :  YYYYMMDD – determines beginning of enforced inactive status

--begin_lock_date 20180602

Jun 2, 2018
–end_lock_date : YYMMDD –  end of enforced inactive status.

--end_lock_date 20180610

Jun 10, 2018
–day_mask : 1234567, 1 = Sunday, 2 = Monday, etc – day of week entity may be activated.

--day_mask 1246

Sun, Mon, Wed, Fri

all together

cli user mod --uid someuser --name anysafetext --timeout 30 --begin_time 0900 --end_time 2359 --begin_date 20150101 --end_date 20191231 --begin_lock_date 20180602 --end_lock_date 20180610 --day_mask 1246
cli role add --name manager --description 'manager works 8-5, M-F' --timeout 10 --begin_time 0800 --end_time 1700 --begin_date 20100101 --end_date none --day_mask 1246

A Few Tips More

  • These commands have a one-to-one mapping to the admin and review APIs.  For example, the perm grant command maps to the admin_mgr.grant function and perm search –uid calls review_mgr.user_perms.
  • The description of the commands, including required arguments, can be inferred via the api doc inline to the admin_mgr and review_mgr modules.
  • The program output echos the inputted arguments and the results.


Two sections,  one each for admin and review commands.  They’re not real-world use cases but include what’s currently working although this code is, how to say it, fresh.  🙂

admin mgr

a. user add

$ cli user add --uid chorowitz --password 'secret' --description 'added with py-fortress cli'
description=added with py-fortress cli
user add

b. user mod

$ cli user mod --uid chorowitz --l my location --ou my-ou --department_number 123
l=my location
user mod

c. user del

$ cli user del --uid chorowitz
user del

d. user assign

$ cli user assign --uid chorowitz --role account-mgr
role name=account-mgr
user assign

e. user deassign

$ cli user deassign --uid chorowitz --role account-mgr
role name=account-mgr
user deassign

f. role add

$ cli role add --name account-mgr
role add

g. role mod

$ cli role mod --name account-mgr --description 'this desc is optional'
description=cli test role
role mod

h. role del

$ cli role del --name account-mgr
role del

i. object add

$ cli object add --obj_name page456
object add

j. object mod

$ cli object mod --obj_name page456 --description 'optional arg' --ou 'another optional arg'
ou=another optional arg
description=optional arg
object mod

k. object del

$ cli object del --obj_name page789
object del

l. perm add

$ cli perm add --obj_name page456 --op_name read
perm add

m. perm mod

$ cli perm mod --obj_name page456 --op_name read --description 'useful for human readable perm name'
description=useful for human readable perm name
perm mod

n. perm del

$ cli perm del --obj_name page456 --op_name search
perm del

o. perm grant

$ cli perm grant --obj_name page456 --op_name update --role account-mgr
role name=account-mgr
perm grant

p. perm revoke

$ cli perm revoke --obj_name page456 --op_name update --role account-mgr
role name=account-mgr
perm revoke

review mgr

a. user read

$ cli user read --uid chorowitz
 user read
 uid: chorowitz
 dn: uid=chorowitz,ou=People,dc=example,dc=com 
 roles: ['account-mgr'] 
 *************** chorowitz *******************

b. user search

 $ cli user search --uid c
 user search
     uid: canders
     dn: uid=canders,ou=People,dc=example,dc=com
     roles: ['csr', 'tester'] 
 *************** c*:0 *******************
     uid: cedwards
     dn: uid=cedwards,ou=People,dc=example,dc=com
     roles: ['manager', 'trainer'] 
 *************** c*:1 *******************
     uid: chandler
     dn: uid=chandler,ou=People,dc=example,dc=com
     roles: ['auditor'] 
 *************** c*:2 *******************
     uid: chorowitz
     dn: uid=chorowitz,ou=People,dc=example,dc=com
     roles: ['account-mgr'] 
 *************** c*:3 ******************* 

c. role read

 $ cli role read --name account-mgr
 role read
 dn: cn=account-mgr,ou=Roles,dc=example,dc=com
 members: ['uid=cli-user2,ou=People,dc=example,dc=com', 'uid=chorowitz,ou=People,dc=example,dc=com']
 internal_id: 5c189235-41b5-4e59-9d80-dfd64d16372c
 name: account-mgr
 constraint: <model.constraint.Constraint object at 0x7fc250bd9e10>
 Role Constraint:
     raw: account-mgr$0$$$$$$$
     timeout: 0 
     name: account-mgr
 *************** account-mgr *******************

d. role search

 $ cli role search --name py-
 role search
     dn: cn=py-role-0,ou=Roles,dc=example,dc=com
     description: py-role-0 Role
     constraint: <model.constraint.Constraint object at 0x7f17e8745f60>
     members: ['uid=py-user-0,ou=People,dc=example,dc=com', 'uid=py-user-1,ou=People,dc=example,dc=com', ... ]
     internal_id: 04b82ce3-974b-4ff5-ad21-b19ecca57722
     name: py-role-0
 *************** py-*:0 *******************
     dn: cn=py-role-1,ou=Roles,dc=example,dc=com
     description: py-role-1 Role
     constraint: <model.constraint.Constraint object at 0x7f17e8733128>
     members: ['uid=py-user-8,ou=People,dc=example,dc=com', 'uid=py-user-9,ou=People,dc=example,dc=com']
     internal_id: 70524da8-3be6-4372-a606-d8175e2ca63b
     name: py-role-1 
 *************** py-*:1 *******************
     dn: cn=py-role-2,ou=Roles,dc=example,dc=com
     description: py-role-2 Role
     constraint: <model.constraint.Constraint object at 0x7f17e87332b0>
     members: ['uid=py-user-3,ou=People,dc=example,dc=com', 'uid=py-user-5,ou=People,dc=example,dc=com', 'uid=py-user-7,ou=People,dc=example,dc=com']
     internal_id: d1b9da70-9302-46c3-b21b-0fc45b863155
     name: py-role-2
 *************** py-*:2 *******************

e. object read

 $ cli object read --obj_name page456
 object read
 description: optional arg
 dn: ftObjNm=page456,ou=Perms,dc=example,dc=com
 internal_id: 1635cb3b-d5e2-4fcb-b61a-b8e91437e536
 obj_name: page456
 ou: another optional arg

f. object search

 $ cli object search --obj_name page
 object search
     obj_name: page456
     description: optional arg
     dn: ftObjNm=page456,ou=Perms,dc=example,dc=com
     ou: another optional arg
     internal_id: 1635cb3b-d5e2-4fcb-b61a-b8e91437e536
     obj_name: page123
     description: optional arg
     dn: ftObjNm=page123,ou=Perms,dc=example,dc=com
     ou: another optional arg
     internal_id: a823ef98-7be4-4f49-a805-83bfef5a0dfb

g. perm read

 $ cli perm read --obj_name page456 --op_name read
 perm read
 internal_id: 0dc55181-968e-4c60-8755-e20fa1ce017d
 dn: ftOpNm=read,ftObjNm=page456,ou=Perms,dc=example,dc=com
 description: useful for human readable perm name
 obj_name: page456
 op_name: read

h. perm search

$ cli perm search --obj_name page
 perm search
     op_name: read
     internal_id: 0dc55181-968e-4c60-8755-e20fa1ce017d
     obj_name: page456
     dn: ftOpNm=read,ftObjNm=page456,ou=Perms,dc=example,dc=com
     description: useful for human readable perm name
     roles: ['account-mgr']
     abstract_name: page456.update
     op_name: update
     internal_id: 626bca86-014b-4186-83a6-a583e39868a1
     obj_name: page456
     dn: ftOpNm=update,ftObjNm=page456,ou=Perms,dc=example,dc=com 
     roles: ['account-mgr']
     abstract_name: page456.delete
     op_name: delete
     internal_id: 6c2fa5fc-d7c3-4e85-ba7f-5e514ca4263f
     obj_name: page456
     dn: ftOpNm=delete,ftObjNm=page456,ou=Perms,dc=example,dc=com

i. perm search (by role)

 $ cli perm search --role account-mgr
 perm search
     abstract_name: page456.update 
     obj_name: page456
     op_name: update
     roles: ['account-mgr']
     dn: ftOpNm=update,ftObjNm=page456,ou=Perms,dc=example,dc=com
     internal_id: 626bca86-014b-4186-83a6-a583e39868a1
     abstract_name: page456.delete
     obj_name: page456
     op_name: delete
     roles: ['account-mgr']
     dn: ftOpNm=delete,ftObjNm=page456,ou=Perms,dc=example,dc=com
     internal_id: 6c2fa5fc-d7c3-4e85-ba7f-5e514ca4263f

j. perm search (by user)

 $ cli perm search --uid chorowitz
 perm search
     dn: ftOpNm=update,ftObjNm=page456,ou=Perms,dc=example,dc=com
     internal_id: 626bca86-014b-4186-83a6-a583e39868a1
     roles: ['account-mgr']
     abstract_name: page456.update
     obj_name: page456
     op_name: update
     dn: ftOpNm=delete,ftObjNm=page456,ou=Perms,dc=example,dc=com
     internal_id: 6c2fa5fc-d7c3-4e85-ba7f-5e514ca4263f
     roles: ['account-mgr']
     abstract_name: page456.delete
     obj_name: page456
     op_name: delete


Next up, Testing the py-fortress RBAC0 System


Introducing a pythonic RBAC API

py-fortress is a Python API implementing Role-Based Access Control level 0 – Core.  It’s still pretty new so there’s going to be some rough edges that will need to be smoothed out in the coming weeks.

To try it out, clone its git repo and use one of the fortress docker images for OpenLDAP or Apache Directory.  The README has the details.

py-fortress git repo

The API is pretty simple to use.

Admin functions work like this

# Add User:
admin_mgr.add_user(User(uid='foo', password='secret'))

# Add Role:

# Assign User:
admin_mgr.assign(User(uid='foo'), Role(name='customer'))

# Add Permission:
admin_mgr.add_perm(Perm(obj_name='shopping-cart', op_name='checkout'))

# Grant:
admin_mgr.grant(Perm(obj_name='shopping-cart', op_name='checkout'),Role(name='customer')) 

Access control functions

# Create Session, False means mandatory password authentication.
session = access_mgr.create_session(User(uid='foo', password='secret'), False)

# Permission check, returns True if allowed:
result = access_mgr.check_access(session, Perm(obj_name='shopping-cart', op_name='checkout'))

# Get all the permissions allowed for user:
perms = access_mgr.session_perms(session)

# Check a role:
result = access_mgr.is_user_in_role(session, Role(name='customer'))

# Get all roles in the session:
roles = access_mgr.session_roles(session)


In addition, there’s the full compliment of review apis as prescribed by RBAC.  If interested, look at the RBAC modules:

Each of the modules have comments that describe the functions, along with their required and optional attributes.

Try it out and let me know what you think.  There will be a release in the near future that will include some additional tooling.  If it takes off, RBAC1 – RBAC3 will follow.


Frequently debated within info sec circles.  Which one of them is better?

Use the right tool for the job as they say. RBAC, like any access control model, has its weaknesses. Many are well understood, even discussed by the original NIST team who framed the model.

Comments on “A Critique of the ANSI Standard on Role-Based Access Control”

However, there are a number of common fallacies wrt how RBAC works.  For example…

1. RBAC is static. It cannot use contextual information e.g. time, user location, device type.

Constraints are commonly applied during user, role and permission activation in RBAC. For example, placing temporal constraints on a role activation. Indeed INCITS 494 prescribes their use:

5.4 RBAC Policy Enhanced Constraints

Enhanced constraints go beyond the INCITS 359 RBAC Standard by including additional types of constraints. Constraints on roles may be static or dynamic. Static constraints are applied off- line before the role is activated by the user. Dynamic constraints are applied on-line after the role(s) are activated. These enhanced dynamic constraints can introduce attributes into the RBAC environment.
INCITS 494-2012, p. 8

2. RBAC cannot perform dynamic segregation-of-duty.

RBAC supports dynamic SoD constraints. From the spec:

5.3.2 Dynamic Separation of Duty Relations

Dynamic Separation of Duty Relations Static separation of duty relations reduce the number of potential permissions that can be made available to a user by placing constraints on the users that can be assigned to a set of roles. Dynamic Separation of duty (DSD) relations, like SSD relations, are intended to limit the permissions that are available to a user. However, DSD relations differ from SSD relations by the context in which these limitations are imposed. SSD relations define and place constraints on a user’s total permission space. This model component defines DSD properties that limit the availability of the permissions over a user’s permission space by placing constraints on the roles that can be activated within or across a user’s sessions.
ANSI INCITS 359-2004, p. 10

3. It relies on custom code within application layers (API, apps, DB…) to implement finer-grained controls.

Presumably what is meant here is that custom code must be written because RBAC controls don’t adequately satisfy security requirements for authorization.

Where are ABAC’s published functional specifications? Where are the standard object (data) and functional (api) model for computing (and storing) its decisions?

Perhaps it is better to use a proven, non-standard ABAC implementation than a custom app widget? If that is what is being said then I agree, but neither are ideal.

ABAC has its place as does RBAC. Knowing when to use one, the other, or both, is important. Understanding the limitations and strengths of each is crucial before adequately addressing the challenges we face as security practitioners.

Apache Fortress Role Engineering Tutorial

Apache Fortress Role Engineering Tutorial

The goals of this tutorial are to

  • Gain understanding of the Role Based Access Control (RBAC) standard
  • Learn the repeatable steps of the Role Engineering Process
  • Learn about using the Apache Fortress RBAC engine

To get started, follow the instructions in the README located on github:

More info here: A Practical Guide to Role Engineering.

What is Delegated Administration?


The ability to control access on the security system itself.  This control is exercised inside the policy administration programs.

In addition to what functions may be executed, we must control which entities to operate on.  A common use case is to allow User X the ability to reset and unlock passwords only for Users within Organization Y.  Another is the administrator may only assign a specific subset of Roles to Users who reside inside their Organization.  Additionally we must also be able to limit an Administrator to a specific subset of Roles in which to Grant to a subset of Permissions.  Indeed every API that changes state inside the back-end security repository must be governed via a well understood delegated administration policy.

Administrative Role-Based Access Control (ARBAC)

Apache Fortress has implemented ARBAC02. [link to paper].  This is a formal model for Delegated Administration and builds on the ANSI RBAC specification.  The control is marshaled into three interfaces:

  1. Delegated Admin Manager – Provides CRUD for related entities like Administrative Roles and Permissions.
  2. Delegated Review Manager – Interrogation of Delegated Admin policy objects.
  3. Delegated Access Manager – Enforcement of Delegated Administration Policies.

1 & 2 are for management of the Delegated Admin policies themselves.  3 is for enforcement of Delegated Admin policies at runtime.

Delegated Admin Policy Enforcement

There are two types of controls:

  1. Ensure that the caller has the permission to call the security administrative method (e.g. addUser, addRole, addPermission,…)
  2. Ensure the caller is entitled to perform the function for a given organization (e.g. which Users and Permissions to grant access rights).

With Fortress, the Delegated Administration control is baked into its APIs.  The enforcement occurs during API invocation which means it can’t be circumvented by poorly implemented administrative programs.

In addition to control, every API invocation leaves an audit trail so you may determine what policies changed, by whom, when and where.

The Seven Steps of Role Engineering


Role Engineering is the process by which an organization develops, defines, enforces, and maintains role-based access control. RBAC is often seen as a way to improve security controls for access and authorization, as well as to enforce access policies such as segregation of duties (SoD) to meet regulatory compliance.  Nov 5, 2014
— Oracle Corporation (Blogs)


Link to slides for a related presentation, A Practical Guide To Role Engineering, JavaOne conference, October 27, 2015.


Link to GitHub project corresponding to this topic: role-engineering-sample


The Role engineering process takes us from a human readable policy syntax to what is loaded into an rbac engine and used by a given application or system.

Here we follow the ANSI RBAC (INCITS 359) spec which prescribes methods like:

This tutorial demonstrates role engineering techniques using standard rbac as applied to a sample set of security use cases.

There is a corresponding github project, written in Java that uses Apache Fortress to show how:


1. Define Security Use Cases for the Application

sample use case:


First we’ll describe the policies in a way humans can understand by writing them down as use cases translated from the diagram.

Use case definitions:

[ legend: red – roles | blue – objects | green – operations ]

use case #1 : User must authenticate before landing on the home page.

Every set of security use cases necessarily contains a logon step.  With rbac, it implies a call to the createSession api, where credentials are checked and roles activated.

use case #2 : User must be a Buyer before placing bid on auction or buying an item.

A role named ‘Buyers’ is granted rights to place bids and purchase auction items.  This use case requires a call to the checkAccess api which we’ll discuss later.

use case #3 : User must be a Seller to create an auction or ship an item purchased.

We add role ‘Sellers’, and grant the authority to create an auction and ship an item that has just been sold.

use case #4 : All Users may create an account and search items.

Another role, named ‘Users’, is granted the rights to create a new account and search a list of items up for auction.  It will be a base role that Buyers and Sellers both extend.

use case #5 : A particular user may be a Buyer, or a Seller, but never both simultaneously.

An interesting scenario to consider.  Perhaps a conflict of interest due to how they collide.  Not to worry, document and move on.

 2. Define the Roles in the App

The use cases must now be converted into entity lists.  Though still human readable, the new data formats are aligned with RBAC.

Create a list of Role names.  Use names pulled from use cases 2, 3, and 4.

Add Roles:

  • role name: “Users” description: “Basic rights for all buyers and sellers”
  • role name: “Buyers” description: “May bid on and purchase items”
  • role name: “Sellers” description: “May setup auctions and ship items”

Buyers and Sellers inherit from Users as described in use case #4.

Add Role Inheritance Relationships

  • child name: “Buyers” parent name: “Users
  • child name: “Sellers” parent name: “Users

Don’t forget the role combination rule in use case #5:

Role Activation Constraint

  • role name: “Buyers
  • role name: “Sellers
  • type: “DYNAMIC
  • cardinality: “2

 3. Define the Resources and Operations

RBAC Permissions are mappings between objects and operations.  Here we list the perms described in use cases 2, 3 and 4.

Add Permissions:

  • object name: “Item” description: “This is a product that is available for purchase”
    • operation name: “search” description: “Search through list of items”
    • operation name: “bid” description: “Place a bid on a given product”
    • operation name: “buy” description: “Purchase a given product”
    • operation name: “ship” description: “Ships a given product after sale”
  • object name: “Auction” description: “Controls a particular online auction”
    • operation name: “create” description: “May start a new auction”
  • object name: “Account” description: “Each user must have one of these”
    • operation name: “create” description: “Ability to setup a new account”

 4. Map the Roles to the Resources and Operations

Get the list of grants.  Again, these mappings naturally derive from the use cases.

Grant Permissions to Roles:

  • role: “Buyers” object name: “Item” oper: “bid
  • role: “Buyers” object name: “Item” oper: “buy
  • role: “Sellers” object name: “Item” oper: “ship
  • role: “Sellers” object name: “Auction” oper: “create
  • role: “Users” object name: “Item” oper: “search
  • role: “Users” object name: “Account” oper: “create

 5. Create the RBAC policy load file

Hand to the analyst, trained in the particulars of the RBAC engine, the entity lists created in steps 2, 3 and 4.  That info will be hand keyed into graphical interface screen, or (better yet) translated to machine readable syntax and loaded automatically by recurrent batch job.

role-engineering-sample-security-policy.xml – download from github.
  <role name="Role_Users" description=“Base Role for Buyers and Sellers"/>
  <role name="Role_Buyers" description="May bid on and purchase products"/>
  <role name="Role_Sellers" description="May start auctions and ship items"/>

  <relationship child="Role_Buyers" parent="Role_Users"/>
  <relationship child="Role_Sellers" parent="Role_Users"/>

  <permgrant objName="SellersPage" opName="link" roleNm="Role_Sellers"/>
  <permgrant objName="BuyersPage" opName="link" roleNm="Role_Buyers"/>
  <permgrant objName="Item" opName="bid" roleNm="Role_Buyers"/>
  <permgrant objName="Item" opName="buy" roleNm="Role_Buyers"/>
  <permgrant objName="Item" opName="ship" roleNm="Role_Sellers"/>
  <permgrant objName="Auction" opName="create" roleNm="Role_Sellers"/>
  <permgrant objName="Item" opName="search" roleNm="Role_Users"/>
  <permgrant objName="Account" opName="create" roleNm="Role_Users"/>

  <sdset name="BuySel" 
         description="Cannot activate both at once."/>

  <permobj objName="Item" description=“..." ou="p1" />
  <permobj objName="Auction" description=“..." ou="p1" />
  <permobj objName="Account" description=“..." ou="p1" />

  <permop objName="Item" opName="bid" description="Bid on a given product"/>
  <permop objName="Item" opName="buy" description="Purchase a given product"/>
  <permop objName="Item" opName="ship" description="Place a product up for sale"/>
  <permop objName="Item" opName="search" description="Search through item list"/>
  <permop objName="Auction" opName="create" description="May start a new auction"/>
  <permop objName="Account" opName="create" description="Ability to add a new account"/>

At the completion of this step, the RBAC policy is loaded into the engine and ready for use.

 6. Add Permission Checks to Application

It’s time to get the developers involved because there will be code that looks (something) like this:

RbacSession session = getSession();
Permission permission = new Permission( "Item", "bid" );
return accessMgr.checkAccess( session, permission );

How to instrument the checks is up to you.  Obviously you won’t hard code the perms.  Observe proper isolation to decouple your app from the details of the underlying security system.  Favor declarative checks over programmatic.  The usual concerns.

A previous post offers ideas, if willing to get dirty hands 🙂

Apache Fortress End-to-End Security Tutorial

 7. Assign Roles to the Users

Before users may access the app, they must be assigned one or more of the corresponding roles.  These relationships may be recorded into the RBAC datastore with a batch script (as below), but often times performed by GUI, e.g. during application enrollment.

Sample user to role assignment policy file
  <userrole userId="johndoe" name="Role_Buyers"/>
  <userrole userId="johndoe" name="Role_Sellers"/>
  <userrole userId="johndoe" name="Super_Users"/>
  <userrole userId="ssmith" name="Role_Buyers"/>
  <userrole userId="rtaylor" name="Role_Sellers"/>

The following diagram depicts the role to role and user to role relationships defined by this policy.

role-role and user-role relationships

role-role and user-role relationships

RBAC Extra Credit

A. What happens when johndoe signs on?

(Will both roles be activated into the RBAC session?)

No, one of the roles must be discarded due to SoD constraint.

begin johndoe logon trace using fortress console
Enter userId:
 name :Sellers
 msg :validate userId [johndoe] failed activation of assignedRole [Sellers] 
 validates DSD Set Name:BuySel Cardinality:2

RBAC allows the caller to select one or more roles during createSession.  So we may call with johndoe passing either of their assigned roles in the argument list.  This process is called selective role activation.  Thus John Doe may be a Buyer during one session and Seller the next, never both at once.

more on createSession:

Session createSession(User user,
                    boolean isTrusted)
                      throws SecurityException

The following attributes may be set when calling this method

B. What if we want to prevent someone from being assigned both roles?

 Use Static Separation of Duties instead

  <sdset name="BuySel" 
         description="Cannot assign both to one user."

What happens now when we try to assign a user both roles?

begin assignUser trace in fortress console
Enter userId:
Enter role name:
ERROR: assignUser failed SSD check, rc=5088
Role [sellers], SSD Set Name [buysel2], Cardinality:2

Remember, constraints applied at role…

  • assignment time: are Static Separation of Duties (SSD)
  • activation time: are Dynamic Separation of Duties (DSD)

C. What perms will a Buyer get?

When a user activates the Buyers role what perms will they have?

begin ssmith perm trace using fortress console
object name [Account]
operation name [create]

object name [Item] 
operation name [search]

object name [Item]
operation name [buy]

object name [Item] 
operation name [bid]

 D. What about a Seller?

When a user activates the Sellers role what perms will they have?

begin rtaylor perm trace using fortress console
object name [Account]
operation name [create]

object name [Item] 
operation name [search] 

object name [Auction] 
operation name [create]
object name [Item]
operation name [ship]

 E. Why do Buyers and Sellers have common perms?

Notice that Buyers and Sellers both have access rights to Account.create and  The reason is both extend a common base role: Users.

F. The above use case is overly simplistic.  Can we do something more realistic?

The Apache Fortress End-to-End Security Tutorial delves into fine-grained access control of data tied to customers.  It demonstrates how to implement a complicated set of requirements, verified with automated selenium test cases.

User to Role Relations in Tutorial

user to role relations in security tutorial

user to role relations in security tutorial

Role to Permission Relations in Tutorial

role to permission relations in security tutorial

role to permission relations in security tutorial

How Much is One Millisecond Worth To You?

For those who don’t keep these kinds of details in their heads a millisecond is 1/1000th of a second.

With respect to security processing what can be done in that time increment – can you perform a fine-grained permission check over the network?  How about logging results into a remote database?

Would you believe me if I told you we can perform both operations within that allotment of time on a modest hardware configuration?  What if I also tried to tell you that over eleven thousand of these requests may be performed a second with the same response time?

Such were the results as documented in this series of benchmarks:


Read more about the accelerator rationale here:


Fortress RBAC Accelerator PDP Benchmark Report

Benchmark Overview

This post provides a summary of a recent benchmark effort for the Fortress RBAC Accelerator.  The RBAC accelerator uses LDAPv3 extended operations to perform the following access control functions:

  1. Create Session – attempts to authenticate client; if successful, initiates an RBAC session by activating one or more user roles
  2. Check Access – determines if user has access rights for a given resource
  3. Add Active Role – attempts activation for a given role into user’s RBAC session
  4. Drop Active Role – deactivates a given role from user’s RBAC session
  5. Delete Session – deletes the given RBAC session from the server
  6. Session Roles – Returns the active roles associated with current session

The result of each of the above functions are persisted to LMDB for audit trail.

Benchmarks performed using a Jmeter test client to drive load for CheckAccess (#2).  The server hosts the OpenLDAP daemon which has the RBAC accelerator overlay.

Client Machine

  • operating system: ubuntu 13.04
  • kernel: 3.8.0-32-generic
  • processor: Intel® Core™ i7-4702MQ CPU @ 2.20GHz × 8
  • memory: 16GB (doesn’t use anywhere close to that)
  • Java version 7

Server Machine

  • operating system: ubuntu 14.04
  • kernel: 3.13.0-32-generic
  • processor: Intel® Core™ i7-4980HQ CPU @ 2.80GHz × 4
  • memory: 8GB
  • OpenLDAP version: 2.4.39

Test Details

  • 25 threads running on client
  • each thread runs checkAccess 50,000 times
  • 1,250,000 total
  • Client CPU load: approximately 50%

Test Results

  • Response time: 1 millisecond
  • Throughput: 11,533 transactions per second
  • Server CPU load: approximately 85%

The Case for a Policy Decision Point inside the LDAP Server

Feature image from:

Why on earth would you do that?

We all understand that runtime characteristics change as processes get moved around the network.  Having problems with network io?  Move the database daemon to the same tier as the client process.  Worried about file io?  Store the data in memory as opposed to disk.  etc…

These same notions apply for system architecture with respect to security.  Location of policy enforcement, decision, and database processes hugely impact the overall welfare of your organization’s computational systems.

With these kinds of thoughts, let’s move the security processes around and see what happens.

But first, we’ll define them:

1. Policy Enforcement Point (PEP)

Invoked by client programs for security policy enforcement.  These gatekeepers are embedded directly into their host thus require platform specific bindings.  The less impact to their host, the better.

2. Database (DB)

Invoked by PDPs to store security credentials, attributes and activity logs.  An important concern is speed; to be used correctly, it’s used often.  Another important concern is reliability; the integrity of its data is mission critical.

3. Policy Decision Point (PDP)

Invoked by PEPs and dependent on a DB.  Responsible for computing:

  • authentication – with passwords or keys
  • authorization – with attributes or permissions
  • audit trail – identify subjects, decisions, time/date/locations, and resources

Three types of PDPs

  • Type 1 – runs in-process to PEP, with out-of-process DB
  • Type 2 – runs out-of-process to PEP, with out-of-process DB
  • Type 3 – runs out-of-process to PEP, with in-process DB

PDP Type 1 (runs in-process to PEP)

The Tomcat JDBC Realm is a Type 1 PDP.  It functions both as PEP and PDP.  Other Type 1’s include Apache Fortress, Shiro and Spring Security.  Most of the open-source security frameworks are this type.  The policy decisions happen synchronously inside the client process.

Type 1 PDP interaction between processes

The PEP and PDP process reside on one tier; the DB process on another.

The PEP and PDP process reside on one tier; the DB process on another.

Benefits of Type 1 PDP

Type 1 PDP advantages
  • simple – only security framework and DB required
  • widely available
  • works well for single deployments of stand-alone apps
Type 1 PDP disadvantages
  • more code exposed to the client (making deployment harder)
  • more load on the client
  • more memory consumed on the client
  • more network io traffic on the client
  • fewer platforms supported (can it run on Java, NET, PHP, Python, and all the others?)

PDP Type 2 (runs out-of-process to PEP and DB)

Here the PDP and DB both run out-of-process to the PEP.  These types of PDPs are more complicated and usually obtained as separate COTS or OSS products.  For example, CA Siteminder, Tivoli Access Manager, Oracle Access Manager, Shibboleth, CAS and many others.

Type 2 PDP interaction between processes

The PEP, PDP and DB processes reside on separate tiers from one another.

The PEP, PDP and DB processes reside on separate tiers from one another.

Benefits of Type 2 PDP

Type 2 PDP advantages
  • less network traffic on client
  • less cpu consumed on client
  • less memory consumed on client
  • less code exposed to client (making deployment simpler)
  • more platforms supported (simple to code PEP ‘shims’ to communicate with centralized PDPs)
Type 2 PDP disadvantages
  • more security processes to maintain due to PEP, PDP and DB all running separately (increasing management burden)
  • poor response time due to extra network hops
  • poor throughput due to PDP reliance on heavyweight communication protocols (xml/json/http)

PDP Type 3 (runs out-of-process to PEP and in-process to DB)

The PDP and DB run in-process and the PEP is out-of-process.  The advantage here is offloading computations from the PEP reducing load and traffic from the client.  It gains speed over the Type 2 because of the embedded database.

Type 3 PDP interaction between processes

The PEP process resides on one tier; the PDP and DB process on another.

The PEP process resides on one tier; the PDP and DB process on another.

Benefits of Type 3 PDP

Type 3 PDP advantages
  • all of Type 2
  • embedded database speed gain
  • embedded database reliability gain
Type 3 PDP disadvantages
  • poor throughput due to reliance on heavyweight communication protocols (xml/json/http)

The Case for a PDP in OpenLDAP

The OpenLDAP RBAC Accelerator is a Type 3 PDP.  It has all the advantages of its type without the disadvantage because using extended LDAP protocols is very efficient.  It runs inside of the OpenLDAP slapd daemon and uses LMDB, which is the fastest embedded, key-value database available, giving a nice turbo boost to read/write speeds.

Now let’s return to the original question:  Why on earth would you do that?

To enable authentication, fine-grained authorization, and audit trail on every platform.  To ease concerns for high cpu, memory, network, and file io consumption.  And to use well understood technologies that can be widely distributed.