spring-projects/spring-security · error · Saml2AuthenticationException

subject_not_found

subject_not_found

Error message

Assertion [" + assertion.getID() + "] is missing a subject

What it means

During authentication, OpenSaml5AuthenticationProvider builds the authenticated principal from the Assertion's Subject. If the assertion carries no Subject/NameID (hasName returns false), it throws a Saml2AuthenticationException with the subjectNotFound error code rather than producing an Authentication, because Spring Security's SAML login requires a subject identity.

Source

Thrown at saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java:947

			Assert.notNull(principalNameConverter, "principalNameConverter cannot be null");
			this.principalNameConverter = principalNameConverter;
		}

		/**
		 * Use this strategy to grant authorities to a principal given the first
		 * {@link Assertion} in the response. By default, this will grant
		 * {@code ROLE_USER}.
		 * @param grantedAuthoritiesConverter the conversion strategy to use
		 */
		public void setGrantedAuthoritiesConverter(
				Converter<Assertion, Collection<GrantedAuthority>> grantedAuthoritiesConverter) {
			Assert.notNull(grantedAuthoritiesConverter, "grantedAuthoritiesConverter cannot be null");
			this.grantedAuthoritiesConverter = grantedAuthoritiesConverter;
		}

		private static String authenticatedPrincipal(Assertion assertion) {
			if (!BaseOpenSamlAuthenticationProvider.hasName(assertion)) {
				throw new Saml2AuthenticationException(
						Saml2Error.subjectNotFound("Assertion [" + assertion.getID() + "] is missing a subject"));
			}
			Subject subject = assertion.getSubject();
			Assert.notNull(subject, "Assertion#Subject cannot be null");
			NameID nameId = subject.getNameID();
			Assert.notNull(nameId, "Assertion#Subject#NameID cannot be null");
			return Objects.requireNonNull(nameId.getValue());
		}

		private static Collection<GrantedAuthority> grantedAuthorities(Assertion assertion) {
			return AuthorityUtils.createAuthorityList("ROLE_USER");
		}

	}

}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Configure the IdP to release a NameID (or an attribute mapped as principal) for this SP — check NameID format and attribute release policies.
  2. Ensure your SP metadata requests a NameIDFormat the IdP supports (e.g. emailAddress or persistent).
  3. If you legitimately use subject-less assertions, set a custom responseAuthenticationConverter / assertion validator that does not require a Subject.
  4. Verify the assertion you are validating is the intended login assertion, not an auxiliary one.

Example fix

// before: IdP omits NameID -> assertion has no Subject
// after: request a supported format in SP metadata
RelyingPartyRegistration.withRegistrationId("idp")
        .nameIdFormat(NameIDFormat.EMAIL)
        ... // IdP then emits <saml2:NameID> and the Subject element
Defensive patterns

Strategy: try-catch

Validate before calling

boolean hasSubject = assertion.getSubject() != null
        && assertion.getSubject().getNameID() != null;
if (!hasSubject) {
    throw new ResponseStatusException(HttpStatus.UNAUTHORIZED,
            "Assertion " + assertion.getID() + " carries no Subject/NameID");
}

Try / catch

try {
    Authentication auth = provider.authenticate(token);
} catch (Saml2AuthenticationException ex) {
    if (Saml2Error.SUBJECT_NOT_FOUND.equals(ex.getSaml2Error().getCode())) {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
                "IdP released no NameID — check NameID format and attribute release policy");
    } else { throw ex; }
}

Prevention

When it happens

Trigger: Validating a signed response whose assertion lacks a <saml2:Subject>/<saml2:NameID> — e.g. attribute-only assertions, assertions used only for authorization, or IdP configured to omit NameID.

Common situations: IdP releases no NameID (misconfigured NameID format or attribute filter suppressing it); SP metadata requests a NameID format the IdP won't provide so it omits the element entirely; using an assertion for logout/attribute flows where the IdP intentionally omits the subject; automated tests constructing assertions without a Subject.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/8c21b8de98bb0645. Report an issue: GitHub.