Hi,
Found an issue with org.pac4j.saml.sso.impl.SAML2AuthnRequestBuilder class in pac4j-saml module which does not comply to SAML 2.0 specification.
AssertionConsumerServiceIndex [Optional]
Indirectly identifies the location to which the <Response> message should be returned to the
requester. It applies only to profiles in which the requester is different from the presenter, such as the
Web Browser SSO profile in [SAMLProf]. The identity provider MUST have a trusted means to map
the index value in the attribute to a location associated with the requester. [SAMLMeta] provides one
possible mechanism. If omitted, then the identity provider MUST return the <Response> message to
the default location associated with the requester for the profile of use. If the index specified is invalid,
then the identity provider MAY return an error <Response> or it MAY use the default location. This
attribute is mutually exclusive with the AssertionConsumerServiceURL and ProtocolBinding
attributes.
AssertionConsumerServiceURL [Optional]
Specifies by value the location to which the <Response> message MUST be returned to the
requester. The responder MUST ensure by some means that the value specified is in fact associated
with the requester. [SAMLMeta] provides one possible mechanism; signing the enclosing
<AuthnRequest> message is another. This attribute is mutually exclusive with the
AssertionConsumerServiceIndex attribute and is typically accompanied by the
ProtocolBinding attribute.
ProtocolBinding [Optional]
A URI reference that identifies a SAML protocol binding to be used when returning the <Response>
message. See [SAMLBind] for more information about protocol bindings and URI references defined
for them. This attribute is mutually exclusive with the AssertionConsumerServiceIndex attribute
and is typically accompanied by the AssertionConsumerServiceURL attribute.
AuthnRequest should provide either AssertionConsumerServiceIndex or AssertionConsumerServiceURL + ProtocolBinding.
However, the code
if (this.configuration.getAssertionConsumerServiceIndex() >= 0) {
request.setAssertionConsumerServiceIndex(this.configuration.getAssertionConsumerServiceIndex() );
} else {
request.setAssertionConsumerServiceURL(assertionConsumerService.getLocation());
}
request.setProtocolBinding(assertionConsumerService.getBinding());
creates the authentication request with AssertionConsumerServiceIndex + ProtocolBinding.
Below is the AuthnRequest sent to the IdP.
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:AuthnRequest
xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
AssertionConsumerServiceIndex="0"
AttributeConsumingServiceIndex="1"
ForceAuthn="true"
ID="_8e959c714077415f855eaf65a183a8f4b7252be"
IsPassive="false"
IssueInstant="2021-09-28T04:42:55.497Z"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
ProviderName="MyCompany::SP1"
Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" NameQualifier="urn:mace:saml:pac4j.org">urn:mace:saml:pac4j.org</saml2:Issuer> <saml2p:NameIDPolicy AllowCreate="false" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
<saml2p:RequestedAuthnContext Comparison="exact">
<saml2:AuthnContextClassRef xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2p:RequestedAuthnContext>
</saml2p:AuthnRequest>
Hence, get rejected by the IdP.
AADSTS900237: AssertionConsumerServiceIndex cannot be set when ProtocolBinding or AssertionConsumerServiceUrl are set.
Regards,
SN Chok