JBoss.orgCommunity Documentation
Table of Contents
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 User
s or Group
s 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
Agent
s, User
s, Group
s or Role
s.
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);
}
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.
The following code example demonstrates how to create a new user with the following properties:
User user = new User("jsmith");
user.setFirstName("John");
user.setLastName("Smith");
user.setEmail("jsmith@acme.com");
identityManager.add(user);
Once the User
is created, it's possible to look it up using its login name:
User user = BasicModel.getUser(identityManager, "jsmith");
User properties can also be modified after the User has already been created. The following example demonstrates how to change the e-mail address of the user we created above:
User user = BasicModel.getUser(identityManager, "jsmith");
user.setEmail("john@smith.com");
identityManager.update(user);
Users may also be deleted. The following example demonstrates how to delete the user previously created:
User user = BasicModel.getUser(identityManager, "jsmith");
identityManager.remove("jsmith");
The following example demonstrates how to create a new group called employees:
Group employees = new Group("employees");
It is also possible to assign a parent group when creating a group. The following example demonstrates how to create a new group called managers, using the employees group created in the previous example as the parent group:
Group managers = new Group("managers", employees);
To lookup an existing Group
, the getGroup()
method may be used. If the group name
is unique, it can be passed as a single parameter:
Group employees = BasicModel.getGroup(identityManager, "employees");
If the group name is not unique, the parent group must be passed as the second parameter (although it can still be provided if the group name is unique):
Group managers = BasicModel.getGroup(identityManager, "managers", employees);
It is also possible to modify a Group
's name and other properties (besides its parent) after it has
been created. The following example demonstrates how to disable the "employees" group we created above:
Group employees = BasicModel.getGroup(identityManager, "employees");
employees.setEnabled(false);
identityManager.update(employees);
To remove an existing group, we can use the remove()
method:
Group employees = BasicModel.getGroup(identityManager, "employees");
identityManager.remove(employees);
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.
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.
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.
Application roles are represented by the Grant
relationship, which is used to assign application-wide
privileges to a User
or Agent
.
The IdentityManager
interface provides methods for directly granting a role. Here's a simple example:
User bob = BasicModel.getUser(identityManager, "bob");
Role superuser = BasicModel.getRole(identityManager, "superuser");
BasicModel.grantRole(relationshipManager, bob, superuser);
The above code is equivalent to the following:
User bob = BasicModel.getUser(identityManager, "bob");
Role superuser = BasicModel.getRole(identityManager, "superuser");
Grant grant = new Grant(bob, superuser);
identityManager.add(grant);
A granted role can also be revoked using the revokeRole()
method:
User bob = BasicModel.getUser(identityManager, "bob");
Role superuser = BasicModel.getRole(identityManager, "superuser");
BasicModel.revokeRole(relationshipManager, bob, superuser);
To check whether an identity has a specific role granted to them, we can use the hasRole()
method:
User bob = BasicModel.getUser(identityManager, "bob");
Role superuser = BasicModel.getRole(identityManager, "superuser");
boolean isBobASuperUser = BasicModel.hasRole(relationshipManager, bob, superuser);
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.
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 terms of API, both the Realm
and Tier
classes implement the Partition
interface,
as shown in the following class diagram:
A Realm is used to define a discrete set of users, groups and roles. A typical use case for realms is the segregation of corporate user accounts within a multi-tenant application, although it is not limited this use case only. As all identity management operations must be performed within the context of an active partition, PicketLink defines the concept of a default realm which becomes the active partition if no other partition has been specified.
A Tier is a more restrictive type of partition than a realm, as it only allows groups and roles to be defined (but not users). A Tier may be used to define a set of application-specific groups and roles, which may then be assigned to groups within the same Tier, or to users and groups within a separate Realm.