Wiring up Grails with Spring Security SAML for federated authentication

When Australian government agencies and ASX-listed companies open their identity stacks to partners, the conversation quickly turns to SAML 2.0. The Security Assertion Markup Language has been the lingua franca for browser-based single sign-on for two decades, and it still anchors the way locals sign in to things like myGov, the Australian Taxation Office portal, and most university learning management systems. Grails developers building internal portals, customer onboarding flows, or partner integrations often need to play in that same playground, which is where Spring Security SAML comes in. It rides on top of the same Spring extension point Grails already exposes, so the wiring feels less like translation work and more like a configuration exercise.

The goal of this piece is to walk through the moving parts of a working SAML federation in a Grails application. Rather than treating it as an academic tour of assertion formats, we will stay grounded in practical configuration, attribute handling, and a few patterns that turn out to matter when the deployment target sits in Australia. Along the way, we will look at where a hosted identity provider fits, how to keep metadata in sync, and what the local regulatory picture means for session handling in a production environment.

Why federated identity matters down under

The Australian government standardised on the SAML family a long time before OAuth became fashionable for citizen-facing services. myGov alone brokers millions of authentications a month into Medicare, Centrelink, the Australian Taxation Office, and state-based services, and every one of those hops carries a SAML assertion under the hood. Corporate Australia has followed a similar path: the big four banks, the major telcos, and most universities publish a SAML metadata feed so that staff and students can move between internal systems without a fresh password prompt every five minutes. For developers, that means requests often arrive already authenticated, and the job becomes trusting the assertion, mapping attributes, and deciding what to do when the user logs out.

A federated approach also reduces the surface area for credential handling. If your Grails app never touches a password, the Australian Cyber Security Centre's Essential Eight becomes considerably easier to argue for during procurement. Auditors tend to appreciate that the credential vault belongs to someone else, and that the only thing your service stores is a session token and a couple of mapped attributes. The cultural expectation in many Australian enterprise environments is that passwords live with the identity provider, not with individual line-of-business applications, which is a useful framing to keep in mind when writing the architecture section of a security control assessment.

Adding the dependencies

The Spring Security SAML plugin for Grails wraps the underlying Spring Security SAML2 stack, so the build configuration is mostly a matter of declaring the right artefact and resolving the transitive dependencies that come with OpenSAML. In a typical build.gradle file, that means adding org.grails.plugins:spring-security-saml alongside the core security plugin, then refreshing the dependency cache. Developers working inside corporate networks should be aware that the Shibboleth metadata aggregator sometimes requires outbound HTTPS to certificate hosts, and Australian proxies often need to be told about that explicitly before the first refresh succeeds.

Once the dependency is in, the next step is the metadata configuration. The plugin expects two feeds: one from the identity provider you trust, and one describing your service as a relying party. Most Australian institutions publish their metadata at a stable URL, and the cleanest approach is to point the plugin at that URL and let it refresh on a scheduled basis. If your test environment connects to the Australian Access Federation (AAF) test instance, you can usually hand the application a static file during development and switch to the live URL only once staging is wired up against the production federation operator.

Configuring the relying party

The relying party configuration defines how Grails presents itself to the identity provider. You will need an entity ID, an assertion consumer service URL, and a key pair for signing outbound requests. The convention in many Australian deployments is to use the application's fully qualified domain name as the entity ID, then to register that same value with the federation operators ahead of going live. The AAF, for example, has a registration process that takes a few working days, and getting ahead of it saves the inevitable last-minute scramble when a project deadline collides with a metadata refresh window.

In application.yml, the relevant section usually sits under grails.plugin.springsecurity.saml.relyingParty, and the values from your metadata file map almost one-to-one. The base URL needs to reflect the public-facing scheme; a service behind a reverse proxy on the AARNet network, or fronted by Cloudflare in front of an AWS Sydney region, will need care to ensure that the assertion consumer URL the provider sees matches what the application is actually expecting once TLS termination has happened further upstream in the stack.

Mapping SAML attributes to Grails authorities

Once assertions flow, the question turns into who the user is and what they are allowed to do. SAML attribute statements carry a richer set of facts than a username and password ever could: eduPersonAffiliation, schacHomeOrganisation, a persistent identifier, and any number of custom claims the federation operators have agreed to expose. Mapping those into Grails authorities is where the real policy decisions live. A typical pattern in Australian university settings is to translate eduPersonAffiliation values like faculty or student into role names, then layer on a course membership lookup from a downstream service.

The plugin exposes an SAMLAttributeMapping interface that lets you decide what happens with each statement. A good rule of thumb is to keep the mapping pure: never trust a display name for authorisation, and always derive anything security-sensitive from a stable, opaque identifier. If the federation operator offers a persistent NameID or an eduPersonUniqueId, use that as the local username and treat the rest as profile enrichment. The myGov environment goes further still, with Identity Federation attributes that map onto the Australian Government Information Security Manual, but the principle remains identical: keep identity stable, decorate with attributes, and let your policy engine do the rest.

Single logout and session lifecycle

Single logout is the part of SAML that causes the most operational grief, and Australian deployments are no exception. There are two flavours: front-channel logout, where the browser carries a logout request between participants through a series of redirects, and back-channel logout, where the identity provider makes a SOAP call directly to each service. Front-channel is simpler to configure but relies on the user having a browser session at each participant; back-channel is more reliable but requires that your service is reachable on a fixed endpoint that the provider can hit. Most Australian SaaS vendors that participate in federations will offer both, and the choice often comes down to whether the deployment sits behind a corporate firewall that blocks inbound SOAP calls.

Grails handles this through the standard Spring Security session management, but you will want to be careful about session fixation and CSRF tokens across the logout redirects. A common pattern is to invalidate the local session at AssertionConsumer time, then propagate the logout through the filter chain so that any downstream service you have called also sees the user as gone. The Australian Cyber Security Centre's guidance on session handling tends to encourage short timeouts and explicit logout, which fits neatly with SAML's own model and tends to align with internal audit expectations around dwell time on customer data.

Hosting and compliance in Australia

Compliance touches everything from the way you store assertions to where your reverse proxy sits. The Notifiable Data Breaches scheme means that if your SAML metadata or signing key leaks, you may need to assess whether an eligible data breach has occurred and notify the Office of the Australian Information Commissioner. Key material should therefore live in a managed secrets store rather than in a build artefact, and rotation needs to happen on a documented schedule. AWS Secrets Manager in the Sydney region, Azure Key Vault in Australia East, and HashiCorp Vault deployments sitting in an Equinix SY3 cage are all common options, and the choice usually depends on what your operations team already knows and supports on call.

There is also the question of data residency. Many Australian government contracts require that session metadata never leaves the country, which pushes deployments towards local regions and away from global endpoints. The ap-southeast-2 region in Sydney, and its younger sibling ap-southeast-4 in New Zealand, are the usual landing pads. If your application participates in a federation, you will also need to confirm that the identity provider supports the same geographic boundary, since assertion signing keys are sometimes cached at points of presence that may sit overseas and that can complicate the story during a security review.

Practical checklist for a clean rollout

The list below reflects the steps that consistently shorten a SAML rollout in Australian environments. None of them are groundbreaking on their own, but skipping any one tends to surface during the cutover window when the change board is watching.

Grails sits comfortably inside the SAML ecosystem once the Spring Security plugin is wired up, and the patterns above translate cleanly to anywhere the framework runs. The lessons learnt from myGov, the AAF, and the major banks amount to a fairly compact playbook: trust a stable identity, keep your keys close, log enough to investigate, and let the federation handle the rest. For developers who want to see the configuration end to end, walkthroughs and runnable code samples live over at grailsexample.net, which is the easiest place to start when the documentation feels a bit thin on examples. Roll the change out behind a feature flag, watch your authentication logs carefully for the first week, and lean on the federation operators when something looks off. They have seen most of the ways this can go wrong before, and a quick email often short-circuits what would otherwise be a long debugging session.