Apereo CAS - Authentication Handler Resolution

Posted by Misagh Moayyed on December 23, 2019 · 6 mins read ·
Content Unavailable
Your browser is blocking content on this website. Please check your browser settings and try again.
This blog post was originally posted on Apereo GitHub Blog.

Overview

Nobody enjoys restrictions and limitations but when it comes to Apereo CAS and dealing with authentication transactions, there may be a few cases where you would want to limit or choose a select collection of authentication handlers to respond to a request. The selection criteria could be based on the format or syntax of the credential, the requesting application or some other arbitrary rule. In this post, we are going to briefly look at strategies that allow one to narrow down the list of authentication handler candidates from a global set.

Our starting position is based on:

Credential Criteria

Most authentication strategies in CAS are given a predicate to examine the requested credential for eligibility. This predicate is simply a fancy a condition whose outcome determines whether the authentication strategy/handler should proceed to operate on the credential:

...
cas.authn.accept.credentialCriteria=.+@example.org
cas.authn.accept.name=Default
...

In the above example, the credentialCriteria is a regular expression pattern that is tested against the credential identifier. In other words, if an authentication request is submitted to CAS with a credential whose identifier is test@example.org, this Default authentication handler will be selected to validate the credential.

Per Application

Imagine that we have defined the following authentication handlers/schemes in our CAS configuration:

...                  
cas.authn.accept.users=casuser::Mellon
cas.authn.accept.credentialCriteria=.+@example.org
cas.authn.accept.name=Static 

cas.authn.json.location=file:/etc/cas/config/json-authn.json
cas.authn.json.name=JSON
...

When an authentication request is submitted to CAS, both of the above strategies are made available and selected to respond and verify the given credential. However, you may want to ignore the Static strategy and restrict the selection criteria to only have the JSON authentication handler respond in case the authentication request is submitted from an https://app.example.org application:

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "https://app.example.org/.+",
  "name" : "ExampleApp",
  "id" : 1,
  "requiredHandlers" : [ "java.util.HashSet", [ "JSON" ] ]
}

Groovy

In more flexible yet programmatic ways, the selection of authentication handlers can also be delegated to a Groovy script. This is the option where you get to have complete control over the selection process and are tasked with designing the script to return the final filtered collection of authentication handlers that should operate on the credential:

cas.authn.core.groovy-authentication-resolution.location=file:/etc/cas/config/AuthenticationSelection.groovy

The AuthenticationSelection.groovy may look like this:

def run(Object[] args) {
    def handlers = args[0]
    def transaction = args[1]
    def servicesManager = args[2]
    def logger = args[3]

    logger.trace("Resolving authentication handlers ${handlers}...") 
    /*
        Return the final Set of AuthenticationHandler
        components from the provided handlers
        back to CAS to try this transaction.
    */
    handlers
}

def supports(Object[] args) {
    def handlers = args[0]
    def transaction = args[1]
    def servicesManager = args[2]
    def logger = args[3]      

    /*
        Determine if the script should be run,
        and whether it can support the given transaction.
    */
    true
}

Bonus

The most extreme option of all is to simply supply your overall strategy for authentication management and override the CAS-provided engine. To do this, you should start by designing your configuration component to include the following bean:

@Bean
public AuthenticationManager casAuthenticationManager() {
    ...
}

You should only take up this option as a last resort, and maybe not even then.

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.

Finally, if you benefit from Apereo CAS as free and open-source software, we invite you to join the Apereo Foundation and financially support the project at a capacity that best suits your deployment. If you consider your CAS deployment to be a critical part of the identity and access management ecosystem and care about its long-term success and sustainability, this is a viable option to consider.

Happy Coding,

Misagh Moayyed