Release notes · 8.1.0 development
8.1.0-RC4
The fourth release candidate is in progress. This page fills in as changes land on the development branch.
- Requires JDK 25
- Built on Spring Boot 4.2
- 618 browser test scenarios
- 94% test coverage
- 22New & noteworthy topics
- 7Changes to review before upgrading
- 2Other changes
- 3Fixes
Before You Upgrade
These changes alter existing behavior. Each one links to its full description below.
-
Action
Theme builder is turned on by default; turn it off for production with
cas.theme-builder.enabled=falsein theme properties.Interface & Accounts -
Changed
External identity providers keep their configured order in the dropdown as well; set
cas.login-providers.sort=truein theme properties to sort them by name.Interface & Accounts -
Changed
Error pages no longer offer the details button unless
cas.error.show-details=trueis set in theme properties.Interface & Accounts -
Action
OpenID Federation relying parties registered automatically must send a signed request object or a pushed authorization request with every authorization request.OAuth & OpenID Connect
-
Removed
Azure CosmosDb service and ticket registries are removed; move service definitions and tickets to another registry before upgrading.Tickets & Sessions
-
Action
Trusted devices include the client IP address in the device fingerprint by default, as documented; devices trusted before the upgrade are asked for multifactor authentication once more. Set
cas.authn.mfa.trusted.device-fingerprint.client-ip.enabled=falseto keep the previous fingerprint.Multifactor & Passkeys -
Action
Interrupt inquirers no longer receive the Spring Webflow request context; custom inquirers drop that parameter, and Groovy interrupt scripts receive the logger as their fifth argument.Interface & Accounts
Spotlight · User interface
Shape the CAS Screens From Theme Properties
Login, error, multifactor and consent screens gain theme properties, each previewed live in the new theme builder.
- Identity providers move before or after the login form, in a stack, a grid or a row, with their own sort and dropdown threshold.
- Multifactor selection, Google Authenticator, WebAuthn and consent screens choose their layout, what they show and what they recommend.
- QR codes take their size, colors and margin from the theme, and device names can start empty, random or with the username.
- The main content of every page can sit anywhere on a 3x3 grid, from the top left to the bottom right of the screen.
Highlights
-
Interface & AccountsNew
Theme Builder
Edit theme properties and custom.css from the CAS header, preview live and download both files for an overlay.
-
Interface & AccountsNew
Theme Properties
Over twenty new theme properties for the login form, identity providers, errors, multifactor, QR codes and consent.
-
Interface & AccountsNew
Account Profile
Sign-in activity, contact methods, refresh tokens, usage policy, impersonation, QR devices and password expiry in the profile.
New & Noteworthy
The following items are new improvements and enhancements presented in this release.
OpenRewrite Recipes
CAS continues to produce and publish OpenRewrite recipes that allow the project to upgrade installations in place from one version to the next. See this guide to learn more.
Graal VM Native Images
A CAS server installation and deployment process can be tuned to build and run as a Graal VM native image. We continue to polish native runtime hints. The collection of end-to-end browser tests based on Puppeteer have selectively switched to build and verify Graal VM native images and we plan to extend the coverage to all such scenarios in the coming releases.
Testing Strategy
The collection of end-to-end browser tests based on Puppeteer continue to grow to cover more use cases
and scenarios. At the moment, total number of jobs stands at approximately 628 distinct scenarios. The overall
test coverage of the CAS codebase is approximately 94%.
- MariaDB integration tests and functional test scenarios use port
3307, so they can run alongside the MySQL tests on3306. - Browser tests now cover service matching strategies (literal, starts with, full and partial
regular expressions), throttled ticket-granting ticket timeouts, per-service service ticket, proxy ticket and proxy-granting
ticket expiration policies, single sign-on participation policies (never, last used time, authentication date), per-service
security headers, encrypted, pattern matching, linked, environment and Groovy script attribute release policies, the
anonymous username provider, multifactor bypass by remote address, request header and credential type, and the REST
multifactor trigger (
cas.authn.mfa.triggers.rest.url). - Browser tests now cover OpenID Connect front-channel logout, refused hybrid and unauthorized response types, encrypted user info and introspection responses, JWT refresh tokens, optional ID token encryption, token revocation with its cascade from refresh tokens to access tokens, WebAuthn signature counters, user verification and attestation, and Google Authenticator replay protection with custom code length, time step and window.
- Browser tests now sign in with SPNEGO against a
real Kerberos KDC: the browser presents a Kerberos ticket and is signed in without a password, with and without
cas.authn.spnego.principal-with-domain-name, and falls back to the login form when it has no ticket. - Browser tests now cover refusal paths of the CAS protocol and its security controls:
validation error codes and per-service supported protocols, refused and mismatched proxy callbacks and multi-hop proxy
chains, plain gateway requests, time-based access strategies, global authentication policies (any with try-all, all
handlers, required handler, not prevented, Groovy and REST), request parameter filtering
(
cas.http-web-request.pattern-to-block), actuator endpointDENY,PERMITandAUTHORITYaccess, audit action filters withcas.audit.engine.ignore-audit-failures, and CAPTCHA verification on the login form. - Browser tests now cover OAuth refresh token rotation and expiration, rejected client
assertions and enforced client authentication methods, PKCE on the OAuth endpoints, expired client secrets, tampered request
objects and logout redirect validation; trusted device fingerprints, expiration and per-service bypass, multifactor bypass by
request attributes, simple multifactor token expiration and rate limiting, YubiKey verification against a mock server, REST
authentication account states, password history (
cas.authn.pm.history.core.enabled), passwordless token expiration, and SAML2 signed logout requests, AuthnRequest rejection, artifact resolution, attribute queries and ECP. - Browser tests now cover OpenID Connect client attestation and JWKS rotation and revocation
across issued tokens, SAML2 back-channel logout, offline metadata signature trust, persistent NameIDs, signing and encryption
algorithms, Active Directory and OpenLDAP password policy warnings, X.509 revocation through CRLs, the ticket registry
cleaner, concurrent ticket validation across nodes, ticket encryption at rest in MongoDb, masking of tickets in logs, and
strict audit failure handling (
cas.audit.engine.ignore-audit-failures).
JSpecify & NullAway
CAS codebase is now annotated with JSpecify annotations to indicate nullness contracts on method parameters, return types and fields. We will gradually extend the coverage of such annotations across the entire codebase in future releases and will integrate the Gradle build tool with tools such as NullAway to prevent nullness contract violations during compile time.
Gradle 9.9
CAS is now built with Gradle 9.9 and the build process has been updated to use the
latest Gradle features and capabilities.
Spring Boot 4.2
CAS is now built on top of Spring Boot 4.2.x. This is an in-progress ongoing minor platform upgrade that
affects almost all aspects of the codebase including many of the third-party core libraries used by CAS
as well as some CAS functionality.
Please refer to the Spring Boot Wiki for more information on the changes and updates in this release.
Theme Builder
The CAS header has a new palette button, next to the notifications button, that opens a
theme builder. It lists every theme property with its
description and current value, and edits the colors, shapes, font, header, footer and background that custom.css usually
controls. Changes are previewed live on the page without a reload, including elements that a theme property would turn off,
and the result downloads as a cas-theme-custom.properties file and a custom.css file ready for an overlay. When the builder
opens on a server that already serves such a custom.css, it reads its own block back so the file can keep evolving.
Nothing is saved on the server; the builder is turned on by default and is controlled by the cas.theme-builder.enabled
theme property.
Palantir Search, User Lookup, Service History, Interrupts & Drafts
Palantir has a search box, opened from the navigation bar or with Ctrl+K
(⌘K on macOS) or /, that goes to any page or section, finds a registered application by name, identifier or service id,
and runs common actions without leaving the keyboard. A new Users page looks up one user and gathers in one place their
single sign-on sessions, multifactor and trusted devices, consent decisions, resolved attributes, impersonation accounts,
passwordless account, password history, throttled login attempts, the interrupt they would see at login and recent audit events, each with its usual actions
such as ending a session, removing a device or releasing a throttled attempt. Only sources with something recorded for
the user are shown, and sources whose actuator endpoints are not enabled are left out. The change history of an application
compares any recorded version side by side with the current definition or the version before it, and restores the
selected version from the same dialog. Under Interrupts, the authentication section shows which
interrupt a user would see at login and what each interrupt
source answered.
Applications can be duplicated into the wizard as new applications, and the wizard and the definition editor ask before
closing with unsaved changes, keeping a draft in the browser that can be resumed for up to thirty days. A keyboard shortcut overlay opens
with ?, and tables and dialogs are easier to use with a keyboard and a screen reader: tables are named, rows with actions
take focus and open their actions with Shift+F10, modal dialogs announce themselves, and icon-only buttons are named.
Theme Properties
Several screens can now be adjusted through theme properties, so they can differ per theme, per application and per tenant, and most of them preview live in the theme builder:
| Screen | Theme properties |
|---|---|
| Every page | cas.main-content.position (topleft … bottomright, default topcenter) |
| Login form | cas.login-form.password-reveal.enabled, cas.login-form.caps-lock-warning.enabled |
| Login card | cas.login-side-panel.position (start, end), cas.login-providers.position (after, before) |
| External identity providers | cas.login-providers.layout (stacked, grid, inline), .select-threshold, .sort |
| Password management links | cas.pm-links.forgot-password.url |
| Error pages | cas.error.show-message, cas.error.show-details |
| WebAuthn | cas.webauthn.authentication.show-device-details, cas.webauthn.registration.recommended |
| Google Authenticator | cas.gauth.registration.show-secret-key, .scratch-codes (chips, list), .show-print |
| QR codes | cas.qr-code.size, cas.qr-code.foreground, cas.qr-code.background, cas.qr-code.margin |
| Multifactor authentication | cas.mfa.selection.layout (list, grid, cards), cas.mfa.device-name.prefill |
| Attribute consent | cas.consent.show-attribute-values, cas.consent.layout (table, list) |
The main content position places the content of every page in a 3x3 grid on the screen: top, middle or bottom, and
left, center or right, as in middleleft or bottomright. Pages taller than the screen still start at the top and scroll,
and Palantir keeps its own layout.
Defaults keep the screens as they were, with two exceptions: external identity providers keep their configured order in
the dropdown that replaces the buttons once there are more than ten, and the error page offers its details button only
when cas.error.show-details is turned on, in which case it now shows the stack trace the server includes rather than an
empty box. QR codes for Google Authenticator, WebAuthn and QR code login use the QR code properties of the theme that
applies to the request; their size stays between 100 and 1000 pixels, and a foreground that is not darker than the
background falls back to black on white so the code remains scannable. Device and account names suggested when
registering trusted devices, Google Authenticator, YubiKey or WebAuthn devices can start empty, random or with the
username.
- Themes other than the default one, including themes chosen per
application or per tenant, now inherit
cas-theme-custom.propertiesbefore falling back tocas-theme-default.properties. Theme files found under the template prefixes now apply regardless of the browser language; they used to be ignored for languages other than English, and the aggregate theme source only honored them for an exactenrequest.
Account Profile
The account profile shows more of what CAS knows about the user:
| Section | What it shows |
|---|---|
| Overview | Days left before the password expires, from the password policy warning, with a shortcut to change it. |
| Sign-ins | Successful, failed and risky sign-in attempts of the last 30 days from the authentication events. |
| Contact | Email addresses and phone numbers for one-time codes and for passwordless sign-in. |
| Tokens | Refresh tokens (offline access) next to access tokens; revoking one revokes its access tokens. |
| Usage policy | Whether the acceptable usage policy is accepted, and the policy terms. |
| Impersonation | Accounts the user may impersonate, and on whose behalf an impersonation session runs. |
| QR devices | Devices authorized for QR code login, which the user can remove. |
| MFA devices | YubiKey registration, new Google Authenticator scratch codes, renaming WebAuthn passkeys. |
YubiKey registration is offered when the user has no device yet or when
cas.authn.mfa.yubikey.multiple-device-registration-enabled is turned on, and an email address for
one-time codes can be added when cas.authn.mfa.simple.mail.accepted-email-pattern is set.
- The account profile only ends single sign-on sessions, revokes OpenID Connect tokens and removes trusted devices that belong to the signed-in user; it used to act on any session, token or device whose identifier was submitted.
- The account profile and account management pages follow the shared card, text and border colors of the theme, and the light Palantir theme follows the theme’s primary and secondary colors.
Service Registries and Access Strategies
- The JPA service registry reads only the
identifier and body of each definition, keeps no entities for reads, and no longer deserializes a definition on reload
when its stored body is unchanged. Deleting a service is a single statement, new services are no longer looked up before
they are stored, bulk saves flush every
batch-sizedefinitions, and the service id and name columns are indexed. - The JPA service registry keeps the identifier of a service that carries one, such as an imported definition; a database sequence used to replace it. New services get a random identifier, as with other service registries.
- A service whose single sign-on participation policy does not set
createCookieOnRenewedAuthentication(for example the last-used-time and authentication-date policies) no longer fails the login flow; such a policy behaves like one that leaves the setting undefined, and the single sign-on session is kept when the service does not take part in it. - Attribute-based activation criteria for access strategies
and attribute release policies match required values against
the entire attribute value, like required and rejected attributes;
adminno longer activates a policy forsysadmin. Use.*admin.*to match part of a value. - Service replication no longer broadcasts every service definition from every node on each reload: a loaded definition is sent only when it differs from the replicated copy, and the replicated copies are kept across reloads instead of being cleared, so nodes started later still receive every definition. A replicated definition that differs from the local one replaces it instead of being listed twice.
- When several service registries are chained, a service URL that is not cached is matched against the best candidate from every registry by evaluation order, instead of the first registry’s match.
- The REST service registry no longer publishes a loaded event for every service when services are counted or looked up, and counting services while the registry is unreachable logs the failure and reports zero instead of failing (for example at startup).
- The REST access strategy calls its endpoint once per access decision, without retries, and waits at most 5 seconds for the response; an endpoint that does not answer in time denies access. It used to retry up to three times on errors and timeouts, holding the login for the duration.
- Groovy single sign-on participation policies and Groovy activation criteria for access strategies and attribute release resolve their script once, and again only when the script changes or expires from the script cache, instead of resolving its location and expressions on every evaluation.
- Service replication through Apache Kafka keeps one entry per service definition; an updated definition used to be stored next to its earlier versions.
- A service definition deleted on one node stays deleted across the cluster with service replication: the deletion marker is kept instead of being removed by the first node that applies it, so nodes that still have the definition remove it rather than sending it back. Deletions now also replicate through Apache Kafka, whose nodes used to drop the marker on arrival.
- With service replication through Apache Kafka, a node reads the replication topic from the beginning when it starts, so it receives the service definitions that other nodes loaded before it joined; it used to rely on every node sending all definitions again on every reload.
- With the services cache turned off (
cas.service-registry.cache.cache-sizeset to0), listing services no longer re-indexes every service it reads, which also made the next service lookup read the whole service registry again. - The deprecated Azure CosmosDb service registry is removed, along with its settings. Definitions stored there should be exported and imported into another service registry.
Tickets & Sessions
- CAS 2.0 proxy validation responses list each proxy of a chain once; a ticket obtained through several proxies listed each of them as many times as there were proxies.
- New deployments of CAS, and upgrades to a new CAS version, should always start with a clean JPA ticket registry table: drop the existing table and let CAS create it. Schema updates do not change the type or length of an existing column, and this version changes several of them.
- With PostgreSQL, the JPA ticket registry
stores ticket attributes as
jsonb, and session lookups by attribute, as in delegated OpenID Connect and SAML2 logout, can be answered by a GIN index instead of reading every session. The index is not created by CAS: the administrator must create it once after the ticket table is created, with the statement on that page. A table created by an earlier version keeps ajsoncolumn, on which those lookups fail; start with a clean table or convert the column. - The JPA ticket registry stores when each
ticket expires, including its idle timeout, and indexes it, and the ticket registry cleaner
asks only for tickets whose time has passed, with a full scan at startup and hourly; it used to read and decode
every ticket on every run. With MySQL, the registry streams scans through a server-side cursor (
useCursorFetch) and leaves single-ticket lookups as they were; the defaults can be overridden withcas.ticket.registry.jpa.properties. - Looking up sessions by attribute in the JPA ticket registry no longer fails on MySQL when the caller runs outside a transaction, as delegated OpenID Connect and SAML2 logout do. Reading sessions and tickets without a transaction no longer fails on PostgreSQL or MySQL either, as the single sign-on sessions and ticket registry endpoints, the MCP server tools, JMX, OAuth token management and deferred verifiable credential issuance do; outside a transaction the registry reads the matching tickets in one of its own. Listing every ticket over JMX or every OAuth token through the management endpoint reads the registry in batches instead of loading all of its tickets first, and the JMX ticket count is a single count query rather than a read of every ticket. Updating a ticket encrypts it once instead of twice when ticket encryption is turned on.
- The JPA ticket registry updates a ticket with a single statement instead of reading the row back first, no longer deletes service tickets twice when a session ends, pages ticket listings in the query instead of reading and skipping the rows before the page, and reads tickets without keeping copies of them for change tracking. Session queries by attribute bind the attribute values as parameters.
- With MySQL, the JPA ticket registry declares shorter
type,principal_idandparent_idcolumns so that its indexes fit MySQL’s key length limit; until now MySQL refused every one of them. Existing tables need the statements listed on that page. The index on the ticket type alone is gone on all databases. - With the stateless ticket registry, device codes keep their requested scopes, so tokens issued for an approved device code carry them; the scopes used to be dropped.
- The compact form of tickets kept by the stateless ticket registry now carries the resources of OAuth codes, access tokens, refresh tokens, device codes and pushed authorization requests, and the audience of exchanged access tokens; its format version changes: tickets and tokens issued before the upgrade can no longer be read, so users sign in again and clients obtain new tokens.
- The deprecated Azure CosmosDb ticket registry is removed, along with its settings. Deployments that still use it should switch to another ticket registry.
- A logout request now looks up its
serviceparameter once for all the steps of the logout flow, where every step, and every single logout protocol in use, used to look it up again. Redirecting logout to the service looks it up once more, and only whencas.logout.follow-service-redirectsis turned on. Logout requests that name unknown services, such as those sent by crawlers, cost far less.
OAuth & OpenID Connect
- Front-channel logout requests now carry the same
sidas the ID token and the back-channel logout token; the session identifier used to be computed differently, so applications could not match it to the session they had recorded. - Access tokens issued as JWTs can be revoked through the revocation endpoint, and refresh tokens issued as
JWTs can be redeemed with the
refresh_tokengrant; both used to be looked up in the ticket registry without being decoded first, so revocation silently did nothing and the refresh request was refused. - JWT access tokens are no longer signed with keys from the application’s own
jwksthat are marked for encryption ("use": "enc"); when the application publishes only encryption keys, CAS signs with its own keys.jwtAccessTokenSigningAlgis honored as documented: CAS picks a signing key whose type fits the algorithm, and the key’s own algorithm only applies when none is configured or the configured one does not fit the key. Signatures made with an EC (ES*) or RSA-PSS (PS*) key are randomized, so such a token is a different string each time it is encoded; the ID token’sat_hashis computed over the access token the response carries. - OAuth relying parties
may request access tokens for specific resources with the RFC 8707
resourceparameter, limited to the resources listed in the service definition’sallowedResources, with authorization and pushed authorization requests, device authorization and CIBA requests, and the password, client credentials, JWT bearer and pre-authorized code grants. Other resources are refused withinvalid_target. Requested resources are added to the access token audience. Redeeming a code or refresh token may narrow the access token to some of the granted resources, while the refresh token keeps them all. A token exchange issues tokens for its own audience or resource only, without the resources of the exchanged token. In request objects,resourcemay be a single value or a list. The consent screen lists the requested resources, and a remembered consent decision covers only the resources it was given for. Resources can be defined in the Palantir service wizard. - The
allowedResourcesof a service definition and of its token exchange policy are regular expressions with the same rule: every requested resource must match one of them in full, case-sensitively. The token exchange policy used to accept a request when any one of its resources was found by any pattern. A token exchange is also checked against the service’s ownallowedResourceswhen the service defines them. - Resources every client may request
can be listed with
cas.authn.oauth.core.allowed-resources, in addition to theallowedResourcesof each service. CAS allows its own MCP server endpoint by default, so that clients registered dynamically, which cannot list resources themselves, may request access tokens for it.checkOidcClientResourcereports whether the client or this setting allowed a resource. - OpenID Connect clients may identify themselves with
client ID metadata documents, as MCP clients do:
the client id is an HTTPS URL whose JSON document CAS fetches, checks and registers, refreshes when its cache lifetime ends
and removes once unused. Documents are only fetched from public addresses, without redirects and up to 5 KB, and these
clients always see a consent screen that names the host of the client id. Turned off by default; enable it with
cas.authn.oidc.registration.client-id-metadata-document.enabled=true. - The keys of an OpenID Connect application defined inline as JSON, as registered through
OpenID Federation or dynamic client
registration, are taken as they are; only keystore locations support
Spring expressions. OpenID Federation relying parties
that publish their keys at a URL other than
httpsare not registered. - OpenID Connect applications whose keys change no longer keep being checked against the keys cached for their earlier definition until that cache expires.
- Unsigned JWTs, whose algorithm is
none, are no longer supported: CAS neither issues nor accepts them. Request objects, including those encrypted without being signed, are refused withinvalid_request_object; subject and actor tokens of a token exchange, risk verification tokens and QR authentication tokens must be signed. JWT access and refresh tokens, JWT service and ticket-granting tickets and JWT authorization responses that would be neither signed nor encrypted are refused rather than issued, so deployments that turn off both must turn on signing. ID tokens are always signed: thesignIdTokenfield of OpenID Connect applications is removed, from the Palantir service editor and MCP client summaries too, and ignored in existing definitions, so applications that turned it off now get signed ID tokens; applications that ask fornoneare refused, and dynamic registration refusesnonewithinvalid_client_metadata.noneas the user info signing algorithm means a plain JSON response, and user info that is only encrypted is signed first; JWT introspection responses are always signed, with the default algorithm when none ornoneis set;noneas an encryption algorithm means no encryption; UMA requesting party tokens are signed with their keystore. Discovery no longer advertisesnonefor ID tokens, user info, introspection, request objects or backchannel authentication requests, even when configured, for example withcas.authn.oidc.discovery.id-token-signing-alg-values-supported. The CAS command-line shell only generates signed JWTs: its JWT commands refuse to run without a signing algorithm and secret size, or without a keystore. - A request object whose
client_iddiffers from theclient_idparameter of the request is refused withinvalid_request_object, as OpenID Connect requires, instead of being used for the client it names. - DPoP proofs are remembered as used for as
long as their
iatkeeps them acceptable, not only for the lifetime of transient session tickets. - Encrypted request objects
now work: CAS decrypts them with the encryption keys it publishes in its JWKS (any rotation state, chosen by
kid) and verifies the nested request object with the client’s keys; before, it tried the client’s own keys and every encrypted request object failed, OpenID Federation relying parties included. Discovery no longer advertises algorithms CAS cannot decrypt with:cas.authn.oidc.discovery.request-object-encryption-alg-values-supportednow defaults toRSA-OAEP,RSA-OAEP-256and theECDH-ESfamily, withoutRSA1_5and symmetric key wrapping.RSA1_5is never accepted nor advertised, even when listed, and the encryption keys are read from the keystore once per JWKS cache period instead of for every request object, and again as soon as the node sees the keystore change or rotates or revokes its keys; signing keys are never used to decrypt. - Elliptic curve keys that CAS generates for its
OpenID Connect keystore carry the signing algorithm of their
curve. P-256 keys used to be tagged
ES512, which the JWKS published and which made signing with them fail, and a key size of521produced P-256 keys instead of P-521. Existing keystores are corrected as they are loaded, without new keys, encryption keys no longer carry a signing algorithm, and a configured signing algorithm only selects an elliptic curve key of the matching curve. - An authorization request whose request object cannot be decrypted or its signature verified
is refused with
invalid_request_object, as OpenID Connect requires. CAS used to ignore such a request object and carry on with the query parameters alone. Request objects signed withHS256,HS384orHS512are verified with the client secret of the application, which is checked for expiry and decoded as when the application authenticates with it; one that names no registered client or verifies with none of its secrets is refused the same way instead of failing with a server error. Backchannel authentication requests whose request object cannot be verified, or is for another client, are refused withinvalid_requestinstead of being answered from their other parameters. Signed backchannel authentication requests must be signed with an asymmetric algorithm, name the client as their issuer, be addressed to the CAS issuer and carryexp,iat,nbfandjti, as CIBA requires; they may not be issued in the future, may be valid for 60 minutes at most and are used once. They are verified with the keys of the client that authenticated the request, also when the request names noclient_id, and refused when CAS does not support the request parameter. - Dynamically registered
OpenID Connect clients, and OpenID Federation
relying parties registered automatically, have their redirect URIs matched exactly, case included. Dynamic registration used to join
them into a pattern where
.matched any character, so look-alike hosts matched, and?was not literal, so a redirect URI with a query never matched; automatic registration joined them so that relying parties with two or more redirect URIs never matched. Clients registered dynamically before keep their pattern until they update their registration. - Pairwise subject identifiers of
clients that CAS registered, dynamically or through OpenID Federation, without a sector identifier URI use the host of
their first redirect URI, as before. When their redirect URIs name no host, as with native applications, each client is
now its own sector; such clients used to share a single sector, so their users receive new identifiers. OpenID
Federation relying parties that ask for pairwise identifiers now receive them; they used to receive the plain user id.
Clients whose definition carries no salt of their own, which includes clients that CAS registers, calculate them with
cas.authn.oidc.core.pairwise-subject-salt, read when they are used and never written into client definitions; without it, federation relying parties that ask for them are not registered, and clients registered dynamically are each given a random salt kept with their registration, where they used to get one that changed with every restart. Clients registered dynamically before keep such a changing salt until the setting is defined or they update their registration. Clients that ask for pairwise identifiers with redirect URIs on several hosts must register a sector identifier URI, which must be anhttpsURL that can be fetched and lists all of their redirect URIs; the sector identifier URI of a federation relying party is fetched and checked the same way. For clients that CAS registers, onlyhttpandhttpsredirect URIs on hosts other than loopback ones give a sector host; any other redirect URI, such as the private-use scheme of a native application or a loopback redirect URI, puts the client in a sector of its own, its client id, whatever it names, so clients registered by CAS with such redirect URIs receive new identifiers, and mixing both kinds needs a sector identifier URI. Clients registered dynamically before keep the sector they had until they next update their registration, which then gives them the sector described here, and so new identifiers, even when their redirect URIs stay the same. Clients defined by hand keep the host read from their service id; those whose service id names no host, such as^https?://app.example.org/.*, in which the?ends what is read as the host, or whose sector identifier URI names no host, used to share one sector, and are now each a sector of their own and receive new identifiers. A service id whose host is a pattern, such as^https://.*, gives that pattern as its sector; without a salt of their own, such clients used to get a salt that changed with every restart, and with the setting above they now share identifiers. Sectors are read the same way when clients register and when identifiers are calculated, and anhttporhttpsredirect URI whose host cannot be read is refused. Sector identifier documents of dynamically registered clients are fetched from public addresses only, without redirects or retries, within a limited time and size, and must be valid JSON, whatever type they are served as. A client configuration update that is refused now leaves the client as it was and is answered withinvalid_client_metadata, and an update keeps the generator of pairwise identifiers the client has. - Pushed authorization requests are
accepted again when verifiable credentials are
turned on; CAS answered them with
401as if they needed a single sign-on session. A wallet that pushes its authorization request now receives the credentials named by theauthorization_detailsit pushed; CAS issued the authorization code without them. Authorization details that cannot be granted are refused withinvalid_authorization_detailswhen they are pushed, instead of after the redirect to the authorization endpoint. - Pushed authorization requests that
fail validation are answered with
400and the actual error, such asinvalid_request_objectorunsupported_response_type, as RFC 9126 requires, instead of403with a genericinvalid_request. When pushed authorization requests are required, an authorization request without one is refused at every path of the authorization endpoint, including encoded ones and the OAuth path under the OpenID Connect base path. Endpoints that require client or token authentication now recognize their paths with path parameters, such as;x=y, too. - The
audof a token introspection response is the audience of the JWT access token: the serviceaudience(or the client ID) and the token’s resources, or the audience requested by a token exchange. It used to be the service URL the token was issued for. Custom introspection response generators now receive the registered service of the client. - OAuth/OpenID Connect clients are held to what they registered. They authenticate with their
registered method, and only as the client the request names, at the token endpoint and also for
pushed authorization,
backchannel authentication, revocation and
verifiable credentials; an access token no longer
authenticates a client. Clients that use mutual TLS
must register the subject DN or a subject alternative name of their certificate, unless their client id is exactly the
certificate’s SPIFFE ID; a subject DN written
as a regular expression must now match the whole subject, as
CN=([^,]+),O=Example,C=USdoes. User profiles keep every value of a multi-valued attribute, and thecas.authn.oauth.csrf-cookiesettings are removed since CAS no longer issues that cookie. - The page where users approve a device user code
now carries an approval token tied to the single sign-on session, and an approval without it is refused, so another site
can no longer make a signed-in browser approve a code. Customized
protocol/oauth/deviceCodeApproval.htmltemplates must add the hiddenapprovaltokeninput of the default template to their form. The error messages of the page are now defined, undercas.oauth.device.error.*. - OAuth/OpenID Connect follow the specifications more closely.
Sender-constrained access tokens always require their proof,
prompt=loginandmax_age=0request parameters always lead to a fresh login andprompt=nonetologin_required, authorization requests keep all their parameters through login and consent, and refused requests receive the error and challenge the specifications call for instead of a server error. OpenID Connect JWT access tokens no longer fail to sign now and then under load. - Access strategies of OAuth/OpenID Connect
applications see the attributes of the authentication, such as
clientIpAddress, at the authorization endpoint and when a code issued from a single sign-on session is exchanged for tokens, as they do for CAS applications. They used to see only the attributes of the principal there, so a strategy that relied on an authentication attribute refused access. - OAuth/OpenID Connect endpoints no longer send the
X-XSS-Protectionheader, which browsers ignore. Only theX-Requested-With: XMLHttpRequestheader now marks a script request that is answered with401instead of a redirect to the login; theis_ajax_requestheader and parameter are no longer recognized. - OpenID Connect logout no longer
follows any
post_logout_redirect_urisent along with aclient_id. The URI must match the client of the ID token hint, one of its logout URLs, or a registered service; otherwise the session ends without a redirect. An ID token hint that is not a JWT, names no registered client or whose signature cannot be verified is answered with400instead of a server error.
OpenID Federation
- OpenID Federation
relying parties registered automatically must prove they control their keys. Every authorization request, on the
OpenID Connect or the OAuth authorization endpoint, wherever they answer and however their path is encoded, carries a signed request object addressed to the CAS issuer, valid
for 10 minutes at most and used once, or refers to a pushed authorization request for which the relying party
authenticated itself; the proof is for the client the request is actually for, taken from the request object when the
request has no
client_id; at the pushed authorization endpoint, a client assertion must be addressed to the CAS issuer only. Requests that fail are refused without a redirect. Entity identifiers must behttpsURLs, relying parties authenticate withprivate_key_jwtortls_client_auth, client assertions may be addressed to the issuer, and relying parties are registered before client authentication, so a pushed authorization request can be the first contact. The end-to-end federation scenario runs against the go-oidfed OFFA relying party. - An OpenID Federation
OpenID provider trusts the trust anchors defined with
cas.authn.oidc.federation.trust-anchors, with their keys obtained out of band, instead of treating its authority hints as trust anchors and taking their keys from whoever answers; without trust anchors, the authority hints are still used, with a warning. Trust chains are resolved within bounds,cas.authn.oidc.federation.max-authority-hintsauthority hints per entity andcas.authn.oidc.federation.max-path-lengthintermediates, and an entity that could not be resolved is not resolved again forcas.authn.oidc.federation.unresolved-entity-retention, during which a registration that failed to refresh is kept. Each resolution sends at mostcas.authn.oidc.federation.max-requests-per-resolutionrequests (50), reusing statements it already fetched, withincas.authn.oidc.federation.resolution-timeout(10 seconds) all requests together, with responses limited in size, the TLS settings of CAS and no redirects; at mostcas.authn.oidc.federation.max-concurrent-resolutionsresolutions (10) run at once. The time limit covers each whole request, host name lookup and TLS handshake included, and requests are only sent overhttpsand never to link-local, unspecified or multicast addresses, IPv6 forms included, unless a proxy of the JVM resolves them: an HTTP proxy, or a SOCKS proxy for host names CAS cannot resolve. A trust anchor that cannot be reached, answer in time or answers with a server error, or whose historical keys cannot be read, a sector identifier document that cannot be fetched for now, and a resolution that runs out of time or requests or finds no room among the running requests make the resolution unavailable rather than failed, so the relying party is not remembered as unresolved; a relying party that is not registered yet is then answered withtemporarily_unavailableinstead of as an unknown client. Using a trust chain the relying party sent and resolving its trust chains share one time limit and request budget. The constraints of subordinate statements (maximum path length, naming constraints, allowed entity types) now apply to the trust chains of relying parties and of their trust mark issuers; they used to be ignored. A maximum path length must be a whole number that is not negative. - Application keys published at a URL are no longer requested at link-local, unspecified or multicast addresses, and redirects are not followed, so keys published behind a redirect must be published at their final location. The OpenID Federation keystore is replaced at once when it changes, so it is never read half written, keeping its permissions and any symbolic link to it. A keystore that holds no keys is given new ones, and one that cannot be read stops CAS from starting, where CAS used to sign with keys of its own on each node and restart, kept nowhere.
- A CAS OpenID Federation
trust anchor or intermediate issues subordinate statements that carry only the subordinate’s keys, its metadata
without the fetch, list and trust mark status endpoints, and the
constraintsof its definition rather than a fixedmax_path_length; statements are valid to the second, so lifetimes under a day work. The fetch endpoint answers unknown subordinates with404 not_foundand other failures, such as malformed metadata policies in a subordinate definition, with JSON errors, the listing filters byentity_type, matching the entity types a subordinate definition lists or else those of its metadata, and byintermediate, and an issuer defined with a trailing slash is used without it as the entity identifier. - The OpenID Federation
entity configuration of a CAS OpenID provider that issues verifiable credentials also describes it as
openid_credential_issuerandoauth_authorization_server, so federation-based wallets can trust the credential issuer through its trust chain. Trust marks issued to CAS, defined withcas.authn.oidc.federation.trust-marks, are published astrust_marks. Discovery advertisesclient_registration_types_supportedonly when CAS is a federation OpenID provider, and the delegated relying party entity statement endpoint answers404for an unknown client instead of an empty page. - OpenID Federation metadata policies:
a CAS trust anchor or intermediate publishes the metadata policies of its subordinates, along with the operators they
mark critical, and no longer requires metadata in subordinate definitions. A CAS OpenID provider resolves the metadata
of relying parties as the specification describes: the metadata their superior states about them comes first,
operators beyond the standard ones are ignored unless marked critical,
scopeis handled as a list, and superiors can only shape entity types the relying party publishes itself. Relying parties whose metadata names noapplication_typeare registered aswebapplications; their registration used to fail. Relying parties without redirect URIs are not registered, and post-logout redirect URIs that contain a comma are left out. - An OpenID Federation
relying party can send its trust chain in its request object or client assertion, which CAS verifies and uses instead
of resolving the relying party, provided it is not older than the current registration and the request is signed with
the keys it carries. A relying party that rolls its keys over is no longer refused until its registration expires: a
request object or client assertion signed with a key its registration does not hold has CAS resolve it again, at
most once per
cas.authn.oidc.federation.unresolved-entity-retention. - An OpenID Federation
OpenID provider can require trust marks of the relying parties it registers automatically, listed with
cas.authn.oidc.federation.required-trust-marks. Each trust mark is checked against the issuers that the trust anchor’s own entity configuration accepts intrust_mark_issuers, verified with its issuer’s keys through the issuer’s own trust chain, its delegation checked when the trust anchor names an owner of the type, and its status asked of the issuer when it publishes a status endpoint, which must be anhttpsURL. A trust mark that cannot be checked for now leaves the relying party unregistered for now, unless another trust mark of its type is valid and no required type is missing. A CAS trust anchor publishes the issuers it accepts, defined withcas.authn.oidc.federation.trust-mark-issuers. - CAS can act as an OpenID Federation trust mark issuer
in any role: the trust mark types it issues and the entities each is issued to are defined with
cas.authn.oidc.federation.issued-trust-marks, and CAS publishes the trust mark, trust mark status and trust marked entities listing endpoints. Removing an entity from a type revokes its trust marks of that type. A trust anchor also publishes the owners of delegated trust mark types, defined withcas.authn.oidc.federation.trust-mark-owners. Trust mark requests can be authenticated withprivate_key_jwtby subordinates, which then only obtain their own trust marks, optionally or always, usingcas.authn.oidc.federation.trust-mark-endpoint-authentication; only signing algorithms CAS can verify are advertised for them. - A CAS OpenID Federation
trust anchor or intermediate publishes a resolve endpoint, which returns the resolved metadata, trust chain and valid
trust marks of an entity for a trust anchor it trusts, as a signed resolve response. Resolutions and entities that
could not be resolved are remembered for at most
cas.authn.oidc.federation.unresolved-entity-retention; a trust mark that cannot be checked for now is left out of the response, which is then not remembered. Resolve requests can be authenticated withprivate_key_jwtby subordinates, optionally or always, usingcas.authn.oidc.federation.resolve-endpoint-authentication; the response is then addressed to the requester. - OpenID Federation keys roll over:
the federation keystore holds current, future and previous keys, all published in the entity configuration, rotated
and retired on a schedule (
cas.authn.oidc.federation.rotation.schedule.enabled,cas.authn.oidc.federation.revocation.schedule.enabled) or through the newoidcFederationJwksactuator endpoint, which can also revoke a key, for instance when it is compromised. Retired and revoked keys are published by the new federation historical keys endpoint. A scheduled rotation or revocation only changes keys that are old enough, at half the time between two runs of its schedule, so it does not run again after a restart, and nodes that share the keystore file read it again when it changes; in a cluster, the schedules are best enabled on one node. Keys are changed on copies and used only once saved. New keystores start with a future key; existing single-key keystores keep working, and published keys carry the algorithm they sign with, matching the key’s curve. A CAS OpenID provider does not use trust chains whose statements do not name their signing key, or that the trust anchor signed with a key it has revoked or had retired before, as the historical keys it publishes overhttpsshow; they are read through the entity configuration fetched from the trust anchor, never one a chain carries, and a trust anchor whose historical keys cannot be checked is not trusted. Trust marks signed with a key that is retired but not revoked remain valid until they expire. - CAS as a verifiable presentation verifier
can identify itself to wallets with the OpenID4VP
openid_federationclient identifier prefix, chosen withcas.authn.oidc.vc.presentation.client-identifier-prefix=OPENID_FEDERATION: the client identifier is the entity identifier of CAS, request objects are signed and named bykidand carry no client metadata, and wallets read theopenid_credential_verifiermetadata (keys, response URI, formats) from the CAS entity configuration through its trust chain. Encrypted responses then use the encryption keys of the OpenID Connect keystore (ECDH-ESorRSA-OAEP-256), in any rotation state, instead of a key per request. Request objects under any prefix are now signed with the algorithm of the signing key’s curve (ES384,ES512), no longer alwaysES256.
Model Context Protocol (MCP)
- The MCP server reports the audience and allowed
resources of OAuth and OpenID Connect clients, and the new
checkOidcClientResourcetool tells whether a client may request a resource, which allowed expression it matches or why it would be refused, and the audience of the token. - The MCP server accepts OAuth access
tokens issued by CAS, alongside Basic authentication. It publishes RFC 9728 protected resource metadata that names CAS as the
authorization server, challenges unauthenticated clients with both
BearerandBasic, and accepts a token only when it was issued for the MCP endpoint with themcp:readscope to an application that is still allowed. TheMCP_ADMINrole comes from the principal attributes listed incas.mcp.oauth.required-attributes, resolved for the person when the token is used rather than taken from the attributes released to the client; they match nobody by default, and the audit record of a call names the OAuth client. TheAI.mcp-oauthfeature toggle turns it off. - The MCP server can offer
tools that change CAS: end the single sign-on sessions of a person with single logout, release throttled logins, turn an
application on or off, change a log level, revoke OAuth tokens and consent decisions, and remove trusted devices,
one-time password devices and WebAuthn devices. They are turned off by default, are turned on with the
AI.mcp-writefeature toggle, and require the newMCP_OPERATORrole. With an OAuth access token, that role also requires themcp:writescope and the principal attributes listed incas.mcp.oauth.operator-required-attributes, which match nobody by default.
Attribute Release
- The pattern matching attribute release policy no longer releases the transformation template itself for values that do not match the pattern; such values are dropped, and the attribute is not released when none of its values match, as the inline Groovy transformation already did.
- The return linked attribute release policy releases the values of the first linked attribute that has a value, as documented; it used to release the last one.
- SAML2 attribute release policies that match metadata entity attributes, entity categories included (InCommon and REFEDS Research and Scholarship, anonymous, pseudonymous and personalized access), accept entity id patterns: a service provider whose metadata does not carry the entity attribute still receives the attributes when its entity id matches one of them. The Palantir service wizard can edit these patterns.
Authentication and Session Security
- The SAML2 identity provider, OAuth/OpenID Connect, UMA, Heimdall, JWT authentication and Duo Security no longer depend on pac4j, which remains only in delegated authentication and the features that hand off to it, such as passwordless authentication and ADFS integration. They are built on Spring Security and CAS components and keep their session state in a CAS session store, in the http session, in browser storage or in the ticket registry as configured. Customizations, Groovy scripts and session store beans that use pac4j types must be updated, and authentication handler names recorded in audit logs no longer carry pac4j class names. OAuth/OpenID Connect sign-ins and pushed authorization requests that are under way during the upgrade must start again. SAML2 requests passed on to SAML2 identity providers keep their forced and passive authentication, authentication contexts and scoping.
- JWT authentication takes the subject
of a token as the principal as it is, and every other claim as an attribute. Tokens built with pac4j, whose subject
carries a profile type such as
org.pac4j.core.profile.CommonProfile#casuser, now sign in as that whole subject and must be issued again with a plain one. A service without a signing secret no longer accepts any token. ThetokenAuthactuator endpoint no longer issues tokens: it validates one and answers the principal and the identifier, name and service id of the service, never its properties or secrets. - When the SAML2 identity provider
or Duo Security keep their session state in browser storage,
the browser receives only the state of that flow rather than every attribute of the http session, and the state
expires with the lifetime of transient session tickets (
cas.ticket.tst.time-to-kill-in-seconds). A state that has expired or belongs to another flow restores nothing; sign-ins under way during the upgrade must start again. - Signing and encryption of values such as tokens and cookies now report a failure to sign, verify or encrypt a value instead of continuing without that step. A JSON web key that carries only a public key can now be used as a signing key to verify signatures produced elsewhere.
- CSRF protection is configured once for all modules, so OpenID Connect and
WebAuthn no longer override each other’s settings, and the
backchannel authentication verification page is now protected.
A custom CSRF token repository is defined once, as the
casCsrfTokenRepositorybean. - Google Authenticator scratch codes are
compared by their exact value, and a stored scratch code that cannot be decrypted is ignored instead of being used as
it was stored. With scratch codes encrypted (
cas.authn.mfa.gauth.core.scratch-codes.encryption.key), the REST registration store no longer loses precision when reading them back. Scratch codes that can no longer be decrypted, such as codes stored under another key, stop working; users can generate new ones from the account profile. - A login request that carries both
renewandgatewaynow shows the login form, as the CAS protocol recommends, instead of returning to the application without a ticket. When renewed authentication is turned off withcas.sso.renew-authn-enabled, thegatewayparameter is honored as before. - The
throttlesactuator endpoint of authentication throttling can return only the throttled records of one username, matched regardless of case, instead of every record.
SAML2
- The ECP profile answers a successful login with the SAML2 response in the SOAP envelope again, instead of a SOAP fault.
- Back-channel SAML2 logout with the SOAP binding sends the SOAP envelope as the body of the request, instead of a URL-encoded copy of it.
- A
nameIdQualifierorserviceProviderNameIdQualifierset tononeon a SAML2 service leaves that qualifier out of the NameID, as documented, instead of sending the valuenone. - The attribute query profile releases the attributes its release policy allows; the policy could not find the metadata of the service provider for a query and released none of them.
- For unsolicited SSO,
the SAML2 identity provider no longer signs the authentication request it builds itself, nor checks it for a signature,
and the
signUnsolicitedAuthnRequestsetting of SAML2 service definitions is removed. Unsolicited SSO also works when the session state is kept in browser storage. Delegated authentication no longer reloads the metadata of a SAML2 identity provider for each request. - SAML2 service provider metadata
that cannot be resolved is no longer retried with one-second pauses during the request, and a failure to load it is
remembered for
cas.authn.saml-idp.metadata.core.failure-cache-expirationinstead of contacting the metadata source on every request. Metadata query servers keep one backup per entity, so an entity no longer falls back onto the metadata of another, and metadata stores such as JPA or MongoDB are cached per entity, so providers that share a service definition no longer evict each other’s metadata. Changes to the metadata settings of a service definition take effect on the next request on every node, and checking whether the JPA metadata store is available no longer opens a new connection pool each time. - SAML2 identity provider metadata,
keys and certificates are fetched again from their storage once
cas.authn.saml-idp.metadata.core.cache-expirationhas passed, even while in constant use, so a key rotation in a shared metadata store reaches every node. - SAML2 service provider metadata downloaded over HTTP or from a metadata query server is fetched with conditional requests, and an unchanged document is no longer downloaded again. Comma-separated locations are all tried before the metadata backup file is used, and a failed load names every location and the reason it failed, in the logs and in the answer of the cached metadata endpoint. Validators are kept in a file next to the backup instead of an extended file attribute, which many file systems do not support.
- Service provider metadata kept in Amazon S3
is no longer downloaded in full to find one provider: only matching documents are fetched, and buckets with more than
1000 documents are read completely. Metadata kept in Git
pulls the repository at most once per
cas.authn.saml-idp.metadata.git.schedule.repeat-intervalinstead of on every load. The metadata health indicator checks each metadata source once per run rather than once per service. - SAML2 service provider metadata
read from files, directories or the JSON metadata file is loaded again once a file changes, checked at most once per
cas.authn.saml-idp.metadata.file-system.change-detection-interval. The cached metadata endpoint lists statistics and entries of the metadata cache, including the failures it remembers, and reports whether each entity is still valid; the cache statistics are also published as metrics. A metadata backup file that its source has not confirmed for longer thancas.authn.saml-idp.metadata.http.metadata-backup-max-ageis logged as an error when used and flagged by the metadata health indicator. Metadata criteria patterns are compiled once per load, metadata signature certificates are downloaded once per load, and downloaded metadata is no longer copied as text. - Cached SAML2 service provider metadata
is loaded again once its
validUntilpasses, and acacheDurationdeclared by the metadata is kept betweencas.authn.saml-idp.metadata.core.minimum-cache-durationandcas.authn.saml-idp.metadata.core.maximum-cache-duration. A request for an entity that an aggregate does not hold no longer walks every entity of the aggregate. Metadata resolvers returned by Groovy scripts that run background tasks are destroyed once no longer used. Metadata kept in Redis is indexed by entity, so a service provider is found without scanning every key. A metadata query location given as an expression, or as one of several comma-separated locations, is cached per entity like any other. - SAML2 identity provider metadata is cached once for all services that have no metadata of their own, instead of once per service, so deployments with many SAML2 services no longer read identity provider metadata from its storage on every response.
- SAML2 identity provider metadata
is served as
application/samlmetadata+xmlwhen asked for, carries anETag, and answers304 Not Modifiedto a client that already holds it. - A signed SAML2 attribute query is answered with the SOAP response alone. The identity provider also wrote the POST-binding form of the response before it, so the service provider received an HTML page and the SOAP response could not be sent.
Authentication Interrupts
- Interrupt inquirers no longer receive the Spring Webflow request context, so they can be asked outside the login flow. Custom inquirers must drop that parameter, and Groovy interrupt scripts now receive the logger as their fifth argument: scripts that read the sixth argument or destructure six arguments must be updated. The REST strategy still passes the language preferences of the current request along to the interrupt endpoint.
- The new
interruptsactuator endpoint determines the interrupt payload produced for a user, optionally signing in to an application: it asks every interrupt strategy in order and reports what each one produced, or why it failed, along with the interrupt the login flow would present.
User Interface
- When password management is turned off, the login page no longer links to
https://pwd.example.org; the address of an external password recovery page is set with thecas.pm-links.forgot-password.urltheme property, and nothing is shown when it is blank. - Date fields in the Palantir service wizard open a calendar to pick from: the expiration date, client secret expiration dates, and the start and end of a time-based access strategy, which take the start and the end of the picked day. Values of the access strategy types (remote, HTTP request, time-based and others) and of the proxy and token exchange policies now reach the generated definition; they used to be left out.
- Generated passwords on the password update form and client secrets generated in Palantir use the browser’s cryptographic random number generator. WebAuthn no longer shows the session token after authentication, and the account unlock page only blocks the context menu on the captcha.
- Browser storage pages show their error panel when progress display is turned off, instead of leaving a blank page.
- Labels and messages that were written in English inside templates and scripts (generic success page, logout confirmation, error pages, QR code login, WebAuthn progress, attribute consent, interrupts, delegated profile selection, impersonation, device code approval, account profile and sign-up dialogs) now come from message bundles.
- Turning on CAS login for Palantir no longer sends other protected endpoints, such as actuator endpoints and the MCP server, to the CAS login page; they challenge for their own credentials again, as API clients expect, and only Palantir redirects to CAS.
Multifactor Authentication
- The device fingerprint
of trusted devices includes the client IP address by default, as documented; it was only used when
cas.authn.mfa.trusted.device-fingerprint.client-ip.enabledwas set explicitly. Devices trusted before the upgrade are asked for multifactor authentication once more; set that setting tofalseto keep the previous fingerprint. - The browser fingerprint that the login form collects is kept for the rest of the multifactor flow, so a device trusted while that fingerprint is part of the device fingerprint is recognized at the next login.
- The Google Authenticator registration QR code includes
digitsandperiodwhencas.authn.mfa.gauth.core.code-digitsorcas.authn.mfa.gauth.core.time-step-sizediffer from the defaults, so authenticator apps generate codes CAS accepts. - Principal attribute triggers per application can map each multifactor provider to a pattern for the attribute values, so the service definition alone decides which provider a user is sent to; Palantir can edit these mappings.
- Custom multifactor authentication triggers register their event resolvers by tagging the resolver bean with an annotation; CAS collects tagged resolvers on its own, and resolvers no longer add themselves to the initial authentication event resolver. Custom resolvers, and beans that override a built-in trigger resolver, must carry the annotation.
- YubiKey accounts kept in a JSON file are written to a temporary file that then replaces the JSON file in one step, so a failed or concurrent write no longer leaves a truncated file behind that stops CAS from starting; removing a single device no longer fails a change made at the same time.
Documentation
- The SPNEGO settings explain that
cas.authn.spnego.properties[0].jcifs-service-passwordis only used whencas.authn.spnego.system.use-subject-creds-onlyistrue(otherwise the service keys come from a keytab), and that setting both the Kerberos KDC and realm makes the JDK ignore the Kerberos configuration file. - Setting lists show default values in full instead of cutting them off; where a list is narrow, the value moves to a second row under the setting name. Each setting in the configuration catalog also has a Copy link button.
- Every page of the documentation has a Markdown copy at the same address ending in
.md, which the page toolbar copies to the clipboard, and each version publishes anllms.txtindex of its pages for AI assistants and other tools. - The new Configuration Properties Changes page lists the CAS settings added, removed, replaced or given a new default since the previous version, generated from the configuration catalogs and also published as JSON.
Other Stuff
Build & Project
- The vulnerability report of the dependencies endpoint follows OSV pagination for each dependency, so vulnerabilities past the first page of a result are no longer left out, and vulnerability details that cannot be read are reported as errors instead of being dropped silently.
- A large number of dependencies and libraries have been updated to their latest versions.


