9

有没有人有一个适用于仅 ASP.NET Core WebAPI 项目(无 Mvc)的 Sustainsys Saml2 库的工作示例,没有 ASP 身份更重要的是什么?github 上提供的示例强烈依赖于我不需要也不想使用的 MVC 和 SignInManager。

我添加了 Saml2 身份验证,起初它在我的 IdP 上运行良好(我还检查了 Sustainsys 提供的 StubIdP)的前几个步骤,所以:

  • IdP 元数据正确加载
  • 我的 API 正确重定向到登录页面
  • 登录页面重定向到 /Saml2/Acs 页面,我在日志中看到它成功解析结果

但是我不知道如何从那里继续并提取用户登录和其他声明(我的 IdP 还提供了一封电子邮件,它包含在我在日志中确认的 SAML 响应中)。

按照在网上找到的一些示例并修改了一些来自 GitHub 的 MVC 示例,我执行了以下操作:

在 Startup.cs 中:

...
.AddSaml2(Saml2Defaults.Scheme,
                       options =>
                       {
                           options.SPOptions.EntityId = new EntityId("...");
                           options.SPOptions.ServiceCertificates.Add(...));
                           options.SPOptions.Logger = new SerilogSaml2Adapter();
                           options.SPOptions.ReturnUrl = new Uri(Culture.Invariant($"https://localhost:44364/Account/Callback?returnUrl=%2F"));

                           var idp =
                               new IdentityProvider(new EntityId("..."), options.SPOptions)
                               {
                                   LoadMetadata = true,
                                   AllowUnsolicitedAuthnResponse = true, // At first /Saml2/Acs page throwed an exception that response was unsolicited so I set it to true
                                   MetadataLocation = "...",
                                   SingleSignOnServiceUrl = new Uri("...") // I need to set it explicitly because my IdP returns different url in the metadata
                               };
                           options.IdentityProviders.Add(idp);
                       });

在 AccountContoller.cs 中(我尝试遵循如何在没有实体框架提供程序的情况下在 .net 核心中实现 google login 中描述的有点类似的情况):

[Route("[controller]")]
[ApiController]
public class AccountController : ControllerBase
{
    private readonly ILog _log;

    public AccountController(ILog log)
    {
        _log = log;
    }

    [HttpGet("Login")]
    [AllowAnonymous]
    public IActionResult Login(string returnUrl)
    {
        return new ChallengeResult(
            Saml2Defaults.Scheme,
            new AuthenticationProperties
            {
                // It looks like this parameter is ignored, so I set ReturnUrl in Startup.cs
                RedirectUri = Url.Action(nameof(LoginCallback), new { returnUrl })
            });
    }

    [HttpGet("Callback")]
    [AllowAnonymous]
    public async Task<IActionResult> LoginCallback(string returnUrl)
    {

        var authenticateResult = await HttpContext.AuthenticateAsync(Constants.Auth.Schema.External);

        _log.Information("Authenticate result: {@authenticateResult}", authenticateResult);

// I get false here and no information on claims etc.
        if (!authenticateResult.Succeeded)
        {
            return Unauthorized();
        }

// HttpContext.User does not contain any data either


// code below is not executed
        var claimsIdentity = new ClaimsIdentity(Constants.Auth.Schema.Application);
claimsIdentity.AddClaim(authenticateResult.Principal.FindFirst(ClaimTypes.NameIdentifier));

        _log.Information("Logged in user with following claims: {@Claims}", authenticateResult.Principal.Claims);           

        await HttpContext.SignInAsync(Constants.Auth.Schema.Application, new ClaimsPrincipal(claimsIdentity));

        return LocalRedirect(returnUrl);
    }

TLDR:我的 ASP.NET Core WebApi 项目中的 SAML 配置看起来不错,并且我在日志中检查了正确的声明并获得了成功响应。我不知道如何提取这些数据(返回 url 错误或者我的回调方法应该以不同的方式工作)。此外,令人费解的是,为什么从 SSO 登录页面成功重定向被视为“未经请求”,也许这就是问题所在?

感谢您的帮助

4

2 回答 2

8

对于在此问题上仍需要帮助的任何人,我将一个完整的工作示例推送到 github,该示例使用 .Net Core WebAPI 作为后端和使用 WebAPI 的 Angular 客户端。您可以从这里找到示例:

https://github.com/hmacat/Saml2WebAPIAndAngularSpaExample

于 2020-02-15T18:30:38.153 回答
1

事实证明,我遇到的各种错误是由于我的解决方案托管在容器中。这导致内部 aspnet 钥匙串出现小故障。更多细节可以在这里找到(几乎在文章末尾提到了docker):

https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview?tabs=aspnetcore2x&view=aspnetcore-2.2

长话短说,为了使代码正常工作,我只需要添加以下几行:

services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo("/some/volume/outside/docker")); // it needs to be outside container, even better if it's in redis or other common resource

它修复了所有问题,其中包括:

  • 对外部 cookie 的登录操作
  • 未经请求的 SSO 呼叫
  • 数据保护密钥链的例外情况

所以很难找到,因为代码抛出的异常并没有指出发生了什么(而且未经请求的 SSO 调用让我认为 SSO 提供程序配置错误)。只有当我反汇编 Saml2 包并逐个尝试各种代码片段时,我才终于遇到了适当的异常(关于钥匙链),这反过来又让我找到了一篇关于 aspnet 数据保护的文章。

我提供了这个答案,以便它可能对某人有所帮助,并且我为适当的受众添加了 docker 标签。

于 2019-03-11T14:02:02.820 回答