Product SiteDocumentation Site

Chapter 8. Identity Management - Working with JPA

8.1. JPAIdentityStoreConfiguration

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.
In the PicketLink site you can find useful information about how to provide your own custom identity model and use the annotations described in the next sections to store your custom types using the JPA Identity Store. Take a look at this guide for more details http://picketlink.org/gettingstarted/custom_idm_model/

8.1.1. Default Database Schema

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.PartitionTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.AbstractCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.TokenCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity</class>
<class>org.picketlink.idm.jpa.model.sample.simple.PermissionTypeEntity</class>
The default database schema provides a generic and very flexible database schema ready to support most of PicketLink IDM features. Specially if you want to write your own identity model and still be able to store your data without necessarily having to provide your own JPA entity mapping. In conjunction with Section 6.4, “Managed attributes”, you can start writing your own identity model very easily.
This schema is able support any IdentityType, Partition or Relationship type without any change to the schema or the JPA entities provided by PicketLink.

8.1.2. Configuring an EntityManager

Before the JPA identity store can be used, it must be provided with an EntityManager so that it can connect to a database. In Java EE this can be done by providing a producer method within your application as follows:
@Produces
@PersistenceContext
private EntityManager picketLinkEntityManager;
If you are using multiple persistence units, you can specify which EntityManager should be used by PicketLink by specifying the @org.picketlink.annotations.PicketLink qualifier, for example like so:
@Produces
@PicketLink
@PersistenceContext
private EntityManager picketLinkEntityManager(unitName = "picketlink");
In the latter case, the EntityManager with the @PicketLink qualifier will always be preferred over any other EntityManager produced by your application.
Another important thing you should keep in mind when configuring the EntityManager is how you define the entity classes in your /META-INF/persistence.xml. By default, PicketLink will read all entities from your persistence unit to automatically discover those annotated with the PicketLink IDM JPA Annotations.
For example, for a simple application using the JPA Identity Store in conjunction with the Basic Identity Model you should have something like this:
<persistence-unit name="picketlink-forge-app-persistence-unit" transaction-type="JTA">
    <description>PicketLink IDM Persistence Unit Using the Basic Identity Model</description>

    // connection properties

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

8.1.3. Mapping IdentityType Types

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

Table 8.1. IdentityType Annotations

Annotation Description Property Type Required
@IdentityManaged This annotation is a type-level annotation and must be used to specify the IdentityType types that should be mapped by the annotated entity. - True
@AttributeValue This annotation can be used to map a entity property to a IdentityType property. The name property of this annotation can be used in case the property names are different. Any Type False
@Identifier The unique identifier value for the identity. String True
@IdentityClass The type for the identity. When a IdentityType is stored the FQN of its type is stored in a property annotated with this annotation. String True
@OwnerReference The reference to a Partition mapped entity. This annotation is used to identify the property that holds a reference to the partition where a IdentityType belongs. Usually this annotation is used in conjunction with a @ManyToOne property referencing the entity used to store partitions. The same type used to map a Partition True
The following code shows an example of an entity class configured to store User types:

Example 8.1. Example

@IdentityManaged (User.class)
@Entity
public class IdentityTypeEntity implements Serializable {

  @Id
  @Identifier
  private String id;

  @IdentityClass
  private String typeName;

  @AttributeValue
  private String loginName;

  @AttributeValue
  private Date createdDate;

  @AttributeValue
  private Date expirationDate;

  @AttributeValue
  private boolean enabled;

  @OwnerReference
  @ManyToOne
  private PartitionTypeEntity partition;

    // getters and setters
}

8.1.4. Mapping Partition Types

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

Table 8.2. Partition Annotations

Annotation Description Property Type Required
@IdentityManaged This annotation is a type-level annotation and must be used to specify the Partition types that should be mapped by the annotated entity. - True
@AttributeValue This annotation can be used to map a entity property to a Partition property. The name property of this annotation can be used in case the property names are different. Any Type False
@Identifier The unique identifier value for the partition. String True
@PartitionClass The type for the partition. When a Partition is stored the FQN of its type is stored in a property annotated with this annotation. String True
@ConfigurationName This annotation must be used to indicate the field to store the configuration name for a partition. String True
The following code shows an example of an entity class configured to store Realm types:

Example 8.2. Example

@IdentityManaged (Realm.class)
@Entity
public class PartitionTypeEntity implements Serializable {

  @Id
  @Identifier
  private String id;

  @AttributeValue
  private String name;

  @PartitionClass
  private String typeName;

  @ConfigurationName
  private String configurationName;

    // getters and setters
}

8.1.5. Mapping Relationship Types

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

Table 8.3. Relationship Annotations

Annotation Description Property Type Required
@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 Type False
@Identifier The unique identifier value for the relationship. String True
@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. String True
@RelationshipDescriptor This annotation must be used to indicate the field to store the name of the relationship role of a member. String True
@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 IdentityType True
@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:

Example 8.3. Example

@IdentityManaged (Relationship.class)
@Entity
public class RelationshipTypeEntity implements Serializable {

  @Id
  @Identifier
  private String id;

  @RelationshipClass
  private String typeName;

    // getters and setters
}
When mapping a relationship you also need to provide a specific entity to store its members:

Example 8.4. Example


@Entity
public class RelationshipIdentityTypeEntity implements Serializable {

  @Id
  @GeneratedValue
  private Long id;

  @RelationshipDescriptor
  private String descriptor;

  @RelationshipMember
  @ManyToOne
  private IdentityTypeEntity identityType;

  @OwnerReference
  @ManyToOne
  private RelationshipTypeEntity owner;

    // getters and setters
}

8.1.6. Mapping Attributes for AttributedType Types

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

Table 8.4. Partition Annotations

Annotation Description Property Type Required
@AttributeName The name of the attribute. A property with this annotation is used to store the name of the attribute. String True
@AttributeValue The value of the attribute. A property with this annotation is used to store the value of the attribute. Values are Base64 encoded. String True
@AttributeClass The type for the attribute. When a attribute is stored the FQN of its type is stored in a property annotated with this annotation. String True
@OwnerReference The reference to a IdentityType, or a Partition or a Relationship mapped entity. This annotation is used to identify the property that holds a reference to the owner of the attributes. The same type used to map IdentityType, or a Partition or a Relationship type. True
The following code shows an example of an entity class configured to store attributes for IdentityType types:

Example 8.5. Example


@Entity
public class IdentityTypeAttributeEntity implements Serializable {

  @OwnerReference
  @ManyToOne
  private IdentityTypeEntity owner;

  @AttributeClass
  private String typeName;

  @AttributeName
  private String name;

  @AttributeValue
  private String value;

    // getters and setters
}

8.1.7. Mapping a CredentialStorage type

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

Table 8.5. Partition Annotations

Annotation Description Property Type Required
@CredentialClass The type for the credential. When a credential is stored the FQN of its corresponding CredentialStorage type is stored in a property annotated with this annotation. String True
@CredentialProperty This annotation can be used to map a entity property to a CredentialStorage property. The name property of this annotation can be used in case the property names are different. String True
@EffectiveDate The effective date for a credential. A property annotated with this annotation will be mapped to the effectiveDate of a CredentialStorage type. String True
@ExpiryDate The expiry date for a credential. A property annotated with this annotation will be mapped to the expiryDate of a CredentialStorage type. String True
@OwnerReference The reference to a IdentityType mapped entity. This annotation is used to identify the property that holds a reference to the owner of the credential. The same type used to map a IdentityType type. True
The following code shows an example of an entity class configured to store password-based credentials for IdentityType types:

Example 8.6. Example

@ManagedCredential (EncodedPasswordStorage.class)
@Entity
public class PasswordCredentialTypeEntity implements Serializable {

  @Id
  @GeneratedValue
  private Long id;

  @OwnerReference
  @ManyToOne
  private IdentityTypeEntity owner;

  @CredentialClass
  private String typeName;

  @EffectiveDate
  private Date effectiveDate;

  @ExpiryDate
  private Date expiryDate;

  @CredentialProperty (name = "encodedHash")
  private String passwordEncodedHash;

  @CredentialProperty (name = "salt")
  private String passwordSalt;

    // getters and setters
}

8.1.8. Configuring the Mapped Entities

Once your entities are properly mapped, you're ready to configure the JPA store with them. To do that you only need to:
IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();

builder
  .stores()
    .jpa()
      .mappedEntity(IdentityTypeEntity.class, PartitionTypeEntity.class, ...);

8.1.9. Providing a EntityManager

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 Section 7.1.9, “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.