Product SiteDocumentation Site

5.3. Managing Relationships

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 RelationshipManager 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.
  • The createRelationshipQuery() method is used to perform relationship queries.
  • The inheritsPrivileges() method is used to check whether an identity inherits privileges from another.

Note

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

5.3.1. Built In Relationship Types

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.

5.3.1.1. Application Roles

Application roles are represented by the Grant relationship, which is used to assign application-wide privileges to a User or Agent.
The RelationshipManager 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);

5.3.1.2. Groups and Group Roles

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);