A CAS server implementing OAauth 2.0 (OAuth2) and OpenID Connect (OIDC) in addition to CAS' own protocol.
Configuration files are
- src/main/resources/bootstrap.properties
- src/main/resources/application-base.properties
Active profile is currently hardcoded to base in src/main/resources/bootstrap.properties
.
To build run mvn clean package
from the command line, it will produce ./target/cas-oidc-server-<version>.war
, where <version> is something like OBOPS-2019.02
-
Create directory $ACSDATA/config/cas and copy the contents of the config directory to that. (Note the config/services directory.)
-
The config directory includes a private/public JSON Web Key Set to generate JWTs in $ACSDATA/config/cas/oidc-keystore.jwks. The keypair set can be regenerated with some Web service like https://mkjwk.org or https://connect2id.com/products/nimbus-jose-jwt/generator (in production). It looks like this:
{ "keys": [ { "kty": "RSA", "d": "fgP6WU2n7uVMs...VADspF2Q", "e": "AQAB", "use": "sig", "kid": "alma.obops.cas", "alg": "RS256", "n": "ilDEzMlLAvEzw..._QhkybvcJkMQw" } ] }
NOTE The keypair set is used for signing the JWTs generated buy OAuth2/OIDC. To allow a distributed OIDC service the set should be shared by all participating instances.
-
The config/services directory includes:
- generic-0.json: allows any application to participate in SSO using the CAS protocol
- demoOIDC-1000.json: A basic, demo OAuth2/OIDC service following the naming convention:
fileName = serviceName + "-" + serviceNumericId + ".json"
- RegexRegisteredService-4252....json: generated by CAS itself for obscure purposes
-
Database connection configuration follows the ALMA conventions and is externalized to $ACSDATA/config/archiveConfig.properties. Relevant properties are (with example values):
archive.relational.connection = jdbc:oracle:thin:@xyz.example.com:1521/ABCD archive.relational.user = someuser archive.relational.passwd = s0me/passWD
CAS must be reached via HTTPS and requires a secure environment to be configured for Spring Boot — see https://www.thomasvitale.com/https-spring-boot-ssl-certificate
You'll need an SSL certificate in a keystore.
If you have a "real" SSL certificate, provided by a CA, you should import it into a keystore – there are many resources on the Web about that. Ultimately, the keystore file must be copied to the CAS config directory, e.g.
cp .../keystore.jks ${ACSDATA}/config/cas
(A self-signed certificate is included in the keystore provided in the config directory, it is specific to my development environment and should be ignored.)
During development you you can easily create a self-signed certificate:
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650
Use changeit when requested a password.
Move keystore.p12, the generated keystore, to $ACSDATA/config/cas
To view the contents of the keystore: keytool -list -v -storetype pkcs12 -keystore $ACSDATA/config/cas/keystore.p12
If you have a self-signed certificate you'll need to make the JRE trust it. First of all, you need to extact it from the keystore:
keytool -export -keystore $ACSDATA/config/cas/keystore.p12 -alias tomcat -file certificate.crt
You then need to locate your JDK home and import the certificate.
On MacOS: export JAVA_HOME=$(/usr/libexec/java_home)
On Linux the value of JAVA_HOME depends on how your JVM is installed, it could be something like /usr/lib/jvm/java-1.8.0-openjdk-1.8.0....
Then (you'll probably need sudo privileges):
sudo keytool -importcert -file certificate.crt -alias tomcat -keystore $JAVA_HOME/jre/lib/security/cacerts
If everything went right, you’d see the message Certificate was added to keystore.
Assuming your JDK is 1.8.0_162:
cd "c:\Program Files\Java\jdk1.8.0_162"
bin\keytool.exe -importcert -file path-to-certificate.crt -alias tomcat -keystore jre\lib\security\cacerts
Make sure your cas.properties file includes the following Spring Boot properties:
security.require-ssl=true
server.ssl.key-store-type=PKCS12
server.ssl.key-store=file:${ACSDATA}/config/cas/<name-of-keystore-file>
server.ssl.key-store-password=changeit
server.ssl.key-alias=tomcat
- The CAS application will write its log files to
/var/log/cas
** make sure that directory exists and is writable ** see src/main/resources/log4j2.xml to change that path export _JAVA_OPTIONS="-Dcas.standalone.configurationDirectory=$ACSDATA/config"
java -jar target/cas-oidc-server-<version>.war
NOTE In the following examples, replace ma24088.ads.eso.org with the fully qualified hostname of the machine running the CAS server; never use localhost.
NOTE You may also want to open a new incognito/anonymous window for the examples to avoid old cookies to interfere.
- Access the login page as https://ma24088.ads.eso.org:8019/cas/login and login with your credentials
- Log out again at https://ma24088.ads.eso.org:8019/cas/logout
See here for a description of the OAuth2/OIDC grant (flow) types.
See here for more info on the Implicit Authorization grant type.
Navigate to:
https://ma24088.ads.eso.org:8019/cas/oauth2.0/authorize?response_type=token&client_id=demoOIDC&redirect_uri=https%3A%2F%2Fapp.example.com%2Fredirect
After login you will be redirected to example.com/redirect: the URL will contain the OAuth2 access token:
https://app.example.com/redirect#access_token=AT-14-Sdj1AA...&token_type=bearer&expires_in=7200
See here for for more info on the Authorization Code grant type.
In a browser navigate to https://ma24088.ads.eso.org:8019/cas/oauth2.0/authorize?response_type=code&client_id=demoOIDC&redirect_uri=https%3A%2F%2Fapp.example.com%2Fredirect
, will redirect to login page, then to https://app.example.com/redirect?code=OC-10-1jHfj....
with some authorization code.
NOTE The authorization code (OC-10-1jHfj....
) has limited validity, please perform the next step(s) within a minuto or so.
Query the auth server with that auth code:
curl -k -u demoOIDC:s3cr3t \
https://ma24088.ads.eso.org:8019/cas/oauth2.0/accessToken \
-d grant_type=authorization_code \
-d redirect_uri=https://app.example.com/redirect \
-d code=OC-10-1jHfj....
Will return an access token:
{"access_token":"AT-11-BHoGu4r..." ...}
(Alternatively, you can navigate to
https://ma24088.ads.eso.org:8019/cas/oauth2.0/accessToken?grant_type=authorization_code&client_id=demoOIDC&client_secret=s3cr3t&redirect_uri=https%3A%2F%2Fapp.example.com%2Fredirect&code=OC-10-1jHfj....
in a browser, and you should get the same access token.)
With that token you for instance retrieve the user profile.
See here for for more info on the Resource Owner Credentials grant (called Password grant in the CAS documentation).
You can obtain an access token passing the credentials of a Resource Owner (end user) in the URL:
https://ma24088.ads.eso.org:8019/cas/oauth2.0/accessToken?grant_type=password&client_id=demoOIDC&username=...&password=...
You can obtain an access token passing the credentials of a Client (application) in the URL:
https://ma24088.ads.eso.org:8019/cas/oauth2.0/accessToken?grant_type=client_credentials&client_id=demoOIDC&client_secret=s3cr3t
Once you have an access token you can retrieve the profile of the logged-in user:
https://ma24088.ads.eso.org:8019/cas/oauth2.0/profile?response_type=token&client_id=demoOIDC&access_token=AT-14-Sdj1AA..
Example:
{
"givenName" : "ObOps",
"lastName" : "Subsystem",
"mail" : "obops1183@noname.domain.org",
"roles" : [ "ARCHIVE/SOURCECAT_ADMIN", ... ],
...
"id" : "obops"
}
Alternatively, you can pass the access token in an HTTP Header: Authorization: Bearer AT-14-Sdj1AA...
NOTE If you obtained the access token by way of a Client Credentials grant the profile will only include the client ID.
See here for a description of the OAuth2/OIDC grant (flow) types.
For more info about OpenID Connect endpoints, see here.
To retrieve the JSON Web Key Set used by the authentication server to sign the JWTs it produces:
https://ma24088.ads.eso.org:8019/cas/oidc/jwks
Navigate to:
https://ma24088.ads.eso.org:8019/cas/oidc/authorize?response_type=id_token%20token&client_id=demoOIDC&scope=openid%20profile%20profile_full&redirect_uri=https%3A%2F%2Fapp.example.com%2Fredirect
You should be taken to CAS' login page. Once the authentication/authorization procedure is completed you should be redirected to app.example.com with a URL including an id_token, a JWT. Copy the token string from the URL and paste it into e.g. the debugger of https://jwt.io to see its contents.
NOTE URL parameters state and nonce are optional, for instance ...&state=3km36n5yp2l9h26&nonce=po7s2tr6wnc8xs2
— see here for more info.
See here for for more info on the Authorization Code grant type.
In a browser navigate to https://ma24088.ads.eso.org:8019/cas/oidc/authorize?response_type=code&client_id=demoOIDC&redirect_uri=https%3A%2F%2Fapp.example.com%2Fredirect
, will redirect to login page, then to https://app.example.com/redirect?code=OC-17-i43YO...
with some authorization code.
NOTE The authorization code (OC-17-i43YO...
) has limited validity, please perform the next step(s) within a minuto or so.
Query the auth server with that authorization code, you can use any http client, we're using cURL:
curl -k -u demoOIDC:s3cr3t \
https://ma24088.ads.eso.org:8019/cas/oidc/token \
-d grant_type=authorization_code \
-d redirect_uri=https://app.example.com/redirect \
-d code=OC-17-i43YO....
Will return an access token and an ID token (JWT):
{"access_token":"AT-13-fyPZz...","id_token":"eyJhbGciOi..."}
(Alternatively, you can navigate to
https://ma24088.ads.eso.org:8019/oidc/token?grant_type=authorization_code&client_id=demoOIDC&client_secret=s3cr3t&redirect_uri=https%3A%2F%2Fapp.example.com%2Fredirect&code=OC-10-1jHfj....
in a browser, and you should get the same tokens.)
You can obtain an JWT ID token passing the credentials of a Client (application) in the URL:
https://ma24088.ads.eso.org:8019/cas/oidc/token?response_type=id_token%20token&grant_type=password&client_id=demoOIDC&username=...&password=...
That will return a JSON structure including the JWT:
{
"access_token": "AT-1-DJAub2UhX2ftcOyJMbHyNPYG5MnBSN7f",
"token_type": "bearer",
"expires_in": 28800,
"id_token": "eyJhbGciOiJSUzI1NiIsI..."
}
-
Java package
alma.obops.cas
contain ALMA- and Oracle-specific code for verifying credentials and retrieving user roles. -
Java packages
org.apereo.cas...
contain patched versions of the CAS source code. -
Very useful documentation
- About CAS/OIDC: https://mirzlab.github.io/2017/07/16/cas5-oidc-provider/
- About keytool, etc: https://www.sslshopper.com/