Пример Sustainys SAML2 для ASP.NET Core WebAPI без идентификатора - PullRequest
0 голосов
/ 06 марта 2019

Есть ли у кого-нибудь рабочий образец библиотеки Sustainsys Saml2 для проекта только ASP.NET Core WebAPI (без Mvc), и что важнее без ASP Identity?Образец, предоставленный на github, сильно полагается на MVC и SignInManager, которые мне не нужны и не нужны.

Я добавил аутентификацию Saml2, и сначала она работала нормально с моим IdP (я также проверил StubIdP, предоставленный Sustainsys)для первых нескольких шагов так:

  • Метаданные IdP загружаются правильно
  • Мой API правильно перенаправляет на страницу входа
  • Страница входа перенаправляет на / Saml2 /Страница ACS, и я вижу в журналах, что она успешно анализирует результат

Однако я не знаю, как двигаться дальше и извлекать логин пользователя и дополнительные требования (мой IdP также предоставил e-mail, и он включен в ответ SAML, который я подтвердил в журналах).

После некоторых примеров, найденных в Интернете, и небольшого изменения образца MVC из GitHub я сделал следующее:

В 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 (Я пытался следовать несколько похожей ситуации, описанной в , как реализовать вход в Google.net core без провайдера entityframework ):

[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: Конфигурация SAML в моем проекте ASP.NET Core WebApi выглядит нормально, и я получаю ответ об успешном завершении с правильными утверждениями, которые я проверил в журналах,Я не знаю, как извлечь эти данные (либо возврат URL неверен, либо мой метод обратного вызова должен работать по-другому).Кроме того, удивительно, почему успешное перенаправление со страницы входа в единый вход считается «незапрошенным», может быть, в этом проблема?

Спасибо за любую помощь

1 Ответ

0 голосов
/ 11 марта 2019

Как оказалось, различные ошибки, которые я получал, были связаны с размещением моего решения внутри контейнера .Это вызвало небольшую неисправность внутренней цепочки ключей aspnet.Более подробную информацию можно найти здесь (докер упоминается почти в конце статьи):

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
  • Нежелательные вызовы единого входа
  • Исключенияс цепочкой ключей защиты данных

Так что было очень трудно найти, так как исключения, сгенерированные кодом, не указывали на то, что происходит (и незапрошенные вызовы единого входа заставили меня думать, что поставщик единого входа былнеправильно настроен).Только когда я разобрал пакет Saml2 и попробовал различные фрагменты кода один за другим, я наконец-то обнаружил правильное исключение (о цепочке ключей), которое, в свою очередь, привело меня к статье о защите данных aspnet.

Я предоставляю этоответь, так что, возможно, это кому-нибудь поможет, и я добавил тег докера для правильной аудитории.

...