Configure custom authentication (Tomcat Valve)¶
FMR's Custom security mode lets an external authentication mechanism — CAS, ECAS, SPNEGO/Kerberos, or any bespoke scheme — establish the user's identity in Apache Tomcat, and then have FMR adopt that identity as its own logged-in user.
FMR does not implement these protocols itself. Instead it trusts the java.security.Principal that a Tomcat authentication valve has already created, and maps the fields of that principal onto an FMR user.
This makes Custom security the right choice when:
- your organisation already operates a single sign-on service that ships as a Tomcat valve
- you want FMR to apply each individual end user's own permissions, without FMR ever handling their credentials
- the identity mechanism is not OIDC, Active Directory, LDAP, or X509 client certificates — all of which have dedicated support and should be preferred where they fit
Note
Custom security is mutually exclusive with the OIDC / AD / LDAP mode. Selecting it clears any stored OIDC configuration.
How it works¶
An authentication valve is a component inserted into the Tomcat request processing pipeline. It handles credentials before the request reaches the FMR web application, and on success sets the request's user principal.
The end-to-end sequence is:
- FMR calls
HttpServletRequest.authenticate(response). - Tomcat passes the call to the configured authentication valve.
- The valve performs its protocol exchange with the client. If the valve needs the client to present credentials it writes a challenge — for example
401withWWW-Authenticate: Negotiatefor SPNEGO — and the client repeats the request with a token. - On success the valve sets the request's user principal, which is an arbitrary Java object of the valve's own choosing.
- FMR reads that principal and, using the field mappings you configure, extracts the username, email address, first name, last name and group memberships.
- The groups are resolved to FMR roles through Role Mappings.
- The resulting FMR user is stored in the HTTP session, and the browser or client continues with the session cookie.
Where FMR invokes the valve¶
This is the single most important thing to understand when planning an integration. Tomcat authentication valves only challenge automatically for URLs covered by a <security-constraint> in the web application's web.xml, and FMR ships without any security constraints. The valve therefore runs only at the points where FMR explicitly calls HttpServletRequest.authenticate():
| Entry point | When the valve runs | Purpose |
|---|---|---|
GET /login.html |
Every request, whenever Custom security is configured | Interactive sign-in. This is the URL at which a valve issues its challenge. On success FMR creates the session and redirects to the application URL. |
/ws/secure/** with a ?ticket= query parameter |
Only when the ticket parameter is present |
Machine-to-machine access using a service ticket. Added in FMR 12.3.0 and validated against ECAS, the European Commission's CAS service. |
No other URL triggers the valve. In particular, the public SDMX REST API paths — /sdmx/v1/** and /sdmx/v2/** — are anonymous by default and are never passed to the valve. When such a request targets a restricted dataflow, FMR returns 401 from the application layer, with no WWW-Authenticate header, because no container-level authentication challenge is involved. See Calling the REST APIs below for the supported patterns.
Configure Tomcat¶
The valve must be working at the Tomcat layer before FMR can use it. This part of the configuration is specific to your chosen authentication service and is outside FMR's control — consult the valve's own documentation.
The general shape is a <Valve> element in the FMR context descriptor, for example:
<Context>
<Valve className="com.example.sso.MyAuthenticationValve"
... valve-specific attributes ... />
</Context>
For SPNEGO/Kerberos, Tomcat provides a built-in authenticator, org.apache.catalina.authenticator.SpnegoAuthenticator. Configuring it requires, in addition to the valve itself:
- a service principal name (SPN) registered in Active Directory for the Tomcat host, for example
HTTP/fmr.example.org@EXAMPLE.ORG - a keytab for that SPN, readable by the Tomcat process account
- a Kerberos configuration file (
krb5.conf/krb5.ini) and a JAAS login configuration, referenced from the JVM'sjava.security.krb5.confandjava.security.auth.login.configsystem properties - a Tomcat
Realmthat turns the authenticated Kerberos name into a principal
Follow the Apache Tomcat Windows Authentication How-To for the full procedure, then confirm that Tomcat itself is issuing WWW-Authenticate: Negotiate before configuring FMR.
Verify the challenge before going further
Once the valve is deployed, request /login.html with an anonymous client. A correctly configured valve responds with 401 and a WWW-Authenticate header naming its scheme. If no such header appears, the valve is not active and no amount of FMR configuration will change the outcome.
Configure FMR¶
Custom security is configured from Security Settings → Authentication Service.
- Set Authentication mode to Custom.
- Set User Details Service to Valve.
- Complete the five field mappings described below.
- Click Apply Settings.
The change takes effect immediately; Tomcat does not need to be restarted. The configuration is persisted as JSON in the registry setting security.auth.prov.
Field mappings¶
The five values you supply are not literal user attributes. Each is the name of a Java field on the principal object that the valve created. FMR reads those fields by reflection when a user signs in.
| Setting | Maps to | Notes |
|---|---|---|
| Username | The FMR user's identity | Must match the identity used in Role Mappings, otherwise the user's roles cannot be resolved |
| The user's email address | If the field is absent or empty, FMR substitutes unset@unknown.com |
|
| First Name | Given name | Combined with Last Name to form the user's display name |
| Last Name | Family name | Combined with First Name to form the user's display name |
| Group Details | The user's group or role memberships | Must resolve to a Java array or Collection; each element's string value becomes one group |
All five fields are mandatory in the user interface.
Reflection behaves as follows:
- Private fields are read directly; no getter method is required.
- Fields declared on a superclass are found — FMR walks up the class hierarchy.
- Nested objects are addressed with dot notation, for example
userDetails.email. - If a named field does not exist anywhere on the principal's class hierarchy, authentication fails and the user cannot sign in.
When the principal does not carry all five attributes
Many valves produce a minimal principal. Tomcat's own GenericPrincipal, for instance, carries the account name and the roles but has no email or name fields.
Because a field name may be reused, you can map several settings to the same field. Mapping Username, Email, First Name and Last Name all to the principal's name field yields a working — if plainly-presented — FMR user. Group Details should still be mapped to the roles field so that authorisation works correctly.
Where richer user detail matters, use a Tomcat Realm or valve that produces a principal carrying the additional attributes.
Discovering the field names¶
If you do not know the shape of the object your valve produces, let FMR tell you. Set the following logger to DEBUG in WEB-INF/classes/logback.xml:
On the next sign-in attempt, FusionRegistry.log contains a line beginning Received UserDetails Object: followed by the entire principal serialised as JSON. The JSON property names are the field names to enter into the mapping settings.
Logback rescans its configuration every 30 seconds, so no restart is required. Remember to return the logger to its previous level afterwards — see Logging.
Assign roles¶
Authentication establishes who the user is. It does not grant any permission on its own.
Each group returned by the valve must be mapped to an Agency, Data Provider, Data Consumer, or to Administrator, on the Role Mappings page. A user whose groups match no mapping signs in successfully but has only the access available to an anonymous caller.
Calling the REST APIs¶
Because the valve is invoked only at the entry points listed above, applications calling FMR on behalf of a user need to follow one of the following patterns.
This is the general pattern, and the one to use for SPNEGO/Kerberos.
The calling application performs the valve's authentication exchange once against /login.html, captures the resulting session cookie, and reuses it for subsequent API calls:
- Issue
GET {fmr-url}/login.htmlusing the end user's credentials or delegated identity. - Complete whatever challenge/response exchange the valve requires. Most HTTP client libraries do this automatically once the server sends a
WWW-Authenticateheader they recognise — for example .NET'sHttpClientHandlerwithUseDefaultCredentials, orcurl --negotiate. - Retain the
JSESSIONIDcookie returned on success. - Send that cookie with every subsequent request, including requests to
/sdmx/v2/**.
# Step 1-3: authenticate and store the session cookie
curl -c cookies.txt --negotiate -u : \
"http://fmr.example.org/FusionRegistry/login.html"
# Step 4: call the data API as the authenticated user
curl -b cookies.txt \
"http://fmr.example.org/FusionRegistry/sdmx/v2/data/dataflow/AGENCY/FLOW/1.0/"
A server-side application acting for many users should keep one session per end user and re-run the bootstrap when a session expires. The FMR user applied to each request is the one that established that session, so its own permissions are enforced.
Where the valve validates a ticket presented as a request parameter, FMR's secure REST APIs accept it directly:
FMR passes the request to the valve for validation, builds the user from the returned principal, and stores the result in the session so that the returned cookie can be reused for later calls.
This applies to /ws/secure/** only. It was introduced in FMR 12.3.0 and has been validated against ECAS.
The public SDMX API does not issue a challenge
Requests to /sdmx/v1/** and /sdmx/v2/** that carry no session are treated as anonymous. If the requested dataflow is restricted, FMR answers 401 with no WWW-Authenticate header.
Reactive HTTP clients — which send credentials only in response to a challenge — will therefore never attach their credentials to such a request, regardless of how the client is configured. Establish a session first, as described above.
Troubleshooting¶
401 with no WWW-Authenticate header¶
The request reached a URL where FMR does not invoke the valve. This is expected on /sdmx/v1/** and /sdmx/v2/**, and on /ws/secure/** without a ticket parameter. Use one of the REST API patterns above.
401 with WWW-Authenticate on /login.html¶
This is the valve working correctly. It is a challenge, not a failure: the client is expected to repeat the request with the appropriate token. Clients that do not understand the offered scheme, or that have no credentials to offer, will stop at this point.
"Valve authentication service might not be set up correctly"¶
FMR called HttpServletRequest.authenticate() and the container raised an error. Usually this means no authenticator is present in the Tomcat pipeline for the FMR context. Check catalina.log for valve initialisation errors, and confirm the <Valve> declaration is in the context descriptor that actually applies to the FMR web application.
The user signs in but has no permissions¶
Authentication succeeded and the principal was mapped, but the groups did not resolve to any FMR role. Check that:
- the Group Details mapping names a field holding an array or
Collection - the group values returned by the valve match the group names entered on the Role Mappings page, exactly and case-sensitively
- the Username mapping yields the identity your group service expects
Enabling DEBUG on FusionTomcatValveUserDetailsMapper, as described above, shows exactly what was extracted from the principal.
Sign-in fails immediately with no obvious cause¶
A field named in the mappings probably does not exist on the principal class. FMR logs does not have property against FusionTomcatValveUserDetailsMapper. Re-check the field names against the DEBUG output of the principal object.
Limitations¶
Be aware of the following when planning an integration:
- The valve is invoked at
/login.htmland, with aticketparameter, on/ws/secure/**. There is no per-request container authentication challenge on the public SDMX API paths. - FMR does not read a principal set by a valve outside those entry points. A valve that sets the request principal on every request will not, by itself, cause FMR to treat the caller as signed in.
- The five field mappings are all mandatory, and every named field must exist on the principal object.
- Custom security cannot be combined with OIDC. It can, however, coexist with X509 client certificate authentication, which is often a good complement for machine-to-machine callers.
If your deployment needs a pattern that is not covered here, contact support — the set of entry points at which FMR consults the valve can be extended.