Apereo CAS - SAML2 Metadata with MongoDb

Posted by Misagh Moayyed on November 03, 2018 · 9 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 and 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 SAML2 identity provider and service provider metadata documents.

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"]})

Point your browser to http://localhost:8081 and let’s create a collection called cas-saml-sp-metadata with the following document:

image

Note the value field which contains a base64-encoded version of the metadata for a SAML2 service provider which makes it easier to get the metadata added to the MongoDB document. I am also skipping over the metadata signature that would have been used to validate its integrity and that could have just as easily been added to the document using a signature field.

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

CAS

SAML2 Service Provider Metadata

So in order to enable a CAS integration with MongoDB directly, you want to start with the CAS Overlay, clone the project and follow the notes here to get CAS acting as SAML2 identity provider. In its simplest form, it comes to down to the following settings:

cas.authn.samlIdp.entityId=https://sso.example.org/idp
cas.authn.samlIdp.scope=example.org
cas.authn.samlIdp.metadata.location=file:/etc/cas/config/saml

…and this module in the CAS build:

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

To keep things simple, we could use the JSON service registry to manage our SAML2 service provider definitions. Here is what our service definition might look like for SAML2 service provider in a SAML-1.json file:

{
  "@class" : "org.apereo.cas.support.saml.services.SamlRegisteredService",
  "serviceId" : "<your-sp-entity-id>",
  "name" : "SAML",
  "id" : 1,
  "description" : "This SP has its metadata in MongoDB somewhere.",
  "metadataLocation" : "mongodb://"
}

The metadata location in the registration record above simply needs to be specified as mongodb:// to signal to CAS that SAML metadata for our service provider must be fetched from MongoDB data sources defined in CAS configuration. As the next step, let’s teach CAS) about our MongoDB setup. Just like before, you’d need this module in your CAS build:

compile "org.apereo.cas:cas-server-support-saml-idp-metadata-mongo:${project.'cas.version'}"

…and CAS needs to know how to connect to MongoDB to fetch stuff:

cas.authn.samlIdp.metadata.mongo.host=localhost
cas.authn.samlIdp.metadata.mongo.port=27017
cas.authn.samlIdp.metadata.mongo.userId=casuser
cas.authn.samlIdp.metadata.mongo.password=Mellon
cas.authn.samlIdp.metadata.mongo.collection=cas-saml-sp-metadata
cas.authn.samlIdp.metadata.mongo.databaseName=cas

That’s it. Build and run CAS. At this point, you should be able to log into service provider successfully whose metadata is fetched and processed by CAS from MongoDB.

SAML2 Identity Provider Metadata

If you examine your CAS startup logs, you might notice the following statement:

[...FileSystemSamlIdPMetadataLocator] - <Metadata directory location is at [/etc/cas/config/saml]>

…which matches our setting above:

cas.authn.samlIdp.metadata.location=file:/etc/cas/config/saml

Metadata artifacts that belong to CAS as a SAML2 identity provider may also be managed and stored via MongoDb. This includes things such as the metadata XML document, signing and encryption keys, etc. While CAS has the ability to generate brand new metadata in MongoDB, let’s instead figure out how our existing metadata might be relocated to MongoDB.

Let’s create a MongoDB collection called saml-idp-metadata in our cas database to hold IdP artifacts with the following document in it:

{
    "signingCertificate": "...",
    "signingKey": "...",
    "encryptionCertificate": "...",
    "encryptionKey": "...",
    "metadata": "..."
}

Here is the drill:

  • The metadata, signing and encryption certificates may be base64-encoded.
  • The signing and encryption keys MUST be signed and encrypted using CAS crypto settings and keys.

The signing secret key and the encryption secret key are both JWKs of size 512 and 256. We can use the command-line shell to create the two keys:

cas> generate-key key-size 512
$signingKey
cas> generate-key key-size 256
$encryptionKey

Once you have the keys, you can try to secure the metadata keys:

cas> cipher-text file /etc/cas/config/saml/idp-signing.key signing-key $signingKey encryption-key $encryptionKey
...
cas> cipher-text file /etc/cas/config/saml/idp-encryption.key signing-key $signingKey encryption-key $encryptionKey
...

The signing and encryption SAML2 metadata keys plus the base64-encoded versions of the signing and encryption certificates and the metadata XML can next be put into the MongoDB document.

image

CAS settings will then take on the following form:

# cas.authn.samlIdp.metadata.location=file:/etc/cas/config/saml
cas.authn.samlIdp.metadata.mongo.idpMetadataCollection=saml-idp-metadata
cas.authn.samlIdp.metadata.mongo.crypto.encryption.key=$encryptionKey
cas.authn.samlIdp.metadata.mongo.crypto.signing.key=$signingKey

Build and run CAS. At this point, you should be able to log into the service provider successfully with CAS using its own SAML2 metadata from MongoDB to produce a SAML2 response, etc.

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