Сбой корреляции OID C во всплывающем окне аутентификации Microsoft Teams (нет проблем в браузере) - PullRequest
0 голосов
/ 21 января 2020

Использование ASP. NET Core w /. NET Core 3.1.
OID C поток аутентификации, обработанный Microsoft.AspNetCore.Authentication.OpenIdConnect.
После того, как я начал получать ошибку, я фактически включил вышеуказанное пространство имен в моем проекте, так что я могу устанавливать точки останова и легко проверять данные.

Согласно этому документу: https://developer.microsoft.com/en-us/office/blogs/authentication-in-microsoft-teams-apps-tabs/ то, что я пытаюсь достичь, должно быть возможным.

Допустим, мы настроили вкладку в командах Microsoft, которая размещается в нашем ASP. NET Core MVC приложении на https://localhost:60151 (не через IIS Express, но самостоятельно). Приложение MS Teams может получить доступ к нашему приложению с помощью ngrok , которое запускается с помощью командной строки:

./ngrok http https://localhost:60151

В этом приложении TabController определен следующим образом:

public class TabController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [Authorize]
    public IActionResult TabAuthStart()
    {
        return RedirectToAction(nameof(TabAuthEnd), new { serializedClaims = string.Join("; ", User.Claims.Select(x => $"{x.Type}: {x.Value}")) });
    }

    // for simplicity, let's assume no one navigates to this action 
    // except when redirected from TabAuthStart after the authentication flow completes
    public IActionResult TabAuthEnd(string serializedClaims)
    {
        return View(model: serializedClaims);
    }
}

Пусть представление индекса будет определено следующим образом:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>MS Teams Tab</title>
    <script src="https://statics.teams.microsoft.com/sdk/v1.4.2/js/MicrosoftTeams.min.js" crossorigin="anonymous"></script>
    <script>

        // Call the initialize API first
        microsoftTeams.initialize();

        function authenticate() {
            microsoftTeams.authentication.authenticate({
                url: window.location.origin + "/tab/tabauthstart",
                successCallback: function (result) {
                    // do something on success
                },
                failureCallback: function (reason) {
                    // do something on failure
                }
            });
        }

    </script>
</head>
<body>
    @if (!User.Identity.IsAuthenticated)
    {
        <button onclick="authenticate()">authenticate</button>
    }
    else
    {
        <p>Hello, @User.Identity.Name</p>
    }
</body>
</html>

При перенаправлении в / tab / tabauthstart атрибут [Authorize] гарантирует, что обработчик вызова OID C примет запрос и перенаправит его. на настроенную страницу авторизации IdentityServer.

Если говорить об обработчике OID C, он настроен в Startup.cs следующим образом:

services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
    options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
    options.Cookie.Name = "mvchybridautorefresh";
})
.AddOpenIdConnect(options =>
{
    options.Authority = "https://localhost:44333/"; // The local IdentityServer instance
    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.ClientId = "msteams";
    options.ResponseType = "code id_token"; // Hybrid flow
    options.Scope.Clear();
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("offline_access");

    options.ClaimActions.MapAllExcept("iss", "nbf", "exp", "aud", "nonce", "iat", "c_hash");

    options.GetClaimsFromUserInfoEndpoint = true;
    options.SaveTokens = true;

    // The following were added in despair. However, they don't have any effect on the process.
    options.CorrelationCookie.Path = null;
    options.CorrelationCookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None;
    options.CorrelationCookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.Always;
    options.CorrelationCookie.HttpOnly = false;
});

, а затем у нас есть метод Configure, например это:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseDefaultFiles();
    app.UseStaticFiles();

    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}"
        );
    });
}

В IdentityServer предположим, что клиент настроен правильно.
Итак, когда мы запускаем наше приложение и go на вкладке в приложении Microsoft Teams, мы видим кнопку с надписью «аутентифицировать» , Нажатие этой кнопки запускает обработчик запроса OID C, который подготавливает свойства аутентификации, записывает одноразовые и корреляционные файлы cookie в коллекцию Response.Cookies.

После генерации Id корреляции у нас есть следующие параметры запроса:

  • Схема: https
  • Хост: [назначенный поддомен] .ngrok.io
  • Путь: / tab / tabauthstart

Заголовок ответа Set-Cookie содержит следующее:

.AspNetCore.OpenIdConnect.Nonce.blabla; expires=Tue, 21 Jan 2020 20:54:28 GMT; path=/signin-oidc; secure; samesite=none; httponly,
.AspNetCore.Correlation.OpenIdConnect.blabla; expires=Tue, 21 Jan 2020 20:58:57 GMT; path=/signin-oidc; secure; samesite=none

После этого мы перенаправлены на страницу входа IdSrv .

Там мы вводим наш знак в деталях и завершаем sh процесс входа в систему, что возвращает нас к нашему обработчику OID C, который затем проверяет наличие корреляции cook ie. Однако средство корреляции ie не существует и, следовательно, генерируется исключение, говорящее «Корреляция не удалась».

Это параметры запроса перед проверкой корреляции:

  • Схема: https
  • Хост: [назначенный поддомен] .ngrok.io
  • Путь: / signin-oid c

Коллекция файлов cookie пуста. Почему?

Чтобы сделать вещи еще более интересными, при открытии браузера перейдите к https: // [назначенный поддомен] .ngrok.io / tab / index и запустите аутентификацию, нажав кнопку, процесс завершится успешно, и мы, наконец, перенаправлены на / tab / tabAuthEnd , чье представление, кстати, выглядит так:

@model string
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Authentication successful</title>
    <script src="https://statics.teams.microsoft.com/sdk/v1.4.2/js/MicrosoftTeams.min.js" crossorigin="anonymous"></script>
    <script>

        // Call the initialize API first
        microsoftTeams.initialize();
        microsoftTeams.authentication.notifySuccess(@Model);

    </script>
</head>
<body>

    <p>Redirecting back..</p>

</body>
</html>

Итак ... есть какая-нибудь подсказка, почему файлы cookie OID C не сохраняются при перенаправлении на страницу входа в IdSrv?

1 Ответ

2 голосов
/ 27 января 2020

Вы увидите, что заголовок ответа Set-Cook ie оканчивается на "secure; samesite = none;" и команды основаны на версии Chrome, которая не позволяет этого, и куки не сохраняются, что вызывает эту проблему.

Вы также увидите, что установка для SameSite значения Lax или Strict не изменит Set-Cook ie заголовок. Вам придется управлять этим в классе запуска (в aspnetcore) следующим образом:

private void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
    if (options.SameSite == SameSiteMode.None)
    {
        var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
        // TODO: Use your User Agent library of choice here.
        if (/* UserAgent doesn’t support new behavior */)
        {
               // For .NET Core < 3.1 set SameSite = (SameSiteMode)(-1)
               options.SameSite = SameSiteMode.Unspecified;
         }
    }
}

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
        options.OnAppendCookie = cookieContext => 
            CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
        options.OnDeleteCookie = cookieContext => 
            CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
    });
}

public void Configure(IApplicationBuilder app)
{
    app.UseCookiePolicy(); // Before UseAuthentication or anything else that writes cookies.
    app.UseAuthentication();
    // …
}

В этом проверяется: if (/ * UserAgent не поддерживает новое поведение * /)

... вы проверяете заголовок User-Agent. Аналогично экземпляру fon, если он содержит «Команды» или более, указав c.

Команды Microsoft, идентифицируемые командами этого агента пользователя: Mozilla / 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit / 537.36 ( K HTML, как у Gecko) Команды / 1.3.00.362 Chrome / 66.0.3359.181 Electron / 3.1.13 Safari / 537.36

Источник для этого находится здесь: https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/

...