Apereo CAS 6.1.x - Attribute Repositories w/ Person Directory


Collaborate
This blog is managed and hosted on GitHub. If you wish to update the contents of this post or if you have found an inaccuracy and wish to make corrections, we recommend that you please submit a pull request to this repository.

Overview

The ability to fetch attributes from external data stores has been present in CAS since the days of 3.x. This functionality was and, to this day, is provided by an Apereo project called Person Directory which is a Java framework for resolving persons and attributes from a variety of underlying sources. It consists of a collection of components that retrieve, cache, resolve, aggregate and merge person attributes from JDBC, LDAP and more. CAS attempts to take advantage of this framework through a concept called PrincipalResolver whose goal is to construct a final identifiable authenticated principal for CAS which carries a number of attributes inside it fetched from attribute repository sources. This meant that for instance, one could authenticate with LDAP in one query and then turn around the ask the same LDAP, a relational database and a Groovy script to fetch attributes for the resolved principal and combine all results into a final collection.

Note that in most cases, and starting around CAS 4.x, the authentication engine has been enhanced to be able to retrieve and resolve attributes from the authentication source, which would eliminate the need for configuring a separate attribute repository especially if both the authentication and the attribute source are the same. Using separate resolvers and sources should only be required when sources are different, or when there is a need to tackle more advanced attribute resolution use cases such as cascading, merging, etc.

What About...?
Note that attribute resolution via PrincipalResolver components and Person Directory's attribute repositories shall always execute, if and when configured, regardless of how the authentication event occurs. Whether the user is authenticating against a CAS-owned account store or is handed off to an external identity provider, in either scenario CAS is able to put together attributes from both the authentication source as well as any and all attribute repositories configured.

This tutorial focuses on a number of use case involving attribute repositories, fetching attributes from an external store a JSON file and a collection of hard-coded stubbed attributes. We will demonstrate variations on how attribute sources may be cached, filtered and released in a number of fancy ways.

Our starting position is based on:

Baseline Configuration

Our JSON attribute repository source, separate from the CAS authentication store is fairly simple:

{
    "casuser": {
        "firstName": ["Bob"],
        "employeeNumber": ["123456"],
        "lastName": ["Johnson"]
    }
}

Our external attribute repositories are then taught to CAS:

cas.authn.attributeRepository.json[0].location=file://etc/cas/config/attribute-repository.json
cas.authn.attributeRepository.json[0].id=MyJson

cas.authn.attributeRepository.stub.id=StaticStub
cas.authn.attributeRepository.stub.attributes.uid=mmoayyed
cas.authn.attributeRepository.stub.attributes.displayName=Misagh Moayyed
cas.authn.attributeRepository.stub.attributes.firstName=Misagh
cas.authn.attributeRepository.stub.attributes.lastName=Moayyed

Note that each attribute repository is given an id which can the be used as a filter to narrow the resolution logic down to matching repositories.

Use Cases

1

The requirements for this use case are as follows:

  • Disable attribute resolution from external attribute repositories via Person Directory.
  • Resolve attributes at release time for a given application only using the MyJson attribute repository.
  • No caching of attributes shall happen either globally or for the application.

The relevant properties for this use case are:

cas.authn.attributeRepository.expirationTime=0
cas.authn.attributeRepository.expirationTimeUnit=seconds
cas.authn.attributeRepository.merger=multivalued

cas.personDirectory.attributeResolutionEnabled=false

Our service definition matches the following:

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "https://app.example.org",
  "name" : "ExampleApplication",
  "id" : 1,
  "attributeReleasePolicy" : {
    "@class" : "org.apereo.cas.services.ReturnAllAttributeReleasePolicy",
    "principalAttributesRepository" : {
      "@class" : "org.apereo.cas.authentication.principal.DefaultPrincipalAttributesRepository",
      "attributeRepositoryIds": ["java.util.HashSet", [ "myjson" ]]
    }
  }
}

Since caching is disabled, you can change the underlying attribute value in the JSON attribute repository and CAS should pick up the change and release the new attribute value to the example application.

2

The requirements for this use case are as follows:

  • Disable attribute resolution from external attribute repositories via Person Directory.
  • Resolve attributes at release time for a given application only using the MyJson attribute repository.
  • Turn on global caching of attributes for 60 seconds.

The relevant properties for this use case are:

cas.authn.attributeRepository.expirationTime=60
cas.authn.attributeRepository.expirationTimeUnit=seconds
cas.authn.attributeRepository.merger=multivalued

cas.personDirectory.attributeResolutionEnabled=false

Our service definition matches the following:

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "https://app.example.org",
  "name" : "ExampleApplication",
  "id" : 1,
  "attributeReleasePolicy" : {
    "@class" : "org.apereo.cas.services.ReturnAllAttributeReleasePolicy",
    "principalAttributesRepository" : {
      "@class" : "org.apereo.cas.authentication.principal.DefaultPrincipalAttributesRepository",
      "attributeRepositoryIds": ["java.util.HashSet", [ "myjson" ]]
    }
  }
}

Since caching is disabled, you can change the underlying attribute value in the JSON attribute repository and CAS should pick up the change and release the new attribute value to the example application in about 60 seconds.

3

The requirements for this use case are as follows:

  • Disable attribute resolution from external attribute repositories via Person Directory.
  • Resolve attributes at release time for a given application only using the MyJson attribute repository.
  • Turn on global caching of attributes for 5 seconds and service-level caching for 30 seconds.

The relevant properties for this use case are:

cas.authn.attributeRepository.expirationTime=5
cas.authn.attributeRepository.expirationTimeUnit=seconds
cas.authn.attributeRepository.merger=multivalued

cas.personDirectory.attributeResolutionEnabled=false

Our service definition matches the following:

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "https://app.example.org",
  "name" : "ExampleApplication",
  "id" : 1,
  "attributeReleasePolicy" : {
    "@class" : "org.apereo.cas.services.ReturnAllAttributeReleasePolicy",
    "principalAttributesRepository" : {
      "@class" : "org.apereo.cas.authentication.principal.cache.CachingPrincipalAttributesRepository",
      "duration" : {
        "@class" : "javax.cache.expiry.Duration",
        "timeUnit" : [ "java.util.concurrent.TimeUnit", "SECONDS" ],
        "expiration" : 30
      },
      "attributeRepositoryIds": ["java.util.HashSet", [ "myjson" ]]
    }
  }
}

Attributes fetched and released for this example application may be updated after 30 seconds, while the global cache attempts to expire and resolve attributes for other applications after 5 seconds.

4

The requirements for this use case are as follows:

  • Enable attribute resolution from external attribute repositories via Person Directory.
  • However, let CAS resolve attributes from our StaticStub attribute repository.
  • Resolve attributes at release time for a given application only using the MyJson attribute repository.
  • Combine all attributes into one collection as multi-valued attributes where necessary.
  • Turn on global caching of attributes for 30 seconds.

The relevant properties for this use case are:

cas.authn.attributeRepository.expirationTime=30
cas.authn.attributeRepository.expirationTimeUnit=seconds
cas.authn.attributeRepository.merger=multivalued

cas.personDirectory.attributeResolutionEnabled=true
cas.personDirectory.activeAttributeRepositoryIds=StaticStub

Our service definition matches the following:

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "https://app.example.org",
  "name" : "ExampleApplication",
  "id" : 1,
  "attributeReleasePolicy" : {
    "@class" : "org.apereo.cas.services.ReturnAllAttributeReleasePolicy",
    "principalAttributesRepository" : {
      "@class" : "org.apereo.cas.authentication.principal.DefaultPrincipalAttributesRepository",
      "attributeRepositoryIds": ["java.util.HashSet", [ "myjson" ]],
      "mergingStrategy" : "MULTIVALUED"
    }
  }
}

5

The requirements for this use case are identical to the one above. The only difference is, we are going to ignore attributes resolved at authentication time from our StaticSub attribute repository for the example application and only hit our selected attribute repository, MyJson.

Our service definition matches the following:

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "https://app.example.org",
  "name" : "ExampleApplication",
  "id" : 1,
  "attributeReleasePolicy" : {
    "@class" : "org.apereo.cas.services.ReturnAllAttributeReleasePolicy",
    "principalAttributesRepository" : {
      "@class" : "org.apereo.cas.authentication.principal.DefaultPrincipalAttributesRepository",
      "attributeRepositoryIds": ["java.util.HashSet", [ "myjson" ]],
      "ignoreResolvedAttributes": true,
      "mergingStrategy" : "MULTIVALUED"
    }
  }
}

6

The requirements for this use case are as follows:

  • Enable attribute resolution from external attribute repositories via Person Directory.
  • However, let CAS resolve attributes from our StaticStub attribute repository.
  • Resolve attributes at release time for a given application only using the MyJson attribute repository.
  • Combine all attributes into one collection as multi-valued attributes where necessary.
  • Turn on global caching of attributes for 30 seconds, and service-level caching for 30 minutes.

The relevant properties for this use case are:

cas.authn.attributeRepository.expirationTime=10
cas.authn.attributeRepository.expirationTimeUnit=seconds
cas.authn.attributeRepository.merger=multivalued

cas.personDirectory.attributeResolutionEnabled=true
cas.personDirectory.activeAttributeRepositoryIds=StaticStub

Our service definition matches the following:

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "https://app.example.org",
  "name" : "ExampleApplication",
  "id" : 1,
  "attributeReleasePolicy" : {
    "@class" : "org.apereo.cas.services.ReturnAllAttributeReleasePolicy",
    "principalAttributesRepository" : {
      "@class" : "org.apereo.cas.authentication.principal.cache.CachingPrincipalAttributesRepository",
      "duration" : {
        "@class" : "javax.cache.expiry.Duration",
        "timeUnit" : [ "java.util.concurrent.TimeUnit", "MINUTES" ],
        "expiration" : 30
      },
      "attributeRepositoryIds": ["java.util.HashSet", [ "myjson" ]]
    }
  }
}

So…

I hope this review was of some help to you and I am sure that both this post as well as the functionality it attempts to explain can be improved in any number of ways. Please know that all other use cases, scenarios, features and theories certainly are possible as well. Feel free to engage and contribute as best as you can.

Happy Coding,

Misagh Moayyed

Related Posts

CAS Vulnerability Disclosure

Disclosure of a security issue with the CAS software.

CAS Multifactor Authentication with U2F and Bypass

A short walkthrough to demonstrate how one might turn on multifactor authentication with CAS using U2F and default bypass rule.

CAS Vulnerability Disclosure

Disclosure of a security issue with the CAS software.

CAS Release Notes Moved

CAS Release Notes are moved to the CAS site.

CAS 6.2.0 RC5 Feature Release

...in which I present an overview of CAS 6.2.0 RC5 release.

CAS 6.2.0 RC4 Feature Release

...in which I present an overview of CAS 6.2.0 RC4 release.

CAS 6.2.0 RC3 Feature Release

...in which I present an overview of CAS 6.2.0 RC3 release.

Apereo CAS - Bootiful CAS Client

Easy to use CAS Client

CAS Vulnerability Disclosure

Disclosure of a security issue with the CAS software.

Checking Out Pull Requests Locally

Check out GitHub pull requests as local branches using a simple bash function.