apereo/cas · error · IllegalArgumentException

Could not extract and identify credentials

Error message

Could not extract and identify credentials

What it means

Thrown by WsFederationResponseValidator.buildCredentialsFromAssertion when the extracted SAML assertion is valid but no WsFederationCredential could be constructed from it. The credential extraction produced null, so CAS logs the relying-party identifier and identity-provider identifier it used and aborts the validation flow.

Solutions

  1. Check identityProviderIdentifier in WsFederationConfiguration exactly matches the IdP's issuer identifier as it appears in the assertion's Issuer element.
  2. Verify the relying party identifier (getRelyingPartyIdentifier derives it from the service / configured realm) matches the WS-Federation realm configured at the IdP for CAS.
  3. Inspect the assertion (debug log or decode wresult) to confirm it contains a subject/NameID.
  4. Compare the relying party identifier and IdP identifier values logged in the error with your CAS properties and correct the mismatch.

Example fix

// before
cas.authn.wsfed[0].identity-provider-identifier=http://wrong-adfs/adfs/services/trust
cas.authn.wsfed[0].relying-party-identifier=urn:cas:wrong
// after: match the ADFS identifiers exactly
cas.authn.wsfed[0].identity-provider-identifier=http://adfs.example.com/adfs/services/trust
cas.authn.wsfed[0].relying-party-identifier=urn:cas:example
Defensive patterns

Strategy: validation

Validate before calling

// assert config identifiers are non-blank before processing a token
if (configuration.getIdentityProviderIdentifier() == null || configuration.getIdentityProviderIdentifier().isBlank()) {
    throw new IllegalStateException("identityProviderIdentifier must be set to the IdP issuer");
}

Type guard

function hasIdentityProviderIdentifier(config) {
  return typeof config.getIdentityProviderIdentifier === 'function' && !!config.getIdentityProviderIdentifier();
}

Try / catch

try {
    validator.validateWsFederationAuthenticationRequest(context);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("Could not extract and identify credentials")) {
        LOGGER.error("Check identityProviderIdentifier/relyingPartyIdentifier against the assertion issuer and realm");
    }
    throw e;
}

Prevention

When it happens

Trigger: wsFederationHelper.getRelyingPartyIdentifier(service, configuration) plus the configured identityProviderIdentifier do not match anything in the assertion, so credential extraction in WsFederationHelper returns null: the NameID/subject cannot be resolved against the RP ID or IdP identifier configured.

Common situations: Wrong cas.authn.wsfed[0].identityProviderIdentifier (does not match the IdP's entity/issuer ID), wrong relyingPartyIdentifier (realm/trust identifier in ADFS does not match the CAS service/realm), or the assertion has no usable subject/NameID.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/fbd1e0a91aa58025. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-wsfederation-webflow/src/main/java/org/apereo/cas/web/flow/WsFederationResponseValidator.java:88

            LOGGER.error(msg);
            throw new IllegalArgumentException(msg);
        }
        buildCredentialsFromAssertion(context, assertion, service);
    }

    private void buildCredentialsFromAssertion(final RequestContext context,
                                               final Pair<Assertion, WsFederationConfiguration> assertion,
                                               final Service service) throws Throwable {
        try {
            LOGGER.debug("Creating credential based on the provided assertion");
            val credential = wsFederationHelper.createCredentialFromToken(assertion.getKey());
            val configuration = assertion.getValue();
            val rpId = wsFederationHelper.getRelyingPartyIdentifier(service, configuration);

            if (credential == null) {
                LOGGER.error("No credential could be extracted from [{}] based on relying party identifier [{}] and identity provider identifier [{}]",
                    assertion.getKey(), rpId, configuration.getIdentityProviderIdentifier());
                throw new IllegalArgumentException("Could not extract and identify credentials");
            }

            if (credential.isValid(rpId, configuration.getIdentityProviderIdentifier(), configuration.getTolerance())) {
                val currentAttributes = credential.getAttributes();
                LOGGER.debug("Validated assertion for the created credential successfully and located attributes [{}]", currentAttributes);
                if (configuration.getAttributeMutator() != null) {
                    LOGGER.debug("Modifying credential attributes based on [{}]", configuration.getAttributeMutator().getClass().getSimpleName());
                    val attributes = configuration.getAttributeMutator().modifyAttributes(currentAttributes);
                    LOGGER.debug("Finalized credential attributes are [{}]", attributes);
                    credential.setAttributes(attributes);
                }
            } else {
                LOGGER.error("SAML assertions are blank or no longer valid based on RP identifier [{}] and identity provider identifier [{}]",
                    rpId, configuration.getIdentityProviderIdentifier());
                throw new IllegalArgumentException("Could not validate the provided assertion");
            }
            WebUtils.putServiceIntoFlowScope(context, service);
            LOGGER.debug("Creating final authentication result based on the given credential");

View on GitHub (pinned to e7288fc434)