Chapter 8. Identity Management - Working with JPA
- 8.1. JPAIdentityStoreConfiguration
- 8.1.1. Default Database Schema
- 8.1.2. Configuring an EntityManager
- 8.1.3. Mapping
IdentityType
Types - 8.1.4. Mapping
Partition
Types - 8.1.5. Mapping
Relationship
Types - 8.1.6. Mapping Attributes for
AttributedType
Types - 8.1.7. Mapping a
CredentialStorage
type - 8.1.8. Configuring the Mapped Entities
- 8.1.9. Providing a
EntityManager
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
.