Apereo CAS - Configuration Management with MongoDb

Posted by Misagh Moayyed on October 31, 2018 · 8 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.

MongoDB is a free and open-source cross-platform document-oriented database program. Classified as a NoSQL database program, MongoDB uses JSON-like documents with schemata. MongoDB is developed by MongoDB Inc., and is published under a combination of the Server Side Public License and the Apache License.

MongoDB is supported in CAS in many different ways. In this walkthrough, we are going to take a pass at getting CAS connected to MongoDB to store properties and settings. We will also try to reload settings dynamically in real-time as they are changed and updated inside MongoDB databases.

Our starting position is based on the following:

MongoDB

To run MongoDB for development and testing, we can use the provided Docker image:

docker run -d -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=root \
  -e MONGO_INITDB_ROOT_PASSWORD=secret --name="mongodb-server" mongo:4.0-xenial
docker ps

This runs a MongoDB database server which is useful for development but SHOULD NOT be used in production.

To access the MongoDB instance using a UI, run:

docker run --link mongodb-server -d -p 8081:8081 \
  -e 'ME_CONFIG_MONGODB_ADMINUSERNAME=root' \
  -e 'ME_CONFIG_MONGODB_ADMINPASSWORD=secret' \
  -e 'ME_CONFIG_MONGODB_SERVER=mongodb-server' mongo-express

The ME_CONFIG_MONGODB_SERVER is the address of the docker container that runs the MongoDB server. By default, Docker containers use the container as the DNS host name. So we can just specify the mongodb-server the name of the container that runs our MongoDB instance.

Shell into the container:

CID=docker ps -aqf name=mongodb-server
docker exec -it $CID /bin/bash

When inside the container:

mongo --host mongodb://root:secret@localhost:27017
use database cas;

# Create a database user for authentication
db.createUser({user:"casuser", pwd:"Mellon", roles: ["readWrite", "dbAdmin"]})

When ready, point your browser to http://localhost:8081 and let’s create a few documents with CAS settings in them. MongoDb documents are required to be found in the collection MongoDbProperty, as the following document:

{
    "id": "...",
    "name": "the-setting-name",
    "value": "the-setting-value"
}

So I am going to create a MongoDB database called cas inside which the MongoDbProperty needs to be created. Next, each of the below settings will be housed inside an indibidual MongoDB document that matches the above JSON structure:

cas.authn.accept.users=casuser::MongoDB
management.endpoints.web.exposure.include=*
management.endpoints.enabled-by-default=true
cas.monitor.endpoints.endpoint.defaults.access=AUTHENTICATED
spring.security.user.name=casuser
spring.security.user.password=Mellon

The end result will look something like this:

image

WATCH OUT!
The above collection of settings MUST only be used for demo purposes and serve as an EXAMPLE. It is not wise to enable and expose all actuator endpoints to the web and certainly, the security of the exposed endpoints should be taken into account very seriously. None of the CAS or Spring Boot actuator endpoints are enabled by default. For production, you should carefully choose which endpoints to expose.

You may also want to create an index on name:

image

That should do for now. Let’s get CAS running.

CAS

Integration with MongoDB in CAS to manage configuration can be done in a number of ways:

  • If you have the Spring Cloud Config Server deployed, MongoDB could be one of its many sources for settings and properties. In this scenario, you will just need to make sure the CAS server can talk to the Spring Cloud Config Server correctly, and the Config Server is then in charge of communicating with MongoDB to fetch settings, etc.

  • Alternatively, you may decide to connect your CAS server directly to MongoDB and fetch settings. This is the approach we are going to try in this tutorial for a quick win, but do note that the strategy is almost the same if we were to use the Cloud Config server.

So in order to enable a CAS integration with MongoDB directly, you want to start with the CAS Overlay, clone the project and then put the following settings into a src/main/resources/bootstrap.properties file:

spring.application.name=cas
spring.profiles.active=mongodb
cas.spring.cloud.mongo.uri=mongodb://casuser:Mellon@localhost:27017/cas

Of course, don’t forget to include the required module in your CAS build:

compile "org.apereo.cas:cas-server-support-configuration-cloud-mongo:${project.'cas.version'}"

Build and deploy. At this point, you should be able to log into CAS using casuser and MongoDB as the credentials!

Refresh & Reload

If a setting changes, MongoDB has no way to broadcast the updated value(s) to its own clients, such as the CAS server itself. Therefore, in order to broadcast such change events, CAS presents various endpoints that allow the user to refresh the configuration as needed. This means that an adopter would simply change a required CAS setting and then would submit a request to CAS to refresh its current state. At runtime! All CAS internal components that are affected by the external change are quietly reloaded and the setting takes immediate effect, completely removing the need for container restarts or CAS re-deployments.

For example, start by changing the value of cas.authn.accept.users in MongoDB to something like casuser::HelloWorld. Then, execute the following command to refresh the CAS application context:

curl -k -u casuser:Mellon https://sso.example.org/cas/actuator/refresh -d {} -H "Content-Type: application/json"

...
["cas.authn.accept.users"]

At this point, you should be able to log into CAS using casuser and HelloWorld as the credentials!

Finale

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 feel free to engage and contribute as best as you can.

Misagh Moayyed