10Duke Entitlements Graph API

Table of Contents

Overview

The Graph API offers a way to get data into and out of a 10Duke Entitlements deployment. It's an HTTP-based API that applications can use to programmatically query or post data, and perform a wide variety of other tasks relating to managing users, groups and organisations.

Note: If you are already familiar with the 10Duke Identity Provider Graph API, the first section of this API reference will already be familiar to you. You may wish to jump directly to the 10Duke Entitlements specific operation examples.

The Basics

The Graph API is a representation of the information held in a 10Duke Entitlements deployment. It is an API that models the data in terms of objects and the relationships between them and allows the client to interact with multiple nodes in a single request.

In the Graph API, there is one endpoint: /graph/

In order to access and use the graph, it is structured and accessed as follows:

API Model

In order to interact with the Graph API, it has the following key elements:

  1. Object - individual objects, such as a Profile, an Organization, or a ProfileGroup (a group of related profiles/users). Note that on the graph, each object has a unique ID.

  2. Relation - a relation between two Objects, indicating relation multiplicity and possibly carrying relation attributes.

  3. Operation - an action taken on a graph object.

Graph Selector

This is a relational path to or between an object or a set of objects on the graph. If you want to access data on the graph, you need to construct a graph selector in order to define and execute your query. A graph selector can also include conditional expressions limiting the selected object set. Parameters can be used in order to better define or articulate an individual query. For example, specifying a date range when requesting a list of all new Profile objects registered in the IdP. Request parameters are specific to each operation you may call on the Graph API.

JSON API

This is used for standard Create, Read, Update and Delete (CRUD) operations on Graph Objects and Relations, as well as for other higher level operations. The JSON API maps HTTP methods POST, GET, PUT and DELETE to the CRUD operations that are generally available for all Objects and Relations. Other operations can be selected by using operation request parameter. JSON is used for representing Objects and Relations returned by reading operations, and for submitting Object and Relation data to writing operations.

Form API

This is used for creating or updating objects directly from HTML forms. Object and Relation data is given as form input values, where input names are graph selectors describing the item to create or update, and the respective input value gives the value for the item.

Operations vs http methods

In the context of the Graph API, it is important to note that an Operation is not the same as HTTP method. There are tens of operations that can be used to query the Graph API, while there are just four HTTP methods that are relevant in the same context. The connection between the two is that if no operation is explicitly specified by giving "operation" parameter, a default operation is inferred from the used HTTP method like this:

  • HTTP POST: create
  • HTTP GET: read
  • HTTP PUT: update
  • HTTP DELETE: delete

Example Objects on the Graph

The images below depicts some of objects that you are likely to interact with on the graph most frequently. This is by no means an exhaustive list, and you can of course, create new objects on the graph, but is it meant to give you an idea of the core objects on the graph and an indication of the possible relations between them.

Entitlement model

  • Entitlement - collection of licenses owned by a single license owner and administered together as a single entity
  • License - license owned by an Organization or by a Profile
  • LicensedItem - describes a licensed item like a feature of a software application
  • LicenseModel - describes terms (constraints and behaviours) for granting and consuming Licenses
  • ProductPackage - collection of LicensedItems and a LicenseModel that can be used for granting License
  • ConsumptionConstraint - specifies constraints for consuming Licenses granted to a license owner
  • LicensedItemCountBehavior - specifies defaults for licensed item count (seat count) in licensing operations
  • UtilizationConstraint - specifies license over-utilization rules
  • LeaseTimeBehavior - specifies how short-term or long-term leases are granted for License consumers
  • LicensePoolBehavior - specifies whether Licenses to same LicensedItems will build on a single pool, or whether they will be separate licenses or license pools
  • AssignedLicenseConstraint - allows License consumption to only Profiles with an earlier created license assignment
  • ConcurrentSessions - specifies rules for concurrent consumption of a single license seat from several license consuming devices
  • ValidityPeriodConstraint - specifies constraints for validity period of granted Licenses
  • AggregateUseConstraint - specifies constraints for time-based License consumption
  • ScopedLicenseConstraint - constrains License consumption to a specific scope like a project

Diagram 1 Diagram 1 - 10Duke Entitlements - Example Graph objects and object relationships

Diagram 2 Diagram 2 - 10Duke Entitlements - Example of License Model Graph objects and object relationships

Relation types

Generally, a graph Object can exist in relation to other graph objects with the following relation multiplicities (varieties):

  • One-to-one, where the Object can be connected to maximum of one Object of another type, and the connected Object can not be connected to other Objects of this type

  • One-to-many, where multiple Objects of another type can be connected to the Object, and the connected Objects can not be connected to other Objects of this type

  • Many-to-one, where the Object can be connected to maximum of one Object of another type, and the connected object can be connected to multiple Objects of this type

  • Many-to-many, where multiple Objects of another type can be connected to the Object, and the connected object can be connected to multiple Objects of this type

The relation types can be used for building graph, even dynamically. In graph selectors, the relation types are marked with a leading tilde as follows:

  • ~OneToMany
  • ~ManyToOne
  • ~ManyToMany

One-to-one relations must be expressed as one-to-many or many-to-one in graph selectors. (Note that ~OnetoOne is not a possible relation type due to limitations of relational databases, hence the need to use one-to-many or many-to-one in order to express one-to-one relations.)

In addition to the standard, all-purpose relation objects, many-to-many relations can be extended to contain relation attributes. For instance a Membership relation is a many-to-many relation with attributes for membership validity period.

Creating a Graph Selector

When you want to query data held in the graph, you need to create your graph selector which means you need to ‘build’ a graph url or path to define the data your accessing or posting.

The structure of a graph selector is as follows:

[/ObjectPart][/~RelationPart/ObjectPart]*[SelectorParametersPart]

This can be read as:

  • first there is an optional ObjectPart
  • then there are 0-n times RelationPart followed by ObjectPart
  • then there is an optional parameter part

Within the ObjectPart there is a sub-structure as follows:

ObjectName[:CollectionName][FieldSelector]

The RelationPart starts with a tilde, but is otherwise identical to ObjectPart.

These parts can be chained ad infinitum, but:

  • the first part must be an Object part
  • when chaining more parts, there must always be both a Relation part and an Object part, i.e. a graph selector can never end with a Relation part

~OneToMany and ~ManyToOne are special cases. When they are used the relation part doesn't have anything else within it, i.e. there is no CollectionName of FieldSelector

SelectorParameterPart contains parameters for paging and sorting query results.

So if we look at an example query, you can see its composition:

GET /graph/Organization[@name=’ACME’]/~OneToMany/ProfileGroup[@type=’employees’][/ObjectPart][/~RelationPart/ObjectPart]*[SelectorParametersPart]

Key characters used

Note the use of:

  • {count} to request total size of result set instead of the objects
  • ~ in the field selector to denote a “like” condition for field value matching
  • * (asterix) in the field selector specify value starts with matching
  • {i=0,r=5} to say offset 0, limit 5
  • / (forward slash) to denote the start of a type selector
  • [] brackets to enclose a field selector
  • @ to denote a field and corresponding condition on value
  • ~ to denote a relation type

Generic Graph Operations Applicable to all Objects

Below is a list of generic graph operations that can be used with all objects on the Graph.

CRUD operation introduction / examples

Creating / Updating objects

Creating and updating object(s) is done by post / put an object graph to the graph API.

Note: Update calls to the Graph API will perform business logic closer to a merge compared update. In many case create and update work together as an object graph may consist of new objects and existing objects.

Please experiment with the client application to decide if it is more feasible to implement a full query of all data subject to update vs. just a partial query letting the server side apply default logic. Client sent data will always take priority over automated server side logic.

The below example shows creating a Company (type: Organization) with a related employees group (type: ProfileGroup):

POST /graph

{
  "__objType": "Organization",
  "type": "company",
  "name": "ACME",
  "id": "f2f7416a-eb3e-42c5-85dc-db31b3ed5613",
  "rel_Relations": [
    {
      "rel_Relation": {
        "__objType": "ObjectRelation",
        "multiplicity": "ONE_TO_MANY",
        "relatedObjectType": "com.tenduke.sdk2.objectmodel.identity.ProfileGroup"
      },
      "rel_RelatedObjectList": {
        "__objType": "RelatedObjectList",
        "rel_RelatedObjects": [
          {
            "__objType": "ProfileGroup",
            "name": "Employees",
            "referenceFields": {
              "__objType": "HashMap",
              "Entries": [
                {
                  "__objType": "KeyValue",
                  "value": {
                    "__objType": "UUID",
                    "value": "f2f7416a-eb3e-42c5-85dc-db31b3ed5613"
                  },
                  "key": {
                    "__objType": "String",
                    "value": "ref_Organization_id"
                  }
                }
              ]
            },
            "id": "cfd252be-2d14-41df-a671-c9ccac857c37",
            "type": "employees"
          }
        ]
      }
    }
  ]
}

Read / Query objects

Read / query works by issuing an HTTP GET request with a selector as the Request URI. The next example shows reading back the profile group created in the above example:

GET /graph/Organization[@name=’ACME’]/~OneToMany/ProfileGroup[@type=’employees’]

Note the use of:

  • / (forward slash) to denote the start of a type selector
  • [] brackets to enclose a field selector
  • @ to denote a field and corresponding condition on value
  • ~ to denote a relation type

Extending the example slightly:

  1. GET /graph/Organization[@name~’Acme*’]/~OneToMany/ProfileGroup{count}
  2. GET /graph/Organization[@name~’Acme*’]/~OneToMany/ProfileGroup{count}

Delete objects

Delete works by issuing an HTTP DELETE request with a selector as the Request URI. The next example shows deleting a profile group by id:

DELETE /graph/ProfileGroup[@id=ID-HERE’]

Example Operations

Below are some entitlement management calls by example use case:

Grant licenses to an Organization

POST /graph/ProductPackage[@title='DemoPackage']

operation=InitializeOrganizationLicenses&licensedItemCount=HOW_MANY_LICENSES&ownerOrganizationId=ORGANIZATION_ID&validFrom=ISO_8601_TIMESTAMP&validUntil=ISO_8601_TIMESTAMP&validFrom=ISO_8601_TIMESTAMP

Grant licenses to an individual user

POST /graph/ProductPackage[@title='DemoPackage']

operation=InitializePersonalLicenses&licensedItemCount=HOW_MANY_LICENSES&initializeForProfileId=PROFILE_ID&validFrom=ISO_8601_TIMESTAMP&validUntil=ISO_8601_TIMESTAMP&validFrom=ISO_8601_TIMESTAMP

License consumption by Organization

GET /graph/Organization[@name=’Acme Inc’]/~OneToMany/Entitlement/~OneToMany/License/~OneToMany/Assignment:LicenseProfileAssignment/~OneToMany/Consumption:LicenseProfileAssignment

Who is using an Organization’s licenses

GET /graph/Organization/~OneToMany/Entitlement/~OneToMany/License/~Assignment:LicenseProfileAssignment/~ManyToOne/Profile

List Company’s licenses with names of users

GET /graph/Organization/~OneToMany/Entitlement/~OneToMany/License?/~ManyToOne/LicensedItem&/~Assignment:LicenseProfileAssignment/~ManyToOne/Profile

Change license validity

POST /graph/License[@id=’LICENSE_ID’]

change=validity&validFrom=ISO_8601_TIMESTAMP&validUntil=ISO_8601_TIMESTAMP

Change license count / quota

POST /graph/License[@id=’LICENSE_ID’]

change=quota&licensedItemCount=NEW_COUNT

Change a license’s maximum aggregate use time

POST /graph/License[@id=’LICENSE_ID’]

change=aggregateUseTime&maxAggregateUseTime=NEW_TIME_LIMIT_MILLISECONDS&incrementModel=NEW_INCREMENT_MODEL

Supported incrementModel values are: fair OR append, where:

  • Fair increment model appends the time difference from last consumption to aggregate time. Example: a client consumes a license with a 1 day duration. After 2 hours the client refreshes the license with a new consumption call for another 1 day duration. The addition to aggregate use time at time of the first call was 1 day. The fair increment resulted by the second call adds 2 hours to the aggregate use time.

  • The append increment model appends consumption duration time mechanically. It never considers the time difference between consecutive calls and comparing that to the consume duration. Example: a client application consumes a license with a 1 day duration. The client makes a license refresh call after 2 hours. The resulting aggregate use time after the second call will be 2 days (mechanically adding 1 day duration from both calls).

  • NOTE: this API call allows setting the maximum use time after granting the licenses. The convenience is that there’s no need for multiple license models that define different values. The customer specific time value can be set in a customer specific way.

Reserve a license seat

If a license has named seat model, a license seat is reserved for user by creating a reservation assignment. The static reservation can be also used with floating licences to reserve a license seat for critical users.

POST /graph/

operation=CreateOrUpdateAssignments&createAssignment=true&profileId=PROFILE_ID&reservationType=reserved&licenseId=LICENSE_ID

Remove a seat reservation

If it is needed to change the named license seat to another user or otherwise remove seat reservation from a user, the reservation is cleared by resetting the reservation type of an assignment. This operation does not affect to the existing session ie. the seat’s lease period promised in the last license check, but the user will have the same seat reserved until he/she releases it or the lease period expires.

POST /graph/

operation=CreateOrUpdateAssignments&createAssignment=true&profileId=PROFILE_ID&reservationType=&licenseId=LICENSE_ID

Deny license consumption

License consumption can be denied from specific users by creating a denial assignment. After denial, user can consume the license till the end of the session ie. the period promised in the last license check.

POST /graph/

operation=CreateOrUpdateAssignments&createAssignment=true&profileId=PROFILE_ID&reservationType=deny&licenseId=LICENSE_ID

Remove denial

To clear denial state ie. to allow user to consume a floating license, the reservation type of assignment is reset (the same operation as when clearing seat reservation).

POST /graph/ 
operation=CreateOrUpdateAssignments&createAssignment=true&profileId=PROFILE_ID&reservationType=&licenseId=LICENSE_ID

Release licenses

POST /authz/?AssignmentConsumptionId&release

How to figure out "AssignmentConsumptionId"

  1. If you have the client application that called the license check, then you probably have the jti field from the token stored: The jti field value is the identifier of the Consumption --> you can use it in the /authz/?release call

    {
    "DemoItem1": true,
    "iss": "df585c1b-f09d-4c04-87f8-b72a515c6f3e",
    "exp": 1452750138,
    "iat": 1452690138,
    "ibe": 101452690135,
    "jti": "5e3831d6-352e-48c8-84a7-54ecc651fa0e",
    "rfr": 1452690738
    }
  2. If it is a user / client application you do not have access to --> using the Profile id you can use this (will read all Consumption identifiers, which are result of that specific user consuming licenses. Using that resultset you can iterate over it and call /authz/?release with each id):

    GET /graph/Profile[@id='PROFILE_ID_HERE]/Assignment:LicenseProfileAssignment/~OneToMany/Consumption:LicenseProfileAssignmentConsumption/@id

Resolve an Organization’s default entitlement

If:

/graph/Organization[@id='ORG_ID']/~OneToMany/Entitlement{count}

Gives count > 1

Then use

/graph/Organization[@id='ORG_ID']/~OneToMany/Entitlement[@defaultEntitlement=true]

Else

/graph/Organization[@id='ORG_ID']/~OneToMany/Entitlement

is sufficient

NOTE:

  • If an Organization is assigned > 1 Entitlement instances then exactly one of them must have defaultEntitlement=true
  • If an Organization has just one Entitlement and its defaultEntitlement=true OR null then it is treated as the default.

Create / Update default Entitlement for an Organization

NOTE: just change the defaultEntitlement=false to create and update non default ones

POST /graph 

{
    "__objType": "Entitlement",
    "referenceFields": {
        "__objType": "HashMap",
        "Entries": [{
            "__objType": "KeyValue",
            "value": {
                "__objType": "String",
                "value": "${ORGANIZATION_ID}"
            },
            "key": {
                "__objType": "String",
                "value": "ref_Organization_id"
            }
        }]
    },
    "active": true,
    "title": "${ORGANIZATION_NAME} default entitlement",
    "defaultEntitlement": true,
    "id": "${ENTITLEMENT_ID}"
}

Example Objects and Operations

Entitlement

Generic Operations

POST, GET, PUT, DELETE

Add license consumer relations

POST /graph?operation=AddLicenseConsumerRelations

Enables a user or members of a group to consume licenses of an Entitlement.

Parameters
Parameter In Type Required
entitlementId - id of the entitlement that owns licenses query or form UUID true
profileGroupId - id of a group whose members are granted right to consume licenses query or form UUID false
profileId - id of a user who is granted right to consume licenses query or form UUID false
allowExistingRelation - flag determining if this operation succeeds even if the relation to create already exists query or form boolean false

Remove license consumer relations

POST /graph?operation=RemoveLicenseConsumerRelations

Removes license consumption rights from a user or members of a group.

Parameters
Parameter In Type Required
entitlementId - id of the entitlement that owns licenses query or form UUID true
profileGroupId - id of a group whose members are denied right to consume licenses query or form UUID false
profileId - id of a user who is denied right to consume licenses query or form UUID false
allowAlreadyRemoved - flag determining if this operation succeeds even if the relation to remove does not exist query or form boolean false

~OneToMany/License
~LicenseConsumerRelation/ProfileGroup
~LicenseConsumerRelation/Profile
~ManyToOne/Organization
~ManyToOne/Profile

Assignment

Generic Operations

POST, GET, PUT, DELETE

~OneToMany/Consumption
~ManyToOne/Profile
~ManyToOne/License

Consumption

Generic Operations

POST, GET, PUT, DELETE

~ManyToOne/Assignment

License

Generic Operations

POST, GET, PUT, DELETE

Move licenses

POST /graph/License[@id='LIC_ID']?operation=MoveLicenses

Moves a License from the current Entitlement to another Entitlement.

Parameters
Parameter In Type Required
license selector - selects one or more licenses to move. Example: /License[@id='8cd13682-7735-40dd-9f7f-8a6d35949eef'] path Graph Selector true
to - id of target entitlement, or a Graph Selector for selecting the target entitlement query or form UUID or Graph Selector true
create - flag determining if a new entitlement is created if no entitlement found. Default is false. query or form boolean false

Create or update license assignments

POST /graph?operation=CreateOrUpdateAssignments

Manages Assignments that define how a License relates to a Profile that is a potential consumer of the License. Assignment can describe that:

  • the License is currently used by the Profile (user occupies a license seat), but may released
  • The License is reserved to the Profile with a long-term reservation. This kind or reservation reserves a license seat also when not actively consuming the license.
  • license consumption is denied from the Profile, even when the Profile belongs to a ProfileGroup for which the license has been granted
Parameters
Parameter In Type Required
createAssignment - flag controlling if a new assignment is created, if an assignment does not exist already query or form boolean false
profileId - id of the profile for whom license assignment is managed query or form UUID true
licenseId - id of the license to manage query or form UUID true
reservationType - type of reservation, one of:
  • "" (empty string): dynamically occupying a license seat, can be released
  • "reserved": long-term reservation
  • "denied": consumption denied
query or form string false
validFrom - assignment validity start time query or form ISO date false
validUntil - assignment validity end time query or form ISO date false

~ManyToOne/Entitlement
~ManyToOne/LicensedItem
~OneToMany/LicenseMetadata
~OneToMany/LicenseScope

LicensedItem

Generic Operations

POST, GET, PUT, DELETE

~OneToMany/License
~Includes/LicensedItem
~ManyToMany/ProductPackage

LicenseScope

Generic Operations

POST, GET, PUT, DELETE

~ManyToOne/License

LicenseMetadata

Generic Operations

POST, GET, PUT, DELETE

~ManyToOne/License

ProductPackage

Generic Operations

POST, GET, PUT, DELETE

Use product package for granting licenses to an organization

POST /graph/ProductPackage[@id='PP_ID']?operation=InitializeOrganizationLicenses

Grants licenses to an Organization.

Parameters
Parameter In Type Required
product package selector - selects a product package containing items for which licenses are granted path Graph Selector true
ownerOrganizationId - id of the organization to own the granted licenses query or form UUID false
licensedItemCount - number of license seats query or form int false
validFrom - license validity period start time query or form ISO date false
validUntil - license validity period end time query or form ISO date false
initializeForProfileGroupId - id of a group, licenses will be granted to members of this group query or form UUID false
entitlementId - id of an entitlement, licenses will added in this entitlement query or form UUID false
externalReference - reference to an external entity related to the granted licenses, e.g. an order number query or form string false
clientData - JSON string for any data specified by the caller when creating licenses query or form JSON string false

Use product package for granting licenses to a user

POST /graph/ProductPackage[@id='PP_ID']?operation=InitializePersonalLicenses

Grants licenses to a user, as represented by a Profile.

Parameters
Parameter In Type Required
initializeForProfileId - id of the user to own the granted licenses query or form UUID true
licensedItemCount - number of license seats query or form int false
validFrom - license validity period start time query or form ISO date false
validUntil - license validity period end time query or form ISO date false

LicensedItem

SeatCountCredit

Generic Operations

POST, GET, PUT, DELETE

~ManyToOne/License

UseTimeCredit

Generic Operations

POST, GET, PUT, DELETE

~ManyToOne/License