Ignore AuthenticationContext In SAML2 Response

Viewed 276

We have an asp.net 5 web app that will serve as a Service Provider to our users.
We have chosen ITfoxtec Identity SAML 2.0 library for this purpose.
The request is successful, but in the response we get the following error:

System.ArgumentException: IDX13300: 'System.String' must be an absolute Uri, was: 'System.Uri'

For completeness here is the full stack trace:

Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenReadException: IDX13102: Exception thrown while reading 'System.String' for Saml2SecurityToken. Inner exception: 'System.ArgumentException'. ---> System.ArgumentException: IDX13300: 'System.String' must be an absolute Uri, was: 'System.Uri' at Microsoft.IdentityModel.Tokens.Saml2.Saml2AuthenticationContext.set_DeclarationReference(Uri value) at Microsoft.IdentityModel.Tokens.Saml2.Saml2Serializer.ReadAuthenticationContext(XmlDictionaryReader reader) --- End of inner exception stack trace --- at Microsoft.IdentityModel.Tokens.Saml2.Saml2Serializer.ReadAuthenticationContext(XmlDictionaryReader reader) at Microsoft.IdentityModel.Tokens.Saml2.Saml2Serializer.ReadAuthenticationStatement(XmlDictionaryReader reader) at Microsoft.IdentityModel.Tokens.Saml2.Saml2Serializer.ReadAssertion(XmlReader reader) at Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ReadSaml2Token(XmlReader reader) at Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ReadSaml2Token(String token) at ITfoxtec.Identity.Saml2.Saml2AuthnResponse.ReadSecurityToken(String tokenString) at ITfoxtec.Identity.Saml2.Saml2AuthnResponse.Read(String xml, Boolean validateXmlSignature) at ITfoxtec.Identity.Saml2.Saml2PostBinding.Read(HttpRequest request, Saml2Request saml2RequestResponse, String messageName, Boolean validateXmlSignature) at ITfoxtec.Identity.Saml2.Saml2Binding1.ReadSamlResponse(HttpRequest request, Saml2Response saml2Response) at SsoGovILApi.Controllers.SamlController.AssertionConsumerService() in F:\Dev\ashilon\SsoGovIlApi\Controllers\SamlController.cs:line 45 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Serilog.AspNetCore.RequestLoggingMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Builder.Extensions.UsePathBaseMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT1.ProcessRequestAsync()

I have looked up the error and found that the authentication context can be ignored, and some libraries give this option, like this one for example:
IgnoreAuthenticationContextInResponse compatibility flag

Is there a way to this in the ITfoxtec library too?

Thanks in advance,
ashilon

2 Answers

You can implement you own version of Saml2AuthnResponse and on the Saml2SecurityTokenHandler property set your own implementation of Saml2ResponseSecurityTokenHandler.

I think it should be possible to change the authentication context validation in your own implementation of the Saml2ResponseSecurityTokenHandler.

As a simple workaround for this problem, what I did was to simply remove the saml:AuthnContextDeclRef element from the response's xml.
Here's the code, in POC state, before cleaning up:

    public async Task<IActionResult> AssertionConsumerService()
    {
        var binding = new Saml2PostBinding();
        var saml2AuthnResponse = new Saml2AuthnResponse(_config);

        var httpRequest = Request.ToGenericHttpRequest();

        // Remove AuthnContextDeclRef element
        var samlResponseXml = Encoding.UTF8.GetString(Convert.FromBase64String(httpRequest.Form["SAMLResponse"] ?? string.Empty));
        var root = XElement.Parse(samlResponseXml);
        XNamespace ns = "urn:oasis:names:tc:SAML:2.0:assertion";
        root.Element(ns + "Assertion")?.Element(ns + "AuthnStatement")?.Element(ns + "AuthnContext")?.Element(ns + "AuthnContextDeclRef")?.Remove();
        httpRequest.Form["SAMLResponse"] = Convert.ToBase64String(Encoding.UTF8.GetBytes(root.ToString()));

        binding.ReadSamlResponse(httpRequest, saml2AuthnResponse);
        if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
        {
            throw new AuthenticationException($"SAML Response status: {saml2AuthnResponse.Status}");
        }
        binding.Unbind(httpRequest, saml2AuthnResponse);
        await saml2AuthnResponse.CreateSession(HttpContext, claimsTransform: ClaimsTransform.Transform);

        var relayStateQuery = binding.GetRelayStateQuery();
        var returnUrl = relayStateQuery.ContainsKey(RelayStateReturnUrl) ? relayStateQuery[RelayStateReturnUrl] : Url.Content("~/");
        return Redirect(returnUrl);
    }  
Related