Managing OpenDJ with REST

OpenDJ, the open source LDAP Directory Server, was the first to propose a native HTTP REST / JSON access to the data.

In the next major release, OpenDJ will be providing many enhancements to the REST interface, that I will describe in a series of posts. To start with, let’s talk about the new administrative interfaces added to manage the OpenDJ server.

When the HTTP access is enabled, OpenDJ creates by default 2 administrative endpoints: /admin/config and /admin/monitor.

/admin/config provides a read-write access to the configuration, with the same view and hierarchy of objects as the LDAP access. All of the operations that are possible with the dsconfig command, can be done over LDAP, and now REST.  As a matter of fact, the /admin/config API is automatically generated from the same XML description files that are used to generate the LDAP view and the dsconfig command line utilities. This means that any extension, plugin added to the server will also be exposed via REST without additional code.

screen-shot-2016-10-25-at-15-03-54

Above is an example of query of the /admin/config endpoint, querying for all  backends , done as a user who has the privilege to read the configuration. A similar query done with a user that doesn’t have the config-read privilege does fail as below:

$ curl -s -u user.2 http://localhost:8080/admin/config/backends/userRoot
Enter host password for user 'user.2': 
{
 "message" : "Insufficient Access Rights: You do not have sufficient 
privileges to perform search operations in the Directory Server
configuration",
 "code" : 403,
 "reason" : "Forbidden"
}

/admin/monitor provides a read-only view on all of the OpenDJ monitoring information that was already accessible via LDAP under the "cn=Monitor" naming context, and JMX.

$ curl -s -u user.0 http://localhost:8080/admin/monitor/
Enter host password for user 'user.0':
{
 "_id" : "monitor",
 "upTime" : "0 days 2 hours 49 minutes 54 seconds",
 "currentConnections" : "1",
 "totalConnections" : "32",
 "currentTime" : "20161024103215Z",
 "startTime" : "20161024074220Z",
 "productName" : "OpenDJ Server",
 "_rev" : "00000000644a67b2",
 "maxConnections" : "3"
}

The /admin REST endpoints can be protected with different authorization mechanisms, from HTTP basic to OAuth2. And the whole endpoint can be disabled as well if needed using dsconfig.

These administrative REST endpoints can be tested with the OpenDJ nightly builds. They are also available to ForgeRock customers as part of our latest update of the ForgeRock Identity Platform.


Filed under: Directory Services Tagged: administration, directory, Directory Services, directory-server, ForgeRock, Json, ldap, opensource, REST, rest2ldap

Managing OpenDJ with REST

OpenDJ, the open source LDAP Directory Server, was the first to propose a native HTTP REST / JSON access to the data.

In the next major release, OpenDJ will be providing many enhancements to the REST interface, that I will describe in a series of posts. To start with, let’s talk about the new administrative interfaces added to manage the OpenDJ server.

When the HTTP access is enabled, OpenDJ creates by default 2 administrative endpoints: /admin/config and /admin/monitor.

/admin/config provides a read-write access to the configuration, with the same view and hierarchy of objects as the LDAP access. All of the operations that are possible with the dsconfig command, can be done over LDAP, and now REST.  As a matter of fact, the /admin/config API is automatically generated from the same XML description files that are used to generate the LDAP view and the dsconfig command line utilities. This means that any extension, plugin added to the server will also be exposed via REST without additional code.

screen-shot-2016-10-25-at-15-03-54

Above is an example of query of the /admin/config endpoint, querying for all  backends , done as a user who has the privilege to read the configuration. A similar query done with a user that doesn’t have the config-read privilege does fail as below:

$ curl -s -u user.2 http://localhost:8080/admin/config/backends/userRoot
Enter host password for user 'user.2': 
{
 "message" : "Insufficient Access Rights: You do not have sufficient 
privileges to perform search operations in the Directory Server
configuration",
 "code" : 403,
 "reason" : "Forbidden"
}

/admin/monitor provides a read-only view on all of the OpenDJ monitoring information that was already accessible via LDAP under the "cn=Monitor" naming context, and JMX.

$ curl -s -u user.0 http://localhost:8080/admin/monitor/
Enter host password for user 'user.0':
{
 "_id" : "monitor",
 "upTime" : "0 days 2 hours 49 minutes 54 seconds",
 "currentConnections" : "1",
 "totalConnections" : "32",
 "currentTime" : "20161024103215Z",
 "startTime" : "20161024074220Z",
 "productName" : "OpenDJ Server",
 "_rev" : "00000000644a67b2",
 "maxConnections" : "3"
}

The /admin REST endpoints can be protected with different authorization mechanisms, from HTTP basic to OAuth2. And the whole endpoint can be disabled as well if needed using dsconfig.

These administrative REST endpoints can be tested with the OpenDJ nightly builds. They are also available to ForgeRock customers as part of our latest update of the ForgeRock Identity Platform.

Filed under: Directory Services Tagged: administration, directory, Directory Services, directory-server, ForgeRock, Json, ldap, opensource, REST, rest2ldap

This blog post was first published @ ludopoitou.com, included here with permission.

Storing JSON objects in LDAP attributes…

jsonUntil recently, the only way to store a JSON object to an LDAP directory server, was to store it as string (either a Directory String i.e a sequence of UTF-8 characters, or an Octet String i.e. a blob of octets).

But now, in OpenDJ, the Open source LDAP Directory services in Java, there is now support for new syntaxes : one for JSON objects and one for JSON Query. Associated with the JSON query, a couple of matching rules, that can be easily customised and extended, have been defined.

To use the syntax and matching rules, you should first extend the LDAP schema with one or more new attributes, and use these attributes in object classes. For example :

dn: cn=schema
objectClass: top
objectClass: ldapSubentry
objectClass: subschema
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.999 NAME 'json'
SYNTAX 1.3.6.1.4.1.36733.2.1.3.1 EQUALITY caseIgnoreJsonQueryMatch SINGLE-VALUE )
objectClasses: (1.3.6.1.4.1.36733.2.1.2.999 NAME 'jsonObject'
SUP top MUST (cn $ json ) )

Just copy the LDIF above into config/schema/95-json.ldif, and restart the OpenDJ server. Make sure you use your own OIDs when defining schema elements. The ones above are samples and should not be used in production.

Then, you can add entries in the OpenDJ directory server like this:

$ ldapmodify -a -D cn=directory manager -w secret12 -h localhost -p 1389

dn: cn=bjensen,ou=people,dc=example,dc=com
objectClass: top
objectClass: jsonObject
cn: bjensen
json: { "_id":"bjensen", "_rev":"123", "name": { "first": "Babs", "surname": "Jensen" }, "age": 25, "roles": [ "sales", "admin" ] }

dn: cn=scarter,ou=people,dc=example,dc=com
objectClass: top
objectClass: jsonObject
cn: scarter
json: { "_id":"scarter", "_rev":"456", "name": { "first": "Sam", "surname": "Carter" }, "age": 48, "roles": [ "manager", "eng" ] }

The very nice thing about the JSON syntax and matching rules, is that OpenDJ understands how the values of the json attribute are structured, and it becomes possible to make specific queries, using the JSON Query syntax.

Let’s search for all jsonObjects that have a json value with a specific _id :

$ ldapsearch -D cn=directory manager -w secret12 -h localhost -p 1389 -b "dc=example,dc=com" -s sub "(json=_id eq 'scarter')"

dn: cn=scarter,ou=people,dc=example,dc=com
objectClass: top
objectClass: jsonObject
json: { "_id":"scarter", "_rev":"456", "name": { "first": "Sam", "surname": "Carter" }, "age": 48, "roles": [ "manager", "eng" ] }
cn: scarter

We can run more complex queries, still using the JSON Query Syntax:

$ ldapsearch -D cn=directory manager -w secret12 -h localhost -p 1389 -b "dc=example,dc=com" -s sub "(json=name/first sw 'b' and age lt 30)"

dn: cn=bjensen,ou=people,dc=example,dc=com
objectClass: top
objectClass: jsonObject
json: { "_id":"bjensen", "_rev":"123", "name": { "first": "Babs", "surname": "Jensen" }, "age": 25, "roles": [ "sales", "admin" ] }
cn: bjensen

For a complete description of the query  filter expressions, please refer to ForgeRock Common  REST (CREST) Query Filter documentation.

The JSON matching rule supports indexing which can be enabled using dsconfig against the appropriate attribute index. By default all JSON fields of the attribute are indexed.

In a followup post, I will give more advanced configuration of the JSON Syntax, detail how to customise the matching rule to index only specific JSON fields, and will outline some best practices with the JSON syntax and attributes.

Filed under: Directory Services Tagged: attributes, Directory Services, directory-server, ForgeRock, Json, ldap, opendj, opensource, query, REST, schema, search

This blog post was first published @ ludopoitou.com, included here with permission.

Storing JSON objects in LDAP attributes…

jsonUntil recently, the only way to store a JSON object to an LDAP directory server, was to store it as string (either a Directory String i.e a sequence of UTF-8 characters, or an Octet String i.e. a blob of octets).

But now, in OpenDJ, the Open source LDAP Directory services in Java, there is now support for new syntaxes : one for JSON objects and one for JSON Query. Associated with the JSON query, a couple of matching rules, that can be easily customised and extended, have been defined.

To use the syntax and matching rules, you should first extend the LDAP schema with one or more new attributes, and use these attributes in object classes. For example :

dn: cn=schema
objectClass: top
objectClass: ldapSubentry
objectClass: subschema
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.999 NAME 'json'
SYNTAX 1.3.6.1.4.1.36733.2.1.3.1 EQUALITY caseIgnoreJsonQueryMatch SINGLE-VALUE )
objectClasses: (1.3.6.1.4.1.36733.2.1.2.999 NAME 'jsonObject'
SUP top MUST (cn $ json ) )

Just copy the LDIF above into config/schema/95-json.ldif, and restart the OpenDJ server. Make sure you use your own OIDs when defining schema elements. The ones above are samples and should not be used in production.

Then, you can add entries in the OpenDJ directory server like this:

$ ldapmodify -a -D cn=directory\ manager -w secret12 -h localhost -p 1389

dn: cn=bjensen,ou=people,dc=example,dc=com
objectClass: top
objectClass: jsonObject
cn: bjensen
json: { "_id":"bjensen", "_rev":"123", "name": { "first": "Babs", "surname": "Jensen" }, "age": 25, "roles": [ "sales", "admin" ] }

dn: cn=scarter,ou=people,dc=example,dc=com
objectClass: top
objectClass: jsonObject
cn: scarter
json: { "_id":"scarter", "_rev":"456", "name": { "first": "Sam", "surname": "Carter" }, "age": 48, "roles": [ "manager", "eng" ] }

The very nice thing about the JSON syntax and matching rules, is that OpenDJ understands how the values of the json attribute are structured, and it becomes possible to make specific queries, using the JSON Query syntax.

Let’s search for all jsonObjects that have a json value with a specific _id :

$ ldapsearch -D cn=directory\ manager -w secret12 -h localhost -p 1389 -b "dc=example,dc=com" -s sub "(json=_id eq 'scarter')"

dn: cn=scarter,ou=people,dc=example,dc=com
objectClass: top
objectClass: jsonObject
json: { "_id":"scarter", "_rev":"456", "name": { "first": "Sam", "surname": "Carter" }, "age": 48, "roles": [ "manager", "eng" ] }
cn: scarter

We can run more complex queries, still using the JSON Query Syntax:

$ ldapsearch -D cn=directory\ manager -w secret12 -h localhost -p 1389 -b "dc=example,dc=com" -s sub "(json=name/first sw 'b' and age lt 30)"

dn: cn=bjensen,ou=people,dc=example,dc=com
objectClass: top
objectClass: jsonObject
json: { "_id":"bjensen", "_rev":"123", "name": { "first": "Babs", "surname": "Jensen" }, "age": 25, "roles": [ "sales", "admin" ] }
cn: bjensen

For a complete description of the query  filter expressions, please refer to ForgeRock Common  REST (CREST) Query Filter documentation.

The JSON matching rule supports indexing which can be enabled using dsconfig against the appropriate attribute index. By default all JSON fields of the attribute are indexed.

In a followup post, I will give more advanced configuration of the JSON Syntax, detail how to customise the matching rule to index only specific JSON fields, and will outline some best practices with the JSON syntax and attributes.


Filed under: Directory Services Tagged: attributes, Directory Services, directory-server, ForgeRock, Json, ldap, opendj, opensource, query, REST, schema, search

A Beginners Guide to OpenIDM – Part 3 – Connectors

Overview

Previously in this series we have looked at a general overview of OpenIDM and had a detailed look at objects. In this blog I want to explore connectors.
Connectors are the integration glue that enables you to bring data into OpenIDM from all sorts of different systems and data stores. We will take a look at the different types of connectors available in OpenIDM, how they work and end with a practical example of how to actually configure a connector.

Connectors

Architecture

Every identity system that I have ever worked with has a concept similar of a connector. Usually they comprise of Java libraries or scripts that perform the actual push and pull of data to and from a target data source.
Standard connector operations in OpenIDM include:
  • Create: Create a new object ( usually an account ) in a target data store.
  • Update: Update an existing object e.g. if a user changes their email address then we may want to update the user record in a target data store.
  • Get: Retrieve a specific instance of an object ( e.g. an account) from a target data store.
  • Search: Query the collection and return a specific set of results.
There are a number of other operations which we will explore in later blogs.
At a high level connectors are comprised of:
  • Provisioner configuration: configuration data defining the connector usually containing:
    • Reference to the underlying Java class that implements the connector. This should be populated automatically when you choose your connector type. You can explore the connector source code if you like but for the most part you shouldn’t need to be concerned with the underlying classes.
    • All of the credentials and configuration needed to access the data store. You need to configure this.
    • The data store schema for the object or account. You need to configure this.
Connectors are configured through the user interface but like all OpenIDM configuration they are also stored ( and can be edited ) locally on the file system. Connector configuration files ( like most OpenIDM configuration files) can be found in openidm/conf and have the following naming convention:
provisioner.openicf-something.json ( where something is whatever you have named your connector ).
Note connector configuration files will not appear unless you have configured a connector using the UI, we will revisit this later.
The logical flow in OpenIDM for utilising connectors is as follows:
  • Data Synchronization engine outputs data and a requested operation e.g. create, delete, update or one of several others
  • Provisioner engine invokes the connector class with the requested operation and the data from the synchronization engine.
  • Connector class uses the configuration parameters from the provisioner file and the data passed in the invocation to actually do the work and push or pull to or from the target.

Connector Example

So now we have a basic understanding of how connectors work, lets try configuring one.
I’m going to use the CSV connector for this example and we are going to read users from a Comma Seperate Value list. Ultimately we will be reading this data into the managed user object using a mapping. For this blog though we will just focus on configuring the connector.
Feel free to use any CSV file but if you want to follow along with the example then download the CSV here that I created using Mockaroo.



Copy the file to somewhere on the same file system that OpenIDM has been installed on, it doesn’t matter where so long as OpenIDM can access it. I’m going to use /home/data/users.csv
Then log in to OpenIDM as administrator. Navigate to Configure, then Connectors.


 

Press “New Connector”



You will see the UI for configuring a new connector:



Give your new connector a name (I have used UserLoadCSV above – no spaces permitted), and look at the connector types. These are all the different systems you can integrate with.
Note that with further configuration, more connectors are available, and using the scripted connector you can pretty much integrate with any system that offers a suitable API.
 
Select the “CSV File Connector”. Now we need to complete the “Base Connector Details”. Starting with the path to the CSV File we actually want to process.


Now let’s take a look at the next few fields:



They are populated by default but we need to configure these up to match our spreadsheet.
Looking at the data:
  • Header UID = id
  • Header Name = username
So in this instance we just need to change the Header UID to match.



You will note there are a few more fields:
  • Header Password: We will not be processing any passwords from this CSV, that might be something you want to do, although typically you will have OpenIDM generate passwords for you ( more on that later ).
  • Quote Character: If you have an unusually formatted CSV, you can change the character that surrounds your data values. This is used by OpenIDM to successfully parse the CSV file.
  • Field Delimiter: Similarly if you are using a delimiter ( the character that splits up data entries ) that is anything other than a “,” you can tell OpenIDM here.
  • Newline String: As above.
  • Sync Retention Count: Todo
Note that these parameters are all unique to the CSV connector. If you were to use another connector, say the database connector, you would have a different set of parameters that must be configure for OpenIDM to successfully connect to the database and query the table.
Ok, with all that done lets add the connector:



All being well you should get a positive confirmation message. Congratulations, you have added a connector! All very well but what can we do with it?
Click on the menu option ( the vertical dots):


Then Data (_ACCOUNT_)



If you have done everything correctly you should see the data from the CSV in OpenIDM!



It is important to understand, that at this point the data has not been loaded into OpenIDM, OpenIDM is simply providing a live view of the data in the CSV. This works for any connector and we will revisit it at the end of this blog.
Before that, there are a few things I want to cover. Go back to the Connector screen, you should have a new Connector:



Select it, and select “Object Types”:



Then edit “_ACCOUNT_”.




What you should be able to see if a list of all of the attributes in the CSV file. OpenIDM has automatically parsed the CSV and built a schema for interpreting the data. You may also spot “__NAME__”. This is a special attribute, and it maps to the  Header Name attribute we configured earlier.

Again, the concept of Object Type is universal to all our connectors and sometimes additional configuration of the Object Type may be required in order to successfully process data.


Finally, let’s take a look at Sync:

On this page you can configure LiveSync. LiveSync is a special case of synchronization. Ordinarily synchronization is performed through the mappings interface ( or automatically on a schedule ).

However if the connector and target system support it, then LiveSync can be used. With LiveSync changes are picked up as they occur in the target. Ordinarily with a normal synchronization ( often called reconciliation ) all accounts in the target must be examined against the source for changes. With LiveSync, only accounts in the target that have changed will be processed. For this to work the target must support some form of change log that OpenIDM can read. In systems with large numbers of accounts this is a much more efficient way of keeping data in sync.

Connectors And The REST API

As before, we can make use of the REST API here to query our new connector. We can actually use the API to read or write to the underlying CSV data store. Just take a moment to think about what that means. In an enterprise implementation you might have hundreds of different data stores of every type. Once you have configured connectors to OpenIDM you can query those data stores using a single, consistent and centralised RESTful API via OpenIDM. That really is a very powerful tool.

Let’s take a look at this now. Navigate back to the data accounts page from earlier:




Take a look at the URL:

As before, this corresponds to our REST API. Please fire up Postman again.

Enter the following URL

http://localhost.localdomain.com:8080/openidm/system/UserLoadCSV/__ACCOUNT__?_queryId=query-all-ids

You should see the following result



We have just queried the CSV file using the REST API, and retrieved the list of usernames.
Let’s try retrieving the data for a specific user:

http://localhost.localdomain.com:8080/openidm/system/UserLoadCSV/__ACCOUNT__?_queryFilter=/email eq “tgardner0@nsw.gov.au”


Here we are searching for the user with the email address tgardner0@nsw.gov.au.

 



Again, this is just a small sample of what the REST API is capable of, you can learn much more here:
https://forgerock.org/openidm/doc/bootstrap/integrators-guide/index.html#appendix-rest
And more on how queries work here:

https://forgerock.org/openidm/doc/bootstrap/integrators-guide/#constructing-queries

 

Come back next time for a look at mappings where we will join together the managed user and the connector to actually create some users in the system.

This blog post was first published @ http://identity-implementation.blogspot.no/, included here with permission from the author.

A Beginners Guide to OpenIDM – Part 2 – Objects & Relationships

Overview

At the heart of OpenIDM are managed objects. Out of the box three managed objects are configured:
  • User: User identities, effectively this is your central identity store.
  • Role: An object for modelling roles.
  • Assignment: An object for modelling assignments. Assignments are effectively ways of capturing sets of entitlements across mapping. Which can then be associated with roles.
In this blog we will examine the user managed object in detail, roles and assignments will be explored later in the series.
It is important to understand that objects can really be anything and you can create new objects very easily. This is an incredibly powerful way to model all sorts of different things:
  • Users
  • Organisations, divisions, teams or other parts of a business.
  • Devices and hardware.
  • Products and offerings.
  • Anything else you can think of! Managed objects are completely configurable.
Not only can you model things, but you can also model the relationships between things. For example:
  • Which organisations a user belongs to.
  • The devices that a user owns.
  • The products a user has.
  • The teams that belong to an organisation.
  • Anything else you can think of!

Objects

All objects have the following properties:
  • Details: The name and icon that represents the object in the UI.
  • Schema: Properties, their validation rules and their relationships.
  • Scripts: Different hooks for running scripts throughout the object lifecycle e.g. postCreate
  • Properties: Rules for special attribute behaviors e.g. passwords should be encrypted and private.
Lets look at each of this in detail.

Details

Not much to say here. Just the name of your object and you can select a funky icon that will be displayed throughout the interface wherever your object is used.

Schema

The properties that actually comprise your object. Lets take a look at the managed user schema.
On the left, under Schema Properties you can see each property that comprises a user. There are many properties available out of the box and you can easily add or remove properties as required.
Let’s look at a property in detail.
So what does a property comprise of:
  • Property Name: The internal name users within the OpenIDM platform to refer to the property, think of it like a variable name only used internally.
  • Readable Title: The name that will be used to refer to the property in the user interface.
  • Description: Simple description of the attribute that when populated is used throughout the interface as a tooltip.
  • Viewable: Can it be seen in the UI?
  • Searchable: Is it indexed and searchable in the UI?
  • End users allowed to edit: Used are allowed to update the value using self service.
  • Minimum Length: Minimum length of the attribute value.
  • Pattern: Any specific pattern to which the value of the property must adhere. e.g. date formats.
  • Validation Policies: Rules that can be used to define attribute behavior. We will look at these in detail in a moment.
  • Required: Must be populated with a value.
  • Return by Default: If true, will be returned when user details are requested via the API. If false, will only be returned if specifically asked for.
  • Type: Type of the attribute: String, Array, Boolean, Integer, Number. Object or Relationship. We will look at relationships in a moment.

Validation Policies

Validation policies are ways to validate the attribute. The example below checks that the mail attribute is a valid email address. This prevents the user from inputting an invalid email address during self registration or an administrator changing the email incorrectly.
 
Similarly for the password attribute validation policies allow you to enforce password rules, for example:

Relationships

Relationships are incredibly powerful and really at the heart of what OpenIDM does. If you have installed OpenIDM in part 1 then I recommend you take a look at the out of the box managed objects to really understand this, however we will briefly discuss it.
The out of the box managed user object defines a relationship between managers and reports.
manager:
reports:
What are we saying here?
  • User’s have a manager. This is a Relationship. It is in fact a reverse relationship. As manager A, has reports X,Y,Z and reports X,Y,Z have the manager A.
  • User’s can also have reports. They may have multiple reports. Note this is an Array of Relationships: A manages X, A manages Y, A manages Z. Likewise this is a reverse relationship.
Relationships let you model relationships between all sorts of types of objects, users, organisations, devices, products, anything.

Scripts

Objects also have events which can be used to trigger events.
Out of the box, the above scripts are configured:
onCreate: The script that runs when the object is created. In this case, a script used to set the default fields for a user.
onDelete: The script that runs when the object is deleted. In this case, a script is used to cleanup users after deletion.
These scripts are completely configurable and new scripts can easily be added.
If you try add a new script you will see there are three options:
  1. Script Inline Script: script defined within the UI.
  2. Script File Path: a script stored within the OpenIDM configuration directory. This is how out of the box scripts work. If you navigate to /openidm/bin/defaults/script/ui you can examine these out of the box scripts to see what they do.
  3. Workflow – Event can be used to trigger a workflow.
Note: If you add new scripts, these should be placed somewhere else, usually: /usr/local/env/box/openidm/script
 
Scripting is a great way to do all sorts of things to help you manage objects.

Properties

Properties let you define additional behaviors for attributes.
  • Encrypted: The attribute value is encrypted. This means it can be decrypted and the value retrieved if required. 
  • Private: Restricts HTTP access to sensitive data, if this is true the attribute is not returned when using the REST API.
  • Virtual: The attribute is calculated on the fly, usually from a script.
  • Hashed: The attribute is hashed. Hashing is a one way function and the usual way that passwords should be stored. You hash the password when a user registers for the first time. When they log in again subsequently you hash the password that they enter against the original password hash. If they match you know the passwords are the same. Crucially, it is impossible to take a hash and extract the original password from it.
A common use for this is calculating effective roles. Effective roles are dynamically calculated using an out of the box script:
You can examine the script here: /openidm/bin/defaults/script/roles/effectiveRoles.js. 

Managed Objects and the REST API

For the final part of this blog I want to take a look at something I think is pretty cool. The OpenIDM REST API.
All managed objects ( including the ones you can create yourself ) are automatically made available using a REST API.

Using the API you can Create, Return, Update and Delete objects ( CRUD ) as well as search for and query objects. We will dive into the REST API in a later series but we can do a quick demo just to get a feel for how it works.

I recommend downloading Postman for this, Postman is a plug in for Chrome that lets you easiy invoke REST API’s. You can grab it here: https://www.getpostman.com/
Once you have Postman. Log into OpenIDM as administrator and go to Manage, then User and create a new user:
Press Save. Now look at the URL:
Note the long string of letters and numbers. This is the object id for our new user.
Now if we go to Postman, we can setup a new request:
Make sure you populate the headers as I have above. Set the request to a GET and enter a URL to return. In our case:
How does this break down:
Now, if you press Send, you should retrieve the user we just created:
This is just a small taster of what the REST API can do and we will explore it in much more detail in later blogs. You can also read all about the REST API here:

 

 

This blog post was first published @ http://identity-implementation.blogspot.no/, included here with permission from the author.

Invoking HOTP over REST

HOTP Introduction

An excellent article about the core OpenAM HOTP capability is: Use HOTP for two factor authentication

Building on the article, we show here a typical REST-based programmatic interaction when invoking HOTP from a client, such as a Portal.

Configuration in OpenAM

Setup HOTP as REQUISITE after DataStore under a realm called “levels”. You could choose not to use realms and create the authentication chain at the top level realm. However, you would modify the REST URL for all the ensuing calls.

Using PostMan, invoke a POST on the realm=/levels

Body-

Empty

Response-

{ "authId": "eyAiYWxnIjogIkhTMjU2IiwgInR5cCI6ICJqd3QiIH0.eyAib3RrIjogIm05ZWVpdjltNmsxdGRoN2dkdGM4MG5qdWFmIiwgInNlc3Npb25JZCI6ICJBUUlDNXdNMkxZNFNmY3hieHYzZjI0aXlzNDlEaG9NUlU3VENhMkU3dFdfcXY1Zy4qQUFKVFNRQUNNREVBQWxOTEFCUXROelU0TmpBME1UZzJNVFl5TWpnNU5EWXdOZy4uKiIsICJyZWFsbSI6ICJvPWxldmVscyxvdT1zZXJ2aWNlcyxkYz1vcGVuYW0sZGM9Zm9yZ2Vyb2NrLGRjPW9yZyIgfQ.SsOE-9DyAZ6apnj5SXaD9ED28T_RDFfpjV8hslHP99g", "template": "", "stage": "DataStore1", "callbacks": [ { "type": "NameCallback", "output": [ { "name": "prompt", "value": " User Name: " } ], "input": [ { "name": "IDToken1", "value": "" } ] }, { "type": "PasswordCallback", "output": [ { "name": "prompt", "value": " Password: " } ], "input": [ { "name": "IDToken2", "value": "" } ] } ] }

 

Add in the username and password as shown below:

Body (from the screenshot above)-

{ "authId": "eyAiYWxnIjogIkhTMjU2IiwgInR5cCI6ICJqd3QiIH0.eyAib3RrIjogIjl2Mm1lZGQ3NmpwdXViZGlncGkyZjFtNzk5IiwgInNlc3Npb25JZCI6ICJBUUlDNXdNMkxZNFNmY3d1amwzczR4TXdyMHI0S3paMFI2Qmk3LV9aTHMxcnRQby4qQUFKVFNRQUNNREVBQWxOTEFCTXlOelE1TmpJeU5qUTBOVFUwTlRreE5EQTMqIiwgInJlYWxtIjogIm89bGV2ZWxzLG91PXNlcnZpY2VzLGRjPW9wZW5hbSxkYz1mb3JnZXJvY2ssZGM9b3JnIiB9.WGemKm2u0O-vbhAkAClg0l0rndGEhDbhS3pncAsn6PA", "template": "", "stage": "DataStore1", "callbacks": [ { "type": "NameCallback", "output": [ { "name": "prompt", "value": " User Name: " } ], "input": [ { "name": "IDToken1", "value": "user.4" } ] }, { "type": "PasswordCallback", "output": [ { "name": "prompt", "value": " Password: " } ], "input": [ { "name": "IDToken2", "value": "Password2" } ] } ] }

 

Response

{ "authId": "eyAiYWxnIjogIkhTMjU2IiwgInR5cCI6ICJqd3QiIH0.eyAib3RrIjogIjl2Mm1lZGQ3NmpwdXViZGlncGkyZjFtNzk5IiwgInNlc3Npb25JZCI6ICJBUUlDNXdNMkxZNFNmY3d1amwzczR4TXdyMHI0S3paMFI2Qmk3LV9aTHMxcnRQby4qQUFKVFNRQUNNREVBQWxOTEFCTXlOelE1TmpJeU5qUTBOVFUwTlRreE5EQTMqIiwgInJlYWxtIjogIm89bGV2ZWxzLG91PXNlcnZpY2VzLGRjPW9wZW5hbSxkYz1mb3JnZXJvY2ssZGM9b3JnIiB9.WGemKm2u0O-vbhAkAClg0l0rndGEhDbhS3pncAsn6PA", "template": "", "stage": "HOTP2", "callbacks": [ { "type": "PasswordCallback", "output": [ { "name": "prompt", "value": " Enter OTP " } ], "input": [ { "name": "IDToken1", "value": "" } ] }, { "type": "ConfirmationCallback", "output": [ { "name": "prompt", "value": "" }, { "name": "messageType", "value": 0 }, { "name": "options", "value": [ " Submit OTP ", " Request OTP " ] }, { "name": "optionType", "value": -1 }, { "name": "defaultOption", "value": 0 } ], "input": [ { "name": "IDToken2", "value": 0 } ] } ] }

 

Set IDToken2 to value “1”, and re submit as a POST. OpenAM will generate the OTP code and send it to the user.

 

Body-

{ "authId": "eyAiYWxnIjogIkhTMjU2IiwgInR5cCI6ICJqd3QiIH0.eyAib3RrIjogImYwZW5xYTI2aHZla3Q0bG5tc24wbDFlbTI5IiwgInNlc3Npb25JZCI6ICJBUUlDNXdNMkxZNFNmY3k4cllnb2V3MDBWNkpOUW5rR1RjLVoyVjZmcjZFMS11US4qQUFKVFNRQUNNREVBQWxOTEFCTTRNak01TXpRMU9EazROekl4TlRnNU16UXkqIiwgInJlYWxtIjogIm89bGV2ZWxzLG91PXNlcnZpY2VzLGRjPW9wZW5hbSxkYz1mb3JnZXJvY2ssZGM9b3JnIiB9.Dfxj7bAtxHEenVPA_9t3iCFhu92zqk8lXAqxmQD1COU", "template": "", "stage": "HOTP2", "callbacks": [ { "type": "PasswordCallback", "output": [ { "name": "prompt", "value": " Enter OTP " } ], "input": [ { "name": "IDToken1", "value": "" } ] }, { "type": "ConfirmationCallback", "output": [ { "name": "prompt", "value": "" }, { "name": "messageType", "value": 0 }, { "name": "options", "value": [ " Submit OTP ", " Request OTP " ] }, { "name": "optionType", "value": -1 }, { "name": "defaultOption", "value": 0 } ], "input": [ { "name": "IDToken2", "value": 1 } ] } ] }

 

Response-

{ "authId": "eyAiYWxnIjogIkhTMjU2IiwgInR5cCI6ICJqd3QiIH0.eyAib3RrIjogImYwZW5xYTI2aHZla3Q0bG5tc24wbDFlbTI5IiwgInNlc3Npb25JZCI6ICJBUUlDNXdNMkxZNFNmY3k4cllnb2V3MDBWNkpOUW5rR1RjLVoyVjZmcjZFMS11US4qQUFKVFNRQUNNREVBQWxOTEFCTTRNak01TXpRMU9EazROekl4TlRnNU16UXkqIiwgInJlYWxtIjogIm89bGV2ZWxzLG91PXNlcnZpY2VzLGRjPW9wZW5hbSxkYz1mb3JnZXJvY2ssZGM9b3JnIiB9.Dfxj7bAtxHEenVPA_9t3iCFhu92zqk8lXAqxmQD1COU", "template": "", "stage": "HOTP2", "callbacks": [ { "type": "PasswordCallback", "output": [ { "name": "prompt", "value": " Enter OTP " } ], "input": [ { "name": "IDToken1", "value": "" } ] }, { "type": "ConfirmationCallback", "output": [ { "name": "prompt", "value": "" }, { "name": "messageType", "value": 0 }, { "name": "options", "value": [ " Submit OTP ", " Request OTP " ] }, { "name": "optionType", "value": -1 }, { "name": "defaultOption", "value": 0 } ], "input": [ { "name": "IDToken2", "value": 1 } ] } ] }

 

Supply OTP Code

Change IDToken2 to value “0” and this time have the user supply the OTP code s/he received:

 

Body-

{ "authId": "eyAiYWxnIjogIkhTMjU2IiwgInR5cCI6ICJqd3QiIH0.eyAib3RrIjogImYwZW5xYTI2aHZla3Q0bG5tc24wbDFlbTI5IiwgInNlc3Npb25JZCI6ICJBUUlDNXdNMkxZNFNmY3k4cllnb2V3MDBWNkpOUW5rR1RjLVoyVjZmcjZFMS11US4qQUFKVFNRQUNNREVBQWxOTEFCTTRNak01TXpRMU9EazROekl4TlRnNU16UXkqIiwgInJlYWxtIjogIm89bGV2ZWxzLG91PXNlcnZpY2VzLGRjPW9wZW5hbSxkYz1mb3JnZXJvY2ssZGM9b3JnIiB9.Dfxj7bAtxHEenVPA_9t3iCFhu92zqk8lXAqxmQD1COU", "template": "", "stage": "HOTP2", "callbacks": [ { "type": "PasswordCallback", "output": [ { "name": "prompt", "value": " Enter OTP " } ], "input": [ { "name": "IDToken1", "value": "86848280" } ] }, { "type": "ConfirmationCallback", "output": [ { "name": "prompt", "value": "" }, { "name": "messageType", "value": 0 }, { "name": "options", "value": [ " Submit OTP ", " Request OTP " ] }, { "name": "optionType", "value": -1}, { "name": "defaultOption", "value": 0 } ], "input": [ { "name": "IDToken2", "value": 0 } ] } ] }

 

At this time, if the OTP code was correct, the user will be logged into OpenAM.

The value of the iPlanetDirectoryPro cookie will be returned as tokenId.

 

Response-

{ "tokenId": "AQIC5wM2LY4Sfcyt-pO9V3hEMYK924cDC2_SlWLROXUBpsc.*AAJTSQACMDEAAlNLABQtMTcyMDQ4ODk5NTU0ODUzNTQ4MQ..*", "successUrl": "/openam/console" }

 

The iPlanetDirectoryPro can then be used to do other stuff, such as list user data values over REST:

User Self Registration in ForgeRock OpenAM Concluding Part – Using REST

This blog post was first published @ www.fedji.com, included here with permission.

In an earlier post, we saw User Self Registration in ForgeRock OpenAM using XUI. It’s likely that you may not want to use the UI that comes with OpenAM, but may have reasons to build your own UI/Application on the REST API to operate on ForgeRock’s Access Management Solution. Keeping that in mind, a discussion on User Self Registration in OpenAM is incomplete without showing you how it is done using REST. Like many other examples you may already be familiar with around REST calls to ForgeRock products, you’ll see the usage of simple, yet powerful ‘curl’ to invoke REST calls to OpenAM for Self Registering a User. Here’s a list of related video blogs that you may want to watch before watching the one that’s embedded below.

User Self Registration in ForgeRock OpenAM Part I – Using XUI
E-mail Service Configuration in ForgeRock OpenAM

If you are ready, let’s go:

REST on every side

This blog post was first published @ http://identityrocks.blogspot.fr/, included here with permission.

Regardless if web application, mobile application, device application or thing application development – identity management is there for you. Be it internal or external. The fast way in is REST. ForgeRock’s identity management platform delivers through REST. I’ll illustrate by example authentication via REST against a complex authentication chain.

“Representational State Transfer (REST) is a software architecture style for building scalable web services.” [1] [2]

The Authentication Chain
OpenAM’s authentication service can be composed of multiple authentication modules. The authentication chain consists 4 authentication modules including LDAP and device fingerprint. The relevance of such a chain was discussed in a previous article titled “Smarter Security with Device Fingerprints”.
For the purpose of simplicity, the OneTimePassword is replaced with a DataStore authentication module. Rather than providing a one time password (e.g. SMS passcode), the user has to provide username and password (same or different than before depending on the OpenAM configuration).
As there is no browser involved, any json structure can be sent back as the fingerprint.
The authentication process consists of 6 steps if no corresponding and valid device fingerprint was previously registered. In case it was, the authentication finishes after step 3.

The Tools: CURL, JQ and the Scripts
As client in this example serves the straightforward curl tool. This allows easy investigation of requests and responses.
Note that the JWT (JSON Web Token) needs to be passed on between all callbacks. For extracting specific elements of json, like the JWT, the jq tool can be of great use (for instance JWT_TOKEN=`echo ${CURL_RESPONSE} | jq –raw-output ‘.authId’`).
In case you want to build this example or something similar, I published in a GitHub project  scripts which could be of inspiration (see in particular 620-deviceid-base-config, 621-deviceid-rest-base, 622-deviceid-rest-ootb).

The Authentication Steps in Detail [3]
Step 1: Get the authentication token
An “empty” request is sent to obtain the JWT (JSON Web Token) and the first set of callbacks.

Request
curl -s –request POST –header “Content-Type: application/json” https://sso.yellowstone.com:443/sso/json/authenticate?realm=/deviceidrealm
Response

{
  "authId": "eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAib3RrIjogImdvbGhwOHFrNDVtbTI5cm91YWpyOHI2b2dkIiwgInJlYWxtIjogIm89ZGV2aWNlaWRyZWFsbSxvdT1zZXJ2aWNlcyxkYz1zc28tY29uZmlnLGRjPWNvbSIsICJzZXNzaW9uSWQiOiAiQVFJQzV3TTJMWTRTZmN5dDJ5VTFoc3J1OHZNZkhzVW1hMjd1QjA0S3YtQk5iZEUuKkFBSlRTUUFDTURJQUFsTkxBQk10TlRrek9UQXlOek0yTURJME1EZ3lNakkyQUFKVE1RQUNNREUuKiIgfQ.ZQGuCe3qDUEchsxcDCLdRU73g1i-isUAZDdp5ZOvVdM",
  "template": "",
  "stage": "LDAP1",
  "header": "Sign in to OpenAM",
  "callbacks": [
    {
      "type": "NameCallback",
      "output": [
        {
          "name": "prompt",
          "value": "User Name:"
        }
      ],
      "input": [
        {
          "name": "IDToken1",
          "value": ""
        }
      ]
    },
    {
      "type": "PasswordCallback",
      "output": [
        {
          "name": "prompt",
          "value": "Password:"
        }
      ],
      "input": [
        {
          "name": "IDToken2",
          "value": ""
        }
      ]
    }
  ]
}

Step 2: Provide callbacks for LDAP module
The JWT is passed with any subsequent request in this authentication process. Username and password are passed as required by the LDAP authentication module’s callback.

Request
curl -s –request POST –header “Content-Type: application/json” –data @callback-step2.json https://sso.yellowstone.com:443/sso/json/authenticate?realm=/deviceidrealm
callback-step2.json :

{
  "authId": "eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAib3RrIjogImdvbGhwOHFrNDVtbTI5cm91YWpyOHI2b2dkIiwgInJlYWxtIjogIm89ZGV2aWNlaWRyZWFsbSxvdT1zZXJ2aWNlcyxkYz1zc28tY29uZmlnLGRjPWNvbSIsICJzZXNzaW9uSWQiOiAiQVFJQzV3TTJMWTRTZmN5dDJ5VTFoc3J1OHZNZkhzVW1hMjd1QjA0S3YtQk5iZEUuKkFBSlRTUUFDTURJQUFsTkxBQk10TlRrek9UQXlOek0yTURJME1EZ3lNakkyQUFKVE1RQUNNREUuKiIgfQ.ZQGuCe3qDUEchsxcDCLdRU73g1i-isUAZDdp5ZOvVdM",
  "template": "",
  "stage": "LDAP1",
  "callbacks": [
    {
      "type": "NameCallback",
      "output": [
        {
          "name": "prompt",
          "value": " User Name: "
        }
      ],
      "input": [
        {
          "name": "IDToken1",
          "value": "demo"
        }
      ]
    },
    {
      "type": "PasswordCallback",
      "output": [
        {
          "name": "prompt",
          "value": " Password: "
        }
      ],
      "input": [
        {
          "name": "IDToken2",
          "value": "changeit"
        }
      ]
    }
  ]
}

Response
After successful LDAP authentication, the JavaScript which computes the fingerprint is sent in the TextOutputCallback.

{
  "authId": "eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAib3RrIjogImdvbGhwOHFrNDVtbTI5cm91YWpyOHI2b2dkIiwgInJlYWxtIjogIm89ZGV2aWNlaWRyZWFsbSxvdT1zZXJ2aWNlcyxkYz1zc28tY29uZmlnLGRjPWNvbSIsICJzZXNzaW9uSWQiOiAiQVFJQzV3TTJMWTRTZmN5dDJ5VTFoc3J1OHZNZkhzVW1hMjd1QjA0S3YtQk5iZEUuKkFBSlRTUUFDTURJQUFsTkxBQk10TlRrek9UQXlOek0yTURJME1EZ3lNakkyQUFKVE1RQUNNREUuKiIgfQ.ZQGuCe3qDUEchsxcDCLdRU73g1i-isUAZDdp5ZOvVdM",
  "template": "",
  "stage": "DeviceIdMatch2",
  "header": "Sign in to OpenAM",
  "callbacks": [
    {
      "type": "HiddenValueCallback",
      "output": [
        {
          "name": "value",
          "value": ""
        }
      ],
      "input": [
        {
          "name": "IDToken1",
          "value": "clientScriptOutputData"
        }
      ]
    },
    {
      "type": "TextOutputCallback",
      "output": [
        {
          "name": "message",
          "value": "JAVASCRIPT TO BE EXECUTED IN THE CLIENT BROWSER. OMITTED FOR READABILITY"
        },
        {
          "name": "messageType",
          "value": "4"
        }
      ]
    }
  ]
}

Step 3: Provide callbacks for DeviceId (Match) module
The fingerprint is sent back to the authentication process through the HiddenValueCallback. As there is no browser involved, any json element can be sent in. Note that the value element is of type String and the String contains the json. So properly encode the json (i.e. escape double quotes).

Request
curl -s –request POST –header “Content-Type: application/json” –data @callback-step3.json https://sso.yellowstone.com:443/sso/json/authenticate?realm=/deviceidrealmcallback-step3.json :

{
  "authId": "eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAib3RrIjogImdvbGhwOHFrNDVtbTI5cm91YWpyOHI2b2dkIiwgInJlYWxtIjogIm89ZGV2aWNlaWRyZWFsbSxvdT1zZXJ2aWNlcyxkYz1zc28tY29uZmlnLGRjPWNvbSIsICJzZXNzaW9uSWQiOiAiQVFJQzV3TTJMWTRTZmN5dDJ5VTFoc3J1OHZNZkhzVW1hMjd1QjA0S3YtQk5iZEUuKkFBSlRTUUFDTURJQUFsTkxBQk10TlRrek9UQXlOek0yTURJME1EZ3lNakkyQUFKVE1RQUNNREUuKiIgfQ.ZQGuCe3qDUEchsxcDCLdRU73g1i-isUAZDdp5ZOvVdM",
  "template": "",
  "stage": "DeviceIdMatch2",
  "callbacks": [
    {
      "type": "HiddenValueCallback",
      "input": [
        {
          "name": "IDToken1",
          "value": "THE FINGERPRINT GATHERED "
        }
      ]
    },
    {
      "type": "TextOutputCallback",
      "output": [
        {
          "name": "messageType",
          "value": "4"
        }
      ]
    }
  ]
}
Response

If the fingerprint corresponds to a registered fingerprint, then the authentication process would return successfully at this point. Otherwise (in this case), a second factor is required (DataStore module).

{
  "authId": "eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAib3RrIjogImdvbGhwOHFrNDVtbTI5cm91YWpyOHI2b2dkIiwgInJlYWxtIjogIm89ZGV2aWNlaWRyZWFsbSxvdT1zZXJ2aWNlcyxkYz1zc28tY29uZmlnLGRjPWNvbSIsICJzZXNzaW9uSWQiOiAiQVFJQzV3TTJMWTRTZmN5dDJ5VTFoc3J1OHZNZkhzVW1hMjd1QjA0S3YtQk5iZEUuKkFBSlRTUUFDTURJQUFsTkxBQk10TlRrek9UQXlOek0yTURJME1EZ3lNakkyQUFKVE1RQUNNREUuKiIgfQ.ZQGuCe3qDUEchsxcDCLdRU73g1i-isUAZDdp5ZOvVdM",
  "template": "",
  "stage": "DataStore1",
  "header": "Sign in to OpenAM",
  "callbacks": [
    {
      "type": "NameCallback",
      "output": [
        {
          "name": "prompt",
          "value": "User Name:"
        }
      ],
      "input": [
        {
          "name": "IDToken1",
          "value": ""
        }
      ]
    },
    {
      "type": "PasswordCallback",
      "output": [
        {
          "name": "prompt",
          "value": "Password:"
        }
      ],
      "input": [
        {
          "name": "IDToken2",
          "value": ""
        }
      ]
    }
  ]
}

Step 4: Provide callbacks for DataStore module
Request
curl -s –request POST –header “Content-Type: application/json” –data @callback-step4.json https://sso.yellowstone.com:443/sso/json/authenticate?realm=/deviceidrealm

callback-step4.json :

{
  "authId": "eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAib3RrIjogImdvbGhwOHFrNDVtbTI5cm91YWpyOHI2b2dkIiwgInJlYWxtIjogIm89ZGV2aWNlaWRyZWFsbSxvdT1zZXJ2aWNlcyxkYz1zc28tY29uZmlnLGRjPWNvbSIsICJzZXNzaW9uSWQiOiAiQVFJQzV3TTJMWTRTZmN5dDJ5VTFoc3J1OHZNZkhzVW1hMjd1QjA0S3YtQk5iZEUuKkFBSlRTUUFDTURJQUFsTkxBQk10TlRrek9UQXlOek0yTURJME1EZ3lNakkyQUFKVE1RQUNNREUuKiIgfQ.ZQGuCe3qDUEchsxcDCLdRU73g1i-isUAZDdp5ZOvVdM",
  "template": "",
  "stage": "DataStore1",
  "callbacks": [
    {
      "type": "NameCallback",
      "output": [
        {
          "name": "prompt",
          "value": " User Name: "
        }
      ],
      "input": [
        {
          "name": "IDToken1",
          "value": "demo"
        }
      ]
    },
    {
      "type": "PasswordCallback",
      "output": [
        {
          "name": "prompt",
          "value": " Password: "
        }
      ],
      "input": [
        {
          "name": "IDToken2",
          "value": "changeit"
        }
      ]
    }
  ]
}
Response 

Now that both factors succeeded, the user is asked whether to store the device fingerprint or not.

{
  "authId": "eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAib3RrIjogImdvbGhwOHFrNDVtbTI5cm91YWpyOHI2b2dkIiwgInJlYWxtIjogIm89ZGV2aWNlaWRyZWFsbSxvdT1zZXJ2aWNlcyxkYz1zc28tY29uZmlnLGRjPWNvbSIsICJzZXNzaW9uSWQiOiAiQVFJQzV3TTJMWTRTZmN5dDJ5VTFoc3J1OHZNZkhzVW1hMjd1QjA0S3YtQk5iZEUuKkFBSlRTUUFDTURJQUFsTkxBQk10TlRrek9UQXlOek0yTURJME1EZ3lNakkyQUFKVE1RQUNNREUuKiIgfQ.ZQGuCe3qDUEchsxcDCLdRU73g1i-isUAZDdp5ZOvVdM",
  "template": "",
  "stage": "DeviceIdSave2",
  "header": "Add to Trusted Devices",
  "callbacks": [
    {
      "type": "ChoiceCallback",
      "output": [
        {
          "name": "prompt",
          "value": "Add to Trusted Devices?"
        },
        {
          "name": "choices",
          "value": [
            "Yes",
            "No"
          ]
        },
        {
          "name": "defaultChoice",
          "value": 1
        }
      ],
      "input": [
        {
          "name": "IDToken1",
          "value": 1
        }
      ]
    }
  ]
} 

Step 5: Provide callbacks for DeviceId (Save) module – Consent to store device profile
The value 0 in the ChoiceCallback indicates that the user want to store the device fingerprint with his profile.

Request
curl -s –request POST –header “Content-Type: application/json” –data @callback-step5.json https://sso.yellowstone.com:443/sso/json/authenticate?realm=/deviceidrealm 
callback-step5.json :

{
  "authId": "eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAib3RrIjogImdvbGhwOHFrNDVtbTI5cm91YWpyOHI2b2dkIiwgInJlYWxtIjogIm89ZGV2aWNlaWRyZWFsbSxvdT1zZXJ2aWNlcyxkYz1zc28tY29uZmlnLGRjPWNvbSIsICJzZXNzaW9uSWQiOiAiQVFJQzV3TTJMWTRTZmN5dDJ5VTFoc3J1OHZNZkhzVW1hMjd1QjA0S3YtQk5iZEUuKkFBSlRTUUFDTURJQUFsTkxBQk10TlRrek9UQXlOek0yTURJME1EZ3lNakkyQUFKVE1RQUNNREUuKiIgfQ.ZQGuCe3qDUEchsxcDCLdRU73g1i-isUAZDdp5ZOvVdM",
  "template": "",
  "stage": "DeviceSave2",
  "callbacks": [
    {
      "type": "ChoiceCallback",
      "input": [
        {
          "name": "IDToken1",
          "value": "0"
        }
      ]
    }
  ]
}
Response

Then the user is prompted to provide a name under which the new profile shall be stored.

{
  "authId": "eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAib3RrIjogImdvbGhwOHFrNDVtbTI5cm91YWpyOHI2b2dkIiwgInJlYWxtIjogIm89ZGV2aWNlaWRyZWFsbSxvdT1zZXJ2aWNlcyxkYz1zc28tY29uZmlnLGRjPWNvbSIsICJzZXNzaW9uSWQiOiAiQVFJQzV3TTJMWTRTZmN5dDJ5VTFoc3J1OHZNZkhzVW1hMjd1QjA0S3YtQk5iZEUuKkFBSlRTUUFDTURJQUFsTkxBQk10TlRrek9UQXlOek0yTURJME1EZ3lNakkyQUFKVE1RQUNNREUuKiIgfQ.ZQGuCe3qDUEchsxcDCLdRU73g1i-isUAZDdp5ZOvVdM",
  "template": "",
  "stage": "DeviceIdSave3",
  "header": "Trusted Device Name",
  "callbacks": [
    {
      "type": "NameCallback",
      "output": [
        {
          "name": "prompt",
          "value": "Trusted Device Name?"
        }
      ],
      "input": [
        {
          "name": "IDToken1",
          "value": ""
        }
      ]
    }
  ]
}

Step 6: Provide callbacks for DeviceId (Save) module – Device profile name
Then If an empty Then If an empty v is provided as the device name, the authentication module will compute one which looks like “Profile: 21/08/2015 15:51”.
Request
curl -s –request POST –header “Content-Type: application/json” –data @callback-step6.json https://sso.yellowstone.com:443/sso/json/authenticate?realm=/deviceidrealm 
callback-step6.json :

{
  "authId": "eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAib3RrIjogImdvbGhwOHFrNDVtbTI5cm91YWpyOHI2b2dkIiwgInJlYWxtIjogIm89ZGV2aWNlaWRyZWFsbSxvdT1zZXJ2aWNlcyxkYz1zc28tY29uZmlnLGRjPWNvbSIsICJzZXNzaW9uSWQiOiAiQVFJQzV3TTJMWTRTZmN5dDJ5VTFoc3J1OHZNZkhzVW1hMjd1QjA0S3YtQk5iZEUuKkFBSlRTUUFDTURJQUFsTkxBQk10TlRrek9UQXlOek0yTURJME1EZ3lNakkyQUFKVE1RQUNNREUuKiIgfQ.ZQGuCe3qDUEchsxcDCLdRU73g1i-isUAZDdp5ZOvVdM",
  "template": "",
  "stage": "DeviceIdSave3",
  "callbacks": [
    {
      "type": "NameCallback",
      "input": [
        {
          "name": "IDToken1",
          "value": ""
        }
      ]
    }
  ]
} 
Response
Now the response contains an SSOToken. This means the authentication was successful.
{
  "tokenId": "AQIC5wM2LY4SfczOURj5zOskLzpSNfuSU9GYnW5XTu8Tudg.*AAJTSQACMDIAAlNLABM2OTIyMTc1MTIwOTUxMTA2NTcxAAJTMQACMDE.*",
  "successUrl": "/sso/console"
}

“And the LORD gave them rest on every side”. Joshua 21:44 [4]

 

References

[1] Pautasso, Cesare; Wilde, Erik; Alarcon, Rosa (2014), REST: Advanced Research Topics and Practical Applications
[2] Wikipedia contributors. “Representational state transfer.” Wikipedia, The Free Encyclopedia. Wikipedia, The Free Encyclopedia, 1 Sep. 2015. Web. 1 Sep. 2015.
[3] Craig, Mark; Goldsmith, David; Hirayama, Gene: Lee, Chris, et al. OpenAM Developer’s Guide Version 13.0.0-SNAPSHOT. ForgeRock, AS., 2015. <http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/webhelp/dev-guide/rest-api-auth-json.html>
[4] The Holy Bible, New International Version, NIV Copyright 1973, 1978, 1984, 2011 by Biblica

Introduction to OpenIG (Part 1: Use cases)

Welcome

You've probably landed here because you want to know something about OpenIG. This is the right place to be :)

This post is the first one of a serie of OpenIG-related articles that would gives you hand-on samples with explanations.

Identity Gateway

OpenIG stands for Open Identity Gateway, it is an identity/security specialized reverse proxy. That means that it control the access to a set of internal services.

By controling the access, I mean that it intercepts all the requests coming to the protected service (be it a RESTful API or a web application) and process them before (and after) forwarding them to the server.

Different kind of processing can be handled:

  • Request authorization
  • Capture and password replay
  • Message logging
  • Transformation

Commons use cases

Ok, that was a bit of a generalist description (transformation is intentionally vague :) ). Having some real-life use cases will help to have a better feeling/understanding of what OpenIG is capable of.

SAML Application Federation

In this use case, OpenIG acts as a SAML-enabled facade to a somehow legacy application that cannot be adapted to support SAML federation. The Identity Provider (could be OpenAM) will consider OpenIG as a standard SAML Service Provider.

SAML CoT with OpenIG used as a facade to a legacy application

Application Authentication

Here, OpenIG acts as an OpenID Connect Relying Party (OIDC terminology for client) and requires the user to authenticate to an OpenID Connect Provider (the identity provider) before giving him/her access to the protected application.

Authenticated user's profile information (such as name, email, address, picture, ...) are available to enrich the user experience, or make further verifications.

OpenID Connect - OpenIG Relying Party

RESTful Services Protection

This simple case shows OpenIG verifying request to a proxified RESTful API: each request must contains a valid OAuth 2.0 Bearer Token to be allowed to reach the service API. In this case, OpenIG acts as an OAuth 2.0 Resource Server.

Very useful if you have an old-fashioned REST API that you cannot easily update to deal with OAuth 2.0 tokens.

OAuth 2.0 - OpenIG ResourceServer

Not enough ?

Well, we're done with the 'marketing' stuff. In the next post, we will start to play with OpenIG.

See you soon!