忽略 SAML2 响应中的 AuthenticationContext

Ignore AuthenticationContext In SAML2 Response

我们有一个 asp.net 5 网络应用程序,它将作为我们用户的服务提供商。
为此,我们选择了 ITfoxtec Identity SAML 2.0 个库。
请求成功,但在响应中我们得到以下错误:

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

为完整起见,这里是完整的堆栈跟踪:

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()

我查了错误,发现可以忽略身份验证上下文,有些库提供了这个选项,例如这个:
IgnoreAuthenticationContextInResponse compatibility flag

ITfoxtec 库中也有解决这个问题的方法吗?

提前致谢,
阿希隆

您可以实施您自己的 Saml2AuthnResponse 版本,并在 Saml2SecurityTokenHandler 属性 上设置您自己的 Saml2ResponseSecurityTokenHandler.

实施

我认为应该可以在您自己的 Saml2ResponseSecurityTokenHandler 实现中更改身份验证上下文验证。

作为此问题的简单解决方法,我所做的只是从响应的 xml.
中删除 saml:AuthnContextDeclRef 元素 这是清理之前处于 POC 状态的代码:

    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);
    }