自定义 SAML 身份验证控制器操作后丢失上下文用户

时间:2021-02-12 18:40:14

标签: asp.net-mvc asp.net-core authentication

我正在实施 SAML2 身份验证消费者模式,而没有像 ITfoxtec 或 Sustainsys 这样的 3rd 方库,这似乎有点矫枉过正。因此,外部服务使用我可以用于 authz 的所有相关角色和属性来处理 SAML 标记的身份验证、证书和铸造。然后他们将其发布到我的控制器,我可以派生我的 authz 并设置我的上下文用户。

我可以解析 SAML 并创建我的声明身份。我将 HttpContext.User 和 Thread.CurrentPrincipal 设置为这个新的 ClaimsPrincipal(userClaimsIdentity)。但是,一旦我从此控制器重定向到经过身份验证的端点,Context.User.Identity 将丢失所有声明,并且 IsAuthenticated 为假。

public class ReadSamlController : Controller
    {
        [HttpPost()]
        public ActionResult Index([FromBody] XmlDocument samlResponse)
        {
            var manager = new XmlNamespaceManager(samlResponse.NameTable);
            manager.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);
            manager.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion");
            manager.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol");


            var assertionNode = samlResponse.SelectSingleNode("/samlp:Response/saml:Assertion", manager);
            if (assertionNode == null)
            {
                throw new InvalidOperationException("Unable to obtain the SAML Assertion for the request.");
            }
            
            var saml2Serializer = new Saml2Serializer();

            var xmlNodeReader = new XmlNodeReader(assertionNode);

            var samlAssertion = saml2Serializer.ReadAssertion(xmlNodeReader);

            if (samlAssertion == null)
            {
                throw new InvalidOperationException("Unable to serialize the assertion into a Saml2Assertion");
            }

            var samlAttributes = samlAssertion.Statements
                                            .Single(att => att.GetType() == typeof(Saml2AttributeStatement)) as Saml2AttributeStatement;


            var userClaimsIdentity = new ClaimsIdentity("ReleaseDash");
            foreach (var rdClaimTypeKey in RdClaimTypes.Keys)
            {
                var samlAttr =
                    samlAttributes.Attributes.Single(
                        attr => attr.Name.Equals(rdClaimTypeKey, StringComparison.InvariantCultureIgnoreCase));
                foreach (var samlAttrValue in samlAttr.Values)
                {
                    userClaimsIdentity.AddClaim(new Claim(rdClaimTypeKey, samlAttrValue));
                }

            }

            Thread.CurrentPrincipal = HttpContext.User = new ClaimsPrincipal(userClaimsIdentity); // the user is set up correctly, IsAuthenticated, role claims etc is all there

            return RedirectToAction("Index", "Home");
        }
    }

似乎我没有设置可以在整个会话上下文中“持久化”的 UserManager 或 SignInManager。我已经为一个方案设置了一堆自定义身份验证代码,并像这样在 Startup 中进行设置

services
  .AddAuthentication()
  .AddScheme<ReleaseDashAuthenticationOptions, ReleaseDashAuthenticationHandler>("ReleaseDash", _ => { }); 

在我的身份验证处理程序中,当我查看上下文端点时,我看到上下文标识缺少我在 ReadSaml 控制器中设置的所有属性。

protected override Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            var endpoint = Context.GetEndpoint();
            
            ...
        }

1 个答案:

答案 0 :(得分:0)

我对此进行了严重的过度设计。我转向了 Cookie Scheme,当我添加时一切正常

await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);

在我重定向到我的 ReadSaml 控制器之前...ahhhh