{"record":{"id":"8c21b8de98bb0645","repo":"spring-projects/spring-security","slug":"subject-not-found","errorCode":"subject_not_found","errorMessage":"Assertion [\" + assertion.getID() + \"] is missing a subject","messagePattern":"Assertion \\[\" \\+ assertion\\.getID\\(\\) \\+ \"\\] is missing a subject","errorType":"exception","errorClass":"Saml2AuthenticationException","httpStatus":null,"severity":"error","filePath":"saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java","lineNumber":947,"sourceCode":"\t\t\tAssert.notNull(principalNameConverter, \"principalNameConverter cannot be null\");\n\t\t\tthis.principalNameConverter = principalNameConverter;\n\t\t}\n\n\t\t/**\n\t\t * Use this strategy to grant authorities to a principal given the first\n\t\t * {@link Assertion} in the response. By default, this will grant\n\t\t * {@code ROLE_USER}.\n\t\t * @param grantedAuthoritiesConverter the conversion strategy to use\n\t\t */\n\t\tpublic void setGrantedAuthoritiesConverter(\n\t\t\t\tConverter<Assertion, Collection<GrantedAuthority>> grantedAuthoritiesConverter) {\n\t\t\tAssert.notNull(grantedAuthoritiesConverter, \"grantedAuthoritiesConverter cannot be null\");\n\t\t\tthis.grantedAuthoritiesConverter = grantedAuthoritiesConverter;\n\t\t}\n\n\t\tprivate static String authenticatedPrincipal(Assertion assertion) {\n\t\t\tif (!BaseOpenSamlAuthenticationProvider.hasName(assertion)) {\n\t\t\t\tthrow new Saml2AuthenticationException(\n\t\t\t\t\t\tSaml2Error.subjectNotFound(\"Assertion [\" + assertion.getID() + \"] is missing a subject\"));\n\t\t\t}\n\t\t\tSubject subject = assertion.getSubject();\n\t\t\tAssert.notNull(subject, \"Assertion#Subject cannot be null\");\n\t\t\tNameID nameId = subject.getNameID();\n\t\t\tAssert.notNull(nameId, \"Assertion#Subject#NameID cannot be null\");\n\t\t\treturn Objects.requireNonNull(nameId.getValue());\n\t\t}\n\n\t\tprivate static Collection<GrantedAuthority> grantedAuthorities(Assertion assertion) {\n\t\t\treturn AuthorityUtils.createAuthorityList(\"ROLE_USER\");\n\t\t}\n\n\t}\n\n}\n","sourceCodeStart":929,"sourceCodeEnd":964,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java#L929-L964","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Configure the IdP to release a NameID (or an attribute mapped as principal) for this SP — check NameID format and attribute release policies.","Ensure your SP metadata requests a NameIDFormat the IdP supports (e.g. emailAddress or persistent).","If you legitimately use subject-less assertions, set a custom responseAuthenticationConverter / assertion validator that does not require a Subject.","Verify the assertion you are validating is the intended login assertion, not an auxiliary one."],"exampleFix":"// before: IdP omits NameID -> assertion has no Subject\n// after: request a supported format in SP metadata\nRelyingPartyRegistration.withRegistrationId(\"idp\")\n        .nameIdFormat(NameIDFormat.EMAIL)\n        ... // IdP then emits <saml2:NameID> and the Subject element","handlingStrategy":"try-catch","validationCode":"boolean hasSubject = assertion.getSubject() != null\n        && assertion.getSubject().getNameID() != null;\nif (!hasSubject) {\n    throw new ResponseStatusException(HttpStatus.UNAUTHORIZED,\n            \"Assertion \" + assertion.getID() + \" carries no Subject/NameID\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    Authentication auth = provider.authenticate(token);\n} catch (Saml2AuthenticationException ex) {\n    if (Saml2Error.SUBJECT_NOT_FOUND.equals(ex.getSaml2Error().getCode())) {\n        response.sendError(HttpServletResponse.SC_UNAUTHORIZED,\n                \"IdP released no NameID — check NameID format and attribute release policy\");\n    } else { throw ex; }\n}","preventionTips":["Declare a NameIDFormat in SP metadata that your IdP actually supports.","Confirm the IdP's attribute release/NameID policy for this SP entityID.","Integration-test the full SSO round-trip, not just signature validation.","Inspect assertions in a SAML tracer to see exactly what the IdP emits."],"tags":["saml2","opensaml","authentication","subject"],"backgroundTag":"empty-required-field","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}