Apereo CAS - Reloading Configuration Dynamically

Posted by Misagh Moayyed on May 02, 2020 · 5 mins read

When it comes to managing and tracking CAS settings, there is a plethora options to choose from for the modest as well as the enterprise-ready. Quickly put, CAS settings can be managed via key-value stores in form of standalone properties or YAML files. Such files can be split up per environment profile, can be fed directly to CAS at runtime or via command-line parameters, environment variables, inline JSON feeds, JVM system properties, slurpped via Groovy or even managed inside a separate and external configuration server which feed data to a CAS server from many other storage services and databases on a per-profile basis. All of this capability is provided by and built on top of Spring Boot and Spring Cloud frameworks that provide quite a flexible design in keeping track of one’s application settings.

A reasonable question one might casually wonder about could be: “If I make a change to CAS configuration, can the server recognize it automatically without a restart?”

The answer, like most things in life, is: “That depends”. This blog post attempts to address that question and explores a number of options in this area that might serve as good starting points for further development and tuning.

Our starting position is based on:

Initial Setup

Let’s start with a simple use case: our CAS server should have the option to hand off authentication requests to an external CAS server. To enable delegated authentication, we would start by including the proper extension module in the overlay:

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

…and our cas.properties would at a minimum include the following:

cas.authn.pac4j.cas[0].loginUrl=https://othersso.example.org/cas/login
cas.authn.pac4j.cas[0].protocol=CAS30
cas.authn.pac4j.cas[0].clientName=External CAS
cas.authn.pac4j.cas[0].enabled=true

Also, to allow for configuration reloadability, we would need the following module as well:

compile "org.apereo.cas:cas-server-core-events-configuration:${project.'cas.version'}"
compile "org.apereo.cas:cas-server-support-reports:${project.'cas.version'}"

If you build and run CAS next, you’d something similar to the below image:

image

Dynamic Reloads

Standalone Configuration

Let’s say you’re disappointed with the chosen name of the external CAS server as External CAS and you would be a lot more comfortable if the label (and the identity provider’s name) changed to Interesting CAS. To apply the change while CAS is running, simply change the property value and wait a few tiny seconds for it to take effect:

cas.authn.pac4j.cas[0].clientName=Interesting CAS

If you watch your logs next once you have saved the file, you would likely see something similar to the below lines:

...
<CAS finished rebinding configuration with new settings [[cas.authn.pac4j.cas[0].clientName]]>
...

At this point, if you simply refresh the browser screen the label should have changed to Interesting CAS.

Removing Settings
Spring Cloud, the underlying library responsible for refreshing the CAS Spring application context on changes, does not recognize properties and settings that are removed and commented out; only actual changes to the settings are recognized. See this issue for better details.

Spring Boot Admin

Once you have the Spring Boot Admin web application up and running, you can browse over to the Configuration Properties panel to see all CAS settings. To make the same change, hop over to the Environment panel and under Environment Manager type in cas.authn.pac4j.cas[0].clientName for the property name and Fancy CAS Here for the value:

image

…and at this point, if you simply refresh the browser screen:

image

Refreshing Collections
Spring Boot has opted for much stricter rules when it comes to refresh and binding values and settings that belong to a collection. See this issue for better details.

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