For my current project I was faced with an application requiring only parts of a security framework
- Users are externally managed by an Active Directory server
- Only two application roles exists but more could be used in future
- Permissions are not used yet but might be handy to aovid hard-coding an implicit security model
In addition we have a tight schedule (was there ever any project without a tight schedule?!) which rules out any complicated solutions and/or steep learning curve so I was left puzzled how to proceed from here. Just thinking of writing the simplest possible security framework is too painful - can be called a futile exercise or a waste of time (depending on your temper & mood). I vaguely remembered the old days of the Turbine Security Service which offers a simple solution for my modest requirements but using Apache Turbine is soo old-style for my younger colleagues. After checking Google for a couple of hours I came across PicketLink.
1. Introducing PicketLink
PicketLink describes itself as Simplified Security and Identity management for Java Applications. Reading quickly through the PicketLink Overview and additional documentation revealed interesting features
- PicketLink is a set of libraries and not a server installation (e.g. compared to Apache Syncope)
- There is plenty of documentation but I’m quite frankly overwhelmed by most of it
- It supports JDBC and JPA Persistence in addition to LDAP
- It has a lot of bells and whistles we probably never need but it could make management happy
- The core libraries are not pulling in an insane amount of dependencies therefore integration into an existing code base looks feasible
- Last but not least it ships with a FileIdentityStore to be used for testing and prototyping
- And yes, it has a business-friendy ASL 2.0 licence
In my case having a FileIdentityStore is an important feature
- It allows to execute tests without having a database around
- Using file based storage allows a step-wise integration without tinkering with JPA persistence context, Flyway migrations and deployment scripts.
- And if everything works out we have a clear migration path to the JPAIdentityStore
2. Core Identity Model
PicketLink ships with the usual suspects (aka Identity Management Objects or IDM) such as
- Realm
- Group
- Roles
- Permission
- User
- Agent
In addition to that there are some nifty details
- Support of nested groups gives you additional flexibility in modeling real-world organizations
- Each of the Identity Management Objects (e.g. realm, group, role) supports a collection of name/value pairs ** The values are actually of type Serializable and mapped to some encoded VARCHAR in the database ** Please note that Oracle only supports 4.000 character for VARCHAR2
- Permissions can be assigned to all Identity Management Objects catering for a hierarchical permissions computation
A simplified API using the out-of-the-box Identity Management Objects is exposed as the so-called BasicModel.
3. The First Steps
Writing unit tests to explore features of a new piece of software is a good habit - this time I had the following goals
- Setup a FileIdentityStore with a handful of IDM instances and store it on disk
- Load the FileIdentityStore and used the BaiscModel to access the IDM instances
The code can be found at https://github.com/sgoeschl/picketlink-demo.
3.1 Requires Libraries
Maven Dependencies
The following POM snippet was pulling in PicketLink and convenience libraries for testing
</project>
<properties>
<junit.version>4.11</junit.version>
<picketlink.version>2.7.0.CR1</picketlink.version>
</properties>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-impl</artifactId>
<version>${picketlink.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.1.3.GA</version>
</dependency>
<!-- Testing dependencies -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</project>
I also double-checked the transitive dependencies which are pulling in about 700 KB of libraries
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ demo ---
[INFO] org.github.sgoeschl.picketlink:demo:pom:0.0.1-SNAPSHOT
[INFO] +- org.picketlink:picketlink-idm-impl:jar:2.7.0.CR1:compile
[INFO] | +- org.picketlink:picketlink-common:jar:2.7.0.CR1:compile
[INFO] | \- org.picketlink:picketlink-idm-api:jar:2.7.0.CR1:compile
[INFO] +- org.jboss.logging:jboss-logging:jar:3.1.3.GA:compile
3.2 Setting Up A File Identity Store
PicketLinke provides tow flavors of setting up a FileIdentityStore
- Fluent API in your code
- XML configuration file
Fluent API
The coding approach pretty much looks like this
IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
builder
.named(file-store-preserve-state)
.stores()
.file()
.preserveState(true)
.workingDirectory(directory.getAbsolutePath())
.supportAllFeatures();
The preserveState allows you to enforce a read-only store
XML Configuration
Using the XML configuration approach requires an additional the library (picketlink-config)
public List<IdentityConfiguration> buildFromFile(String configFilePath) {
ClassLoader tcl = Thread.currentThread().getContextClassLoader();
InputStream configStream = tcl.getResourceAsStream(configFilePath);
XMLConfigurationProvider xmlConfigurationProvider = new XMLConfigurationProvider();
IdentityConfigurationBuilder idmConfigBuilder = xmlConfigurationProvider.readIDMConfiguration(configStream);
assertNotNull(idmConfigBuilder);
return idmConfigBuilder.buildAll();
}
and an XML configuration file loaded from the class path
<PicketLink xmlns=***urn:picketlink:identity-federation:config:2.1***>
<PicketLinkIDM>
<named value=***SIMPLE_FILE_STORE_CONFIG***>
<stores>
<file>
<preserveState value=***true*** />
<supportGlobalRelationship value=***org.picketlink.idm.model.Relationship*** />
<supportAllFeatures />
</file>
</stores>
</named>
</PicketLinkIDM>
</PicketLink>
3.2 FileIdentyStore & Permissions
Initially I used picketlink-2.6.1.Final since I’m currently running an older JBoss EA server but it turned out that storing permissions is supported beginning with version 2.7.0.CR1 whereas the latest version is 2.7.0.CR3.
4. Integrating PicketLink
4.1 Technical Integration
The following options are available
- JDBCIdentityStore
- FileIdentityStore is the choice for unit testing
- JPAIdentityStore requires CDI support (which does a lot of JPA wiring in the background)
4.2 Domain Integration
Technically there are two options to integrate PicketLink into my current project
- Provide a service facade & some DTOs which uses the Core IDM Objects and BasicModel underneath. Assuming that the DTOs will require a lot of additional attributes those attributes will be persisted as a collection of name/value pairs.
- Extend the Core IDM Objects to cater for the additional attributes.
Extending the Core IDM Objects is supported by PicketLink but looks too complicated for the moment so we will try the first option.
JPA Integration
TODO
5. Conclusion
After playing with PicketLink for two evenings I think it looks good. I’m well aware the security and identity management are a vast topics but for now I have simple requirements.