Demonstrate how to fix RBAC role explosion with ABAC inside Apache Wicket Web app using Apache Fortress
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
images
src
.gitignore
LICENSE
README.md
UNLICENSE
pom.xml

README.md

Overview of the fortress-abac-demo README


Table of Contents

  • SECTION 1. Prerequisites
  • SECTION 2. Prepare Tomcat for Java EE Security
  • SECTION 3. Prepare package
  • SECTION 4. Prepare Tomcat for Java EE Security
  • SECTION 5. Build and deploy sample
  • SECTION 6. Understand the security policy
  • SECTION 7. Manually Test the sample
  • SECTION 8. Automatically Test the sample (using Selenium)
  • SECTION 9. Under the Hood (Learn how it works here)

SECTION I. Prerequisites

  1. Java 8
  2. Apache Maven 3++
  3. Apache Tomcat 7++
  4. Basic LDAP server setup by completing either Quickstart

SECTION II. Prepare Tomcat for Java EE Security

This sample web app uses Java EE security.

1. Download the fortress realm proxy jar into tomcat/lib folder:

wget http://repo.maven.apache.org/maven2/org/apache/directory/fortress/fortress-realm-proxy/2.0.2/fortress-realm-proxy-2.0.2.jar -P $TOMCAT_HOME/lib
  • Where $TOMCAT_HOME points to the execution env.

Note: The realm proxy enables Tomcat container-managed security functions to call back to fortress.

2. Optional - Prepare tomcat to allow autodeploy of fortress-abac-demo web app:

sudo vi /usr/local/tomcat8/conf/tomcat-users.xml

3. Optional - Add tomcat user to deploy fortress-abac-demo:

<role rolename="manager-script"/>
<user username="tcmanager" password="m@nager123" roles="manager-script"/>

4. Restart tomcat for new settings to take effect.


SECTION III. Prepare package

1. Stage the project.

a. Download and extract from Github:

wget https://github.com/shawnmckinney/fortress-abac-demo/archive/master.zip

-- Or --

b. Or git clone locally:

git clone https://github.com/shawnmckinney/fortress-abac-demo.git

2. Change directory into it:

cd fortress-abac-demo

3. Enable an LDAP server:

a. Copy the example:

cp src/main/resources/fortress.properties.example src/main/resources/fortress.properties

b. Edit the file:

vi src/main/resources/fortress.properties

Pick either Apache Directory or OpenLDAP server:

c. Prepare fortress for ApacheDS usage:

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

# Use value from [Set Hostname Entry]:
host=localhost

# ApacheDS defaults to this:
port=10389

# These credentials are used for read/write access to all nodes under suffix:
admin.user=uid=admin,ou=system
admin.pw=secret

-- Or --

d. Prepare fortress for OpenLDAP usage:

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

# Use value from [Set Hostname Entry]:
host=localhost

# OpenLDAP defaults to this:
port=389

# These credentials are used for read/write access to all nodes under suffix:
admin.user=cn=Manager,dc=example,dc=com
admin.pw=secret

SECTION IV. Prepare Tomcat for Java EE Security

This sample web app uses Java EE security.

1. Download the fortress realm proxy jar into tomcat/lib folder:

wget http://repo.maven.apache.org/maven2/org/apache/directory/fortress/fortress-realm-proxy/2.0.2/fortress-realm-proxy-2.0.2.jar -P $TOMCAT_HOME/lib

where TOMCAT_HOME matches your target env.

2. Prepare tomcat to allow autodeploy of fortress-abac-demo web app:

sudo vi /usr/local/tomcat8/conf/tomcat-users.xml

3. Add tomcat user to deploy role-engineering-sample:

<role rolename="manager-script"/>
<role rolename="manager-gui"/>
<user username="tcmanager" password="m@nager123" roles="manager-script"/>

4. Restart tomcat for new settings to take effect.

Note: The proxy is a shim that uses a URLClassLoader to reach its implementation libs. It 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.


SECTION V. Build and deploy sample

1. Verify the java and maven home env variables are set.

mvn -version

This sample requires Java 8 and Maven 3 to be setup within the execution env.

2. Build the sample and load test data:

mvn install -Dload.file

Build Notes:

  • -Dload.file automatically loads the fortress-abac-demo-load-policy.xml data into ldap.
  • This load needs to happen just once for the default test cases to work and may be dropped from future mvn commands.

3. Deploy the sample to Tomcat:

a. If using autodeploy feature, verify the Tomcat auto-deploy options are set correctly in the pom.xml file:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>tomcat-maven-plugin</artifactId>
    <version>1.0-beta-1</version>
    <configuration>
    ...
        <url>http://localhost:8080/manager/text</url>
        <path>/${project.artifactId}</path>
        <username>tcmanager</username>
        <password>m@nager123</password>
    </configuration>
</plugin>

b. Now, automatically deploy to tomcat server:

mvn clean tomcat:deploy

c. To automatically redeploy sample app:

mvn clean tomcat:redeploy

d. To manually deploy app to Tomcat:

cp target/fortress-abac-demo.war $TOMCAT_HOME/webapps
  • Where $TOMCAT_HOME points to the execution env.

SECTION VI. Understand the security policy

To gain full understanding, check out the file used to load it into the LDAP directory: fortress-abac-demo-load-policy.xml.

1. User-to-Role Assignment Table

For this app, user-to-role assignments are:

user Page1 Page2 Page3
poweruser true true true
user123 true true true
user456 true true true
user789 true true true
user1 true false false
user1_123 true false false
user1_456 false true false
user1_789 false false true
user2 false true false
user2_123 true false false
user2_456 false true false
user2_789 false false true
user3 false false true
user3_123 true false false
user3_456 false true false
user3_789 false false true

2. User-to-Role Activation Table by Branch

But we want to control role activation using attributes based on Customer number:

user Page1 Page2 Page3
poweruser 123,456,789 123,456,789 123,456,789
user123 123 123 123
user456 456 456 456
user789 789 789 789
user1 123,456,789
user1_123 123
user1_456 456
user1_789 789
user2 123,456,789
user2_123 123
user2_456 456
user2_789 789
user3 123,456,789
user3_123 123
user3_456 456
user3_789 789

SECTION VII. Manually Test the sample

1. Open link to http://localhost:8080/fortress-abac-demo

2. Login with Java EE authentication form:

3. User-Password Table

Password = 'password' for all:

userId Password
------------- -------------
user1 password
user1_123 password
user1_456 password
user1_789 password
user2 password
user3 password
... password

4. Click on a page link.

5. Enter a customer number for user and click on the button.

Enter 123, 456, or 789

Image1

6. Once the location is set, buttons appear simulating user access for that particular customer.

Image2

7. Try a different user.

Each has different access rights to application based on their constraints.

SECTION VII. Automatically Test the sample

  • Work-in-progress....

Run the selenium automated test:

mvn test -Dtest=X

Selenium Test Notes:

  • This test will log in as each user, perform positive and negative test cases.
  • Requires Firefox on target machine.

SECTION VIII. Under the Hood

How does this work? Have a look at some code...

Paraphrased from MyBasePage.java:

Every time a constraint is activated, some code executes like this....

// Nothing new here:
 User user = new User(userId);

 // This is new:
 RoleConstraint constraint = new RoleConstraint( );

 // In practice we're not gonna pass hard-coded key-values in here, but you get the idea:
 constraint.setKey( "customer" );
 constraint.setValue( "123" );

 // This is just boilerplate goop:
 List<RoleConstraint> constraints = new ArrayList();
 constraints.add( constraint );

 try
 {
     // Now, create the RBAC session with an ABAC constraint, customer=123, asserted:
     Session session = accessMgr.createSession( user, constraints );
     ...
 }

Pushing the customer attribute into the User's RBAC session the runtime will match that instance data with their stored policy.

Image4

Notice that this user has been assigned Page1, Page2 and Page3 roles, via ftRA attribute, and that another attribute, ftRC, constrains which customer it can be activated.

How the ABAC algorithm works:

  • When the runtime iterates over assigned roles (ftRA), trying to activate them one-by-one, it matches the constraint pushed in, e.g. customer=123, with its associated role constraint (ftRC).
  • If it finds a match, the role can be activated into the session, otherwise not.

When does it get executed:

One more thing:

  • ABAC constraints work with any kind of instance data, e.g. account, organization, etc. Let your imagination set the boundaries.