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.

Secure Web Apps with JavaEE and Apache Fortress

ApacheCon is just a couple months away — coming up May 16-18 in Miami. We asked Shawn McKinney, Software Architect at Symas Corporation,  to share some details about his talk at ApacheCon. His presentation — “The Anatomy of a Secure Web Application Using Java EE, Spring Security, and Apache Fortress” will focus on an end-to-end application security architecture for an Apache Wicket Web app running in Tomcat. McKinney explains more in this interview.

Source: Secure Web Apps with JavaEE and Apache Fortress

Project Link: Apache Fortress Demo Project

On the Essential Question of Identity

For years I’ve been on record proclaiming that identity centralization is good and synchronization is bad.  I reasoned it is better to re-engineer processes to share identities than to distribute and fragment them.

I still believe this to be true.  However I have come to realize that centralization of identities will not happen — during our lifetimes.  The reasons are numerous, obvious, and beyond the scope of this post.

Where does this leave us on the essential question, i.e. how do we maintain identities now they must be distributed across the known universe?

The answer to this question will included within a series of blog posts.  Stay tuned…


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.

What Are Temporal Constraints?


Ability to control when an entity activation occurs based on time and date criteria.  Temporal constraints are typically applied during User and Role activation as part of an authentication or authorization check.

What Are They For?

Can be used to limit when a User may log onto or activate a particular Role within a security domain.  Follows the principle of least privilege as it ensures access rights are only granted when appropriate.

How Do They Work?

There may be policies to control what dates, times, and days of week a User may access a particular area of the system and in what Role.  Can also be used to enforce a lockout period when the User is inactive or otherwise away for an extended period of time.

Apache Fortress Temporal Constraints

Fortress allows constraints to be applied onto both User and Role entities.  There are rules that fire during an activation event (any policy enforcement API call):

  1. Can the entity be active on this Date?
  2. Is the entity within a lockout period?
  3. Has the entity exceeded a particular inactive period?
  4. Can the entity be used at this time?
  5. Can the entity be used on this day?
  6. Are there mutual exclusion constraints that prevent activating this entity?  (Roles Only)

These temporal constraint rules are pluggable and may be added, overridden or removed.

What are Password Policies?


A set of rules surrounding the content, quality and lifecycle of a password.

What Are They For?

Helps to safeguard the integrity of password values within a particular security domain.  With moves toward Multi-Factor Authentication (MFA) and other biometric authentication measures one can make the argument that the password’s days are numbered.  Nevertheless they remain in use widely today and will continue for the foreseeable future.

How Do They Work?

Define a set of rules to be enforced during a password lifecycle event.  An example of a lifecycle event is authentication, password change and password expiration.  There are a few standards that govern how systems should behave in this area.

IETF Password Policies

Apache Fortress adheres to IETF Password Policy Draft.  While this draft was never formally adopted it has traction within the various directory implementations and remains the de facto standard today.

Password Policy Enforcement

Password enforcement options include:

  1. A configurable limit on failed authentication attempts.
  2. A counter to track the number of failed authentication attempts.
  3. A time frame in which the limit of consecutive failed authentication attempts must happen before action is taken.
  4. The action to be taken when the limit is reached. The action will either be nothing, or the account will be locked.
  5. An amount of time the account is locked (if it is to be locked) This can be indefinite.
  6. Password expiration.
  7. Expiration warning
  8. Grace authentications
  9. Password history
  10. Password minimum age
  11. Password minimum length
  12. Password Change after Reset
  13. Safe Modification of Password
  14. Password Policy for LDAP Directories

Enabling Java EE and Fortress Security inside an Apache Wicket Web App

JavaDukeJammingfortress100    Wicket-Image


The aim of this tutorial is to demonstrate how a simple wicket web app can be converted to use java EE and fortress security.  It’s not intended to highlight all of the possible locations in code where security checks may be applied.  For that take a look at The Apache Fortress End-to-End Security Tutorial.

Course Prerequisites

Before starting, you need a working fortress environment up and running.  Complete one of the following:

 Steps to Enable Security in Wicket Sample

1. Download the fortress wicket-sample project

a. extract the zip

b. follow the instructions in

You may now hit the sample web app:


no security

no security

This is the view you will see when clicking on link for Page1.  Despite what it says about rbac perms, it’s an example of an app that’s not secured.  Users are not required to logon and may navigate freely.

To enable security for this app, continue on…

The following instructions are duplicated by:

2. Add the Java EE security required artifacts

If you are using the wicket-sample source, this is already done.  It includes wicket components, (plus associated markup files LoginPage.html, LogoutPage.html), and the static html files under the /login folder.  These files control the flow between the container and wicket with java EE security enabled.

java EE login page

java EE login page

more on java EE security

Declarative style of security, one with no api calls made by programmer (during logon).  This makes java EE security both error resistant and hardened to attack, though it tends to get in the way of the page flows.  We’ll cover this topic, in more detail, on a future post.

3. Edit the pom.xml

Prepare maven for fortress.

a. Uncomment the fortress web dependency at the top of the file.

 <!-- TODO STEP 3: uncomment for fortress security dependency: -->

b. Uncomment the maven ant task near the bottom of the file.

This plugin calls the fortress load procedure during normal maven tasks like install or deploy.  The fortress load inserts the app’s security policy into ldap.  It can be overridden by passing param -Dnoload which tells the plugin not to execute.

     <target name="fortress-load"
       description="Loads wicket sample security policy into ldap">

At the completion of this step, the necessary binaries will be available to the app and the app’s security policy file will be ready to load.

4. Edit the web.xml

Prepare the app for fortress.

a. Uncomment the spring settings.

 <!-- TODO STEP 4a: uncomment to enable fortress spring bean injection: -->


Notice that we’re including a link to a spring context file: applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
  <bean id="accessMgr" 
    <constructor-arg value="HOME"/>

  <bean id="j2eePolicyMgr" 

The context file holds the metadata necessary to wire the fortress objects in with their constructors and subsequently get injected into the web app as spring beans.

b. Uncomment the java ee security constraints from web.xml:

 <!-- TODO STEP 4b: uncomment to enable Java EE Security: -->

Now container security has been enabled for this web app.  It authenticates, checks roles and maintains the session.

The wicket logout page is excluded from java EE security constraints.  Otherwise, a problem occurs preventing unauthorized users from logging out.

   <!-- OMIT auth-constraint -->

5. Rename context.xml.example to context.xml

Prepare the app for the fortress realm.

<Context reloadable="true">
 <Realm className=""

This file hooks a web app into the tomcat fortress realm which performs security functions like authenticate and isUserInRole. It’s also where the security session gets created by fortress.

more on the realm

The fortress realm’s proxy jar must be present under tomcat’s lib folder (as discussed in the quickstarts).

The proxy jar is a shim that uses a URLClassLoader to reach its implementation libs.  The proxy prevents the realm impl libs, pulled in as dependency to web app, from interfering with the container’s system classpath thus providing an error free deployment process free from classloader issues.  The proxy offers the flexibility for each web app to determine its own version/type of security realm to use, satisfying a variety of requirements related to web hosting and multitenancy.

6. Rename to

Prepare fortress for either apacheds or openldap server usage.

Pick One:

a. ApacheDS

# This param tells fortress what type of ldap server in use:

# ldap host:

# ldap port:

# These credentials are used for read/write access to all nodes under suffix:

# This is min/max settings for LDAP administrator pool connections that have read/write access to all nodes under suffix:

# This node contains fortress properties stored on behalf of connecting LDAP clients:

# Used by application security components:

# Fortress uses a cache:

b. OpenLDAP

# This param tells fortress what type of ldap server in use:

# ldap host:

# openldap default port:

# These credentials are used for read/write access to all nodes under suffix:

# This is min/max settings for LDAP administrator pool connections that have read/write access to all nodes under suffix:

# This node contains fortress properties stored on behalf of connecting LDAP clients:

# Used by application security components:

# Fortress uses a cache:

7. Edit

Tell wicket about fortress sessions and objects.

a. Uncomment fortress session override.

Here we override app’s wicket session with a new one that can hold onto fortress session and perms:

 // TODO STEP 7a: uncomment save fortress session to wicket session:
 public Session newSession(Request request, Response response)
   return new WicketSession(request);

b. Uncomment fortress spring bean injector.

Next we tell the app to use spring to inject references to fortress security objects:

 // TODO STEP 7b: uncomment to enable injection of fortress spring beans:
 getComponentInstantiationListeners().add(new SpringComponentInjector(this));

These steps are necessary to get fortress runtime wired into the sample app.

8. Edit

Get fortress objects injected to the wicket base page, enable fortress secured page links.

a. Uncomment fortress spring bean injection.

This step automatically instantiates the fortress objects needed for security processing.

 // TODO STEP 8a: enable spring injection of fortress bean here:
 private AccessMgr accessMgr;

 private J2eePolicyMgr j2eePolicyMgr;

These objects are used by the app to make AccessMgr calls to functions like checkAccess and sessionPermissions.

b. Uncomment call to enableFortress.

This performs the boilerplate security functions required by fortress during app session startup:

 // TODO STEP 8b: uncomment call to enableFortress:
      this, ( HttpServletRequest ) getRequest().getContainerRequest(), 
      j2eePolicyMgr, accessMgr );
 catch ( se)

c. Change to FtBookmarkablePageLink

The advantage here is other than a name change, everything else stays the same, and now the links are secured.

 // TODO STEP 8c: change to FtBookmarkablePageLink:
 add( new FtBookmarkablePageLink( "", Page1.class ) );
 add( new FtBookmarkablePageLink( "", Page2.class ) );
 add( new FtBookmarkablePageLink( "", Page3.class ) );

This component maps a page link to a fortress permission.  The wicket id passed in, e.g., is converted to a fortress permission, objName: page1, opName: link.

9. Edit,,

Enable fortress secured buttons.  Each page has three buttons.  Same as before, only the name changes.

a – i. change the button class name to FtIndicatingAjaxButton:

 // TODO STEP 9a: change to FtIndicatingAjaxButton:
 add( new FtIndicatingAjaxButton( "page1.button1" )

This component maps the buttons to fortress permissions.  The wicket id, e.g. page1.button1, is converted to a fortress permission, objName: page1, opName: button1.

10. Build & Deploy Web App

Deploy to tomcat server:

mvn clean tomcat:deploy -Dload.file

Or if already deployed:

mvn clean tomcat:redeploy -Dload.file

The -Dload.file system parameter tells maven to load the wicket sample security policy into ldap in addition to deploying the app.  Since the load needs to happen just once, you may drop it from future invocations:

mvn tomcat:redeploy

We’re done with setup.  Now onto testing…

Testing the Sample App Security Policy

The wicket-sample security policy is loaded automatically during maven deployment step.  The file:  wicket-sample-security-policy.xml

How to create an rbac policy was covered recently:

The Seven Steps of Role Engineering

The diagram below depicts the wicket sample role hierarchy and its user to role assignments:

sample security policy

sample security policy

  • wsBaseRole is inherited by all other roles
  • wsSuperUsers inherits wsUsers1Role, wsUsers2Role and wsUsers3Role
  • wsUser1 is assigned wsUsers1Role and has access to buttons on Page1
  • wsUser2 is assigned wsUsers2Role and can hit buttons on Page2
  • wsUser3 is assigned wsUsers3Role and has buttons on Page3
  • wsSuperUser is assigned wsSuperUser role has all pages and all buttons

Use Cases for Testing

a. wssuperuser/password

Receives links for Page1, Page2 and Page3.

wsSuperUser launch page

wsSuperUser launch page

b. wsuser1/password

Receives a page link for Page1.  May only view and click on Page1’s buttons.

wsUser1 launch page

wsUser1 launch page

c. wsuser2/password

Receives link for Page2.  May only view and click on Page2’s buttons.

wsUser2 launch page

wsUser2 launch page

d. wsuser3/password

Receives link for Page3.  May only view and click on Page3’s buttons.

wsUser3 launch page

wsUser3 launch page

More on sample security policy

As stated in the beginning, the sample wicket security controls are not comprehensive.  For example, a user may navigate by manually entering page urls thus sidestepping the secured page link component.  In this scenario the user will be prevented from clicking on buttons unless otherwise authorized.  Still, allowing users to navigate to unauthorized pages is a bad practice.  The Apache Fortress End-to-End Security Tutorial uses spring security controls to lock down pages.  There are many other ways – how would you do it?