Apereo CAS - REST API Integrations


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

REST protocol support in Apereo CAS has been available since the early days of CAS 3.x. Since then, a lot of additional REST-based features and extensions are brought into the software to enable one to not only authenticate and/or exchange tokens but also add service definitions for relying parties or fetch attributes from remote REST endpoints, etc. The focus of this tutorial is to provide a brief overview of some of the REST-based features of CAS.

Our starting position is based on:

Configuration

Let’s assume that we have the following service definition in CAS JSON service registry:

{
  "@class": "org.apereo.cas.services.RegexRegisteredService",
  "serviceId": "https://app.example.org",
  "name": "ExampleApp",
  "id": 1,
  "description": "This service definition defined our example application.",
}

Let’s also instruct CAS to fetch attributes (i.e. email) from a static/stubbed attribute repository source:

cas.authn.attributeRepository.stub.attributes.email=casuser@example.org

Next, to enable the CAS REST protocol the overlay must primarily be prepped with the following modules:

compile "org.apereo.cas:cas-server-support-rest:${project.'cas.version'}"
compile "org.apereo.cas:cas-server-support-rest-services:${project.'cas.version'}"

Exchange Tokens

Let’s invoke the REST API to authenticate a user and get back a ticket-granting ticket:

curl -k -X POST -H "Content-Type: Application/x-www-form-urlencoded" \
  https://sso.example.org/cas/v1/tickets \
  -d "username=casuser&password=Mellon"

…where the response would be:

<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">
<html>
  <head><title>201 CREATED</title></head>
  <body><h1>TGT Created</h1>
    <form action="https://sso.example.org/cas/v1/tickets/TGT-2-abcdefg"
      method="POST">Service:<input type="text" name="service" value="">
      <br><input type="submit" value="Submit">
    </form>
  </body>
</html>

The ticket produced in the response is embedded inside an HTML form. We can adjust the Accept header to produce a more JSON-friendly response:

curl -X POST -H "Content-Type: Application/x-www-form-urlencoded" \
  -H "Accept: application/json" https://sso.example.org/cas/v1/tickets \
  -d "username=casuser&password=Mellon"
...
TGT-2-abcdefg

The ticket-granting ticket that is produced can be used to obtain a service ticket:

curl -X POST -H "Content-Type: Application/x-www-form-urlencoded" \
  -H "Accept: application/json" https://sso.example.org/cas/v1/tickets/ \
  TGT-2-abcdefg?service=https://www.google.com
ST-1-VGF-yzB8

The service ticket can then be validated so we could obtain the user profile:

curl -k https://sso.example.org/cas/p3/serviceValidate\
  ?service=https://www.google.com"&"ticket=ST-1-VGF-yzB8

…where the response would be:

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
    <cas:authenticationSuccess>
        <cas:user>casuser</cas:user>
        <cas:attributes>
            <cas:credentialType>UsernamePasswordCredential</cas:credentialType>
            <cas:isFromNewLogin>true</cas:isFromNewLogin>
            ...
            </cas:attributes>
    </cas:authenticationSuccess>
</cas:serviceResponse>

You could also specify a format=json parameter to produce a more JSON-friendly response:

curl -k https://sso.example.org/cas/p3/serviceValidate\
  ?service=https://www.google.com"&"ticket=ST-1-VGF-yzB8"&"format=json

Registering Applications

REST calls to CAS to register applications must be authenticated using basic authentication where credentials are authenticated and accepted by the existing CAS authentication strategy, which in our case would be casuser and Mellon.

Furthermore, the authenticated principal must be authorized with a pre-configured role/attribute name and value that is designated in the CAS configuration via the CAS properties:

cas.rest.attributeName=email
cas.rest.attributeValue=.+example.*

The above outlines only users who carry an email attribute with a value that matches the above pattern can be authorized to add application definitions to CAS. In our case, we should be able to successfully do so with our sample casuser since the test account has a stubbed email attribute with a value of casuser@example.org that matches the above pattern.

Finally, the body of the request must be the service definition that shall be registered in JSON format and of course, CAS must be configured to accept the particular service type defined in the body.

So, the final call to CAS would be as such:

curl -k -H "Content-Type: application/json" -X POST \
  https://sso.example.org/cas/v1/services \
  -u casuser:Mellon -d@/path/to/app2.json

…where our app2.json would be as:

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "https://app2.example.org.+",
  "name" : "ExampleApp2",
  "id" : 2,
  "description": "This is our second application"
}

Upon success, the CAS server would produce a 200 status code and its audit logs would indicate the successful registration of the application:

=============================================================
WHO: casuser
WHAT: AbstractRegisteredService(serviceId=https://app2.example.org.+...
ACTION: SAVE_SERVICE_SUCCESS
APPLICATION: CAS
WHEN: Mon Jun 12 14:46:58 MST 2019
CLIENT IP ADDRESS: 0:0:0:0:0:0:0:1
SERVER IP ADDRESS: 0:0:0:0:0:0:0:1
=============================================================

If you attempt the same operation with an unauthorized user:

curl -i -H "Content-Type: application/json" \
  -X POST https://sso.example.org/cas/v1/services \
  -u otheruser:somePassword -d@/path/to/app2.json

…you might see the following in the response with a 403 status code:

Request is not authorized

RESTful Attribute Resolution

CAS can be configured to fetch attributes from a remote REST endpoint. This functionality stands on its own, and does not require the presence of any extensions or modules in the overlay. It is offered by default, and activated only if the following CAS configuration is defined:

cas.authn.attributeRepository.rest[0].basicAuthUsername=uid
cas.authn.attributeRepository.rest[0].basicAuthPassword=password
cas.authn.attributeRepository.rest[0].method=GET
cas.authn.attributeRepository.rest[0].url=https://rest.somewhere.org/casattributes

The authenticating user id is passed in form of a request parameter under username. The response is expected to be a JSON map as such:

{
  "name" : "JohnSmith",
  "age" : 29,
  "groups": ["g1", "g2", "g3"]
}

Upon a successful authentication attempt, CAS would reach out to the REST endpoint to fetch attributes. The results are then merged with our stubbed collection of attributes and aggregated into one collection that would be available for attribute release. Specifically, in the end, the final collection of attributes for our casuser would be:

{
  "name" : "JohnSmith",
  "age" : 29,
  "email" : "casuser@example.org",
  "groups": ["g1", "g2", "g3"]
}

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 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.

CAS 6.2.0 RC2 Feature Release

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

Apereo CAS - Authentication Handler Resolution

Learn how to resolve and select authentication handlers based on configurable and flexible filtering criteria.

CAS Vulnerability Disclosure

Disclosure of a security issue with the CAS software.

Apereo CAS - SAML2 Metadata Overrides

Learn how to manage SAML2 service provider registrations in CAS and override metadata artifacts on a per-application basis.

Apereo CAS - Managing Configuration Metadata

Learn how to manage CAS configuration and properties using Spring Boot Configuration metadata.