忽略 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);
}
我们有一个 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);
}