JBoss.orgCommunity Documentation

PicketLink Reference Documentation

Version 2.5.2.Final


Table of Contents

1. Overview
1.1. What is PicketLink?
1.2. Where do I get started?
1.2.1. QuickStarts
1.2.2. API Documentation
1.3. Modules
1.3.1. Base module
1.3.2. Identity Management
1.3.3. Federation
1.4. License
1.5. Maven Dependencies
1.6. PicketLink Installer
1.7. Help us improve the docs!
2. Authentication
2.1. Overview
2.2. Authentication API - the Identity bean
2.3. The Authentication Process
2.3.1. A Basic Authenticator
2.3.2. Multiple Authenticator Support
2.3.3. Credentials
2.3.4. DefaultLoginCredentials
3. Identity Management - Overview
3.1. Introduction
3.1.1. Injecting the Identity Management Objects
3.1.2. Interacting with PicketLink IDM During Application Startup
3.1.3. Configuring the Default Partition
3.2. Getting Started - The 5 Minute Guide
3.3. Identity Model
3.3.1. Which Identity Model Should My Application Use?
3.4. Creating a Custom Identity Model
3.4.1. The @AttributeProperty Annotation
3.4.2. The @Unique Annotation
3.5. Creating Custom Relationships
3.6. Partition Management
3.6.1. Creating Custom Partitions
4. Identity Management - Credential Validation and Management
4.1. Authentication
4.2. Managing Credentials
4.3. Credential Handlers
4.3.1. The CredentialStore interface
4.4. Built-in Credential Handlers
4.4.1. Username/Password-based Credential Handler
4.4.2. DIGEST-based Credential Handler
4.4.3. X509-based Credential Handler
4.4.4. Time-based One Time Password Credential Handler
4.5. Credentials for Custom Account Types
5. Identity Management - Basic Identity Model
5.1. Basic Identity Model
5.1.1. Utility Class for the Basic Identity Model
5.2. Managing Users, Groups and Roles
5.2.1. Managing Users
5.2.2. Managing Groups
5.3. Managing Relationships
5.3.1. Built In Relationship Types
5.4. Realms and Tiers
6. Identity Management - Configuration
6.1. Configuration
6.1.1. Architectural Overview
6.1.2. Default Configuration
6.1.3. Providing a Custom Configuration
6.1.4. Programmatic Configuration Overview
6.1.5. Providing Multiple Configurations
6.1.6. Providing Multiple Stores for a Configuration
6.1.7. Configuring Credential Handlers
6.1.8. Identity Context Configuration
6.1.9. IDM configuration from XML file
7. Identity Management - Working with JPA
7.1. JPAIdentityStoreConfiguration
7.1.1. Default Database Schema
7.1.2. Configuring an EntityManager
7.1.3. Mapping IdentityType Types
7.1.4. Mapping Partition Types
7.1.5. Mapping Relationship Types
7.1.6. Mapping Attributes for AttributedType Types
7.1.7. Mapping a CredentialStorage type
7.1.8. Configuring the Mapped Entities
7.1.9. Providing a EntityManager
8. Identity Management - Working with LDAP
8.1. LDAPIdentityStoreConfiguration
8.1.1. Configuration
9. PicketLink Subsystem
9.1. Overview
9.2. Installation and Configuration
9.3. Configuring the PicketLink Dependencies for your Deployment
9.4. Domain Model
9.5. Identity Management
9.5.1. JPAIdentityStore
9.5.2. Usage Examples
9.6. Federation
9.6.1. The Federation concept (Circle of Trust)
9.6.2. Federation Domain Model
9.6.3. Usage Examples
9.6.4. Metrics and Statistics
9.7. Management Capabilities
10. Federation
10.1. Overview
10.2. SAML SSO
10.3. SAML Web Browser Profile
10.4. PicketLink SAML Specification Support
10.5. SAML v2.0
10.5.1. Which Profiles are supported ?
10.5.2. Which Bindings are supported ?
10.5.3. PicketLink Identity Provider (PIDP)
10.5.4. PicketLink Service Provider (PSP)
10.5.5. SAML Authenticators (Tomcat,JBossAS)
10.5.6. Digital Signatures in SAML Assertions
10.5.7. SAML2 Handlers
10.5.8. Single Logout
10.5.9. SAML2 Configuration Providers
10.5.10. Metadata Support
10.5.11. Token Registry
10.5.12. Standalone vs JBossAS Distribution
10.5.13. Standalone Web Applications(All Servlet Containers)
10.6. SAML v1.1
10.6.1. SAML v1.1
10.6.2. PicketLink SAML v1.1 Support
10.7. Trust
10.7.1. Security Token Server (STS)
10.8. Extensions
10.8.1. Extensions
10.8.2. PicketLinkAuthenticator
10.9. PicketLink API
10.9.1. Working with SAML Assertions
10.10. 3rd party integration
10.10.1. Picketlink as IDP, Salesforce as SP
10.10.2. Picketlink as SP, Salesforce as IDP
10.10.3. Picketlink as IDP, Google Apps as SP
11. PicketLink Quickstarts
11.1. Overview
11.2. Available Quickstarts
11.3. PicketLink Federation Quickstarts
11.4. Contributing
Glossary

List of Figures

10.1. TODO InformalFigure image title empty
10.2. TODO InformalFigure image title empty
10.3. TODO InformalFigure image title empty
10.4. TODO Gliffy image title empty
10.5. TODO InformalFigure image title empty
10.6. TODO InformalFigure image title empty
10.7. TODO InformalFigure image title empty
10.8. TODO InformalFigure image title empty
10.9. TODO InformalFigure image title empty
10.10. TODO InformalFigure image title empty
10.11. TODO InformalFigure image title empty

List of Tables

3.1. Identity Management Objects
4.1. Built-in credential types
4.2. Configuration Parameters
4.3. Configuration Parameters
7.1. IdentityType Annotations
7.2. Partition Annotations
7.3. Relationship Annotations
7.4. Partition Annotations
7.5. Partition Annotations
8.1. LDAP Configuration Options

List of Examples

7.1. Example
7.2. Example
7.3. Example
7.4. Example
7.5. Example
7.6. Example
10.1. context.xml
10.2. context.xml
10.3. context.xml
10.4. context.xml
10.5. context.xml
10.6. WEB-INF/picketlink-handlers.xml
10.7. WEB-INF/picketlink-handlers.xml
10.8. WEB-INF/picketlink-handlers.xml
10.9. WEB-INF/picketlink-handlers.xml
10.10. WEB-INF/picketlink-handlers.xml
10.11. WEB-INF/picketlink-handlers.xml
10.12. WEB-INF/picketlink-handlers.xml
10.13. WEB-INF/picketlink-handlers.xml
10.14. web.xml
10.15. web.xml
10.16. jsp/login.jsp
10.17. jsp/error.jsp
10.18. STSWSClientTestCase.java
10.19. handlers.xml

Depending on exactly which PicketLink features you'd like to use, getting started can be as simple as adding the PicketLink jar libraries to your project (see Section 1.5, “Maven Dependencies” below for more info) and writing a few lines of code. To get started using PicketLink Identity Management to manage the users and other identity objects in your application, you can head straight to Section 3.2, “Getting Started - The 5 Minute Guide”. If you don't wish to use PicketLink IDM but would like to use PicketLink for authentication in your Java EE application but control the authentication process yourself then head to Section 2.3.1, “A Basic Authenticator” for simplistic example which you may adapt for your own application. If you wish to use SAML SSO then you can head to Chapter 10, Federation.

Here's some additional resources also to help you get started:

Please head to Chapter 11, PicketLink Quickstarts for more information about our quickstarts, covering some useful usecases and most of PicketLink features.

The latest version of the PicketLink API documentation can be found at http://docs.jboss.org/picketlink/2/latest/api/. This handy reference describes the user-facing classes and methods provided by the PicketLink libraries.

The PicketLink libraries are available from the Maven Central Repository. The dependencies can be easily configured in your Maven-based project by using the PicketLink Bill of Materials(BOM). A BOM is a very handy tool to properly manage your dependencies, their versions and keep your project in sync with the libraries supported and distributed by a specific PicketLink version.

For most applications using Java EE 6.0, the picketlink-javaee-6.0 BOM can be used to define the PicketLink and Java EE 6.0 specification APIs dependencies to your project.


<properties>
  <!-- PicketLink dependency versions -->
  <version.picketlink.javaee.bom>2.5.2.Final</version.picketlink.javaee.bom>
</properties>

<dependencyManagement>
  <dependencies>
    <!-- Dependency Management for PicketLink and Java EE 6.0. -->
    <dependency>
      <groupId>org.picketlink</groupId>
      <artifactId>picketlink-javaee-6.0</artifactId>
      <version>${version.picketlink.javaee.bom}</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>
  </dependencies>
</dependencyManagement>

Once the BOM is included, required PicketLink dependencies may be added to the section of your pom.xml. When using a BOM you don't need to specify their versions because this is automatically managed, the version in use depends on the BOM's version. For example, the configuration above is defining a version 2.5.2.Final of the picketlink-javaee-6.0 BOM, which means you'll be using version 2.5.2.Final of the PicketLink libraries.

For a typical application, it is suggested that you include the following PicketLink dependencies:


<dependencies>
<!-- Import the PicketLink API, we deploy this as library with the application,
        and can compile against it -->
  <dependency>
    <groupId>org.picketlink</groupId>
    <artifactId>picketlink-api</artifactId>
  </dependency>

  <!-- Import the PicketLink implementation, we deploy this as library with the application,
        but don't compile against it -->
  <dependency>
    <groupId>org.picketlink</groupId>
    <artifactId>picketlink-impl</artifactId>
    <scope>runtime</scope>
  </dependency>
</dependencies>

PicketLink also provides a specific BOM with the Apache Deltaspike(core and security modules) dependencies if you want to use it in conjunction with PicketLink.


<properties>
  <!-- PicketLink dependency versions -->
  <version.picketlink.javaee.bom>2.5.2.Final</version.picketlink.javaee.bom>
</properties>

<dependencyManagement>
  <dependencies>
    <!-- Dependency Management for PicketLink and Apache Deltaspike. -->
    <dependency>
      <groupId>org.picketlink</groupId>
      <artifactId>picketlink-javaee-6.0-with-deltaspike</artifactId>
      <version>${version.picketlink.javaee.bom}</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>
  </dependencies>
</dependencyManagement>

The identity management library is a required dependency of the base module and so will be automatically included. If you don't wish to use the base module and want to use the PicketLink IDM library on its own, then only add the following dependencies:


<dependencies>
  <dependency>
      <groupId>org.picketlink</groupId>
      <artifactId>picketlink-idm-api</artifactId>
      <scope>compile</scope>
  </dependency>
  
  <dependency>
      <groupId>org.picketlink</groupId>
      <artifactId>picketlink-idm-impl</artifactId>
      <scope>runtime</scope>
  </dependency>

If you wish to use PicketLink's Identity Management features and want to include the default database schema (see the Identity Management chapter for more details) then configure the following dependency also:


  <dependency>
    <groupId>org.picketlink</groupId>
    <artifactId>picketlink-idm-simple-schema</artifactId>
  </dependency>

Another way to configure the PicketLink dependencies (without using the PicketLink BOM) is to manually define them in your project's pom.xml file like so:


<properties>
  <picketlink.version>2.5.2.Final</picketlink.version>
</properties>

<dependencies>
  <dependency>
      <groupId>org.picketlink</groupId>
      <artifactId>picketlink-idm-api</artifactId>
      <scope>compile</scope>
      <version>${picketlink.version}</version>
  </dependency>

  <dependency>
      <groupId>org.picketlink</groupId>
      <artifactId>picketlink-idm-impl</artifactId>
      <scope>runtime</scope>
      <version>${picketlink.version}</version>
  </dependency>
</dependencies>

This last option may be more suitable for projects that don't use Java EE (for example in a Java SE environment).

Note

We strongly recommend using a BOM to configure your project with the PicketLink dependencies. This can avoid some very common and tricky issues like keep the versions in the project using the artifacts in sync with the versions distributed in a release.

The PicketLink Installer is a simple Apache Ant script that applies all the necessary changes to your JBoss Enterprise Application Platform 6.1 installation, including:

  • Updates the PicketLink module with the latest libraries.

  • Installs the PicketLink Subsystem.

  • Configures some of the PicketLink Quickstarts. Specially the PicketLink Federation examples. What means you can start using them to get a picture of the SAML Single Sign-On and other features provided by PicketLink Federation. !

Important

The installer is not a required step in order to get you started with PicketLink. But if you want the PicketLink Subsystem installed and the PicketLink module updated (in order to avoid ship the libraries inside your deployment) in your JBoss Enterprise Application Platform installation, it can be very useful.

The installer can be obtained from JBoss Nexus Repository. Once you've downloaded, extract the ZIP file, enter the directory that was created and execute the following command:


user@host picketlink-installer-1.1.3.Final]$ ant

Now you should be prompted for the full path of your JBoss Application Server installation.


prepare:
     [echo]
     [echo]       ####################################################################################
     [echo]       Welcome to the PicketLink Installer
     [echo]
     [echo]       This installer will update your JBoss Enterprise Application Platform 6 installation with the
     [echo]       following libraries and their dependencies:
     [echo]
     [echo]       - PicketLink Core 2.5.2.Final
     [echo]       - PicketLink Identity Management 2.5.2.Final
     [echo]       - PicketLink Federation 2.5.2.Final
     [echo]       - PicketLink Federation Quickstarts 2.1.8.Final
     [echo]       - PicketLink Subsystem 1.1.1.Final
     [echo]
     [echo]       New modules will be added to your installation.
     [echo]       ####################################################################################
     [echo]
    [input] Please enter the path to your JBoss Enterprise Application Platform 6 installation:

And it is done !

The Identity bean (which can be found in the org.picketlink package) is central to PicketLink's security API. This bean represents the authenticated user for the current session, and provides many useful methods for controlling the authentication process and querying the user's assigned privileges. In terms of authentication, the Identity bean provides the following methods:

AuthenticationResult login();


void logout();      
boolean isLoggedIn();
Account getAccount();

The login() method is the primary point of entry for the authentication process. Invoking this method will cause PicketLink to attempt to authenticate the user based on the credentials that they have provided. The AuthenticationResult type returned by the login() method is a simple enum that defines the following two values:

public enum AuthenticationResult {

    SUCCESS, FAILED
}

If the authentication process is successful, the login() method returns a result of SUCCESS, otherwise it returns a result of FAILED. The default implementation of the Identity bean is a @SessionScoped CDI bean, which means that once a user is authenticated they will stay authenticated for the duration of the session.

Note

One significant point to note is the presence of the @Named annotation on the Identity bean, which means that its methods may be invoked directly from the view layer (if the view layer, such as JSF, supports it) via an EL expression.

One possible way to control the authentication process is by using an action bean, for example the following code might be used in a JSF application:

public @RequestScoped @Named class LoginAction {


    @Inject Identity identity;
    public void login() {
        AuthenticationResult result = identity.login();
        if (AuthenticationResult.FAILED.equals(result)) {
            FacesContext.getCurrentInstance().addMessage(null, 
                new FacesMessage(
                        "Authentication was unsuccessful.  Please check your username and password " +
                        "before trying again."));
        }
    }
}

In the above code, the Identity bean is injected into the action bean via the CDI @Inject annotation. The login() method is essentially a wrapper method that delegates to Identity.login() and stores the authentication result in a variable. If authentication was unsuccessful, a FacesMessage is created to let the user know that their login failed. Also, since the bean is @Named it can be invoked directly from a JSF control like so:


<h:commandButton value="LOGIN" action="#{loginAction.login}"/>

The Identity.isLoggedIn() method may be used to determine whether there is a user logged in for the current session. It is typically used as an authorization check to control either an aspect of the user interface (for example, not displaying a menu item if the user isn't logged in), or to restrict certain business logic. While logged in, the getAccount() method can be used to retrieve the currently authenticated account (i.e. the user). If the current session is not authenticated, then getAccount() will return null. The following example shows both the isLoggedIn() and getAgent() methods being used inside a JSF page:


<ui:fragment rendered="#{identity.loggedIn}">Welcome, #{identity.account.loginName}

Note

If you're wondering what an Account is, it is simply a representation of the external entity that is interacting and authenticating with your application. The Account interface is actually the superclass of the User and Agent - see the Identity Management chapter for more details.

The logout() method allows the user to log out, thereby clearing the authentication state for their session. Also, if the user's session expires (for example due to inactivity) their authentication state will also be lost requiring the user to authenticate again.

The following JSF code example demonstrates how to render a log out button when the current user is logged in:


<ui:fragment rendered="#{identity.loggedIn}">
    <h:form>
        <h:commandButton value="Log out" action="#{identity.logout}"/>
    </h:form>
</ui:fragment>

While it is the Identity bean that controls the overall authentication process, the actual authentication "business logic" is defined by the Authenticator interface:

public interface Authenticator {

    public enum AuthenticationStatus {
        SUCCESS, 
        FAILURE, 
        DEFERRED
    }
    void authenticate();
    void postAuthenticate();
    AuthenticationStatus getStatus();
    Account getAccount();
}

During the authentication process, the Identity bean will invoke the methods of the active Authenticator (more on this in a moment) to perform user authentication. The authenticate() method is the most important of these, as it defines the actual authentication logic. After authenticate() has been invoked by the Identity bean, the getStatus() method will reflect the authentication status (either SUCCESS, FAILURE or DEFERRED). If the authentication process was a success, the getAccount() method will return the authenticated Account object and the postAuthenticate() method will be invoked also. If the authentication was not a success, getAccount() will return null.

Now that we've looked at all the individual pieces, let's take a look at how they all work together to process an authentication request. For starters, the following sequence diagram shows the class interaction that occurs during a successful authentication:

  • 1 - The user invokes the login() method of the Identity bean.

  • 1.1 - The Identity bean (after performing a couple of validations) invokes its own authenticate() method.

  • 1.1.1 - Next the Identity bean invokes the Authenticator bean's authenticate() method (which has a return value of void).

  • 1.1.2 - To determine whether authentication was successful, the Identity bean invokes the Authenticator's getStatus() method, which returns a SUCCESS.

  • 1.1.3 - Upon a successful authentication, the Identity bean then invokes the Authenticator's postAuthenticate() method to perform any post-authentication logic.

  • 1.1.4 - The Identity bean then invokes the Authenticator's getAccount() method, which returns an Account object representing the authenticated agent, which is then stored as a private field in the Identity bean.

The authentication process ends when the Identity.authenticate() method returns a value of true to the login() method, which in turn returns an authentication result of SUCCESS to the invoking user.

Let's take a closer look at an extremely simple example of an Authenticator. The following code demonstrates an Authenticator implementation that simply tests the username and password credentials that the user has provided against hard coded values of jsmith for the username, and abc123 for the password, and if they match then authentication is deemed to be a success:

@PicketLink

public class SimpleAuthenticator extends BaseAuthenticator {
    @Inject DefaultLoginCredentials credentials;
    @Override
    public void authenticate() {
        if ("jsmith".equals(credentials.getUserId()) &&
                "abc123".equals(credentials.getPassword())) {
            setStatus(AuthenticationStatus.SUCCESS);
            setAccount(new User("jsmith"));
        } else {
            setStatus(AuthenticationStatus.FAILURE);
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(
                    "Authentication Failure - The username or password you provided were invalid."));
        }
    }
}

The first thing we can notice about the above code is that the class is annotated with the @PicketLink annotation. This annotation indicates that this bean should be used for the authentication process. The next thing is that the authenticator class extends something called BaseAuthenticator. This abstract base class provided by PicketLink implements the Authenticator interface and provides implementations of the getStatus() and getAccount() methods (while also providing matching setStatus() and setAccount() methods), and also provides an empty implementation of the postAuthenticate() method. By extending BaseAuthenticator, our Authenticator implementation simply needs to implement the authenticate() method itself.

We can see in the above code that in the case of a successful authentication, the setStatus() method is used to set the authentication status to SUCCESS, and the setAccount() method is used to set the user (in this case by creating a new instance of User). For an unsuccessful authentication, the setStatus() method is used to set the authentication status to FAILURE, and a new FacesMessage is created to indicate to the user that authentication has failed. While this code is obviously meant for a JSF application, it's possible to execute whichever suitable business logic is required for the view layer technology being used.

One thing that hasn't been touched on yet is the following line of code:

@Inject DefaultLoginCredentials credentials;

This line of code injects the credentials that have been provided by the user using CDI's @Inject annotation, so that our Authenticator implementation can query the credential values to determine whether they're valid or not. We'll take a look at credentials in more detail in the next section.

Note

You may be wondering what happens if you don't provide an Authenticator bean in your application. If this is the case, PicketLink will automatically authenticate via the identity management API, using a sensible default configuration. See the Identity Management chapter for more information.

Credentials are something that provides evidence of a user's identity; for example a username and password, an X509 certificate or some kind of biometric data such as a fingerprint. PicketLink has extensive support for a variety of credential types, and also makes it relatively simple to add custom support for credential types that PicketLink doesn't support out of the box itself.

In the previous section, we saw a code example in which a DefaultLoginCredentials (an implementation of the Credentials interface that supports a user ID and a credential value) was injected into the SimpleAuthenticator bean. The most important thing to know about the Credentials interface in relation to writing your own custom Authenticator implementation is that you're not forced to use it. However, while the Credentials interface is mainly designed for use with the Identity Management API (which is documented in a separate chapter) and its methods would rarely be used in a custom Authenticator, PicketLink provides some implementations which are suitably convenient to use as such, DefaultLoginCredentials being one of them.

So, in a custom Authenticator such as this:

public class SimpleAuthenticator extends BaseAuthenticator {


    @Inject DefaultLoginCredentials credentials;
    
    // code snipped
}

The credential injection is totally optional. As an alternative example, it is totally valid to create a request-scoped bean called UsernamePassword with simple getters and setters like so:

public @RequestScoped class UsernamePassword {

    private String username;
    private String password;
    
    public String getUsername() { return username; }
    public String getPassword() { return password; }
    
    public void setUsername(String username) { this.username = username; }
    public void setPassword(String password) { this.password = password; }
}

And then inject that into the Authenticator bean instead:

public class SimpleAuthenticator extends BaseAuthenticator {


    @Inject UsernamePassword usernamePassword;
    
    // code snipped
}

Of course it is not recommended that you actually do this, however this simplistic example serves adequately for demonstrating the case in point.

PicketLink Identity Management (IDM) is a fundamental module of PicketLink, with all other modules building on top of the IDM component to implement their extended features. It features provide a rich and extensible API for managing the identities (such as users, groups and roles) of your applications and services. It also supports a flexible system for identity partitioning, allowing it to be used as a complete security solution in simple web applications and/or as an Identity Provider (IDP) in more complex multi-domain scenarios. It also provides the core Identity Model API classes (see below) upon which an application's identity classes are defined to provide the security structure for that application.

The Identity Management features of PicketLink are accessed primarily via the following three interfaces:

  • PartitionManager is used to manage identity partitions, which are essentially a container for a set of identity objects. The PartitionManager interface provides a set of CRUD methods for creating, reading, updating and deleting partitions, as well as methods for creating an IdentityManager or RelationshipManager (more on these next). A typical Java EE application with simple security requirements will likely not be required to access the PartitionManager API directly.

  • IdentityManager is used to manage identity objects within the scope of a partition. Some examples of identity objects are users, groups and roles, although PicketLink is not limited to just these. Besides providing the standard set of CRUD methods for managing and locating identity objects, the IdentityManager interface also defines methods for managing credentials and for creating identity queries which may be used to locate identities by their properties and attributes.

  • RelationshipManager is used to manage relationships - a relationship is a typed association between two or more identities, with each identity having a definitive meaning within the relationship. Some examples of relationships that may already be familiar are group memberships (where a user is a member of a particular group) or granted roles (where a user is assigned to a role to afford them a certain set of privileges). The RelationshipManager provides CRUD methods for managing relationships, and also for creating a relationship query which may be used to locate relationships between identities based on the relationship type and participating identity object/s.

Note

In case you are wondering why a separate RelationshipManager interface is required for managing relationships between identites, it is because PicketLink supports relationships between identities belonging to separate partitions; therefore the scope of a RelationshipManager instance is not constrained to a single partition in the same way as the IdentityManager.

Interaction with the backend store that provides the persistent identity state is performed by configuring one or more IdentityStores. PicketLink provides a few built-in IdentityStore implementations for storing identity state in a database, file system or LDAP directory server, and it is possible to provide your own custom implementation to support storing your application's identity data in other backends, or extend the built-in implementations to override their default behaviour.

If you'd like to get up and running with IDM quickly, the good news is that PicketLink will provide a default configuration that stores your identity data on the file system if no other configuration is available. This means that if you have the PicketLink libraries in your project, you can simply inject the PartitionManager, IdentityManager or RelationshipManager beans into your own application and start using them immediately:

@Inject PartitionManager partitionManager;

@Inject IdentityManager identityManager;
@Inject RelationshipManager relationshipManager;

Once you have injected an IdentityManager you can begin creating users, groups and roles for your application:

User user = new User("jdoe");

user.setFirstName("Jane");
user.setLastName("Doe");
identityManager.add(user);
Group group = new Group("employees");
identityManager.add(group);
Role admin = new Role("admin");
identityManager.add(admin);

Use the RelationshipManager to create relationships, such as role assignments and group memberships:

// Grant the admin role to the user

relationshipManager.add(new Grant(user, admin));
// Add the user to the employees group
relationshipManager.add(new GroupMembership(user, group));

The static methods provided by the org.picketlink.idm.model.basic.BasicModel class are based on the basic identity model and may be used to lookup various identity objects, or test whether certain relationships exist. These methods accept either an IdentityManager or RelationshipManager object as a parameter.

// Lookup the user by their username

User user = BasicModel.getUser(identityManager, "jdoe");
// Test if the user has the admin role
boolean isAdmin = BasicModel.hasRole(relationshipManager, user, role);
// Test if the user is a member of the employee group
boolean isEmployee = BasicModel.isMember(relationshipManager, user, group);

The Identity Model is a set of classes that define the security structure of an application. It may consist of identity objects such as users, groups and roles; relationships such as group and role memberships; and partitions such as realms or tiers. The classes found in the org.picketlink.idm.model package define the base types upon which the identity model is built upon:

  • AttributedType is the base interface for the identity model. It declares a number of methods for managing a set of attribute values, plus getId() and setId() methods for setting a unique identifier value.

  • Attribute is used to represent an attribute value. An attribute has a name and a (generically typed) value, and may be marked as read-only. Attribute values that are expensive to load (such as large binary data) may be lazy-loaded; the isLoaded() method may be used to determine whether the Attribute has been loaded or not.

  • Partition is the base interface for partitions. Since each partition must have a name it declares a getName() method.

  • Relationship is the base interface for relationships. Besides the base methods defined by the AttributedType interface, relationship implementations have no further contractual requirements, however they will define methods that return the identities and attribute values in accordance with the relationship type.

  • IdentityType is the base interface for Identity objects. It declares properties that indicate whether the identity object is enabled or not, optional created and expiry dates, plus methods to read and set the owning Partition.

  • Account is the base interface for identities that are capable of authenticating. Since the authentication process may not depend on one particular type of attribute (not all authentication is performed with a username and password) there are no hard-coded property accessors defined by this interface. It is up to each application to define the Account implementations required according to the application's requirements.

  • AbstractAttributedType is an abstract base class for creating AttributedType implementations.

  • AbstractPartition is an abstract base class that implements the base methods of the Partition interface, to simplify the development of partition implementations.

  • AbstractIdentityType is an abstract base class that implements the base methods of the IdentityType interface, to simplify the development of identity objects.

A custom identity model typically consists of two types of objects - the identity objects which define the security constructs of an application, and the relationships which define how the identity objects interract with each other to establish a meaningful security policy. PicketLink treats both types of object in an abstract manner, so it is up to the developer to create meaning for these objects and their relationships within the context of their own application. This section will describe how to create new identity objects and customize their properties and attributes, while the following section will complete the picture by describing how custom relationships are created.

Let's start by looking at the source for some of the identity objects in the basic model, starting with the Agent and User objects:

public class Agent extends AbstractIdentityType implements Account {

    private String loginName;
    public Agent() { }
    public Agent(String loginName) {
        this.loginName = loginName;
    }
    @AttributeProperty
    @Unique
    public String getLoginName() {
        return loginName;
    }
    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }
}
public class User extends Agent {

    private String firstName;
    private String lastName;
    private String email;
    public User() { }
    public User(String loginName) {
        super(loginName);
    }
    @AttributeProperty
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    @AttributeProperty
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    @AttributeProperty
    public String getEmail() {
        return this.email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
}

The Agent class is intended to represent a third party entity that may authenticate against an application, whether human (a user) or non-human (an external or remote process). Because Agent implements the Account marker interface, it is making a declaration that this identity object is capable of authenticating. To support the typical username/password authentication method, the Agent class defines a loginName property, however since the Account interface enforces no particular method of authentication (instead of a using username for authentication your application may require a certificate or fingerprint) this property is arbitrary.

The User class represents a human user and extends Agent to add the human-specific properties firstName, lastName and email. Since human users are also capable of authenticating it will also inherit the loginName property from the Agent.

One of the strengths of PicketLink is its ability to support custom relationship types. This extensibility allows you, the developer to create specific relationship types between two or more identities to address the domain-specific requirements of your own application.

Note

Please note that custom relationship types are not supported by all IdentityStore implementations - see the Identity Store section above for more information.

To create a custom relationship type, we start by creating a new class that implements the Relationship interface. To save time, we also extend the AbstractAttributedType abstract class which takes care of the identifier and attribute management methods for us:

  public class Authorization extends AbstractAttributedType implements Relationship {

        
  }

The next step is to define which identities participate in the relationship. Once we create our identity property methods, we also need to annotate them with the org.picketlink.idm.model.annotation.RelationshipIdentity annotation. This is done by creating a property for each identity type.

  private User user;

  private Agent application;
  
  @RelationshipIdentity
  public User getUser() {
    return user;
  }
  
  public void setUser(User user) {
    this.user = user;
  }
  
  @RelationshipIdentity
  public Agent getApplication() {
    return application;
  }
  
  public void setApplication(Agent application) {
    this.application = application;
  }

We can also define some attribute properties, using the @RelationshipAttribute annotation:

  private String accessToken;

  
  @RelationshipAttribute
  public String getAccessToken() {
    return accessToken;
  }
  
  public void setAccessToken(String accessToken) {
    this.accessToken = accessToken;
  }

PicketLink has been designed from the ground up to support a system of partitioning, allowing the identity objects it manages to be separated into logical groupings. Partitions may be used to split identities into separate realms, allowing an application to serve multiple organisations (for example in a SaaS architecture) or to support a multi-tier application allowing each tier to define its own set of identity objects (such as groups or roles). PicketLink's architecture also allows you to define your own custom partition types, allowing more complex use cases to be supported.

The PartitionManager interface provides the following methods for managing partitions:

public interface PartitionManager extends Serializable {


    <extends Partition> T getPartition(Class<T> partitionClass, String name);
    <extends Partition> List<T> getPartitions(Class<T> partitionClass);
    <extends Partition> T lookupById(final Class<T> partitionClass, String id);
    void add(Partition partition);
    void add(Partition partition, String configurationName);
    void update(Partition partition);
    void remove(Partition partition);
}

To create a new Partition object you may use either of the add() methods. If a configurationName parameter value isn't provided (see Chapter 6, Identity Management - Configuration for more information), then the newly created Partition will use the default configuration.

// Create a new Realm partition called "acme"

partitionManager.add(new Realm("acme"));
// Create a new Tier partition called "sales" using the named configuration "companyAD"

partitionManager.add(new Tier("sales"), "companyAD");

Each new Partition object created will be automatically assigned a unique identifier value, which can be accessed via its getId() method:

Realm realm = new Realm("acme");

partitionManager.add(realm);      
String partitionId = realm.getId();

Partitions may be retrieved using either their name or their unique identifier value. Both methods require the exact partition class to be provided as a parameter:

Realm realm = partitionManager.getPartition(Realm.class, "acme");

Tier tier = partitionManager.lookupById(Tier.class, tierId);

It is also possible to retrieve all partitions for a given partition class. In this case you can retrieve all partitions for a given type or all of them:

List<Realm> realms = partitionManager.getPartitions(Realm.class);

List<Partition> allPartitions = partitionManager.getPartitions(Partition.class);

Since Partition objects all implement the AttributedType interface, it is also possible to set arbitrary attribute values:

realm.setAttribute(new Attribute<Date>("created", new Date()));

After making changes to an existing Partition object, the update() method may be used to persist those changes:

partitionManager.update(realm);

A Partition object may also be removed with the remove() method:

Warning

Removing a Partition object is permanent, and will also remove all identity objects that exist within that partition!

partitionManager.remove(realm);

PicketLink IDM provides an authentication subsystem that allows user credentials to be validated thereby confirming that an authenticating user is who they claim to be. The IdentityManager interface provides a single method for performing credential validation, as follows:

void validateCredentials(Credentials credentials);

The validateCredentials() method accepts a single Credentials parameter, which should contain all of the state required to determine who is attempting to authenticate, and the credential (such as a password, certificate, etc) that they are authenticating with. Let's take a look at the Credentials interface:

public interface Credentials {

    public enum Status {
        UNVALIDATED, IN_PROGRESS, INVALID, VALID, EXPIRED
    };
   Account getValidatedAccount();
   
   Status getStatus();
   
   void invalidate();
}
  • The Status enum defines the following values, which reflect the various credential states:

    • UNVALIDATED - The credential is yet to be validated.

    • IN_PROGRESS - The credential is in the process of being validated.

    • INVALID - The credential has been validated unsuccessfully

    • VALID - The credential has been validated successfully

    • EXPIRED - The credential has expired

  • getValidatedAccount() - If the credential was successfully validated, this method returns the Account object representing the validated user.

  • getStatus() - Returns the current status of the credential, i.e. one of the above enum values.

  • invalidate() - Invalidate the credential. Implementations of Credential should use this method to clean up internal credential state.

Let's take a look at a concrete example - UsernamePasswordCredentials is a Credentials implementation that supports traditional username/password-based authentication:

public class UsernamePasswordCredentials extends AbstractBaseCredentials {


    private String username;
    private Password password;
    public UsernamePasswordCredentials() { }
    public UsernamePasswordCredentials(String userName, Password password) {
        this.username = userName;
        this.password = password;
    }
    public String getUsername() {
        return username;
    }
    public UsernamePasswordCredentials setUsername(String username) {
        this.username = username;
        return this;
    }
    public Password getPassword() {
        return password;
    }
    public UsernamePasswordCredentials setPassword(Password password) {
        this.password = password;
        return this;
    }
    @Override
    public void invalidate() {
        setStatus(Status.INVALID);
        password.clear();
    }
}

The first thing we may notice about the above code is that the UsernamePasswordCredentials class extends AbstractBaseCredentials. This abstract base class implements the basic functionality required by the Credentials interface. Next, we can see that two fields are defined; username and password. These fields are used to hold the username and password state, and can be set either via the constructor, or by their associated setter methods. Finally, we can also see that the invalidate() method sets the status to INVALID, and also clears the password value.

Let's take a look at an example of the above classes in action. The following code demonstrates how we would authenticate a user with a username of "john" and a password of "abcde":

Credentials creds = new UsernamePasswordCredentials("john",

    new Password("abcde"));
identityManager.validate(creds);
if (Status.VALID.equals(creds.getStatus())) {
  // authentication was successful
}

We can also test if the credentials that were provided have expired (if an expiry date was set). In this case we might redirect the user to a form where they can enter a new password.

Credentials creds = new UsernamePasswordCredentials("john",

    new Password("abcde"));
identityManager.validate(creds);
if (Status.EXPIRED.equals(creds.getStatus())) {
  // password has expired, redirect the user to a password change screen
}

Updating user credentials is even easier than validating them. The IdentityManager interface provides the following two methods for updating credentials:

void updateCredential(Account account, Object credential);

void updateCredential(Account account, Object credential, Date effectiveDate, Date expiryDate);

Both of these methods essentially do the same thing; they update a credential value for a specified Account. The second overloaded method however also accepts effectiveDate and expiryDate parameters, which allow some temporal control over when the credential will be valid. Use cases for this feature include implementing a strict password expiry policy (by providing an expiry date), or creating a new account that might not become active until a date in the future (by providing an effective date). Invoking the first overloaded method will store the credential with an effective date of the current date and time, and no expiry date.

Note

One important point to note is that the credential parameter is of type java.lang.Object. Since credentials can come in all shapes and sizes (and may even be defined by third party libraries), there is no common base interface for credential implementations to extend. To support this type of flexibility in an extensible way, PicketLink provides an SPI that allows custom credential handlers to be configured that override or extend the default credential handling logic. Please see the next section for more information on how this SPI may be used.

Let's take a look at a couple of examples. Here's some code demonstrating how a password can be assigned to user "jsmith":

User user = BasicModel.getUser(identityManager, "jsmith");

identityManager.updateCredential(user, new Password("abcd1234"));

This example creates a digest and assigns it to user "jdoe":

User user = BasicModel.getUser(identityManager, "jdoe");

Digest digest = new Digest();
digest.setRealm("default");
digest.setUsername(user.getLoginName());
digest.setPassword("abcd1234");        
identityManager.updateCredential(user, digest);

For IdentityStore implementations that support multiple credential types, PicketLink provides an optional SPI to allow the default credential handling logic to be easily customized and extended. To get a better picture of the overall workings of the Credential Handler SPI, let's take a look at the sequence of events during the credential validation process when validating a username and password against JPAIdentityStore:

  • 1 - The user (or some other code) first invokes the validateCredentials() method on IdentityManager, passing in the Credentials instance to validate.

  • 1.1 - After looking up the correct IdentityStore (i.e. the one that has been configured to validate credentials) the IdentityManager invokes the store's validateCredentials() method, passing in the IdentityContext and the credentials to validate.

  • 1.1.1 - In JPAIdentityStore's implementation of the validateCredentials() method, the IdentityContext is used to look up the CredentialHandler implementation that has been configured to process validation requests for usernames and passwords, which is then stored in a local variable called handler.

  • 1.1.2 - The validate() method is invoked on the CredentialHandler, passing in the security context, the credentials value and a reference back to the identity store. The reference to the identity store is important as the credential handler may require it to invoke certain methods upon the store to validate the credentials.

The CredentialHandler interface declares three methods, as follows:

public interface CredentialHandler {

    void setup(IdentityStore<?> identityStore);
    void validate(IdentityContext context, Credentials credentials,
                  IdentityStore<?> identityStore);
    void update(IdentityContext context, Account account, Object credential,
                IdentityStore<?> identityStore, Date effectiveDate, Date expiryDate);
}

The setup() method is called once, when the CredentialHandler instance is first created. Credential handler instantiation is controlled by the CredentialHandlerFactory, which creates a single instance of each CredentialHandler implementation to service all credential requests for that handler. Each CredentialHandler implementation must declare the types of credentials that it is capable of supporting, which is done by annotating the implementation class with the @SupportsCredentials annotation like so:

@SupportsCredentials(

  credentialClass = { UsernamePasswordCredentials.class, Password.class },
  credentialStorage = EncodedPasswordStorage.class
)
public class PasswordCredentialHandler implements CredentialHandler {

Since the validate() and update() methods receive different parameter types (validate() takes a Credentials parameter value while update() takes an Object that represents a single credential value), the @SupportsCredentials annotation must contain a complete list of all types supported by that handler.

Similarly, if the IdentityStore implementation makes use of the credential handler SPI then it also must declare which credential handlers support that identity store. This is done using the @CredentialHandlers annotation; for example, the following code shows how JPAIdentityStore is configured to be capable of handling credential requests for usernames and passwords, X509 certificates and digest-based authentication:

@CredentialHandlers({ PasswordCredentialHandler.class,

          X509CertificateCredentialHandler.class, DigestCredentialHandler.class })
public class JPAIdentityStore implements IdentityStore<JPAIdentityStoreConfiguration>, 
                                         CredentialStore {

For IdentityStore implementations that support multiple credential types (such as JPAIdentityStore and FileBasedIdentityStore), the implementation may choose to also implement the CredentialStore interface to simplify the interaction between the CredentialHandler and the IdentityStore. The CredentialStore interface declares methods for storing and retrieving credential values within an identity store, as follows:

public interface CredentialStore {

   void storeCredential(IdentityContext context, Account account,
                        CredentialStorage storage);
   <extends CredentialStorage> T retrieveCurrentCredential(IdentityContext context,
                                                 Account account, Class<T> storageClass);
   <extends CredentialStorage> List<T> retrieveCredentials(IdentityContext context,
                                                 Account account, Class<T> storageClass);
}

The CredentialStorage interface is quite simple and only declares two methods, getEffectiveDate() and getExpiryDate():

public interface CredentialStorage {

   @Stored Date getEffectiveDate();
   @Stored Date getExpiryDate();
}

The most important thing to note above is the usage of the @Stored annotation. This annotation is used to mark the properties of the CredentialStorage implementation that should be persisted. The only requirement for any property values that are marked as @Stored is that they are serializable (i.e. they implement the java.io.Serializable interface). The @Stored annotation may be placed on either the getter method or the field variable itself. Here's an example of one of a CredentialStorage implementation that is built into PicketLink - EncodedPasswordStorage is used to store a password hash and salt value:

public class EncodedPasswordStorage implements CredentialStorage {


    private Date effectiveDate;
    private Date expiryDate;
    private String encodedHash;
    private String salt;
    @Override @Stored
    public Date getEffectiveDate() {
        return effectiveDate;
    }
    public void setEffectiveDate(Date effectiveDate) {
        this.effectiveDate = effectiveDate;
    }
    @Override @Stored
    public Date getExpiryDate() {
        return expiryDate;
    }
    public void setExpiryDate(Date expiryDate) {
        this.expiryDate = expiryDate;
    }
    @Stored
    public String getEncodedHash() {
        return encodedHash;
    }
    public void setEncodedHash(String encodedHash) {
        this.encodedHash = encodedHash;
    }
    @Stored
    public String getSalt() {
        return this.salt;
    }
    public void setSalt(String salt) {
        this.salt = salt;
    }
}

PicketLink provides built-in support for the following credential types:

Warning

Not all built-in IdentityStore implementations support all credential types. For example, since the LDAPIdentityStore is backed by an LDAP directory server, only password credentials are supported. The following table lists the built-in IdentityStore implementations that support each credential type.


The next sections will describe each of these built-in types individually.

This credential handlers supports a username/password based authentication.

Credentials can be updated as follows:

User user = BasicModel.getUser(identityManager, "jsmith");

identityManager.updateCredential(user, new Password("abcd1234"));

In order to validate a credential you need to the following code:

UsernamePasswordCredentials credential = new UsernamePasswordCredentials();


Password password = new Password("abcd1234");
credential.setUsername("jsmith");
credential.setPassword(password);
identityManager.validateCredentials(credential);
if (Status.VALID.equals(credential.getStatus()) {
  // successful validation
} else {
  // invalid credential
}

This credential handlers supports a username/password based authentication.

Credentials can be updated as follows:

User user = BasicModel.getUser(identityManager, "jsmith");


TOTPCredential credential = new TOTPCredential("abcd1234", "my_totp_secret");
identityManager.updateCredential(user, credential);

Users can have multiple TOTP tokens, one for each device. You can provide configure tokens for a specific user device as follows:

User user = BasicModel.getUser(identityManager, "jsmith");


TOTPCredential credential = new TOTPCredential("abcd1234", "my_totp_secret");
credential.setDevice("My Cool Android Phone");
identityManager.updateCredential(user, credential);

In order to validate a credential you need to the following code:

User user = BasicModel.getUser(identityManager, "jsmith");


TOTPCredentials credential = new TOTPCredentials();
credential.setUsername(user.getLoginName());
credential.setPassword(new Password("abcd1234"));
TimeBasedOTP totp = new TimeBasedOTP();
// let's manually generate a token based on the user secret
String token = totp.generate("my_totp_secret");
credential.setToken(token);
// if you want to validate the token for a specific device
// credential.setDevice("My Cool Android Phone");
identityManager.validateCredentials(credential);
if (Status.VALID.equals(credential.getStatus()) {
  // successful validation
} else {
  // invalid credential
}

The built-in credential handlers can be used without any specific configuration if you're using the basic identity model. But in certain cases you may want to provide your own Account type and get it able to be authenticated.

Custom types require some additional steps in order to get their credentials updated/validated. Basically, what you need to do is:

As an example, let's suppose we have a custom Account type named SalesAgent and the application must support password-based authentication for this type:

 public class UserPasswordCredentialHandler extends PasswordCredentialHandler {


    @Override
    protected Account getAccount(final IdentityContext context, final UsernamePasswordCredentials credentials) {
      IdentityManager identityManager = getIdentityManager(context);
      IdentityQuery<SalesAgent> query = identityManager.createIdentityQuery(SalesAgent.class);
      query.setParameter(SalesAgent.LOGIN_NAME, credentials.getUsername());
      List<SalesAgent> result = query.getResultList();
      if (result.isEmpty()) {
        return null;
      }
      return result.get(0);
    }
}

Warning

If you're using a custom Account type and trying to authenticate using this type without providing a specific credential handler, the authentication will always fail.

For the sake of convenience, PicketLink provides a basic identity model that consists of a number of core interfaces which define a set of fundamental identity types which might be found in a typical application. The usage of this identity model is entirely optional; for an application with basic security requirements the basic identity model might be more than sufficient, however for a more complex application or application with custom security requirements it may be necessary to create a custom identity model.

The following class diagram shows the classes and interfaces in the org.picketlink.idm.model.basic package:

  • Agent represents a unique entity that may access the services secured by PicketLink. In contrast to a user which represents a human, Agent is intended to represent a third party non-human (i.e. machine to machine) process that may authenticate and interact with your application or services. It declares methods for reading and setting the Agent's login name.

  • User represents a human user that accesses your application and services. In addition to the login name property defined by its parent interface Agent, the User interface declares a number of other methods for managing the user's first name, last name and e-mail address.

  • Group is used to manage collections of identity types. Each Group has a name and an optional parent group.

  • Role is used in various relationship types to designate authority to another identity type to perform various operations within an application. For example, a forum application may define a role called moderator which may be assigned to one or more Users or Groups to indicate that they are authorized to perform moderator functions.

  • Grant relationship represents the assignment of a Role to an identity.

  • GroupMembership relationship represents a User (or Agent) membership within a Group.

  • GroupRole relationship represents the the assignment of a specific Role within a Group to a User or Agent. The reason this relationship extends the GroupMembership relationship is simply so it inherits the getMember() and getGroup() methods - being assigned to a GroupRole does not mean that the User (or Agent) that was assigned the group role also becomes a member of the group.

  • Realm is a partition type, and may be used to store any IdentityType objects (including Agents, Users, Groups or Roles.

  • Tier is a specialized partition type, and may be only used to store Group or Role objects specific to an application.

PicketLink also provides an utility class with some very useful and common methods to manipulate the basic identity model. Along the documentation you'll find a lot of examples using the the following class: org.picketlink.idm.model.basic.BasicModel. If you're using the basic identity model, this helper class can save you a lot of code and make your application even more simple.

The list below summarizes some of the functionalities provided by this class:

  • Retrieve User and Agent instances by login name.

  • Retrieve Role and Group instances by name.

  • Add users as group members, grant roles to users. As well check if an user is member of a group or has a specific role.

One import thing to keep in mind is that the BasicModel helper class is only suitable if you're using the types provided by the basic identity model, only. If you are using custom types, even if those are sub-types of any of the types provided by the basic identity model, you should handle those custom types directly using the PicketLink IDM API.

As an example, let's suppose you have a custom type which extends the Agent type.

  SalesAgent salesAgent = BasicModel.getUser(identityManager, "someSalesAgent");

The code above will never return a SalesAgent instance. The correct way of doing that is using the Query API directly as follows:

  public SaleAgent findSalesAgent(String loginName) {

      List<SaleAgent> result = identityManager
                                .createIdentityQuery(SaleAgent.class)
                                .setParameter(SaleAgent.LOGIN_NAME, loginName)
                                .getResultList();
      return result.isEmpty() ? null : result.get(0);
}

Warning

Please note that the BasicModel helper class is only suitable for use cases where only the types provided by the basic identity model are used. If your application have also custom types, they need to be handled directly using the PicketLink IDM API.

PicketLink IDM provides a number of basic implementations of the identity model interfaces for convenience, in the org.picketlink.idm.model.basic package. The following sections provide examples that show these implementations in action.

Relationships are used to model typed associations between two or more identities. All concrete relationship types must implement the marker interface org.picketlink.idm.model.Relationship:

The IdentityManager interface provides three standard methods for managing relationships:

  void add(Relationship relationship);

  void update(Relationship relationship);
  void remove(Relationship relationship);
  • The add() method is used to create a new relationship.

  • The update() method is used to update an existing relationship.

    Note

    Please note that the identities that participate in a relationship cannot be updated themselves, however the attribute values of the relationship can be updated. If you absolutely need to modify the identities of a relationship, then delete the relationship and create it again.

  • The remove() method is used to remove an existing relationship.

Note

To search for existing relationships between identity objects, use the Relationship Query API described later in this chapter.

Besides the above methods, IdentityManager also provides a number of convenience methods for managing many of the built-in relationship types. See the next section for more details.

PicketLink provides a number of built-in relationship types, designed to address the most common requirements of a typical application. The following sections describe the built-in relationships and how they are intended to be used. Every built-in relationship type extends the AbstractAttributedType abstract class, which provides the basic methods for setting a unique identifier value and managing a set of attribute values:

What this means in practical terms, is that every single relationship is assigned and can be identified by, a unique identifier value. Also, arbitrary attribute values may be set for all relationship types, which is useful if you require additional metadata or any other type of information to be stored with a relationship.

The GroupMembership and GroupRole relationships are used to represent a user's membership within a Group, and a user's role for a group, respectively.

Note

While the GroupRole relationship type extends GroupMembership, it does not mean that a member of a GroupRole automatically receives GroupMembership membership also - these are two distinct relationship types with different semantics.

A Group is typically used to form logical collections of users. Within an organisation, groups are often used to mirror the organisation's structure. For example, a corporate structure might consist of a sales department, administration, management, etc. This structure can be modelled in PicketLink by creating corresponding groups such as sales, administration, and so forth. Users (who would represent the employees in a corporate structure) may then be assigned group memberships corresponding to their place within the company's organisational structure. For example, an employee who works in the sales department may be assigned to the sales group. Specific application privileges can then be blanket assigned to the sales group, and anyone who is a member of the group is free to access the application's features that require those privileges.

The GroupRole relationship type should be used when it is intended for an identity to perform a specific role for a group, but not be an actual member of the group itself. For example, an administrator of a group of doctors may not be a doctor themselves, but have an administrative role to perform for that group. If the intent is for an individual identity to both be a member of a group and have an assigned role in that group also, then the identity should have both GroupRole and GroupMembership relationships for that group.

Let's start by looking at a simple example - we'll begin by making the assumption that our organization is structured in the following way:

The following code demonstrates how we would create the hypothetical Sales group which is displayed at the head of the above organisational chart:

  Group sales = new Group("Sales");

  identityManager.add(sales);

We can then proceed to create its subgroups:

identityManager.add(new Group("North America", sales);

identityManager.add(new Group("EMEA", sales);
identityManager.add(new Group("Asia", sales);
// and so forth

The second parameter of the Group() constructor is used to specify the group's parent group. This allows us to create a hierarchical group structure, which can be used to mirror either a simple or complex personnel structure of an organisation. Let's now take a look at how we assign users to these groups.

The following code demonstrates how to assign an administrator group role for the Northeast sales group to user jsmith. The administrator group role may be used to grant certain users the privilege to modify permissions and roles for that group:

Role admin = BasicModel.getRole(identityManager, "administrator");

User user = BasicModel.getUser(identityManager, "jsmith");
Group group = BasicModel.getGroup(identityManager, "Northeast");
BasicModel.grantGroupRole(relationshipManager, user, admin, group);

A group role can be revoked using the revokeGroupRole() method:

BasicModel.revokeGroupRole(relationshipManager, user, admin, group);

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

boolean isUserAGroupAdmin = BasicModel.hasGroupRole(relationshipManager, user, admin, group);

Next, let's look at some examples of how to work with simple group memberships. The following code demonstrates how we assign sales staff rbrown to the Northeast sales group:

User user = BasicModel.getUser(identityManager, "rbrown");

Group group = BasicModel.getGroup(identityManager, "Northeast");
BasicModel.addToGroup(relationshipManager, user, group);

A User may also be a member of more than one Group; there are no built-in limitations on the number of groups that a User may be a member of.

We can use the removeFromGroup() method to remove the same user from the group:

BasicModel.removeFromGroup(relationshipManager, user, group);

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

boolean isUserAMember = BasicModel.isMember(relationshipManager, user, group);

Relationships can also be created via the add() method. The following code is equivalent to assigning a group role via the grantGroupRole() method shown above:

Role admin = BasicModel.getRole(identityManager, "administrator");

User user = BasicModel.getUser(identityManager, "jsmith");
Group group = BasicModel.getGroup(identityManager, "Northeast");
GroupRole groupRole = new GroupRole(user, group, admin);
identityManager.add(groupRole);

In certain cases the default configuration may not be enough to your application. You can easily provide your own configuration by observing a specific IdentityConfigurationEvent:

@ApplicationScoped

public static class PicketLinkConfiguration {
  public void observeIdentityConfigurationEvent(@Observes IdentityConfigurationEvent event) {
    IdentityConfigurationBuilder builder = event.getConfig();
    // use the builder to provide your own configuration
  }
}

You can also provide your own configuration by producing one or more IdentityConfiguration instances using a @Producer annotated method:

@ApplicationScoped

public static class PicketLinkConfiguration {
  @Produces
  public IdentityConfiguration produceJPAConfiguration() {
      IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
      builder
          .named("jpa.config")
              .stores()
                  .jpa()
                    // configure the JPA store
      return builder.build();
  }
  @Produces
  public IdentityConfiguration produceLDAPConfiguration() {
      IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
      builder
          .named("ldap.config")
              .stores()
                  .ldap()
                      // configure the LDAP store
      return builder.build();
  }
}

The example above produces two distinct configurations: one using a JPA store and another using the LDAP store. During the startup PicketLink will resolve both configurations and initialize the IDM subsystem with them. You can also provide a single configuration.

For last, you can also build your own PartitionManager instance if you want more control.

@ApplicationScoped

public static class PicketLinkConfiguration {
  @PicketLink
  @Produces
  public PartitionManager producePartitionManager() {
      IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
      builder
          .named("produced.partition.manager.config")
              .stores()
                  .jpa()
                      .mappedEntity(
                              AccountTypeEntity.class,
                              RoleTypeEntity.class,
                              GroupTypeEntity.class,
                              IdentityTypeEntity.class,
                              RelationshipTypeEntity.class,
                              RelationshipIdentityTypeEntity.class,
                              PartitionTypeEntity.class,
                              PasswordCredentialTypeEntity.class,
                              DigestCredentialTypeEntity.class,
                              X509CredentialTypeEntity.class,
                              OTPCredentialTypeEntity.class,
                              AttributeTypeEntity.class
                      )
                      .addContextInitializer(this.contextInitializer)
                      .supportAllFeatures();
      return new DefaultPartitionManager(builder.build());
  }
}

The example above allows you to produce your own PartitionManager instance. Note that the producer method is annotated with the PicketLink annotation. Another important thing when producing your own PartitionManager is that you must manually create the partitions before start producing IdentityManager instances (eg.: the default partition).

The Identity Management configuration can be defined programmatically using the Configuration Builder API. The aim of this API is to make it easier to chain coding of configuration options in order to speed up the coding itself and make the configuration more readable.

Let's assume that you want to quick start with PicketLink Identity Management features using a File-based Identity Store. First, a fresh instance of IdentityConfiguration is created using the IdentityConfigurationBuilder helper object, from where we choose which identity store we want to use (in this case a file-based store) and any other configuration option, if necessary. Finally, we use the configuration to create a PartitionManager, from where we can create Partition and IdentityManager instances:

IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();

        
builder
  .named("default")
    .stores()
      .file()
        .supportAllFeatures();
DefaultPartitionManager partitionManager = new DefaultPartitionManager(builder.buildAll());
Realm defaultRealm = new Realm(Realm.DEFAULT_REALM);
// let's add the partition using the default configuration.
partitionManager.add(defaultRealm);
// if no partition is specified to createIdentityManager, defaults to the default Realm.
IdentityManager identityManager = partitionManager.createIdentityManager();
User john = new User("john");
// let's add john to the default partition
identityManager.add(user);

A PartitionManager can be built considering multiple configurations. This is a very powerful feature given that you can manage your identity data between different partitions each one using a specific configuration.

As discussed before, each configuration has a name. The name can be used to identify a configuration set as well to tell PicketLink the configuration that should be used to manage a specific Partition.

Let's take a more close look how you can use multiple configurations:

IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();


builder
    .named("ldap.config")
        .stores()
            .ldap()
              // specific configuration options for the LDAP store
              .supportAllFeatures();
    .named("jpa.config")
        .stores()
            .jpa()
              // specific configuration options for the JPA store
              .supportAllFeatures();
DefaultPartitionManager partitionManager = new DefaultPartitionManager(builder.buildAll());
Realm internalPartition = new Realm("internal");
// the 'internal' partition will use the 'ldap.config' configuration
partitionManager.add(internalPartition, "ldap.config");
// we create an IdentityManager for the LDAP managed partition
IdentityManager internalIdentityManager = partitionManager.createIdentityManager(internalPartition);
User john = new User("john");
// john will be added to the LDAP
internalIdentityManager.add(john);
Realm externalPartition = new Realm("external");
// the 'external' partition will use the 'jpa.config' configuration
partitionManager.add(externalPartition, "jpa.config");
User mary = new User("mary");
// we create an IdentityManager for the JPA managed partition
IdentityManager externalIdentityManager = partitionManager.createIdentityManager(externalPartition);
// mary will be added to the database
externalIdentityManager.add(mary);

The example above is just one of the different things you can do with PicketLink. The code above defines two partitions: one for internal users and another one for external users. Each partition is associated with one of the provided configurations where the internal partition will use LDAP to store users whether the external partition will use JPA.

When you create a IdentityManager for one of those partitions, all identity management operations will be done considering the configuration associated with the current partition. In other words, considering the example above, the user 'john' will be stored in the LDAP and 'mary' in a Database.

It is also possible to use multiple IdentityStore configurations in a single named configuration. This can be very useful when your identity data is distributed in different stores or even if a specific store have any kind of limitation that can be provided by another one.

For instance, the LDAP store have some limitations and does not support all features provided by PicketLink. One of those unsupported features is the ability to handle ad-hoc attributes. When using LDAP you're tied with a schema that usually is very hard to change in order to support all your needs.

In this cases, PicketLink allows you to combine in a single configuration the LDAP and the JPA store, for example. Where you can use LDAP for users, roles and groups and use the JPA store for relationships.

IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();


builder
  .named("default")
    .stores()
      .jpa()
        // configuration options for the jpa store
        .supportGlobalRelationship(Relationship.class)
        .supportAttributes(true)
      .ldap()
        // configuration options for the ldap store
        .supportType(IdentityType.class)

The example above defines a single configuration with two stores: LDAP and JPA. For the LDAP store configuration we define that only IdentityType types should be supported. In other words, we're only storing users, roles and groups. For the JPA store configuration we define that only Relationship types should be supported. In other words, we're only storing relationships such as Grant, GroupMembership, etc.

You may also notice that the JPA store is configured to support attributes too. What means that we can now use ad-hoc attributes for all the supported types.

Each IdentityStore may support a different set of credential handlers. This documentations describes the built-in credential handlers provided by PicketLink, but sometimes you may want to provide your own implementations.

When you write your custom credential handler you need to tell PicketLink the identity store that will support it. This is done by the following code:

 IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();


 builder
   .named("default")
     .stores()
       .jpa()
         // other JPA configuration
         .addCredentialHandler(UserPasswordCredentialHandler.class)
         .supportAllFeatures();

The example above shows how to configure a credential handler for a JPA-based store using the addCredentialHandler method.

The IdentityContext plays an important role in the PicketLink IDM achitecture. It is strongly used during the execution of operations. It carries very sensitive and contextual information for a specific operation and provides access for some of the IDM underlying services such as caching, event handling, id generator for AttributedType instances, among others.

Operations are always executed by a specific IdentityStore in order to persist or store identity data using a specific repository (eg.: LDAP, databases, filesystem, etc). When executing a operation the identity store must be able to:

  • Access the current Partition. Eg.: Realm or Tier.

  • Access the Event Handling API in order to fire events such as when an user is created, updated, etc.

  • Access the Caching API in order to cache identity data and increase performance.

  • Access to external resources, provided before the operation is executed and initialized by a ContextInitializer.

Sometimes you may need to provide additional configuration or even references for external resources before the operation is executed by an identity store. An example is how you tell to the JPAIdentityStore which EntityManager instance should be used. When executing an operation, the JPAIdentityStore must be able to access the current EntityManager to persist or retrieve data from the database. You need someway to populate the IdentityContext with such information. When you're configuring an identity store, there is a configuration option that allows you to provide a ContextInitializer implementation.

public interface ContextInitializer {

    void initContextForStore(IdentityContext context, IdentityStore<?> store);
}

The method initContextForStore will be invoked for every single operation and before its execution by the identity store. It can be implemented to provide all the necessary logic to initialize and populate the IdentityContext for a specific IdentityStore.

The configuration is also very simple:

IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();


builder
  .named("default")
    .stores()
      .file()
        .supportAllFeatures();
        .addContextInitializer(new MyContextInitializer());

You can provide multiple initializers.

Note

Remember that initializers are executed for every single operation. Also, the same instance is used between operations which means your implementation should be stateless. You should be careful about the implementation in order to not impact performance, concurrency or introduce unexpected behaviors.

Actually it's possible to configure IDM with XML configuration. This possibility is good especially in case when you want Picketlink IDM to be part of bigger system and your users won't have a possibility to change source code and so they can't configure it programmatically with the Builder API. So they will just need to change the configuration in XML file instead of doing some changes directly in source code.

Whole Picketlink project provides unified format of configuration file, so that you can configure federation and IDM in same file.


<PicketLink xmlns="urn:picketlink:identity-federation:config:2.1">

  <PicketLinkIDP xmlns="urn:picketlink:identity-federation:config:1.0"
                 ServerEnvironment="tomcat" BindingType="POST" SupportsSignatures="true">
    <!-- SAML2 IDP configuration is here -->
  </PicketLinkIDP>

  <Handlers xmlns="urn:picketlink:identity-federation:handler:config:2.1">
     <!-- Configuration of SAML2 handlers is here -->
  </Handlers>

  <PicketLinkSTS xmlns="urn:picketlink:identity-federation:config:1.0"
                 STSName="Test STS" TokenTimeout="7200" EncryptToken="true">
    <!-- Configuration of Picketlink STS is here -->
  </PicketlinkSTS>

  <PicketLinkIDM>
    <!-- IDM configuration is here -->
  </PicketLinkIDM>

</PicketLink>

Note that if you don't want to use Picketlink Federation, you can omit it's configuration and use just IDM.

XML configuration is leveraging Builder API and Java reflection during it's parsing, so names of XML elements are actually same like names of particular Builder methods.

For example, let's assume that you want to use FileIdentityStore and your programmatic configuration looks like this:

IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();


builder
    .named(SIMPLE_FILE_STORE_CONFIG)
        .stores()
            .file()
            .preserveState(false)
            .supportGlobalRelationship(Relationship.class)
            .supportAllFeatures();

Same XML configuration to configure IDM with FileIdentityStore will look like this:


<PicketLink xmlns="urn:picketlink:identity-federation:config:2.1">

  <PicketLinkIDM>

    <named value="SIMPLE_FILE_STORE_CONFIG">
      <stores>
        <file>
          <preserveState value="false" />
          <supportGlobalRelationship value="org.picketlink.idm.model.Relationship" />
          <supportAllFeatures />
        </file>
      </stores>
    </named>

  </PicketLinkIDM>

</PicketLink>

You can take a look at testsuite to see more examples.

The JPA identity store uses a relational database to store identity state. The configuration for this identity store provides control over which entity beans are used to store identity data, and how their fields should be used to store various identity-related state. The entity beans that store the identity data must be configured using the annotations found in the org.picketlink.jpa.annotations package. All identity configuration annotations listed in the tables below are from this package.

If you do not wish to provide your own JPA entities for storing IDM-related state, you may use the default schema provided by PicketLink in the picketlink-idm-simple-schema module. This module contains a collection of entity beans suitable for use with JPAIdentityStore. To use this module, add the following dependency to your Maven project's pom.xml file:


<dependency>
    <groupId>org.picketlink</groupId>
    <artifactId>picketlink-idm-simple-schema</artifactId>
    <version>${picketlink.version}</version>
</dependency>

In addition to including the above dependency, the default schema entity beans must be configured in your application's persistence.xml file. Add the following entries within the persistence-unit section:


<class>org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity</class>
yes

The following table summarizes all annotations that can be used to map entities to IdentityType types:


The following code shows an example of an entity class configured to store User types:


The following table summarizes all annotations that can be used to map entities to Relationship types:

Table 7.3. Relationship Annotations

AnnotationDescriptionProperty TypeRequired
@IdentityManaged This annotation is a type-level annotation and must be used to specify the Relationship types that should be mapped by the annotated entity. -True
@AttributeValue This annotation can be used to map a entity property to a Relationship property. The name property of this annotation can be used in case the property names are different. Any TypeFalse
@Identifier The unique identifier value for the relationship. StringTrue
@RelationshipClass The type for the relationship. When a Relationship is stored the FQN of its type is stored in a property annotated with this annotation. StringTrue
@RelationshipDescriptor This annotation must be used to indicate the field to store the name of the relationship role of a member. StringTrue
@RelationshipMember The reference to a IdentityType mapped entity. This annotation is used to identify the property that holds a reference to the identity type that belongs to this relationship with a specific descriptor. Usually this annotation is used in conjunction with a @ManyToOne property referencing the entity used to store identity types. The same type used to map a IdentityTypeTrue
@OwnerReference The reference to a Relationship mapped entity. This annotation is used to identify the property that holds a reference to the root entity for relationships, usually the entity annotated with the @RelationshipClass annotation. The same type used to map an entity with the @RelationshipClass annotation.True

The following code shows an example of an entity class configured to store Relationship types:


When mapping a relationship you also need to provide a specific entity to store its members:


The following table summarizes all annotations that can be used to map attributes to AttributedType types:


The following code shows an example of an entity class configured to store password-based credentials for IdentityType types:


Sometimes you may need to configure how the EntityManager is provided to the JPAIdentityStore, like when your application is using CDI and you must run the operations in the scope of the current transaction by using a injected EntityManager instance.

In cases like that, you need to initialize the IdentityContext by providing a ContextInitializer implementation, as discussed in Identity Context Configuration. You can always provide your own implementation for this interface to obtain the EntityManager from your application's environment.

IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();


builder
  .stores()
    .jpa()
      .addContextInitializer(new ContextInitializer() {
        @Override
        public void initContextForStore(IdentityContext context, IdentityStore<?> store) {
          if (store instanceof JPAIdentityStore) {
              EntityManager entityManager = // get the EntityManager
              context.setParameter(JPAIdentityStore.INVOCATION_CTX_ENTITY_MANAGER, entityManager);
          }
        }
      });

In most cases you don't need to provide your own ContextInitializer but use an implementation provided by PicketLink:

@Inject

private EEJPAContextInitializer contextInitializer;
public void observeIdentityConfigurationEvent(@Observes IdentityConfigurationEvent event) {
  IdentityConfigurationBuilder builder = event.getConfig();
  builder
    .stores()
      .jpa()
        // more JPA store config
        .addContextInitializer(this.contextInitializer);
}

The LDAP identity store allows an LDAP directory server to be used to provide identity state. You can use this store in read-only or write-read mode, depending on your permissions on the server.

The LDAP identity store can be configured by providing the following configuration:

IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();


builder
    .named("ldap.config")
        .stores()
            .ldap()
                .baseDN("dc=jboss,dc=org")
                .bindDN("uid=admin,ou=system")
                .bindCredential("passwd")
                .url("ldap://localhost:389")
                .supportType(IdentityType.class)
                .supportGlobalRelationship(Grant.class, GroupMembership.class)
                .mapping(Agent.class)
                    .baseDN("ou=Agent,dc=jboss,dc=org")
                    .objectClasses("account")
                    .attribute("loginName", UID, true)
                    .readOnlyAttribute("createdDate", CREATE_TIMESTAMP)
                .mapping(User.class)
                    .baseDN("ou=User,dc=jboss,dc=org")
                    .objectClasses("inetOrgPerson", "organizationalPerson")
                    .attribute("loginName", UID, true)
                    .attribute("firstName", CN)
                    .attribute("lastName", SN)
                    .attribute("email", EMAIL)
                    .readOnlyAttribute("createdDate", CREATE_TIMESTAMP)
                .mapping(Role.class)
                    .baseDN("ou=Roles,dc=jboss,dc=org")
                    .objectClasses(GROUP_OF_NAMES)
                    .attribute("name", CN, true)
                    .readOnlyAttribute("createdDate", CREATE_TIMESTAMP)
                .mapping(Group.class)
                    .baseDN("ou=Groups,dc=jboss,dc=org")
                    .objectClasses(GROUP_OF_NAMES)
                    .attribute("name", CN, true)
                    .readOnlyAttribute("createdDate", CREATE_TIMESTAMP)
                    .parentMembershipAttributeName("member")
                .mapping(Grant.class)
                    .forMapping(Role.class)
                    .attribute("assignee", "member")
                .mapping(GroupMembership.class)
                    .forMapping(Group.class)
                    .attribute("member", "member");

The following table describes all configuration options:


To get the PicketLink subsystem properly installed you only need to use the PicketLink Installer.

Note

This step may no longer be required once the subsystem is available in a future version of JBoss Enterprise Application Platform.

Once the subsystem is properly installed you need to change your standalone/domain.xml, inside your EAP installation, with the following extension and subsystem:


<extensions>
  ...

  <!-- Add the PicketLink extension -->
  <extension module="org.picketlink.as.extension" />

</extensions>
<profile>

  <!-- Add the PicketLink Subsystem -->
  <subsystem xmlns="urn:jboss:domain:picketlink:1.0" />

  ...
</profile>

One your JBoss Application Server is properly configured with all PicketLink libraries and their respective modules, you can add a META-INF/jboss-deployment-structure.xml file inside the root directory of your deployment to configure the dependencies as follows:


<jboss-deployment-structure>
  <deployment>
      <dependencies>
        <!-- This will enable PicketLink Authentication/Authorization and IDM dependencies to your deployment. -->
      <module name="org.picketlink.core" />
        </dependencies>
  </deployment>
</jboss-deployment-structure>

<jboss-deployment-structure>
  <deployment>
      <dependencies>
        <!-- This will enable only the IDM dependencies to your deployment. -->
      <module name="org.picketlink.idm" />
        </dependencies>
  </deployment>
</jboss-deployment-structure>

It is strongly recommended that you use the PicketLink libraries from your JBoss Application Server modules. When using this way, you don't need to add any additional library to your deployments and you can easily manage the PicketLink libraries without requiring changes to your deployments.

Considering that you no longer need the PicketLink libraries inside your deployment, you must change your Maven dependencies to use the PicketLink dependencies with scope provided:


<dependency>
  <groupId>org.picketlink</groupId>
  <artifactId>picketlink-api</artifactId>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>org.picketlink</groupId>
  <artifactId>picketlink-idm-api</artifactId>
  <scope>provided</scope>
</dependency>

The subsystem provides a domain model that allows you to configure the PicketLink Federation and Identity Management services using the standalone/domain.xml inside your EAP installation. The domain model is very easy to understand if you are already familiar with the PicketLink configuration.


<subsystem xmlns="urn:jboss:domain:picketlink:1.0">
  <!-- An example of the PicketLink Federation configuration -->
  <federation alias="federation-with-signatures">
    <saml token-timeout="4000" clock-skew="0"/>
    <key-store url="/jbid_test_keystore.jks" passwd="changeit" sign-key-alias="localhost" sign-key-passwd="changeit"/>
    <identity-provider url="http://localhost:8080/idp-sig/" alias="idp-sig.war" security-domain="idp" supportsSignatures="true" strict-post-binding="false">
      <trust>
        <trust-domain name="localhost" cert-alias="localhost"/>
        <trust-domain name="127.0.0.1" cert-alias="localhost"/>
      </trust>
    </identity-provider>
    <service-providers>
      <service-provider alias="sales-post-sig.war" security-domain="sp" url="http://localhost:8080/sales-post-sig/" post-binding="true" supportsSignatures="true"/>
      <service-provider alias="sales-redirect-sig.war" security-domain="sp" url="http://localhost:8080/sales-redirect-sig/" post-binding="false" supportsSignatures="true" strict-post-binding="false"/>
    </service-providers>
  </federation>

  <!-- An example of the PicketLink Identity Management configuration -->
  <identity-management jndi-name="picketlink/JPAPartitionManager" alias="jpa.partition.manager">
    <identity-configuration name="jpa.store.config">
      <jpa-store data-source="jboss/datasources/ExampleDS">
        <supportedTypes supportsAll="true"/>
      </jpa-store>
    </identity-configuration>
  </identity-management>
</subsystem>

The subsystem provides a domain model that allows you to configure PicketLink Identity Management Services using the standalone/domain.xml. Basically, what the subsystem does is parse the configuration, automatically build a org.picketlink.idm.PartitionManager and expose it via JNDI for further access.

With the subsystem you can :

  • Externalize and centralize the IDM configuration for deployments.

  • Define multiple configuration for identity management services.

  • Expose the PartitionManager via JNDI for further access.

  • If using CDI, inject the PartitionManager instances using the Resource annotation.

  • If using CDI, use the PicketLink IDM alone without requiring the base module dependencies. In this case you can provide your own configuration without using the subsystem's domain model.

The IDM domain model is an abstraction for all PicketLink IDM configuration, providing a single schema from which all configurations can be defined. If you're already familiar with the Configuration API, you'll find the domain pretty simple and intuitive.


<subsystem xmlns="urn:jboss:domain:picketlink:1.0">
  <identity-management jndi-name="picketlink/FileBasedPartitionManager" alias="file.based.partition.manager">
    <identity-configuration name="file.config">
      <file-store working-dir="/tmp/pl-idm-complete" always-create-files="true" async-write="true"
                  async-write-thread-pool="10">
        <supportedTypes supportsAll="true"/>
      </file-store>
    </identity-configuration>
  </identity-management>

  <identity-management jndi-name="picketlink/JPADSBasedPartitionManager" alias="jpa.ds.based.partition.manager">
    <identity-configuration name="jpa.config">
      <jpa-store data-source="jboss/datasources/ExampleDS">
        <supportedTypes supportsAll="true"/>
      </jpa-store>
    </identity-configuration>
  </identity-management>
</subsystem>

Most of the configuration are known if you are familiar with the PicketLink IDM configuration. But the domain model provides some additional configuration in order to allow deployments to access the configured identity management services. Basically, each configuration must have a:

  • jndi-url, that defines where the PartitionManager should be published in the JNDI tree for further access.

  • alias, an alias for the configuration to allow other subsystems to inject the Identity Management Services using the MSC injection infrastructure.

The rest of the configuration is very similar with how you use the Configuration API to programmaticaly build the IDM configuration. For a complete description of the domain model elements, please take a look at the XML Schema.

In order to provide a better and easy integration with the container, the JPAIdentityStore configuration provides some additional configuration to let you configure how the EntityManagerFactory is built or used by the JPAIdentityStore.

The JPA Identity Store configuration allows you to specify a JBoss Module from where the JPA Persistence Unit and mapped entities will be loaded from.

This configuration can be done using two attributes:

  • entity-module, the module name where the JPA Persistence Unit and all mapped entities are located.

  • entity-module-unit-name, the name of the JPA Persistence Unit name. If you don't provide a name the subsystem will use identity.


<subsystem xmlns="urn:jboss:domain:picketlink:1.0">
    <identity-management jndi-name="picketlink/JPACustomEntityBasedPartitionManager" alias="jpa.custom.entity.based.partition.manager">
      <identity-configuration name="jpa.config">
        <jpa-store entity-module="org.picketlink.test" entity-module-unit-name="custom-pu" module="org.picketlink.test">
          <supportedTypes>
            <supportedType class="org.picketlink.idm.model.Partition"/>
            <supportedType class="org.picketlink.idm.model.IdentityType"/>
            <supportedType class="org.picketlink.idm.model.Relationship"/>
          </supportedTypes>
          <credential-handlers>
            <credential-handler class="test.org.picketlink.as.subsystem.module.idm.SaleAgentPasswordCredentialHandler"/>
          </credential-handlers>
        </jpa-store>
      </identity-configuration>
    </identity-management>
  </subsystem>

All the configuration is external from applications where there is no need to add or change configuration files inside the application being deployed. The subsystem is responsible for during deployment time properly configure the applications being deployed, according with the configurations defined in the domain model:

  • The configurations in picketlink.xml are automatically created. No need to have this file inside your deployment.

  • The PicketLink Authenticators (Apache Tomcat Valves) for Identity Providers and Service Providers are automatically registered. No need to have a jboss-web.xml file inside your deployment.

  • The PicketLink dependencies are automatically configured. No need to have a META-INF/jboss-deployment-structure.xml inside your deployment defining the org.picketlink module as a dependency.

  • The Security Domain is automatically configured using the configurations defined in the domain model. No need to have a WEB-INF/jboss-web.xml file inside your deployment.

The table bellow summarizes the main differences between the traditional configuration and the subsystem configuration for PicketLink applications:

Configuration

Old Configuration

Subsystem Configuration

WEB-INF/picketlink.xml

Required

Not required. If present it will be considered instead of the configurations defined in the domain model.

WEB-INF/jboss-web.xml

Required

Not required. The PicketLink Authenticators (Tomcat Valves) and the Security Domain is read from the domain model.

META-INF/jboss-deployment-structure.xml

Required

Not required. When the PicketLink Extension/Subsystem is enabled, the dependency to the org.picketlink module is automatically configured.

The domain model is an abstraction for all PicketLink Federation configuration, providing a single schema from which all configurations can be defined for Identity Providers or Service Providers, for example.

The example bellow shows how the domain model can used to configure an Identity Provider and a Service Provider.


<subsystem xmlns="urn:jboss:domain:picketlink:1.0">
  <federation alias="federation-without-signatures">

    <saml token-timeout="4000" clock-skew="0" />

    <identity-provider alias="idp.war" security-domain="idp" supportsSignatures="false" url="http://localhost:8080/idp/">
        <trust>
            <trust-domain name="localhost" />
            <trust-domain name="mycompany.com2" />
            <trust-domain name="mycompany.com3" />
            <trust-domain name="mycompany.com4" />
        </trust>
        <handlers>
            <handler class="com.mycompany.CustomHandler">
                <handler-parameter name="param1" value="paramValue1"/>
                <handler-parameter name="param2" value="paramValue2"/>
                <handler-parameter name="param3" value="paramValue3"/>
            </handler>
        </handlers>
    </identity-provider>

    <service-providers>
        <service-provider alias="sales.war" post-binding="true" security-domain="sp" url="http://localhost:8080/sales/" supportsSignatures="false">
            <handlers>
                <handler class="com.mycompany.CustomHandler">
                    <handler-parameter name="param1" value="paramValue1"/>
                    <handler-parameter name="param2" value="paramValue2"/>
                    <handler-parameter name="param3" value="paramValue3"/>
                </handler>
            </handlers>
        </service-provider>
        <service-provider alias="employee.war" post-binding="true" security-domain="sp" url="http://localhost:8080/employee/" supportsSignatures="false" />
    </service-providers>
  </federation>
</subsystem>

This section will guide you through the basic steps to get an Identity Provider and a Service Provider working using the subsystem configuration.

Download the PicketLink Federation Quickstarts from https://repository.jboss.org/nexus/content/groups/public/org/picketlink/quickstarts/picketlink-quickstarts/2.1.8.Final/picketlink-quickstarts-2.1.8.Final-webapps-jboss-as7.zip.

Extract the file and copy the idp.war and sales-post.war to${JBOSS.HOME.dir}/standalone/deployments.

Open both files (idp.war and sales-post.war) and remove the following configuration files:

  • WEB-INF/picketlink.xml

  • META-INF/jboss-deployment-structure.xml

  • WEB-INF/jboss-web.xml

Important

Don't forget to configure the security domains for both applications.

Open the standalone.xml and add the following configuration for the PicketLink subsystem:


<subsystem xmlns="urn:jboss:domain:picketlink:1.0">
  <federation alias="example-federation">
      <!-- Identity Provider configuration -->
      <identity-provider alias="idp.war" security-domain="idp" supportsSignatures="false" url="http://localhost:8080/idp/">
          <trust>
              <trust-domain name="localhost" />
          </trust>
      </identity-provider>

      <!-- Service Provider configuration -->
      <service-providers>
          <service-provider alias="sales-post.war" post-binding="false" security-domain="sp" url="http://localhost:8080/sales-post/" supportsSignatures="false" />
      </service-providers>
  </federation>
</subsystem>

To make sure that everything is ok, please start JBoss AS and try to access the sales application. You should be redirected to the idp application.

To query those metrics and statistics you can use JBoss CLI as follows:


[standalone@localhost:9999 federation=example-federation] ./identity-provider=idp.war:read-resource(include-runtime=true)
{
    "outcome" => "success",
    "result" => {
         "alias" => "idp.war",
         "created-assertions-count" => "1",
         "error-response-to-sp-count" => "0",
         "error-sign-validation-count" => "0",
         "error-trusted-domain-count" => "0",
         "expired-assertions-count" => "0",
         "external" => false,
         "handler" => undefined,
         "login-complete-count" => "0",
         "login-init-count" => "0",
         "response-to-sp-count" => "3",
         "security-domain" => "idp",
         "strict-post-binding" => false,
         "supportsSignatures" => false,
         "url" => "http://localhost:8080/idp",
         "trust-domain" =>{"localhost" => undefined}
    }
}

The PicketLink Authenticator is basically a Tomcat Valve (org.apache.catalina.authenticator.FormAuthenticator). The only thing you need to do is change the valves configuration for your application.

This configuration changes for each supported binding.

IDPWebBrowserSSOValve from PicketLink provides the core IDP functionality on JBoss Application Server or Apache Tomcat.

Before configuring your application as an Identity Provider you need to add some configurations to your web.xml.

Let's start by defining a security-constraint element to restrict access to resources from unauthenticated users:

<security-constraint> 
    <web-resource-collection> 
        <web-resource-name>Manager command</web-resource-name> 
        <url-pattern>/*</url-pattern> 
    </web-resource-collection> 
    <auth-constraint> 
        <role-name>manager</role-name> 
    </auth-constraint> 
</security-constraint>


<security-role>
    <description>
      The role that is required to log in to IDP Application
    </description>
    <role-name>manager</role-name>
</security-role>

As you can see above, we define that only users with a role named manager are allowed to access the protected resources. Make sure to give your users the same role you defined here, otherwise they will get a 403 HTTP status code.

The next step is define your FORM login configuration using the login-config element:

<login-config>
    <auth-method>FORM</auth-method>
    <realm-name>PicketLink IDP Application</realm-name>
    <form-login-config> 
        <form-login-page>/jsp/login.jsp</form-login-page> 
        <form-error-page>/jsp/login-error.jsp</form-error-page> 
    </form-login-config> 
</login-config>

Make sure you have inside your application the pages defined in the elements form-login-page and form-error-page .

Important

Please, make sure you have a welcome file page in your application. You can define it in your web.xml or simply create an index.jsp at the root directory of your application.

All the configuration for an especific Identity Provider goes at the WEB-INF/picketlink.xml file. This file is responsible to define the behaviour of the Authenticator. During the identity provider startup, the authenticator parses this file and configures itself.

Bellow is how the picketlink.xml file should looks like:

<PicketLink xmlns="urn:picketlink:identity-federation:config:2.1">


    <PicketLinkIDP xmlns="urn:picketlink:identity-federation:config:2.1">

        <IdentityURL>http://localhost:8080/idp/ </IdentityURL>


        <Trust>
            <Domains>locahost,mycompany.com</Domains>
        </Trust>

        <KeyProvider ClassName="org.picketlink.identity.federation.core.impl.KeyStoreKeyManager">

            <Auth Key="KeyStoreURL" Value="/jbid_test_keystore.jks" />
            <Auth Key="KeyStorePass" Value="store123" />
            <Auth Key="SigningKeyPass" Value="test123" />
            <Auth Key="SigningKeyAlias" Value="servercert" />

            <ValidatingAlias Key="localhost" Value="servercert" />
            <ValidatingAlias Key="127.0.0.1" Value="servercert" />

        </KeyProvider>

    </PicketLinkIDP>

    <PicketLinkSTS xmlns="urn:picketlink:identity-federation:config:1.0" TokenTimeout="1000" ClockSkew="1000">
        <TokenProviders>
            <TokenProvider ProviderClass="org.picketlink.identity.federation.core.saml.v2.providers.SAML20AssertionTokenProvider"
                TokenType="urn:oasis:names:tc:SAML:2.0:assertion" TokenElement="Assertion"
                TokenElementNS="urn:oasis:names:tc:SAML:2.0:assertion" />
        </TokenProviders>
    </PicketLinkSTS>

    <Handlers xmlns="urn:picketlink:identity-federation:handler:config:2.1">

        <Handler class="org.picketlink.identity.federation.web.handlers.saml2.SAML2IssuerTrustHandler" />
        <Handler class="org.picketlink.identity.federation.web.handlers.saml2.SAML2LogOutHandler" />
        <Handler class="org.picketlink.identity.federation.web.handlers.saml2.SAML2AuthenticationHandler" />
        <Handler class="org.picketlink.identity.federation.web.handlers.saml2.RolesGenerationHandler" />

     </Handlers>

</PicketLink>

This element defines the basic configuration for the identity provider. The table bellow provides more information about the attributes supported by this element:

Name

Description

Value

AssertionValidity

Defines the timeout for the SAML assertion validity, in miliseconds.

Defaults to 300000 . Deprecated. Use the PicketLinkSTS element, instead.

RoleGenerator

Defines the name of the org.picketlink. identity.federation. core.interfaces. RoleGenerator subclass to be used to obtain user roles.

Defaults to org.picketlink.identity. federation.core. impl.EmptyRoleGenerator .

AttributeManager

Defines the name of the org.picketlink. identity.federation. core.interfaces. AttributeManager subclass to be used to obtain the SAML assertion attributes.

Defautls to org.picketlink. identity.federation. core.impl. EmptyAttributeManager .

StrictPostBinding

SAML Web Browser SSO Profile has a requirement that the IDP does not respond back in Redirect Binding. Set this to false if you want to force the IDP to respond to SPs using the Redirect Binding.

Values: true|false . Defaults to true, the IDP always respond via POST Binding.

SupportsSignatures

Indicates if digital signature/verification of SAML assertions are enabled. If this attribute is marked to true the Service Providers must support signatures too, otherwise the SAML messages will be considered as invalid.

Values: true|false. Defaults to false.

Encrypt

Indicates if SAML Assertions should be encrypted. If this attribute is marked to true the Service Providers must support signatures too, otherwise the SAML messages will be considered as invalid.

Values: true|false. Defaults to false

IdentityParticipantStack

Defines the name of the org.picketlink. identity.federation. web.core. IdentityParticipantStack subclass to be used to register and deregister participants in the identity federation.

Defaults to org.picketlink. identity.federation. web.core. IdentityServer.STACK.

PicketLink provides some built-in Handlers to help the Identity Provider Authenticator processing the SAML requests and responses.

The handlers are configured through the Handlers element.

To issue/renew/cancel/validate SAML tokens, the IDP relies on the PicketLink STS API and configuration. This configurations define how the tokens should be used by the IDP.

This PicketLinkSTS element defines the basic configuration for the Security Token Service. The table bellow provides more information about the attributes supported by this element:

Name

Description

Value

STSName

Name for this STS configuration.

Name for this Security Token Service.

TokenTimeout

Defines the token timeout in miliseconds.

Defaults to 3600 miliseconds.

ClockSkew

Defines the clock skew, or timing skew, for the token timeout.

Defaults to 2000 miliseconds.

SignToken

Indicates if the tokens should be signed.

Values: true|false . Defaults to false .

EncryptToken

Indicates if the tokens should be encrypted.

Values: true|false . Defaults to false .

CanonicalizationMethod

Sets the canonicalization method.

Defaults to http://www.w3.org/2001/10/xml-exc-c14n#WithComments

All the configuration for an especific Service Providers goes at the WEB-INF/picketlink.xml file. This file is responsible to define the behaviour of the Authenticator. During the service provider startup, the authenticator parses this file and configures itself.

Bellow is how the picketlink.xml file should looks like:

<PicketLink xmlns="urn:picketlink:identity-federation:config:2.1">


    <PicketLinkSP xmlns="urn:picketlink:identity-federation:config:2.1"
        BindingType="REDIRECT"
        RelayState="someURL"
        ErrorPage="/someerror.jsp"
        LogOutPage="/customLogout.jsp"
        IDPUsesPostBinding="true"
        SupportsSignatures="true">

        <IdentityURL>http://localhost:8080/idp/ </IdentityURL>
        <ServiceURL>http://localhost:8080/employee/ </ServiceURL>

        <KeyProvider ClassName="org.picketlink.identity.federation.core.impl.KeyStoreKeyManager">

            <Auth Key="KeyStoreURL" Value="/jbid_test_keystore.jks" />
            <Auth Key="KeyStorePass" Value="store123" />
            <Auth Key="SigningKeyPass" Value="test123" />
            <Auth Key="SigningKeyAlias" Value="servercert" />

            <ValidatingAlias Key="localhost" Value="servercert" />
            <ValidatingAlias Key="127.0.0.1" Value="servercert" />

        </KeyProvider>

    </PicketLinkSP>

    <Handlers xmlns="urn:picketlink:identity-federation:handler:config:2.1">

        <Handler class="org.picketlink.identity.federation.web.handlers.saml2.SAML2IssuerTrustHandler" />
        <Handler class="org.picketlink.identity.federation.web.handlers.saml2.SAML2LogOutHandler" />
        <Handler class="org.picketlink.identity.federation.web.handlers.saml2.SAML2AuthenticationHandler" />
        <Handler class="org.picketlink.identity.federation.web.handlers.saml2.RolesGenerationHandler" />

     </Handlers>

</PicketLink>

PicketLink provides some built-in Handlers to help the Service Provider Authenticator processing the SAML requests and responses.

The handlers are configured through the Handlers element.

The PicketLink Authenticator is basically a Tomcat Valve (org.apache.catalina.authenticator.FormAuthenticator). The only thing you need to do is change the valves configuration for your application.

This configuration changes for each supported binding.

SPRedirectSignatureFormAuthenticator is used to provide signature/encryption services to a Service Provider (SP) application for HTTP/Redirect binding of SAMLv2 specification. This authenticator

is an extension of the Section 10.5.4.4.6, “SPRedirectFormAuthenticator” .

SPRedirectFormAuthenticator provides the SAMLv2 HTTP/Redirect binding support for service provider (SP) applications.

SPPostSignatureFormAuthenticator is used to provide signature/encryption services to a Service Provider (SP) application for HTTP/POST binding of SAMLv2 specification. This authenticator

is an extension of the Section 10.5.4.4.8, “SPPostFormAuthenticator” .

SPPostFormAuthenticator is the main authenticator used to configure a service provider (SP) application for SAMLv2.0

To support digital signatures of SAML assertions you should define a KeyProvider element inside a PicketLinkIDP or PicketLinkSP.

Important

When using digital signatures you need to configure and enable it in both Identity Provider and Service Providers. Otherwise the SAML assertions would probably be considered as invalid.

<KeyProvider ClassName="org.picketlink.identity.federation.core.impl.KeyStoreKeyManager">
    <Auth Key="KeyStoreURL" Value="/jbid_test_keystore.jks" />
    <Auth Key="KeyStorePass" Value="store123" />
    <Auth Key="SigningKeyPass" Value="test123" />
    <Auth Key="SigningKeyAlias" Value="servercert" />

    <ValidatingAlias Key="idp.example.com" Value="servercert" />
    <ValidatingAlias Key="localhost" Value="servercert" />
</KeyProvider>

In order to configure the KeyProvider, you need to specify some configurations about the Java KeyStore that should be used to sign SAML assertions:

Auth Key

Description

KeyStoreURL

Where the value of the Value attribute points to the location of a Java KeyStore with the properly installed certificates.

KeyStorePass

Where the value of the Value attribute refers to the password of the referenced Java KeyStore.

SigningKeyAlias

Where the value of the Value attribute refers to the password of the installed certificate to be used to sign the SAML assertions.

SigningKeyPass

Where the value of the Value attribute refers to the alias of the certificate to be used to sign the SAML assertions.

The Service Provider also needs to know how to verify the signatures for the SAML assertions. This is done by the ValidationAlias elements.

<ValidatingAlias Key="idp.example.com" Value="servercert" />

Tip

Note that we declare the validating certificate for each domain using the ValidatingAlias .

At the IDP side you need an entry for each server/domain name defined as a trusted domain (Trust/Domains elements).

At the SP side you need an entry for the the server/domain name where the IDP is deployed.

When digital signatures are enabled, the authenticator will look at the ValidatingAlias table for a entry that matches the value of the Key attribute with the host name of the Issuer of the SAML assertion. For example, consider the following SAML Assertion issued by an Identity Provider located at http://idp.example.com:

<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
    ID="ID_ab0392ef-b557-4453-95a8-a7e168da8ac5" IssueInstant="2010-09-30T19:13:37.869Z"
    Version="2.0">
    <saml2:Issuer>http://idp.example.com </saml2:Issuer>
    <saml2:Subject>
        <saml2:NameID NameQualifier="urn:picketlink:identity-federation">jduke</saml2:NameID>
        <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer" />
    </saml2:Subject>
    <saml2:Conditions NotBefore="2010-09-30T19:13:37.869Z"
         NotOnOrAfter="2010-09-30T21:13:37.869Z" />
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments" />
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmlds#rsa-sha1" />
            <ds:Reference URI="#ID_ab0392ef-b557-4453-95a8-a7e168da8ac5">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmlds#enveloped-signature" />
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmlds#sha1" />
                <ds:DigestValue>0Y9QM5c5qCShz5UWmbFzBmbuTus=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
            se/flQ2htUQ0IUYieVkXNn9cfjnfgv6H99nFarsTNTpRI9xuSlw5OTai/2PYdZI2Va9+QzzBf99m
            VFyigfFdfrqug6aKFhF0lsujzlFfPfmXBbDRiTFX+4SkBeV71uuy7rOUI/jRiitEA0QrKqs0e/pV
            \+C8PoaariisK96Mtt7A=
        </ds:SignatureValue>
        <ds:KeyInfo>
            <ds:KeyValue>
                <ds:RSAKeyValue>
                    <ds:Modulus>
                        suGIyhVTbFvDwZdx8Av62zmP+aGOlsBN8WUE3eEEcDtOIZgO78SImMQGwB2C0eIVMhiLRzVPqoW1
                        dCPAveTm653zHOmubaps1fY0lLJDSZbTbhjeYhoQmmaBro/tDpVw5lKJwspqVnMuRK19ju2dxpKw
                        lYGGtrP5VQv00dfNPbs=
                    </ds:Modulus>
                    <ds:Exponent>AQAB</ds:Exponent>
                </ds:RSAKeyValue>
            </ds:KeyValue>
        </ds:KeyInfo>
    </ds:Signature>
</saml2:Assertion>

During the signature validation for this SAML assertion, the authenticator (in this case a Service Provider Authenticator) will try to find a ValidationAlias element with the value idp.example.com for its Key attribute. This alias references a certificate in your Java KeyStore that will be used to check the signature validity.

Usually, Java KeyStores would contain a key pair (public and private keys) to be used for signing and validating messages for an specific server and the trusted public keys to be used to validate messages received from others servers.

#

Name

Type

Objective

SP/IDP

Since Version

1

CLOCK_ SKEW_ MILIS

string

a long value in miliseconds to add a clock skew to assertion expiration validation at the Service provider

SP

2.0

2

DISABLE_ AUTHN_ STATEMENT

boolean

Setting a value will disable the generation of an AuthnStatement

IDP

2.0

3

DISABLE_ SENDING_ ROLES

boolean

Setting any value will disable the generation and return of roles to SP

IDP

2.0

4

DISABLE_ ROLE_ PICKING

boolean

Setting to true will disable picking IDP attribute statements

SP

2.0

5

ROLE_ KEY

String

a csv list of strings that represent the roles coming from IDP

SP

2.0

6

ASSERTION_ CONSUMER_ URL

String

the url to be used for assertionConsumerURL

SP

2.0

7

NAMEID_ FORMAT

String

Setting to a value will provide the nameid format to be sent to IDP

SP

2.0

8

ASSERTION_ SESSION_ ATTRIBUTE_ NAME

String

Specifies the name of the session attribute where the assertion will be stored. The assertion is stored as a DOM Document. This option is useful when you need to obtain the user's assertion to propagate or validate it against the STS.

SP

2.1.7

9

AUTHN_CONTEXT_CLASSES

String

Specifies a single or a comma separated list of SAML Authentication Classes to be used when creating an AuthnRequest. The value can be a full qualified name (FQN) or an alias. For each standard class name there is an alias, as defined by the org.picketlink.common.constants.SAMLAuthenticationContextClass.

SP

2.5.0

9

REQUESTED_AUTHN_CONTEXT_COMPARISON

String

Specifies the Comparison attribute of the RequestedAuthnContext. This option should be used in conjunction with the AUTHN_CONTEXT_CLASSES option. Only the values defined by the specification are supported.

SP

2.5.0

Table of Contents

Even though the SAML v2.0 specification has support for Global Logout, you have to use it very very wisely. Just remember that you need to keep the participants to a low number (say upto 5 participants with one IDP).

Global Logout : The user initiates GLO at one service provider which will log out the user at the IDP and all the service providers.

Local Logout : The user logs out of one service provider only. The session at the IDP and other service providers is intact.

The service provider url should be appended with "?LLO=true"

Basically, in the service provider page, have a url that has the query parameter.

Assume, your service provider is http://localhost:8080/sales/, then the url for the local log out would be http://localhost:8080/sales/?LLO=true

When using LLO, you must be aware of some security implications. The user is only disconnect from the service provider from which he logged out, which means that the user's session in the identity provider and others service providers are still active. In other words, the user's SSO session is still active and he is still able to log in in any other service provider. We strongly recommend to always use the Single Logout Profile (GLO).

Important

In the case of LLO, the service provider invalidates the session and forwards to a default logout page (logout.jsp) .Custom logout page can be configured in picketlink.xml page. Please refer to Service Provider Configuration.

Table of Contents

It is possible to use different Configuration Providers at the IDP and SP.

The configuration providers will then be the sole configuration leaders (instead of picketlink.xml)

Table of Contents

To configure the SAML Metadata Configuration Providers you need to follow these steps:

  • Define the PicketLink Authenticator (SP or IDP valves) and provide the configuration provider class name as an attribute

  • Depending if you're configuring an IDP or SP, provide a metadata file and put it on the classpath:

  • For Identity Providers : WEB-INF/classes/idp-metadata.xml

  • For Service Providers : WEB-INF/classes/sp-metadata.xml

Token Registries are configured through the PicketLinkSTS (Security Token Service configuration) element in the WEB-INF/picketlink.xml file:

<PicketLinkSTS xmlns="urn:picketlink:identity-federation:config:1.0" TokenTimeout="5000" ClockSkew="0">
        <TokenProviders>
		<TokenProvider
			ProviderClass="org.picketlink.identity.federation.core.saml.v2.providers.SAML20AssertionTokenProvider"
			TokenType="urn:oasis:names:tc:SAML:2.0:assertion"
			TokenElement="Assertion" TokenElementNS="urn:oasis:names:tc:SAML:2.0:assertion">
			<Property Key="TokenRegistry" Value="org.picketlink.identity.federation.core.sts.registry.JPABasedTokenRegistry" />
		</TokenProvider>
	</TokenProviders>
</PicketLinkSTS>

The example above uses a SAML v2 Token Provider configured with the org.picketlink.identity.federation.core.sts.registry.JPABasedTokenRegistry implementation. This is done by the TokenRegistry property.

If your IDP or SP applications are not running on JBoss Application Server or Apache Tomcat, then you can use the standalone mode of PicketLink.

For an IDP web application to be SAML enabled on any Servlet Container, you will have to add listeners and servlets as shown in the web.xml below:

Part of the idp-standalone.war


A jsp for login would be:


The jsp for error would be:


Page to list all the JBoss Web Services handlers that are part of the PicketLink project.

  1. SAML2Handler

  2. BinaryTokenHandler

  3. WSAuthenticationHandler

  4. WSAuthorizationHandler

This is a JBossWS handler (stack agnostic) that supports the SAML token profile of the Oasis Web Services Security (WSS) standard.

It can be configured both on the client side and the server side. The configuration is shown below both the client(outbound) as well as server(inbound).

This is the behavior when the handler is configured on the client side.

The client side usage is shown in the following client class. If you need to use an XML file to specify the handler on the client side, then please look in the references section below.

Example 10.18. STSWSClientTestCase.java

package org.picketlink.test.trust.tests;

import java.net.URL;
import java.util.List;

import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import javax.xml.ws.handler.Handler;

import org.junit.Test;
import org.picketlink.identity.federation.api.wstrust.WSTrustClient;
import org.picketlink.identity.federation.api.wstrust.WSTrustClient.SecurityInfo;
import org.picketlink.identity.federation.core.wstrust.WSTrustException;
import org.picketlink.identity.federation.core.wstrust.plugins.saml.SAMLUtil;
import org.picketlink.test.trust.ws.WSTest;
import org.picketlink.trust.jbossws.SAML2Constants;
import org.picketlink.trust.jbossws.handler.SAML2Handler;
import org.w3c.dom.Element;

/**
 * A Simple WS Test for the SAML Profile of WSS
 * @author Marcus Moyses
 * @author Anil Saldhana
 */
public class STSWSClientTestCase
{
   private static String username = "UserA";
   private static String password = "PassA";

   @SuppressWarnings("rawtypes")
   @Test
   public void testWSInteraction() throws Exception {
      WSTrustClient client = new WSTrustClient("PicketLinkSTS", "PicketLinkSTSPort",
            "http://localhost:8080/picketlink-sts/PicketLinkSTS",
            new SecurityInfo(username, password));
    Element assertion = null;
    try {
        System.out.println("Invoking token service to get SAML assertion for " + username);
        assertion = client.issueToken(SAMLUtil.SAML2_TOKEN_TYPE);
        System.out.println("SAML assertion for " + username + " successfully obtained!");
    } catch (WSTrustException wse) {
        System.out.println("Unable to issue assertion: " + wse.getMessage());
        wse.printStackTrace();
        System.exit(1);
    }

    URL wsdl = new URL("http://localhost:8080/picketlink-wstest-tests/WSTestBean?wsdl");
    QName serviceName = new QName("http://ws.trust.test.picketlink.org/", "WSTestBeanService");
    Service service = Service.create(wsdl, serviceName);
    WSTest port = service.getPort(new QName("http://ws.trust.test.picketlink.org/", "WSTestBeanPort"), WSTest.class);
    BindingProvider bp = (BindingProvider)port;
    bp.getRequestContext().put(SAML2Constants.SAML2_ASSERTION_PROPERTY, assertion);
    List<Handler> handlers = bp.getBinding().getHandlerChain();
    handlers.add(new SAML2Handler());
    bp.getBinding().setHandlerChain(handlers);

    port.echo("Test");
   }
}

Note: the SAML2Handler is instantiated and added to the handler list that is obtained from the BindingProvider binding.

There are two ways by which the SAML2Handler picks the SAML2 Assertion to send via the SOAP message.

  • The Client can push the SAML2 Assertion into the SOAP MessageContext under the key " org.picketlink.trust.saml.assertion ". In the example code above, look in the call bindingProvider.getRequestContext().put(xxxxx)

  • The SAML2 Assertion is available as part of the JAAS subject on the security context. This can happen if there has been a JAAS interaction with the usage of PicketLink STS login modules.

Assume that you have a POJO.

package org.picketlink.test.trust.ws;

import javax.jws.HandlerChain;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

/**
 * POJO that is exposed as WS
 * @author Anil Saldhana
 */
@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
@HandlerChain(file="authorize-handlers.xml")
public class POJOBean
{
   @WebMethod
   public void echo(String echo)
   {
      System.out.println(echo);
   }

   @WebMethod
   public void echoUnchecked(String echo)
   {
      System.out.println(echo);
   }
}

Note the use of the @HandlerChain annotation that defines the handler xml.

The handler xml is authorize-handlers.xml.

<?xml version="1.0" encoding="UTF-8"?>


<handler-chains xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee javaee_web_services_1_2.xsd">

  <handler-chain>


    <handler>
      <handler-name>WSAuthorizationHandler</handler-name>
      <handler-class>org.picketlink.trust.jbossws.handler.WSAuthorizationHandler</handler-class>
    </handler>

    <handler>
      <handler-name>WSAuthenticationHandler</handler-name>
      <handler-class>org.picketlink.trust.jbossws.handler.WSAuthenticationHandler</handler-class>
    </handler>

    <handler>
      <handler-name>SAML2Handler</handler-name>
      <handler-class>org.picketlink.trust.jbossws.handler.SAML2Handler</handler-class>
    </handler>


  </handler-chain>


</handler-chains>

Warning

Note : The order of execution of the handlers is SAML2Handler, WSAuthenticationHandler and WSAuthorizationHandler. These need to be defined in reverse order in the xml.

Since we intend to expose a POJO as a webservice, we need to package in a web archive (war).

The web.xml is:

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<servlet>
		<display-name>POJO Web Service</display-name>
		<servlet-name>POJOBeanService</servlet-name>
		<servlet-class>org.picketlink.test.trust.ws.POJOBean</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>POJOBeanService</servlet-name>
		<url-pattern>/POJOBeanService</url-pattern>
	</servlet-mapping>
</web-app>

Warning

Please do not define any <security-constraint> in the web.xml

The jboss-web.xml is:

<jboss-web>
  <security-domain>sts</security-domain>
</jboss-web>

The jboss-wsse.xml is

<jboss-ws-security xmlns="http://www.jboss.com/ws-security/config"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://www.jboss.com/ws-security/config
                   http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd">

  <port name="POJOBeanPort">
    <operation name="{http://ws.trust.test.picketlink.org/}echoUnchecked">
      <config>
        <authorize>
          <unchecked/>
        </authorize>
      </config>
    </operation>

    <operation name="{http://ws.trust.test.picketlink.org/}echo">
      <config>
        <authorize>
          <role>JBossAdmin</role>
        </authorize>
      </config>
    </operation>
  </port>



</jboss-ws-security>

As you can see, there are two operations defined on the POJO web services and each of these operations require different access control. The echoUnchecked() method allows free access to any authenticated user whereas the echo() method requires the caller to have "JBossAdmin" role.

The war should look as:

anil@localhost:~/picketlink/picketlink/integration-tests/trunk/picketlink-trust-tests$ jar tvf target/pojo-test.war
     0 Mon Apr 11 19:48:32 CDT 2011 META-INF/
   123 Mon Apr 11 19:48:30 CDT 2011 META-INF/MANIFEST.MF
     0 Mon Apr 11 19:48:30 CDT 2011 WEB-INF/
     0 Mon Apr 11 19:48:30 CDT 2011 WEB-INF/classes/
     0 Mon Apr 11 19:48:30 CDT 2011 WEB-INF/classes/org/
     0 Mon Apr 11 19:48:30 CDT 2011 WEB-INF/classes/org/picketlink/
     0 Mon Apr 11 19:48:30 CDT 2011 WEB-INF/classes/org/picketlink/test/
     0 Mon Apr 11 19:48:30 CDT 2011 WEB-INF/classes/org/picketlink/test/trust/
     0 Mon Apr 11 19:48:30 CDT 2011 WEB-INF/classes/org/picketlink/test/trust/ws/
     0 Mon Apr 11 19:48:30 CDT 2011 WEB-INF/lib/
   858 Mon Apr 11 19:48:26 CDT 2011 WEB-INF/classes/authorize-handlers.xml
  1021 Mon Apr 11 19:48:28 CDT 2011 WEB-INF/classes/org/picketlink/test/trust/ws/POJOBean.class
    65 Mon Apr 11 12:00:32 CDT 2011 WEB-INF/jboss-web.xml
   770 Mon Apr 11 17:44:16 CDT 2011 WEB-INF/jboss-wsse.xml
   598 Mon Apr 11 16:25:46 CDT 2011 WEB-INF/web.xml
     0 Mon Apr 11 19:48:32 CDT 2011 META-INF/maven/
     0 Mon Apr 11 19:48:32 CDT 2011 META-INF/maven/org.picketlink/
     0 Mon Apr 11 19:48:32 CDT 2011 META-INF/maven/org.picketlink/picketlink-integration-trust-tests/
  7918 Mon Apr 11 18:56:16 CDT 2011 META-INF/maven/org.picketlink/picketlink-integration-trust-tests/pom.xml
   142 Mon Apr 11 19:48:30 CDT 2011 META-INF/maven/org.picketlink/picketlink-integration-trust-tests/pom.properties
anil@localhost:~/picketlink/picketlink/integration-tests/trunk/picketlink-trust-tests

The Test Case is something like:

 package org.picketlink.test.trust.tests;

import java.net.URL;
import java.util.List;

import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import javax.xml.ws.handler.Handler;

import org.junit.Test;
import org.picketlink.identity.federation.api.wstrust.WSTrustClient;
import org.picketlink.identity.federation.api.wstrust.WSTrustClient.SecurityInfo;
import org.picketlink.identity.federation.core.wstrust.WSTrustException;
import org.picketlink.identity.federation.core.wstrust.plugins.saml.SAMLUtil;
import org.picketlink.test.trust.ws.WSTest;
import org.picketlink.trust.jbossws.SAML2Constants;
import org.picketlink.trust.jbossws.handler.SAML2Handler;
import org.w3c.dom.Element;

/**
 * A Simple WS Test for POJO WS Authorization using PicketLink
 * @author Anil Saldhana
 * @since Oct 3, 2010
 */
public class POJOWSAuthorizationTestCase
{
   private static String username = "UserA";
   private static String password = "PassA";

   @SuppressWarnings("rawtypes")
   @Test
   public void testWSInteraction() throws Exception
   {
      // Step 1:  Get a SAML2 Assertion Token from the STS
      WSTrustClient client = new WSTrustClient("PicketLinkSTS", "PicketLinkSTSPort",
            "http://localhost:8080/picketlink-sts/PicketLinkSTS",
            new SecurityInfo(username, password));
      Element assertion = null;
      try {
         System.out.println("Invoking token service to get SAML assertion for " + username);
         assertion = client.issueToken(SAMLUtil.SAML2_TOKEN_TYPE);
         System.out.println("SAML assertion for " + username + " successfully obtained!");
      } catch (WSTrustException wse) {
         System.out.println("Unable to issue assertion: " + wse.getMessage());
         wse.printStackTrace();
         System.exit(1);
      }

      // Step 2: Stuff the Assertion on the SOAP message context and add the SAML2Handler to client side handlers
      URL wsdl = new URL("http://localhost:8080/pojo-test/POJOBeanService?wsdl");
      QName serviceName = new QName("http://ws.trust.test.picketlink.org/", "POJOBeanService");
      Service service = Service.create(wsdl, serviceName);
      WSTest port = service.getPort(new QName("http://ws.trust.test.picketlink.org/", "POJOBeanPort"), WSTest.class);
      BindingProvider bp = (BindingProvider)port;
      bp.getRequestContext().put(SAML2Constants.SAML2_ASSERTION_PROPERTY, assertion);
      List<Handler> handlers = bp.getBinding().getHandlerChain();
      handlers.add(new SAML2Handler());
      bp.getBinding().setHandlerChain(handlers);

      //Step 3: Access the WS. Exceptions will be thrown anyway.
      port.echo("Test");
   }
}

PicketLink provides ways to protect your EJB endpoints using a SAML Security Token Service. This means that you can apply some security to your EJBs where only users with a valid SAML assertion can invoke to them.

This scenario is very common if you are looking for:

  1. Leverage your Single Sign-On infrastructure to your service layer (EJBs, Web Services, etc)

  2. Integrate your SAML Service Providers with your services by trusting the assertion previously issued by the Identity Provider

  3. Any situation that requires the propagation of authorization/authentication information from one domain to another

The client must first obtain the SAML assertion from PicketLink STS by sending a WS-Trust request to the token service. This process usually involves authentication of the client. After obtaining the SAML assertion from the STS, the client includes the assertion in the security context of the EJB request before invoking an operation on the bean. Upon receiving the invocation, the EJB container extracts the assertion and validates it by sending a WS-Trust validate message to the STS. If the assertion is considered valid by the STS (and the proof of possession token has been verified if needed), the client is authenticated.


On JBoss, the SAML assertion validation process is handled by the SAML2STSLoginModule. It reads properties from a configurable file (specified by the configFile option) and establishes communication with the STS based on these properties. We will see how a configuration file looks like later on. If the assertion is valid, a Principal is created using the assertion subject name and if the assertion contains roles, these roles are also extracted and associated with the caller's Subject.

The client must first obtain the SAML assertion from the PicketLink STS or you Identity Provider. This process usually involves authentication of the client. After obtaining the SAML assertion, the client includes the assertion in the security context of the EJB request before invoking an operation on the bean. Upon receiving the invocation, the EJB container extracts the assertion and validates it by sending a WS-Trust validate message to the STS. If the assertion is considered valid by the STS (and the proof of possession token has been verified if needed), the client is authenticated.

On JBoss, the SAML assertion validation process is handled by the Section 10.7.1.5.3, “SAML2STSLoginModule” . It reads properties from a configurable file (specified by the configFile option) and establishes communication with the STS based on these properties. We will see how a configuration file looks like later on. If the assertion is valid, a Principal is created using the assertion subject name and if the assertion contains roles, these roles are also extracted and associated with the caller's Subject.

This section will cover two possible scenarios to protect and access your secured EJB endpoints. The main difference between these two scenarios is where the EJB client is deployed.

  • Remote EJB Client using JNDI

  • EJB Client is deployed at the same instance than your EJB endpoints

Important

Before starting, please take a look at the following documentation Remote EJB invocations via JNDI .

The configuration described in this section only works with versions 7.2.0+ and 7.1.3+ of JBoss Application Server.

If your endpoints are accessible from remote clients (in a different VM or server than your endpoints) you need to configure your JBoss Application Server 7 to allow use a SAML Assertion during the InitialContext creation.

Basically, the configuration envolves the following steps:

  1. Add a new Security Realm to your standalone.xml

  2. Create a Security Domain using the Section 10.7.1.5.3, “SAML2STSLoginModule”

  3. Change the Remoting Connector to use the new Security Realm

Important

Security Realms are better described in the JBoss Application Server Documentation.

Edit your standalone.xml and add the following configuration for a new Security Realm:

<security-realm name="SAMLRealm">
    <authentication>
        <jaas name="ejb-remoting-sts"/>
    </authentication>
</security-realm>

The configuration above defines a Security Realm that delegates the username/password information to a JAAS Security Domain (that we'll create later) in order to authenticate an user.

When using the JAAS configuration for Security Realms, the remoting subsystem enables the PLAIN SASL authentication. This will allow your remote clients send the username/password where the password would be the previously issued SAML Assertion.In our case, the password will be the String representation of the SAML Assertion.

Tip

Make sure you also enable SSL. Otherwise all communication with the server will be done using plain text.

This page references the PicketLink Login Modules for the Security Token Server.

Options Include:

  • configFile : a properties file that gives details on the STS to the login module. This can be optional if you want to specify values directly.

  • handlerChain : Comma separated list of handlers you need to set for handling outgoing message to STS. Values: binary (to inject BinaryTokenHandler), saml2 (to inject SAML2Handler), map (to inject MapBasedTokenHandler) or class name of your own handler with default constructor.

  • cache.invalidation : set it to "true" if you want the JBoss auth cache to invalidate caches based on saml token expiry. By default, this value is false.

  • inject.callerprincipa l: set it to "true" if the login module should add a group principal called "CallerPrincipal" to the subject. This is useful in JBoss AS for programmatic security in web/ejb components.

  • groupPrincipalName : by default, JBoss AS security uses "Roles" as the group principal name in the subject. You can give a different value.

  • endpointAddress : endpoint url of STS

  • serviceName : service Name of STS

  • portName : port name of STS

  • username : username of account on STS.

  • password : password of account on STS

  • wsaIssuer : if you need to customize the WS-Addressing Issuer address in the WS-Trust call to the STS.

  • wspAppliesTo : if you need to customize the WS-Policy AppliesTo in the WS-Trust call to the STS.

  • securityDomainForFactory : if you have a JaasSecurityDomain mbean service in JBoss AS that provides the truststore.

  • map.token.key : key to find binary token in JAAS sharedState map. Defaults to "ClientID".

  • soapBinding : allow to change SOAP binding for SAML reuest.

  • requestType : allows to override SAML request type when sending request to STS. Default: "http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue" Other possible value: "http://docs.oasis-open.org/ws-sx/ws-trust/200512/Validate".

Note: The configFile option is optional. If you provide that, then it should be as below.

Configuration file such as sts-client.properties.

serviceName=PicketLinkSTS

portName=PicketLinkSTSPort

endpointAddress=http://localhost:8080/picketlink-sts/PicketLinkSTS

username=admin

password=admin

wsaIssuer=http://localhost:8080/someissuer

wspAppliesTo=http://localhost:8080/testws

Note:

  • the password can be masked according to http://community.jboss.org/wiki/PicketLinkConfigurationMaskpassword which would give us something like, password=MASK-dsfdsfdslkfh

  • wsaIssuer can be optionally added if you want a value for the WS-Addressing issuer in the WS-Trust call to the STS.

  • wspAppliesTo can be optionally added if you want a value for WS-Policy AppliesTo in the WS-Trust call to the STS.

  • serviceName, portName, endpointAddress are mandatory .

  • username and password keys are not needed if you are using mutual authenticated ssl (MASSL) with the STS.

Either you specify the module options directly or you can use a properties file for the STS related properties.

If the STS sends roles via Attribute Statements in the SAML assertion, then the user has to use the SAMLRoleLoginModule.

<application-policy name="saml">
  <authentication>
    <login-module code="org.picketlink.trust.jbossws.jaas.JBWSTokenIssuingLoginModule"  flag="required">
         <module-option name="endpointAddress">SOME_URL</module-option>
         <module-option name="serviceName">SecurityTokenService</module-option>
         <module-option name="portName">RequestSecurityToken</module-option>
         <module-option name="inject.callerprincipal">true</module-option>
         <module-option name="handlerChain">binary</module-option>
    </login-module>
    <login-module code="org.picketlink.trust.jbossws.jaas.SAMLRoleLoginModule"  flag="required"/>
  </authentication>
</application-policy>

If the STS does not send roles, then the user has to configure a different JAAS login module to pick the roles for the username. Something like the UsernamePasswordLoginModule.

<application-policy xmlns="urn:jboss:security-beans:1.0" name="binary">
      <authentication>
         <login-module code="org.picketlink.trust.jbossws.jaas.JBWSTokenIssuingLoginModule" flag="required">
            <module-option name="endpointAddress">http://localhost:8080/picketlink-sts/PicketLinkSTS</module-option>
            <module-option name="serviceName">PicketLinkSTS</module-option>
            <module-option name="portName">PicketLinkSTSPort</module-option>
            <module-option name="inject.callerprincipal">true</module-option>
            <module-option name="handlerChain">binary</module-option>
            <module-option name="username">admin</module-option>
            <module-option name="password">MASK-0BbleBL2LZk=</module-option>
            <module-option name="salt">18273645</module-option>
            <module-option name="iterationCount">56</module-option>
            <module-option name="useOptionsCredentials">true</module-option>
            <module-option name="overrideDispatch">true</module-option>
            <module-option name="wspAppliesTo">http://services.testcorp.org/provider1</module-option>
            <module-option name="wsaIssuer">http://something</module-option>
            <module-option name="password-stacking">useFirstPass</module-option>
         </login-module>

         <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
            <module-option name="usersProperties">sts-users.properties</module-option>
            <module-option name="rolesProperties">sts-roles.properties</module-option>
            <module-option name="password-stacking">useFirstPass</module-option>
         </login-module>
      </authentication>
   </application-policy>

This module defines the following module options:

  • configFile - this property identifies the properties file that will be used to establish communication with the external security token service.

  • cache.invalidation : set it to true if you require invalidation of JBoss Auth Cache at SAML Principal expiration.

  • jboss.security.security_domain -security domain at which Principal will expire if cache.invalidation is used.

  • roleKey : key of the attribute name that we need to use for Roles from the SAML assertion. This can be a comma-separated string values such as (Role,Membership)

  • localValidation : if you want to validate the assertion locally for signature and expiry

  • localValidationSecurityDomain : the security domain for the trust store information (via the JaasSecurityDomain)

  • tokenEncodingType : encoding type of SAML token delivered via http request's header. Possible values are:

    • base64 - content encoded as base64. In case of encoding will vary between base64 and gzip use base64 and LoginModule will detect gzipped data.

    • gzip - gzipped content encoded as base64

    • none - content not encoded in any way

  • samlTokenHttpHeader - name of http request header to fetch SAML token from. For example: "Authorize"

  • samlTokenHttpHeaderRegEx - Java regular expression to be used to get SAML token from "samlTokenHttpHeader". Example: use: . "(. )".* to parse SAML token from header content like this: SAML_assertion="HHDHS=", at the same time set samlTokenHttpHeaderRegExGroup to 1.

  • samlTokenHttpHeaderRegExGroup - Group value to be used when parsing out value of http request header specified by "samlTokenHttpHeader" using "samlTokenHttpHeaderRegEx".

pattern = Pattern.compile(samlTokenHttpHeaderRegEx, Pattern.DOTALL);
Matcher m = pattern.matcher(content);
m.matches();
m.group(samlTokenHttpHeaderRegExGroup)

Any properties specified besides the above properties are assumed to be used to configure how the STSClient will connect to the STS. For example, the JBossWS StubExt.PROPERTY_SOCKET_FACTORY can be specified in order to inform the socket factory that must be used to connect to the STS. All properties will be set in the request context of the Dispatch instance used by the STSClient to send requests to the STS.

An example of a configFile can be seen bellow:

serviceName=PicketLinkSTS
portName=PicketLinkSTSPort
endpointAddress=[http://localhost:8080/picketlink-sts/PicketLinkSTS]
username=JBoss
password=JBoss

The first three properties specify the STS endpoint URL, service name, and port name. The last two properties specify the username and password that are to be used by the application server to authenticate to the STS and have the SAML assertions validated.

NOTE: Sub-classes can use getSTSClient() method to customize the STSClient class to make calls to STS

Example Configuration 1:

<application-policy xmlns="urn:jboss:security-beans:1.0" name="cache-test">
      <authentication>
         <login-module code="org.picketlink.identity.federation.bindings.jboss.auth.SAML2STSLoginModule" flag="required">
            <module-option name="password-stacking">useFirstPass</module-option>
            <module-option name="configFile">sts-config.properties</module-option>
            <module-option name="cache.invalidation">true</module-option>
            <module-option name="localValidation">true</module-option>
            <module-option name="localValidationSecurityDomain">MASSL</module-option>
         </login-module>
      </authentication>
   </application-policy>

Example Configuration 2 using http header and local validation:

   <application-policy xmlns="urn:jboss:security-beans:1.0" name="service">
      <authentication>
         <login-module code="org.picketlink.identity.federation.bindings.jboss.auth.SAML2STSLoginModule" flag="required">
            <module-option name="password-stacking">useFirstPass</module-option>
            <module-option name="cache.invalidation">true</module-option>
            <module-option name="localValidation">true</module-option>
            <module-option name="localValidationSecurityDomain">java:jaas/localValidationDomain</module-option>
            <module-option name="tokenEncodingType">gzip</module-option>
            <module-option name="samlTokenHttpHeader">Auth</module-option>
            <module-option name="samlTokenHttpHeaderRegEx">.*"(.*)".*</module-option>
            <module-option name="samlTokenHttpHeaderRegExGroup">1</module-option>
         </login-module>
         <login-module code="org.picketlink.trust.jbossws.jaas.SAMLRoleLoginModule" flag="required"/>
      </authentication>
   </application-policy>

In case of local validation here is example of jboss-beans.xml file to use to configure JAAS Security Domain for (JBoss AS6 or EAP5):

<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="urn:jboss:bean-deployer:2.0">
   <!-- localValidationDomain bean -->
   <bean name="LocalValidationBean" class="org.jboss.security.plugins.JaasSecurityDomain">
     <constructor>
          <parameter>localValidationDomain</parameter>
     </constructor>
     <property name="keyStoreURL">file://${jboss.server.home.dir}/conf/stspub.jks</property>
     <property name="keyStorePass">keypass</property>
     <property name="keyStoreAlias">sts</property>
     <property name="securityManagement"><inject bean="JNDIBasedSecurityManagement"/></property>
   </bean>
</deployment>

For JBoss AS7 or JBoss EAP6 add following security domain to your configuration file:

<security-domain name="localValidationDomain">
      <jsse
         keystore-password="keypass"
         keystore-type="JKS"
         keystore-url="file:///${jboss.server.config.dir}/stspub.jks"
         server-alias="sts"/>
</security-domain>

and reference this security domain as: <module-option name="localValidationSecurityDomain">localValidationDomain</module-option>.

org.picketlink.identity.federation.bindings.jboss.auth. SAMLTokenCertValidatingLoginModule

This module defines the following module options:

  • roleKey : key of the attribute name that we need to use for Roles from the SAML assertion. This can be a comma-separated string values such as (Role,Membership)

  • localValidationSecurityDomain : the security domain for the trust store information (via the JaasSecurityDomain)

  • cache.invalidation - set it to true if you require invalidation of JBoss Auth Cache at SAML Principal expiration.

  • jboss.security.security_domain -security domain at which Principal will expire if cache.invalidation is used.

  • tokenEncodingType : encoding type of SAML token delivered via http request's header. Possible values are:

    • base64 - content encoded as base64. In case of encoding will vary between base64 and gzip use base64 and LoginModule will detect gzipped data.

    • gzip - gzipped content encoded as base64

    • none - content not encoded in any way

  • samlTokenHttpHeader - name of http request header to fetch SAML token from. For example: "Authorize"

  • samlTokenHttpHeaderRegEx - Java regular expression to be used to get SAML token from "samlTokenHttpHeader". Example: use: . "(. )".* to parse SAML token from header content like this: SAML_assertion="HHDHS=", at the same time set samlTokenHttpHeaderRegExGroup to 1.

  • samlTokenHttpHeaderRegExGroup - Group value to be used when parsing out value of http request header specified by "samlTokenHttpHeader" using "samlTokenHttpHeaderRegEx".

pattern = Pattern.compile(samlTokenHttpHeaderRegEx, Pattern.DOTALL);
Matcher m = pattern.matcher(content);
m.matches();
m.group(samlTokenHttpHeaderRegExGroup)

Example Configuration 1:

<application-policy xmlns="urn:jboss:security-beans:1.0" name="certpath">
      <authentication>
         <login-module code="org.picketlink.identity.federation.bindings.jboss.auth.SAMLTokenCertValidatingLoginModule" flag="required">
            <module-option name="password-stacking">useFirstPass</module-option>
            <module-option name="cache.invalidation">true</module-option>
            <module-option name="localValidationSecurityDomain">java:jaas/localValidationDomain</module-option>
         </login-module>
      </authentication>
</application-policy>

Example Configuration 2 using http header:

   <application-policy xmlns="urn:jboss:security-beans:1.0" name="service">
      <authentication>
         <login-module code="org.picketlink.identity.federation.bindings.jboss.auth.SAML2STSLoginModule" flag="required">
            <module-option name="password-stacking">useFirstPass</module-option>
            <module-option name="cache.invalidation">true</module-option>
            <module-option name="localValidationSecurityDomain">java:jaas/localValidationDomain</module-option>
            <module-option name="tokenEncodingType">gzip</module-option>
            <module-option name="samlTokenHttpHeader">Auth</module-option>
            <module-option name="samlTokenHttpHeaderRegEx">.*"(.*)".*</module-option>
            <module-option name="samlTokenHttpHeaderRegExGroup">1</module-option>
         </login-module>
      </authentication>
   </application-policy>

Example of jboss-beans.xml file to use to configure JAAS Security Domain containing trust store for above examples:

<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="urn:jboss:bean-deployer:2.0">
   <!-- localValidationDomain bean -->
   <bean name="LocalValidationBean" class="org.jboss.security.plugins.JaasSecurityDomain">
     <constructor>
          <parameter>localValidationDomain</parameter>
     </constructor>
     <property name="keyStoreURL">file://${jboss.server.home.dir}/conf/stspub.jks</property>
     <property name="keyStorePass">keypass</property>
     <property name="keyStoreAlias">sts</property>
     <property name="securityManagement"><inject bean="JNDIBasedSecurityManagement"/></property>
   </bean>
</deployment>

Your web.xml will define some security constraints. But it will define a <login-config> that is different from the servlet specifcation mandated BASIC, CLIENT-CERT, FORM or DIGEST methods. We suggest the use of SECURITY_DOMAIN as the method.

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Restricted Access - Get Only</web-resource-name>
        <url-pattern>/*</url-pattern>
        <http-method>GET</http-method>
    </web-resource-collection>
    <auth-constraint>
 	<role-name>STSClient</role-name>
    </auth-constraint>
    <user-data-constraint>
        <transport-guarantee>NONE</transport-guarantee>
    </user-data-constraint>
</security-constraint>

<security-role>
    <role-name>STSClient</role-name>
</security-role>

<login-config>
    <auth-method>SECURITY_DOMAIN</auth-method>
    <realm-name>SECURITY_DOMAIN</realm-name>
    <form-login-config>
	<form-login-page>/login.html</form-login-page>
	<form-error-page>/error.html</form-error-page>
    </form-login-config>
</login-config>

Important

Note that we defined two pages in the <form-login-config> : login.html and error.html . Both pages must exists inside your deployment.

Change your WEB-INF/jboss-web.xml to configure the PicketLinkAuthenticator as a valve:

<jboss-web>
	<security-domain>authenticator</security-domain>
	<context-root>authenticator</context-root>
	<valve>
		<class-name>org.picketlink.identity.federation.bindings.tomcat.PicketLinkAuthenticator
		</class-name>
	</valve>
</jboss-web>

We also defined a <security-domain> configuration with the name of the security domain that you configured in your standalone.xml:

<security-domain name="authenticator" cache-type="default">
    <authentication>
        <login-module code="org.picketlink.test.trust.loginmodules.TestRequestUserLoginModule" flag="required">
            <module-option name="usersProperties" value="users.properties"/>
            <module-option name="rolesProperties" value="roles.properties"/>
        </login-module>
    </authentication>
</security-domain>

Tip

To use PicketLink you need to define it as a module dependency using the META-INF/jboss-deployment-structure.xml.

Your web.xml will define some security constraints. But it will define a <login-config> that is different from the servlet specifcation mandated BASIC, CLIENT-CERT, FORM or DIGEST methods. We suggest the use of SECURITY-DOMAIN as the method.

Create a context.xml in your WEB-INF directory of your web-archive.

<Context>
  <Valve className="org.picketlink.identity.federation.bindings.tomcat.PicketLinkAuthenticator" />
</Context>

Your web.xml may look as follows:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
   xmlns="http://java.sun.com/xml/ns/j2ee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

   <description>Sales Application</description>

   <security-constraint>
      <display-name>Restricted</display-name>
      <web-resource-collection>
         <web-resource-name>Restricted Access</web-resource-name>
         <url-pattern>/*</url-pattern>
      </web-resource-collection>
      <auth-constraint>
         <role-name>Sales</role-name>
      </auth-constraint>
      <user-data-constraint>
         <transport-guarantee>NONE</transport-guarantee>
      </user-data-constraint>
   </security-constraint>

   <security-role>
      <role-name>Sales</role-name>
   </security-role>

   <login-config>
      <auth-method>SECURITY-DOMAIN</auth-method>
   </login-config>
</web-app>

Warning

NOTE: The use of SECURITY-DOMAIN as the auth-method.

The war should be packaged as a regular web archive.

  1. Go to the deploy directory.

  2. cp -R jmx-console.war test.war

  3. In deploy/test.war/WEB-INF/web.xml, change the auth-method element to SECURITY-DOMAIN.

  4. <login-config>
          <auth-method>SECURITY-DOMAIN</auth-method>
          <realm-name>JBoss JMX Console</realm-name>
       </login-config>
    
  5. Also uncomment the security constraints in web.xml. It should look as follows.

  6. <!-- A security constraint that restricts access to the HTML JMX console
       to users with the role JBossAdmin. Edit the roles to what you want and
       uncomment the WEB-INF/jboss-web.xml/security-domain element to enable
       secured access to the HTML JMX console.
       -->
       <security-constraint>
         <web-resource-collection>
           <web-resource-name>HtmlAdaptor</web-resource-name>
           <description>An example security config that only allows users with the
             role JBossAdmin to access the HTML JMX console web application
           </description>
           <url-pattern>/*</url-pattern>
           <http-method>GET</http-method>
           <http-method>POST</http-method>
         </web-resource-collection>
         <auth-constraint>
           <role-name>JBossAdmin</role-name>
         </auth-constraint>
       </security-constraint>
    
  7. In the /server/default/conf/jboss-log4j.xml , add trace category for org.jboss.security.

  8. Start JBoss AS.

  9. Go to the following url: http://localhost:8080/test/

  10. You should see a HTTP 403 message.

  11. If you look inside the log, log/server.log, you will see the following exception trace:

  12. 2011-04-20 11:02:01,714 TRACE [org.jboss.security.plugins.auth.JaasSecurityManagerBase.jmx-console] (http-127.0.0.1-8080-1) Login failure
    javax.security.auth.login.FailedLoginException: Password Incorrect/Password Required
            at org.jboss.security.auth.spi.UsernamePasswordLoginModule.login(UsernamePasswordLoginModule.java:252)
            at org.jboss.security.auth.spi.UsersRolesLoginModule.login(UsersRolesLoginModule.java:152)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
            at java.lang.reflect.Method.invoke(Method.java:597)
            at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769)
            at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186)
            at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683)
            at java.security.AccessController.doPrivileged(Native Method)
            at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
            at javax.security.auth.login.LoginContext.login(LoginContext.java:579)
            at org.jboss.security.plugins.auth.JaasSecurityManagerBase.defaultLogin(JaasSecurityManagerBase.java:552)
            at org.jboss.security.plugins.auth.JaasSecurityManagerBase.authenticate(JaasSecurityManagerBase.java:486)
            at org.jboss.security.plugins.auth.JaasSecurityManagerBase.isValid(JaasSecurityManagerBase.java:365)
            at org.jboss.security.plugins.JaasSecurityManager.isValid(JaasSecurityManager.java:160)
            at org.jboss.web.tomcat.security.JBossWebRealm.authenticate(JBossWebRealm.java:384)
            at org.picketlink.identity.federation.bindings.tomcat.PicketLinkAuthenticator.authenticate(PicketLinkAuthenticator.java:104)
            at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:491)
            at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
            at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
            at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
            at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
            at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
            at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
            at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
            at java.lang.Thread.run(Thread.java:662)
    

    As you can see from the stack trace, PicketLinkAuthenticator method has been kicked in.

The PicketLink API provides the org.picketlink.identity.federation.saml.v2.assertion.AssertionType class to encapsulate the informations parsed from a SAML Assertion.

Let's suppose we have the following SAML Assertion:

<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="ID_75291c31-93f7-4f7f-8422-aacdb07466ee" IssueInstant="2012-05-25T10:40:58.912-03:00" Version="2.0">
    <saml:Issuer>http: //192.168.1.1:8080/idp-sig/</saml:Issuer> 
    <saml:Subject> 
        <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">user</saml:NameID>
        <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> 
            <saml:SubjectConfirmationData InResponseTo="ID_326a389f-6a8a-4712-b71d-77aa9c36795c" NotBefore="2012-05-25T10:40:58.894-03:00" NotOnOrAfter="2012-05-25T10:41:00.912-03:00" Recipient="http://192.168.1.4:8080/fake-sp" /> 
        </saml:SubjectConfirmation> 
    </saml:Subject> 
    <saml:Conditions NotBefore="2012-05-25T10:40:57.912-03:00" NotOnOrAfter="2012-05-25T10:41:00.912-03:00" /> 
    <saml:AuthnStatement AuthnInstant="2012-05-25T10:40:58.981-03:00"> 
        <saml:AuthnContext> 
            <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> 
        </saml:AuthnContext> 
    </saml:AuthnStatement> 
    <saml:AttributeStatement> 
        <saml:Attribute Name="Role"> 
            <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">test-role1</saml:AttributeValue> 
        </saml:Attribute> 
        <saml:Attribute Name="Role"> 
            <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">test-role2</saml:AttributeValue>
        </saml:Attribute> 
        <saml:Attribute Name="Role"> 
            <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">test-role3</saml:AttributeValue>
        </saml:Attribute>
    </saml:AttributeStatement>
</saml:Assertion>

The code to parse this XML is:

/**
     * <p>
     * Parses a SAML Assertion XML representation and convert it to a {@link AssertionType} instance.
     * </p>
     * 
     * @throws Exception
     */    
    @Test
    public void testParseAssertion() throws Exception {
        // get a InputStream from the source XML file
        InputStream samlAssertionInputStream = getSAMLAssertion();

        SAMLParser samlParser = new SAMLParser();

        Object parsedObject = samlParser.parse(samlAssertionInputStream);

        Assert.assertNotNull(parsedObject);
        Assert.assertTrue(parsedObject.getClass().equals(AssertionType.class));

        // cast the parsed object to the expected type, in this case AssertionType
        AssertionType assertionType = (AssertionType) parsedObject;

        // checks if the Assertion has expired.
        Assert.assertTrue(AssertionUtil.hasExpired(assertionType));

        // let's write the parsed assertion to the sysout
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        SAMLAssertionWriter writer = new SAMLAssertionWriter(StaxUtil.getXMLStreamWriter(baos));

        writer.write(assertionType);

        System.out.println(new String(baos.toByteArray()));
    }

The PicketLink API provides the org.picketlink.identity.federation.api.saml.v2.sig.SAML2Signature to help during signature generation/validation for SAML Assertions.

/**
     * <p>
     * Signs a SAML Assertion.
     * </p>
     *
     * @throws Exception
     */
    @Test
    public void testSignAssertion() throws Exception {
        InputStream samlAssertionInputStream = getSAMLAssertion();
        
        // convert the InputStream to a DOM Document
        Document document = DocumentUtil.getDocument(samlAssertionInputStream);

        SAML2Signature samlSignature = new SAML2Signature();
        
        // get the key store manager instance.
        KeyStoreKeyManager keyStoreKeyManager = getKeyStoreManager();

        samlSignature.signSAMLDocument(document, keyStoreKeyManager.getSigningKeyPair());
        
        // let's print the signed assertion to the sysout
        System.out.println(DocumentUtil.asString(document));
    }

As you can see, we need to create a instance of org.picketlink.identity.federation.core.impl.KeyStoreKeyManager from where the certificates will be retrieved from. The code bellow shows you how to create it:

     /**
     * <p>
     * Creates a {@link KeyStoreKeyManager} instance.
     * </p>
     *
     * @throws Exception
     */
    private KeyStoreKeyManager getKeyStoreManager() 
        throws TrustKeyConfigurationException, TrustKeyProcessingException {

        KeyStoreKeyManager keyStoreKeyManager = new KeyStoreKeyManager();

        ArrayList<AuthPropertyType> authProperties = new ArrayList<AuthPropertyType>();

        authProperties.add(createAuthProperty(KeyStoreKeyManager.KEYSTORE_URL, Thread.currentThread().getContextClassLoader().getResource("./keystore/jbid_test_keystore.jks").getFile()));
        authProperties.add(createAuthProperty(KeyStoreKeyManager.KEYSTORE_PASS, "store123"));

        authProperties.add(createAuthProperty(KeyStoreKeyManager.SIGNING_KEY_ALIAS, "servercert"));
        authProperties.add(createAuthProperty(KeyStoreKeyManager.SIGNING_KEY_PASS, "test123"));

        keyStoreKeyManager.setAuthProperties(authProperties);

        return keyStoreKeyManager;
    }

    public AuthPropertyType createAuthProperty(String key, String value) {
        AuthPropertyType authProperty = new AuthPropertyType();

        authProperty.setKey(key);
        authProperty.setValue(value);

        return authProperty;
    }

Common scenario is to use Picketlink as both Identity Provider (IDP) and Service Provider (SP), but sometimes it may be useful to integrate with 3rd party vendors as well. If your company is using services provided by 3rd party vendors like SalesForce or Google Apps, then SSO with these vendors may be real benefit for you.

We support these scenarios:

In first scenario we will use Salesforce as SAML SP and we will use Picketlink application as SAML IDP. In this tutorial, we will reuse application idp-sig.war from Picketlink quickstarts .