PicketLink 3.0 Alpha1 Released

Posted by    |      

I'm very pleased to announce the first alpha release of PicketLink 3.0. This release is the culmination of many months of effort by the JBoss Security team, with many contributions made from other project teams at JBoss and members of the community. I'd like to thank everyone involved with this release, from those who participated in the many design discussions on the security mailing list over the last few months, to those who contributed code and have started integrating PicketLink into their own projects.

For those who don't know, PicketLink is a CDI-based application security framework for Java EE, much in the same spirit of Seam Security. In fact, PicketLink 3.0 can be considered to be the spiritual successor to Seam Security, as it is more or less based on a similar core design albeit with a much more powerful and flexible identity model and feature set.

Before I go any further, here's the links to the goodies:

PicketLink 3.0.0.Alpha1 Distribution Zip

Reference Documentation * PLEASE NOTE that the reference documentation is still being written, so please be patient with us!

API Documentation

Source Code on GitHub

Report Issues

PicketLink forums

Mailing List

Mailing List Archives

For those of you that use Maven, here's the artifact id's to add to your pom.xml:

<dependency>
  <groupId>org.picketlink</groupId>
  <artifactId>picketlink-core-api</artifactId>
  <version>3.0.0.Alpha1</version>
</dependency>

<dependency>
  <groupId>org.picketlink</groupId>
  <artifactId>picketlink-core-impl</artifactId>
  <version>3.0.0.Alpha1</version>
  <scope>runtime</scope>
</dependency>

<dependency>
  <groupId>org.picketlink</groupId>
  <artifactId>picketlink-idm-api</artifactId>
  <version>3.0.0.Alpha1</version>
</dependency>

<dependency>
  <groupId>org.picketlink</groupId>
  <artifactId>picketlink-idm-impl</artifactId>
  <version>3.0.0.Alpha1</version>
  <scope>runtime</scope>
</dependency>

<!-- Optional database schema when using Identity Management with JPA based Identity Store -->
<dependency>
  <groupId>org.picketlink</groupId>
  <artifactId>picketlink-idm-schema</artifactId>
  <version>3.0.0.Alpha1</version>
  <scope>runtime</scope>
</dependency>

Currently the Maven artifacts are located in the JBoss Maven Repository, however they are planned to be synchronized to Maven Central shortly.

This initial Alpha release primarily concentrates on authentication, authorization and identity management features. Let's take a look at a couple of these features in a little more detail, starting with simple programmatic authentication.

Programmatic authentication

This simple form of authentication should be familiar to many Seam users. To control the authentication process yourself, simply provide a bean in your application that implements the following Authenticator interface:

package org.picketlink.authentication;

import org.picketlink.idm.model.User;

public interface Authenticator {
    public enum AuthenticationStatus {
        SUCCESS, 
        FAILURE, 
        DEFERRED
    }

    void authenticate();

    void postAuthenticate();

    AuthenticationStatus getStatus();

    User getUser();
}

To make things easier, we've provided an abstract base class that's already implemented everything for you except for the authenticate() method. There's only two things you need to do yourself in the authenticate() method; 1) set the authentication status to reflect whether authentication was successful, and 2) set the User object if authentication was successful. In this example, we're going to inject DefaultLoginCredentials (a simple holder bean provided by PicketLink which can be used for traditional username/password authentication) and allow authentication if the provided username is 'jsmith' and the password is '1234':

public class MyAuthenticator extends BaseAuthenticator {
    @Inject DefaultLoginCredentials credentials;

    public void authenticate() {
        if ("jsmith".equals(credentials.getUserId()) && "1234".equals(credentials.getPassword())) {
          setUser(new SimpleUser(credentials.getUserId()));
          setStatus(AuthenticationStatus.SUCCESS);
        } else {
          setStatus(AuthenticationStatus.FAILURE);
        }
    }
}

To actually perform the authentication, simply have your application set the username and password credentials on the DefaultLoginCredentials bean, then invoke the Identity.login() method - you can either do this directly from your view layer, or define a business method in your project that injects the Identity bean and then invokes its login() method. Your Authenticator bean will be found automatically by the authentication process and its authenticate() method invoked to determine whether authentication was successful. An example might look something like this:

public @RequestScoped class LoginAction {

  @Inject DefaultLoginCredentials credentials;
  @Inject Identity identity;
  
  public void login(String username, String password) {
    credentials.setUserId(username);
    credentials.setPassword(password);
    identity.login();
  }
}

Once authenticated, the Identity bean (which by default is session-scoped) can be injected into your application's beans so that you can access the currently authenticated User.

Identity Management

PicketLink's Identity Management (IDM) module provides a formal API for managing the Users, Roles and Groups of your application. Support is provided out of the box for LDAP, Database (via JPA) or File-based identity stores, and an extensible SPI allows for the implementation of additional identity storage backends. The IDM features provided by PicketLink are far too extensive to cover in a single blog post, so let's take a look at a simple example using the JPA identity store. To make things easier we provide a default database schema, included in the picketlink-idm-schema jar file. To make use of this schema, simply add the schema jar file to your project and then add a persistence-unit entry to your project's persistence.xml file, like so:

<persistence-unit name="picketlink-default"
                      transaction-type="JTA">
    <description>PicketLink Persistence Unit</description>
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>

    <class>org.picketlink.idm.jpa.schema.IdentityObject</class>
    <class>org.picketlink.idm.jpa.schema.PartitionObject</class>
    <class>org.picketlink.idm.jpa.schema.RelationshipObject</class>
    <class>org.picketlink.idm.jpa.schema.RelationshipIdentityObject</class>
    <class>org.picketlink.idm.jpa.schema.RelationshipObjectAttribute</class>
    <class>org.picketlink.idm.jpa.schema.IdentityObjectAttribute</class>
    <class>org.picketlink.idm.jpa.schema.CredentialObject</class>
    <class>org.picketlink.idm.jpa.schema.CredentialObjectAttribute</class>

    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
        <property name="hibernate.hbm2ddl.auto" value="create-drop" />
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.format_sql" value="true" />
        <property name="hibernate.transaction.flush_before_completion"
                  value="true" />
    </properties>
</persistence-unit>

The one other thing you must provide is an EntityManager for PicketLink to use, we can do this by writing a CDI producer field - here's an example (make sure the unitName matches the one you've configured in persistence.xml):

public class Resources {
    @SuppressWarnings("unused")
    @Produces
    @PicketLink
    @PersistenceContext(unitName = "picketlink-default")
    private EntityManager picketLinkEntityManager;
}

Once we've done that, we're ready to go! No further configuration is necessary, PicketLink provides an IDM-based Authenticator implementation that is automatically configured if the appropriate entity classes are provided.

The first thing we might want to do is to create some default users for our application. We can do this by providing a @Startup bean - here's an example in which we create a user called 'admin', to which we grant the 'administrator' application role:

@Singleton
@Startup
public class CreateDefaultUser {
    @Inject IdentityManager identityManager;

    @PostConstruct
    public void create() {
        User admin = new SimpleUser("admin");
        admin.setEmail("admin@acme.com");

        this.identityManager.add(admin);
        this.identityManager.updateCredential(admin, new Password("secret"));

        Role roleAdmin = new SimpleRole("administrator");
        this.identityManager.add(roleAdmin);

        identityManager.grantRole(admin, roleAdmin);
    }
}

The IdentityManager bean is the gateway to all of PicketLink's IDM features. It allows you to create, update and delete Users, Groups, Roles and their relationships, plus manage and validate user credentials and attributes. It can be injected into any of your project's beans any time you wish to perform Identity Management related operations.

public class MyApplicationBean {

    @Inject IdentityManager identityManager;   

}

To create a new User, Group or Role, you simply create a new instance of the object (PicketLink provides default implementations called SimpleUser, SimpleGroup and SimpleRole) and pass it to IdentityManager.add():

  User bob = new SimpleUser("bob");
  identityManager.add(bob);
  
  Group managers = new SimpleGroup("managers");
  identityManager.add(managers);
  
  Role admin = new SimpleRole("admin");
  identityManager.add(admin);

To update something, you can first look it up using the appropriate method (such as getUser(), getGroup(), etc), make your changes and then pass the object to the update() method:

  User bob = identityManager.getUser("bob");
  bob.setEmail("bob@acme.com");
  identityManager.update(bob);

To remove something, you pass it to the remove() method:

  User bob = identityManager.getUser("bob");
  identityManager.remove(bob);

Relationships are used to model typed groupings of two or more identities. PicketLink provides a few built-in relationships, and provides support for custom user-defined relationships also. The built-in relationship types are provided to address the most common identity use cases, and the IdentityManager interface declares a number of convenience methods for working with these built-in relationships. Let's take a brief look at a few examples.

Firstly, the Grant relationship is used to represent an application role. This is a role that is typically granted to a user to give them some kind of application-wide privilege. The IdentityManager.grantRole() method is used to grant an application role:

  // Grant user "bob" the "admin" role
  User bob = identityManager.getUser("bob");
  Role admin = identityManager.getRole("admin");
  identityManager.grantRole(bob, admin);

To test whether a user has an application role we use the hasRole() method:

  User bob = identityManager.getUser("bob");
  Role admin = identityManager.getRole("admin");
  boolean bobIsAdmin = identityManager.hasRole(bob, admin);

To revoke an application role, we use revokeRole():

  User bob = identityManager.getUser("bob");
  Role admin = identityManager.getRole("admin");
  identityManager.revokeRole(bob, admin);

Next, the GroupMembership relationship is used to represent a user's membership within a group. The addToGroup() method is used to add a user to a particular group:

  // Add user "bob" to the "managers" group
  User bob = identityManager.getUser("bob");
  Group managers = identityManager.getGroup("managers");
  identityManager.addToGroup(bob, managers);

To test whether a user is a member of a group, we use the isMember() method:

  User bob = identityManager.getUser("bob");
  Group managers = identityManager.getGroup("managers");
  boolean isBobAManager = identityManager.isMember(bob, managers);

Lastly, to remove a member of a group we can use the removeFromGroup() method:

  User bob = identityManager.getUser("bob");
  Group managers = identityManager.getGroup("managers");
  identityManager.removeFromGroup(bob, managers);

The last built-in relationship type is the group role. This is used when we wish to grant a user a particular role for a group, but not make them a member of the group themselves. To grant a group role, we use the grantGroupRole() method:

  // Make user "bob" an admin of the "managers" group
  User bob = identityManager.getUser("bob");
  Role admin = identityManager.getRole("admin");
  Group managers = identityManager.getGroup("managers");
  identityManager.grantGroupRole(bob, admin, managers);

To test whether a user has a particular group role, we use the hasGroupRole() method:

  User bob = identityManager.getUser("bob");
  Role admin = identityManager.getRole("admin");
  Group managers = identityManager.getGroup("managers");
  boolean isBobManagersAdmin = identityManager.hasGroupRole(bob, admin, managers);

Finally, to remove a group role we use the revokeGroupRole() method:

  User bob = identityManager.getUser("bob");
  Role admin = identityManager.getRole("admin");
  Group managers = identityManager.getGroup("managers");
  identityManager.revokeGroupRole(bob, admin, managers);

What's Next

We're aiming to have a beta release ready by mid-March, for which we're planning to have more polished code, more unit tests, better documentation and hopefully an actual example and/or quickstart that you can play around with yourself. For those adventurous enough to take the alpha release for a spin, we would love to hear some feedback from you about what you found easy, what you found hard and what we can do to make things better. For future releases of PicketLink we'll be focusing on adding some really cool features, such as support for OAuth, OpenID, SAML, Rule-based permissions with Drools, a RESTFul API and much more. You can also look forward to some more blog posts that delve further into some of the more complex PicketLink features such as ACL style permissions, identity and relationship queries, plus multi-domain support. If you'd like to leave us some feedback or have questions, please comment below or on the PicketLink forums, or if you'd like to contribute to the development discussion please join the security-dev mailing list, or alternatively catch us on the #picketlink irc channel on FreeNode.

Thanks and enjoy!


Back to top