How to integrate an OpenID Connect claims source

1. OpenID Connect claims

With OpenID Connect clients can retrieve consented claims, or assertions, about the logged in end-user. These are packaged in a simple JSON object, and made available by the OpenID Connect provider (the Connect2id server) at the UserInfo endpoint or included in the ID token.

{
  "sub"        : "83692",
  "name"       : "Alice Adams",
  "email"      : "[email protected]",
  "department" : "Engineering",
  "birthdate"  : "1975-12-31"
}

2. Universal claims source SPI

An enterprise IdP should be able to draw claims from any type of data source. The Connect2id server provides a universal claims source interface just for that. Connectors to any type of source may be devised, such as an Active Directory / LDAP server, an SQL database or an HR management system.

The Connect2id server is shipped with a ready Active Directory / LDAP connector. You can read more about it in the configuration docs.

3. How to develop your own claims source connector

For other types of data sources a custom connector will be required. How to implement one:

  1. Get the Connect2id server toolkit. Its Maven artifact is com.nimbusds:c2id-server-sdk and is publicly available from the Maven Central repo. The toolkit version should match the dependency for the particular Connect2id server that you have. You can find out the expected toolkit version by examining the pom.xml shipped with the c2id.war under /META-INF/maven/com.nimbusds/c2id/pom.xml.

    For Connect2id server 6.0 it will look like this:

    <dependency>
       <groupId>com.nimbusds</groupId>
       <artifactId>c2id-server-sdk</artifactId>
       <version>3.10.1</version>
    </dependency>

    If you’re unsure which toolkit version you need drop our support team an email.

  2. Implement the ClaimsSource interface in your connector.

    Explanations of the methods:

    • init(InitContext) This method is called by the Connect2id server to initialise the connector at startup. At this point you may read a configuration file with connection details for your database, create a connection pool, etc. If you don’t need to initialise anything leave this method empty. The context object also gives you access to Infinispan, in case you want to implement a claims caching strategy.

    • isEnabled For the Connect2id server to check whether the connector is enabled and can be used.

    • supportedClaims Return the names of the claims provided by the connector. The Connect2id server uses this information to find out which connector to call when multiple connectors are present.

    • getClaims(Subject, Set<String>, List<LangTag>) Performs the actual claims retrieval for the given subject (end-user). Inside this method the connector is supposed to make a database request (SQL query, RESTful call, etc) to retrieve the requested claims. You should return null if the end-user wasn’t found. You don’t need to return all claims, if some are not available or withheld for other reasons.

    • shutdown Called by the Connect2id server on shutdown. Use this method to clean up resources, such as database connection pools created by your connector. If you don’t need to clean up anything leave this method empty.

    You can consult the toolkit JavaDocs for more information. Just check out the contents of the com.nimbusds.openid.connect.provider.spi.claims package.

  3. Package your classes (including third-party dependencies) in a JAR file with a suitable manifest for the claims source SPI. The manifest is required to let the Connect2id server know that a connector is available and can be loaded. This happens at server startup.

    How to create the manifest:

    1. Create a folder named /META-INF/services/.

    2. Create a new text file com.nimbusds.openid.connect.provider.spi.claims.ClaimsSource in this folder. The name of this file is basically the fully qualified name of the ClaimsSource interface.

    3. Inside the text file put the fully qualified name of your connector class that implements the ClaimsSource interface. For example:

      com.myapp.MyClaimsSourceConnector
  4. Put the JAR (classes plus manifest) in the WEB-INF/lib directory of the Connect2id server.

  5. Restart the Connect2id server.

  6. The Connect2id server will automatically load the new claims source, and add it to the existing ones (if any).

You can use the source code of the shipped LDAP connector as a template to develop your own connectors.

4. The Connect2id server crashes when loading my claims source connector

If the Connect2id server fails to initialise the claims source for some reason it will abort at startup with an exception. If you use Tomcat check the following log files for a record of the exact exception:

  • /tomcat/logs/c2id-server.log
  • /tomcat/logs/catalina.out
  • /tomcat/logs/[host]_access_log.YYYY-MM-DD.txt

Does your claims source connector have all dependency requirements satisfied? There are two approaches to that: merge the dependency classes into the connector JAR, or adding their JARs to the /WEB-INF/lib of the c2id web application. If a dependency is missing Tomcat will throw a java.lang.NoClassDefFoundError.

It’s also good practice to test your connector before deployment, using a framework for automated tests.

5. How to aggregate claims from multiple sources

The Connect2id server can collect claims from multiple source at once, e.g. certain claims may come from an LDAP directory and others from an SQL database. To do that you just need to provide the additional ClaimsSource connectors.

6. How to monitor your connectors

The aggregate performance of the claims source connectors can be monitored via the claimsSource.retrievalTimer metric. This can help you identify latency and other problems that may in turn affect the overall performance of the IdP service.

Example claimsSource.retrievalTimer metric:

{
  "count"          : 6,
  "max"            : 0.01028953,
  "mean"           : 6.647419832286938E-4,
  "min"            : 6.56503E-4,
  "p50"            : 6.647430000000001E-4,
  "p75"            : 6.647430000000001E-4,
  "p95"            : 6.647430000000001E-4,
  "p98"            : 6.647430000000001E-4,
  "p99"            : 6.647430000000001E-4,
  "p999"           : 6.647430000000001E-4,
  "stddev"         : 9.152683616619665E-8,
  "m15_rate"       : 0.0016652947966130432,
  "m1_rate"        : 1.9309212342695557E-4,
  "m5_rate"        : 0.0015804743529140488,
  "mean_rate"      : 0.0015484305097827385,
  "duration_units" : "seconds",
  "rate_units"     : "calls/second"
}

Claims retrieval should be relatively swift, particularly if ID tokens are used to transport claims to the client apps (serving claims at the UserInfo endpoint with longer delays is less of an issue). If your claims sources incur long latencies you should consider caching them. Let us know if you need assistance with that.

7. How to disable the LDAP connector

There are to possible ways to do that.

By removing the LDAP connector:

  1. Stop the Connect2id server.

  2. Remove oidc-claims-source-ldap-[version].jar from the WEB-INF/lib/ directory.

  3. Start the Connect2id server.

By disabling the LDAP connector from its settings:

  1. Open WEB-INF/ldapClaimsSource.properties

  2. Set op.ldapClaimsSource.enable = false

  3. Restart the Connect2id server.

  4. The Connect2id server will still load the LDAP claims source, but it will not be used.

See the LDAP connector config docs for for more details.