How to secure a Java application with CAS (using Spring Boot)

CAS (Central Authentication Service) is the open source single sign-on server widely used by universities and large organizations, maintained by the Apereo foundation. The protocol is simple: your Java application redirects the user to the CAS login page, CAS sends the browser back with a short-lived service ticket, and your application validates that ticket with the CAS server to learn who the user is.

This guide uses pac4j with Spring Boot to protect a Java web application with a CAS server. The demo authenticates against the public pac4j test server, and the section on service registration shows what to configure on your own CAS server.

What you need:

1) Get the Spring Boot demo

The CAS demo project contains the three classes shown in this guide, ready to run:

git clone --branch cas --single-branch https://github.com/pac4j/simple-spring-boot-pac4j-demos.git
cd simple-spring-boot-pac4j-demos

2) Add the Maven dependencies

The demo’s pom.xml uses the Spring Boot parent. On top of Spring MVC, you need the pac4j Spring MVC integration and the CAS module:

<!-- Spring Boot web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- pac4j implementation for Spring MVC so for Spring Boot as well -->
<dependency>
    <groupId>org.pac4j</groupId>
    <artifactId>spring-webmvc-pac4j</artifactId>
    <version>8.0.3</version>
</dependency>
<!-- pac4j support for CAS -->
<dependency>
    <groupId>org.pac4j</groupId>
    <artifactId>pac4j-cas</artifactId>
    <version>6.5.8</version>
</dependency>

pac4j-cas is a full CAS client: it speaks the CAS protocol versions 1.0, 2.0 and 3.0, and also supports proxy tickets and the CAS REST API, covered at the end of this guide.

3) Configure CAS authentication

The whole security setup fits in one class, SecurityConfig:

@Configuration
public class SecurityConfig extends Pac4jSecurityConfig {

    @Value("${app.base-url:http://localhost:8080}")
    private String baseUri;

    @Value("${cas.login-url:https://www.casserverpac4j.dev/login}")
    private String casLoginUrl;

    @Bean
    public Config config() {
        // configuration of the authentication via the CAS protocol
        return new Config(baseUri + "/callback", new CasClient(new CasConfiguration(casLoginUrl)));
    }

    @Override
    public void addInterceptors(final InterceptorRegistry registry) {
        // the /protected/** URLs require the CAS authentication
        addSecurity(registry, "CasClient").addPathPatterns("/protected/**");
    }
}

What each part does:

pac4j uses the CAS 3.0 protocol by default, which returns the user attributes with the validation response. Switch with config.setProtocol(CasProtocol.CAS20) for an older server. Two other options are worth knowing: setRenew(true) forces the user to re-enter credentials even with an active SSO session, and setGateway(true) returns silently when the user is not logged in instead of showing the login page.

4) Register the service on the CAS server

A CAS server only issues tickets for services it knows. In the CAS service registry, declare a service whose serviceId pattern matches the callback URL. With the JSON service registry of Apereo CAS 7, the definition looks like this:

{
  "@class" : "org.apereo.cas.services.CasRegisteredService",
  "serviceId" : "^http://localhost:8080/callback\\?client_name=CasClient.*",
  "name" : "pac4j Spring Boot demo",
  "id" : 1000,
  "attributeReleasePolicy" : {
    "@class" : "org.apereo.cas.services.ReturnAllAttributeReleasePolicy"
  }
}

Two settings matter here:

See the Apereo CAS service management documentation for the other registries (database, LDAP, Git…) and options.

5) Access the authenticated user

The application controller exposes a public page and a protected page:

@Autowired
private ProfileManager profileManager;

@RequestMapping("/")
@ResponseBody
public String index() {
    return "<h1>Public area</h1><p><a href='/protected/index'>Protected area</a></p>"
            + "<p><a href='/logout'>Logout</a></p>" + profileManager.getProfiles();
}

@RequestMapping("/protected/index")
@ResponseBody
public String secure() {
    return "<h1>Protected area</h1><a href='/'>Home</a><p/>"
            + "<p><a href='/logout'>Logout</a></p>" + profileManager.getProfiles();
}

After login, the ProfileManager returns a CasProfile. Its identifier is the CAS principal, usually the username, and its attributes are exactly those released by the service’s attribute release policy:

final var profile = (CasProfile) profileManager.getProfile().orElseThrow();
profile.getId();                 // the CAS principal
profile.getAttribute("email");
profile.getAttributes();         // everything the release policy allowed

An empty attribute map almost always means the release policy of the service is too restrictive, or the server still uses the CAS 2.0 protocol, which does not carry attributes.

6) Logout

The /logout link removes the profile from the local session. To also end the SSO session on the CAS server, enable the central logout in application.properties:

pac4j.logout.centralLogout=true
pac4j.logout.defaultUrl=/

pac4j then redirects the browser to the CAS /logout endpoint. The reverse direction works too: when the user logs out from CAS or from another application, the CAS server notifies every service that received a ticket during the session, and the CasClient processes these single logout requests to destroy the local session.

7) Run the application

Start SpringBootDemo from your IDE or with mvn spring-boot:run:

@SpringBootApplication
public class SpringBootDemo {
    public static void main(final String[] args) {
        SpringApplication.run(SpringBootDemo.class, args);
    }
}

Open http://localhost:8080/ and follow Protected area. You are redirected to the CAS login page, then sent back to the callback with a service ticket, and the protected page prints your profile.

If something goes wrong:

Beyond the login page

The same pac4j-cas module covers the other CAS use cases:

Learn more

Read the CAS reference for the proxy and REST configurations, the stateless DirectCasClient and all the CasConfiguration options.

Using a different integration? The Jakarta EE guide and Spring Security guide explain the integration using OIDC. Follow their “Switching to SAML or CAS” section to use the CAS client configuration from this guide.

Discover more pac4j frameworks and more authentication mechanisms