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.

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

More about OpenDJ support for JSON attribute values

In a previous post, I introduced the new JSON syntax, JSON query and matching rules that are delivered as part of the OpenDJ LDAP directory server. Today, I will give more insights on how to customise the syntax, tune the matching rules for smarter and more efficient indexing, and I will highlight some best practices with using the JSON syntax.

JSON Syntax Validation

When defining an attribute with a JSON syntax, the server will validate that the JSON value is compliant with JSON RFC.  OpenDJ offers a few options to relax some of the constraints of a valid JSON. To change the settings of the syntax, you must use dsconfig --advanced.

>>>> Configure the properties of the Core Schema

Property Value(s)
 ----------------------------------------------------------------------
 1) allow-attribute-types-with-no-sup-or-syntax true
 2) allow-zero-length-values-directory-string false
 3) disabled-matching-rule NONE
 4) disabled-syntax NONE
 5) enabled true
 6) java-class org.opends.server.schema.CoreSchemaProvider
 7) json-validation-policy strict
 8) strict-format-certificates true
 9) strict-format-country-string true
 10) strict-format-jpeg-photos false
 11) strict-format-telephone-numbers false
 12) strip-syntax-min-upper-bound-attribute-type-description false

?) help
 f) finish - apply any changes to the Core Schema
 c) cancel
 q) quit

Enter choice [f]: 7


>>>> Configuring the "json-validation-policy" property

Specifies the policy that will be used when validating JSON syntax values.

Do you want to modify the "json-validation-policy" property?

1) Keep the default value: strict
 2) Change it to the value: disabled
 3) Change it to the value: lenient

?) help
 q) quit

Enter choice [1]:

Strict is the default mode.

Disabled means that the server will not try to validate the content of a JSON value.

Lenient means that it will validate the JSON value, but tolerate comments, single quotes and unquoted control characters.

JSON Matching Rule and Indexing

Like any attribute in the OpenDJ server, attributes with a JSON syntax can be indexed.

$ dsconfig -h localhost -p 4444 -D "cn=Directory Manager" -w secret12 
 set-backend-index-prop --backend-name userRoot --index-name json 
 --set index-type:equality -X -n

By default, the server actually indexes each field of all JSON values. If the values are large and complex, indexing will  result in many disk I/O, possibly impacting performances for write operations.

If you know which fields of the JSON values will be queried for by the client applications, you can optimise the index and specify the JSON fields that are indexed. This is by creating a new custom schema provider for the JSON query. You can choose to overwrite the default JSON query matching rules (as illustrated below), and this will affect all JSON attributes, or you can choose to create a new rule (with a new name and OID).

In the example below, the custom schema provider overwrites the default caseIgnoreJsonQueryMatch, and only indexes the JSON fields _id and name with its subfields.

$ dsconfig -h localhost -p 4444 -D "cn=Directory Manager" -w secret12 
 create-schema-provider --provider-name "Json Schema" 
 --type json-schema --set enabled:true 
 --set case-sensitive-strings:false --set ignore-white-space:true 
 --set matching-rule-name:caseIgnoreJsonQueryMatch 
 --set matching-rule-oid:1.3.6.1.4.1.36733.2.1.4.1 
 --set indexed-field:_id 
 --set "indexed-field:name/**" 
 -X -n

When you overwrite the default matching rule, or you define a new one, you need to rebuild the indexes for all attributes that are making use of it.

Best Practices

The support for JSON attributes in OpenDJ is very new, but yet, we can recommend how to best use them.

The first thing, is to use the JSON syntax for attributes that are single valued. Indexing is designed to associate values with entries. Because JSON query indexes are built for all fields of the JSON value, an entry will be returned if a query matches all fields, even though they are in different values.

The JSON syntax is handy to store complex JSON objects in a single attribute and query them, through any field. However, the larger the values, the  more impact on the directory server’s performances. As, by default, all JSON fields are indexed, the more fields, the more expensive will be indexing. Also, because the JSON objects are LDAP attributes, the only way to change a value is to replace the value with a new one (or delete the value and add a new one, which are operations with even more bytes). There is no patch operation on the value. Finally, OpenDJ stores all attributes of an entry in a single database record. So any change in the entry itself will require to write the whole entry again.

As we’ve seen above, OpenDJ proposes a way to customise the JSON queries and the JSON fields that are indexed. We suggest that you make use of this capability and optimise the indexing of JSON objects for the queries run by the client applications.

If you plan to store different kinds of JSON objects in an OpenDJ directory service, define different attributes with the JSON syntax, and use a custom JSON query per attribute. For example, lets assume you will have entries that are persons with an address attribute with a JSON syntax, and some other entries that represent OAuth2 tokens, and the token main attribute has a JSON syntax. You can should define an address attribute and a token attribute, both with the JSON syntax, but their specific matching rules, like below.

attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.999 NAME 'address'
  SYNTAX 1.3.6.1.4.1.36733.2.1.3.1
  EQUALITY caseIgnoreJsonAddressQueryMatch SINGLE-VALUE )

attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.999 NAME 'token'
  SYNTAX 1.3.6.1.4.1.36733.2.1.3.1 
  EQUALITY caseIgnoreJsonTokenQueryMatch SINGLE-VALUE )

where the matching rules are defined as such:

$ dsconfig -h localhost -p 4444 -D "cn=Directory Manager" -w secret12 
 create-schema-provider --provider-name "Address Json Schema" 
 --type json-schema --set enabled:true 
 --set case-sensitive-strings:false --set ignore-white-space:true 
 --set matching-rule-name:caseIgnoreJsonAddressQueryMatch 
 --set matching-rule-oid:1.3.6.1.4.1.36733.2.1.4.998 
 -X -n

and

$ dsconfig -h localhost -p 4444 -D "cn=Directory Manager" -w secret12 
 create-schema-provider --provider-name "Token Json Schema" 
 --type json-schema --set enabled:true 
 --set case-sensitive-strings:false --set ignore-white-space:true 
 --set matching-rule-name:caseIgnoreJsonTokenQueryMatch 
 --set matching-rule-oid:1.3.6.1.4.1.36733.2.1.4.999 
 --set indexed-field:token_type 
 --set indexed-field:expires_at 
 --set indexed-field:access_token 
 -X -n

Note that there is an issue with OpenDJ 4.0.0-SNAPSHOTS (nightly builds) and when you define a new Schema Provider, you need to restart the server to have it be effective.

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

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

More about OpenDJ support for JSON attribute values

In a previous post, I introduced the new JSON syntax, JSON query and matching rules that are delivered as part of the OpenDJ LDAP directory server. Today, I will give more insights on how to customise the syntax, tune the matching rules for smarter and more efficient indexing, and I will highlight some best practices with using the JSON syntax.

JSON Syntax Validation

When defining an attribute with a JSON syntax, the server will validate that the JSON value is compliant with JSON RFC.  OpenDJ offers a few options to relax some of the constraints of a valid JSON. To change the settings of the syntax, you must use dsconfig --advanced.

>>>> Configure the properties of the Core Schema

Property Value(s)
 ----------------------------------------------------------------------
 1) allow-attribute-types-with-no-sup-or-syntax true
 2) allow-zero-length-values-directory-string false
 3) disabled-matching-rule NONE
 4) disabled-syntax NONE
 5) enabled true
 6) java-class org.opends.server.schema.CoreSchemaProvider
 7) json-validation-policy strict
 8) strict-format-certificates true
 9) strict-format-country-string true
 10) strict-format-jpeg-photos false
 11) strict-format-telephone-numbers false
 12) strip-syntax-min-upper-bound-attribute-type-description false

?) help
 f) finish - apply any changes to the Core Schema
 c) cancel
 q) quit

Enter choice [f]: 7


>>>> Configuring the "json-validation-policy" property

Specifies the policy that will be used when validating JSON syntax values.

Do you want to modify the "json-validation-policy" property?

1) Keep the default value: strict
 2) Change it to the value: disabled
 3) Change it to the value: lenient

?) help
 q) quit

Enter choice [1]:

Strict is the default mode.

Disabled means that the server will not try to validate the content of a JSON value.

Lenient means that it will validate the JSON value, but tolerate comments, single quotes and unquoted control characters.

JSON Matching Rule and Indexing

Like any attribute in the OpenDJ server, attributes with a JSON syntax can be indexed.

$ dsconfig -h localhost -p 4444 -D "cn=Directory Manager" -w secret12 \
 set-backend-index-prop \--backend-name userRoot --index-name json \
 --set index-type:equality -X -n

By default, the server actually indexes each field of all JSON values. If the values are large and complex, indexing will  result in many disk I/O, possibly impacting performances for write operations.

If you know which fields of the JSON values will be queried for by the client applications, you can optimise the index and specify the JSON fields that are indexed. This is by creating a new custom schema provider for the JSON query. You can choose to overwrite the default JSON query matching rules (as illustrated below), and this will affect all JSON attributes, or you can choose to create a new rule (with a new name and OID).

In the example below, the custom schema provider overwrites the default caseIgnoreJsonQueryMatch, and only indexes the JSON fields _id and name with its subfields.

$ dsconfig -h localhost -p 4444 -D "cn=Directory Manager" -w secret12 \
 create-schema-provider --provider-name "Json Schema" \
 --type json-schema --set enabled:true \
 --set case-sensitive-strings:false --set ignore-white-space:true \
 --set matching-rule-name:caseIgnoreJsonQueryMatch \
 --set matching-rule-oid:1.3.6.1.4.1.36733.2.1.4.1 \
 --set indexed-field:_id \
 --set "indexed-field:name/**" \
 -X -n

When you overwrite the default matching rule, or you define a new one, you need to rebuild the indexes for all attributes that are making use of it.

Best Practices

The support for JSON attributes in OpenDJ is very new, but yet, we can recommend how to best use them.

The first thing, is to use the JSON syntax for attributes that are single valued. Indexing is designed to associate values with entries. Because JSON query indexes are built for all fields of the JSON value, an entry will be returned if a query matches all fields, even though they are in different values.

The JSON syntax is handy to store complex JSON objects in a single attribute and query them, through any field. However, the larger the values, the  more impact on the directory server’s performances. As, by default, all JSON fields are indexed, the more fields, the more expensive will be indexing. Also, because the JSON objects are LDAP attributes, the only way to change a value is to replace the value with a new one (or delete the value and add a new one, which are operations with even more bytes). There is no patch operation on the value. Finally, OpenDJ stores all attributes of an entry in a single database record. So any change in the entry itself will require to write the whole entry again.

As we’ve seen above, OpenDJ proposes a way to customise the JSON queries and the JSON fields that are indexed. We suggest that you make use of this capability and optimise the indexing of JSON objects for the queries run by the client applications.

If you plan to store different kinds of JSON objects in an OpenDJ directory service, define different attributes with the JSON syntax, and use a custom JSON query per attribute. For example, lets assume you will have entries that are persons with an address attribute with a JSON syntax, and some other entries that represent OAuth2 tokens, and the token main attribute has a JSON syntax. You can should define an address attribute and a token attribute, both with the JSON syntax, but their specific matching rules, like below.

attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.999 NAME 'address'
  SYNTAX 1.3.6.1.4.1.36733.2.1.3.1
  EQUALITY caseIgnoreJsonAddressQueryMatch SINGLE-VALUE )

attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.999 NAME 'token'
  SYNTAX 1.3.6.1.4.1.36733.2.1.3.1 
  EQUALITY caseIgnoreJsonTokenQueryMatch SINGLE-VALUE )

where the matching rules are defined as such:

$ dsconfig -h localhost -p 4444 -D "cn=Directory Manager" -w secret12 \
 create-schema-provider --provider-name "Address Json Schema" \
 --type json-schema --set enabled:true \
 --set case-sensitive-strings:false --set ignore-white-space:true \
 --set matching-rule-name:caseIgnoreJsonAddressQueryMatch \
 --set matching-rule-oid:1.3.6.1.4.1.36733.2.1.4.998 \
 -X -n

and

$ dsconfig -h localhost -p 4444 -D "cn=Directory Manager" -w secret12 \
 create-schema-provider --provider-name "Token Json Schema" \
 --type json-schema --set enabled:true \
 --set case-sensitive-strings:false --set ignore-white-space:true \
 --set matching-rule-name:caseIgnoreJsonTokenQueryMatch \
 --set matching-rule-oid:1.3.6.1.4.1.36733.2.1.4.999 \
 --set indexed-field:token_type \
 --set indexed-field:expires_at \
 --set indexed-field:access_token \
 -X -n

Note that there is an issue with OpenDJ 4.0.0-SNAPSHOTS (nightly builds) and when you define a new Schema Provider, you need to restart the server to have it be effective.


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

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

Scripting in OpenAM 13

Scripting Design

This section introduces Client side and Server side scripts in OpenAM 13. These can be glued together to create Scripted Authentication modules that serve to create powerful authentication workflows as shown later in the Examples section.

Client Side Script

Authentication modules can use Client Side scripts and Server Side scripts using either JavaScript or Groovy. Note that the use of a Client side script is optional. If there is a requirement to collect information from the user, or browser plugins, fonts, screen resolution of a device, or even geolocation then by all means use the Client side script to collect and return the data to the Server side script.

The collected data is returned in the clientScriptOutputData object. You can use the .split() method to pull the client side data and parse accordingly.

An example Client side script is shown below.

 

Server Side Script

The Server side script handles authentication and is the place to put authentication workflow business logic. The Server side script has access to clientScriptOutputData and OpenAM’s powerful Scripting API. This script must set the authentication state to either success of failed, for example:

An example of using Server side scripts is as follows:

 

Chaining Scripted Authentication in OpenAM

You would setup your scripted module similar to any other authentication module in OpenAM, such as:

In this particular example, I have required DataStore to be a requisite module, followed immediately by a Scripted module that requires the authenticated user’s userId. See the following code snippet:

 

This Server side script is written in Groovy. The script reads the username and password from Shared State – a protected and shared area in memory – and uses the credential to make REST-based Policy calls to another OpenAM server (which could be a central policy hub in your enterprise, for example).

Scripting API

HTTP Commons Framework

OpenAM 13 introduces the HTTP Commons Framework. The following packages are available to developers:

org.forgerock.http.protocol.* – Request, Cookie, Entity, Header, Headers, and Response objects

org.forgerock.util.promise.* – Promise objects that represent the result of an asynchronous task in OpenAM

groovy.json.JsonSlurper – a very useful JSON parser that can be used in the scripts.

The API documentation is at http://commons.forgerock.org/bom/apidocs/index.html
You can use the new HTTP Commons Framework to create a new Request, and invoke REST API calls from the Server Side Script. For example: httpClient.send(Request), returns a Promise. Promise.get(), returns a Response. You may then parse the Response using JsonSlurper. The Server side script can access the Authentication State via the authState, and sharedState objects, as mentioned earlier.

Note that you will need to add the JsonSlurper, or any other class you wish to use, to the whitelist. Otherwise you will get a Security Exception stating use of the class is prohibited. You can whitelist a class using instructions documented here:

https://backstage.forgerock.com/#!/docs/openam/12.0.0/dev-guide/chap-scripted-auth-module#scripted-auth-module-sandbox

Logging

The logger object provides error(), message() and warning() methods for logging requirements.

Entity Profile

You are able to access user, group or device profile data via the idRepository object that provides the getAttribute(), setAttribute() and addAttribute() methods.

Original Request

You can also access the original login request using the requestData object, that provides the getHeader(s) and getParameter(s) methods.

Examples

Included here are some examples of using the Scripting API.

SSOToken

You can acquire an ssoToken object over REST

Policy Evaluation

Given the following two policies:

AuthnPolicy:

and AuthnPolicyY:

 

You can evaluate policy for the resource “authn/self’ and “authn/view”.

A policy decision is returned:

Check the policy decision and permit authentication if requested actions are ALLOWED:

Finally, logout the service account used for policy invocation using another REST call:

Unlocking the Authorization Asset

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

Consumer identity is a core asset to your business. Unlocking authorization and leveraging it into your business processes and (micro) services helps you in this endeavor as it drives a yet higher level of personalization and how users interact with resources and objects.

In a recent post titled “Authorization for Everything” I outlined how any resource or object can be described in ForgeRock’s identity platform authorization framework by the example of a home cinema.

But who’s going to setup the authorization objects and controls ?
(Question by an attendee of the ForgeRock Identity Summit in Düsseldorf)

User facing applications that operate or control devices or resources, like mobile applications or smart remote controls, are now enabled to call directly in the authorization framework to manage or evaluate permissions. This is also possible go via a hub to which an appliance like the home cinema would register when it is plugged in.

Smart authorization is now unlocked to any of these procedures, services and applications regardless of the platform. And the key is the REST API provided by the ForgeRock identity platform.

The key to drive authorization in the user experience or device management is the API !
Implement it where it creates most value for the consumer.
(My answer)

In full detail now how to manage and evaluate authorization elements via REST by the example of a home cinema.

Authorization Management via REST in detail
Step 1: Creating a resource type TV

First we create a resource type TV and specify the format of how to address the resource (e.g. tv://myhouse/homecinema) and possible actions for the resource.

Request:
curl -s –request POST –header “Content-Type: application/json” –data @request.json https://sso.redstone.com:443/sso/json/authzrealm/resourcetypes?_action=create&_prettyPrint=true
Request (JSON):
{
“patterns”: [
“tv://*/*”
],
“name”: “tv”,
“actions”: {
“ENABLE”: true,
“DISABLE”: true,
“BROADCAST SCREEN”: true,
“BROADCAST CAMERA”: true
}
}
Response (JSON):
{
“uuid” : “9fefc18f-5731-4963-a8d6-fa8aba7923d4”,
“name” : “tv”,
“description” : null,
“patterns” : [ “tv://*/*” ],
“actions” : {
“DISABLE” : true,
“ENABLE” : true,
“BROADCAST CAMERA” : true,
“BROADCAST SCREEN” : true
},
“createdBy” : “id=amadmin,ou=user,dc=sso-config,dc=com”,
“creationDate” : 1447989190178,
“lastModifiedBy” : “id=amadmin,ou=user,dc=sso-config,dc=com”,
“lastModifiedDate” : 1447989190178
}
Note the resource type’s UUID in the response. This value is needed later to assign a resource type to a policy.


Step 2: Creating the policy set (or application)

Next the resource set (or application) needs to be created with the resourceTypeUUID containing the one of resource type TV.

Request:
curl -s –request POST –header “Content-Type: application/json” –data @request.json https://sso.redstone.com:443/sso/json/authzrealm/applications?_action=create&_prettyPrint=true
Request (JSON):
{    “name” : “SmartHome”,
“applicationType” : “iPlanetAMWebAgentService”,
“description” : “Controlling objects in a smart home.”,
“resourceTypeUuids” : [ “9fefc18f-5731-4963-a8d6-fa8aba7923d4”],
“subjects” : [ “Policy”, “NOT”, “OR”, “JwtClaim”, “AuthenticatedUsers”, “AND”, “Identity”, “NONE” ],
“entitlementCombiner” : “DenyOverride”,
“saveIndex” : null,
“searchIndex” : null,
“resourceComparator” : null,
“attributeNames” : [ ],
“editable” : true,
“conditions” : [ “LEAuthLevel”, “Policy”, “Script”, “AuthenticateToService”, “SimpleTime”, “AMIdentityMembership”, “OR”, “IPv6”, “IPv4”, “SessionProperty”, “AuthScheme”, “AuthLevel”, “NOT”, “AuthenticateToRealm”, “AND”, “ResourceEnvIP”, “LDAPFilter”, “OAuth2Scope”, “Session” ]
}
Response (JSON):
{
“lastModifiedBy” : “id=amadmin,ou=user,dc=sso-config,dc=com” ],
“lastModifiedDate” : 1447989192860,
“creationDate” : 1447989192860,
“createdBy” : “id=amadmin,ou=user,dc=sso-config,dc=com”,
“applicationType” : “iPlanetAMWebAgentService”,
“subjects” : [ “Policy”, “NOT”, “OR”, “JwtClaim”, “AuthenticatedUsers”, “AND”, “Identity”, “NONE” ],
“entitlementCombiner” : “DenyOverride”,
“saveIndex” : null,
“searchIndex” : null,
“resourceComparator” : null,
“attributeNames” : [ ],
“editable” : true,
“conditions” : [ “LEAuthLevel”, “Policy”, “Script”, “AuthenticateToService”, “SimpleTime”, “AMIdentityMembership”, “OR”, “IPv6”, “IPv4”, “SessionProperty”, “AuthScheme”, “AuthLevel”, “NOT”, “AuthenticateToRealm”, “AND”, “ResourceEnvIP”, “LDAPFilter”, “OAuth2Scope”, “Session” ],
“description” : “Controlling objects in a smart home.”,
“name” : “SmartHome”
}
Step 3: Creating the policy giving permissions to Bob

Next the resource set (or application) needs to be created with the resourceTypeUUID containing the one of resource type TV.

Request:
curl -s –request POST –header “Content-Type: application/json” –data @request.json https://sso.redstone.com:443/sso/json/authzrealm/policies?_action=create&_prettyPrint=true
Request (JSON):
{
“name” : “HomeCinema”,
“active” : true,
“description” : “”,
“applicationName” : “SmartHome”,
“actionValues” : {
“ENABLE” : true,
“DISABLE” : true,
“BROADCAST SCREEN” : true,
“BROADCAST CAMERA” : true
},
“resources” : [ “tv://myhouse/homecinema” ],
“subject” : {
“type” : “Identity”,
“subjectValues” : [ “id=bob,ou=user,o=authzrealm,ou=services,dc=sso-config,dc=com” ]
},
“resourceTypeUuid” : “9fefc18f-5731-4963-a8d6-fa8aba7923d4”
}
Response (JSON):
{
“name” : “HomeCinema”,
“active” : true,
“description” : “”,
“applicationName” : “SmartHome”,
“actionValues” : {
“DISABLE” : true,
“ENABLE” : true,
“BROADCAST CAMERA” : true,
“BROADCAST SCREEN” : true
},
“resources” : [ “tv://myhouse/homecinema” ],
“subject” : {
“type” : “Identity”,
“subjectValues” : [ “id=bob,ou=user,o=authzrealm,ou=services,dc=sso-config,dc=com” ]
},
“resourceTypeUuid” : “9fefc18f-5731-4963-a8d6-fa8aba7923d4”,
“lastModifiedBy” : “id=amadmin,ou=user,dc=sso-config,dc=com”,
“lastModifiedDate” : “2015-11-20T03:13:14.274Z”,
“createdBy” : “id=amadmin,ou=user,dc=sso-config,dc=com”,
“creationDate” : “2015-11-20T03:13:14.274Z”
}
Step 4: Evaluating the policy for user Bob

Next the resource set (or application) needs to be created with the resourceTypeUUID containing the one of resource type TV. For completeness – the procedure is already outlined in “Authorization for Everything” – here’s how an upstream application would evaluate if Bob can broadcast the screen (or any other action). 

Request URL:

https://sso.redstone.com:443/sso/json/authzrealm/policies?_action=evaluateTree&_prettyPrint=true

Request (JSON):
{
“application”: “SmartHome”,
“resource”: “tv://myhouse/homecinema”,
“subject”: {
“ssoToken”: “AQIC5wM2LY4SfcxbXJgKBtBsbzH0OtxslnEQDHK2RJ5UJho.*AAJTSQACMDIAAlNLABQtOTIwMDUyMDgxMTA2Mzk1NjIzMgACUzEAAjAx*”
}
}
Response (JSON):
[ {
“advices” : { },
“ttl” : 9223372036854775807,
“resource” : “tv://myhouse/homecinema”,
“actions” : {
“DISABLE” : true,
“ENABLE” : true,
“BROADCAST CAMERA” : true,
“BROADCAST SCREEN” : true
},
“attributes” : { }
} ]

If you want to go further, look at the details of policy creation via REST, policy evaluation or maybe even reproduce my demo at the Identity Summit in Düsseldorf, check the openam-high5 GitHub project. In particular the 652-authz-create-policy and 654-authz-evaluate-policy-tv.

 

Introduction to OpenIG (Part 2: First contact…)

What do I need to start ?

First, you need to install OpenIG in the root context of a web container (Tomcat used for the example):

  1. Download OpenIG
  2. Grab a fresh Apache Tomcat instance (Tomcat 7.0 or 8.0) and unzip it
  3. Remove all war files from the webapps/ directory
  4. Move OpenIG-3.0.0.war to that directory and rename it to ROOT.war (OpenIG needs to be installed in the root context: /)
  5. Start Tomcat (bin/catalina.sh run from within the tomcat directory).

    Don't worry if you see some warnings about Offending classes during startup: that's because OpenIG web-app provides its own EL implementation (useful when the web container doesn't provide one). This pollutes the startup logs but does not prevent OpenIG to run properly.

If you're curious, you can go to http://localhost:8080 (or whatever port number you're using), you should see the OpenIG's welcome page (admire the ASCII art).

OpenIG 3.0.0 - Welcome Page

If you don't see anything, or an error, make sure that you don't have a previous OpenIG configuration file in $HOME/.openig/config/config.json ($APP_DATAForgeRockOpenIGconfigconfig.json for our windows users).

You might wonder why OpenIG requires to be installed in the root context. The reason is simple: most of the time, when you want to access a web site, you just wanna type a domain name in your browser navbar (like http://app.example.com).

That gives you a very easy to use and to remember entry point URL as well as the flexibility of mapping incoming requests to any internal URL (really routing requests in fact).

Your first configuration

What would you think of an OpenIG Hello World example? After all that reading, I'm sure you'll be happy to get your hands dirty :)

So, finally some code (let's face it; it's JSON configuration really).

Place that configuration file inside the $HOME/.openig/config/routes/ directory. It will be auto-(re)loaded by OpenIG.

It's quite self-descriptive: if the incoming request's path matches ^/hello (starts with /hello), it is dispatched to this route (a JSON file placed in the routes/ directory is called a route). This route is configured with a single StaticResponseHandler that simply return a Hello World message (we'll see what a Handler is in an upcoming post) to the user-agent.

OpenIG Hello World

At first look, that doesn't seem very fancy, but you've been exposed to multiple core concepts of OpenIG (they'll be covered in more details in subsequent posts):

  • The OpenIG configuration file format (expressed as JSON)
  • The expression language (${} for expressing conditions based the value of some properties)
  • The Exchange HTTP model (exchange.request.uri.path in the expression)
  • The route concept (a simple way to isolate processing chains in different files and to ease setup with auto-(re)loading)

In the next post, we'll have a look at the concepts providing the backbone of OpenIG (Exchange, Handler and Filter).

See you soon.

OpenDJ Contact Manager for Android

With OpenDJ 2.6.0, we’ve introduced a new way to access your directory data, using HTTP, REST and JSon. The REST to LDAP service, available either embedded in the OpenDJ server or as a standalone web application, is designed to facilitate the work of application developers. And to demonstrate the interest and the ease of use of that service, we’ve built a sample application for Android : the OpenDJ Contact Manager

OpenDJ Contact Manager Android AppAbout screen of the OpenDJ Contact Manager Android App

The OpenDJ Contact Manager is an open source Android application that was built by Violette, one of the ForgeRock engineer working in the OpenDJ team. You can get the source code from the SVN repository : https://svn.forgerock.org/commons/mobile/contact-manager/trunk. Mark wrote some quite complete documentation for the project, with details on how to get and build the application. He published it at http://commons.forgerock.org/mobile/contact-manager/.

The whole application is just about 4000 lines of code, and most of it is dealing with the display itself. But you can find code that deals with asynchronous calls to the OpenDJ rest interface, with paging through results, and parsing the resulting JSON stream to populate the Contacts, including photos. Et voila :

OpenDJ Contact Manager displaying a Contact

The application is just a sample but it clearly is usable in its current form and will allow once a contact was retrieved from the OpenDJ directory, to add it to the Contacts standard application, call the person, locate its address on maps, send the person an email, navigate through the management chain…

In future versions, we are planning to add support for OAuth 2.0, removing the need to store credentials in the application settings.

As it’s open source, feel free to play with it, hack and contribute back your changes.


Filed under: Directory Services Tagged: Android, directory-server, ForgeRock, identity, java, Json, ldap, Mobile, opendj, opensource, REST