Конвейер аутентификации OWIN и как правильно использовать промежуточное ПО Katana?

Недавно я начал изучать новую платформу ASP.Net Identity и промежуточное ПО Katana, там удивительное количество кода и документации, но я вижу много противоречивой информации, которая, как я полагаю, является результат учащения обновлений кода.

Я хочу использовать аутентификацию WsFederation для внутренней службы ADFS 2, но способ работы конвейера аутентификации OWIN меня немного смущает, и я надеюсь, что кто-то может предложить некоторую окончательную информацию.

В частности, меня интересует порядок, в котором должно быть подключено промежуточное ПО и какие модули требуются в различных сценариях, я бы хотел избавиться от всего, что не должно быть там, и в то же время убедиться, что процесс максимально безопасен.

Например, может показаться, что UseWsFederationAuthentication следует использовать вместе с UseCookieAuthentication, но я не уверен, какой будет правильный AuthenticationType (этот пост предполагает, что это всего лишь строка идентификатора, но имеет ли значение ее значение?) или даже если нам все еще нужно использовать SetDefaultSignInAsAuthenticationType.

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

Лично я сейчас использую следующее (с настраиваемым обработчиком токена SAML для чтения строки токена в допустимый XML-документ), это работает для меня, но оптимально ли это?

var appURI = ConfigurationManager.AppSettings["app:URI"];
var fedPassiveTokenEndpoint = ConfigurationManager.AppSettings["wsFederation:PassiveTokenEndpoint"];
var fedIssuerURI = ConfigurationManager.AppSettings["wsFederation:IssuerURI"];
var fedCertificateThumbprint = ConfigurationManager.AppSettings["wsFederation:CertificateThumbprint"];

var audienceRestriction = new AudienceRestriction(AudienceUriMode.Always);

audienceRestriction.AllowedAudienceUris.Add(new Uri(appURI));

var issuerRegistry = new ConfigurationBasedIssuerNameRegistry();

issuerRegistry.AddTrustedIssuer(fedCertificateThumbprint, fedIssuerURI);

app.UseCookieAuthentication(
    new CookieAuthenticationOptions
    {
        AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType // "Federation"
    }
);

app.UseWsFederationAuthentication(
    new WsFederationAuthenticationOptions
    {
        Wtrealm = appURI,
        SignOutWreply = appURI,
        Configuration = new WsFederationConfiguration
        {
            TokenEndpoint = fedPassiveTokenEndpoint
        },
        TokenValidationParameters = new TokenValidationParameters
        {
            AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
        },
        SecurityTokenHandlers = new SecurityTokenHandlerCollection
        {                        
            new SamlSecurityTokenHandlerEx
            {
                CertificateValidator = X509CertificateValidator.None,
                Configuration = new SecurityTokenHandlerConfiguration
                {
                    AudienceRestriction = audienceRestriction,
                    IssuerNameRegistry = issuerRegistry
                }
            }
        }
    }
);

Большое спасибо за все, что вы можете предложить, чтобы помочь мне прояснить эту путаницу.


person Tom Tregenna    schedule 04.09.2014    source источник
comment
Кроме того, если я заменяю WsFederationAuthenticationOptions.Configuration местоположением метаданных, я внезапно начинаю видеть следующую ошибку ... Значение по умолчанию для SignInAsAuthenticationType не найдено в свойствах IAppBuilder. Это может произойти, если ваше промежуточное ПО для аутентификации добавлено в неправильном порядке или если оно отсутствует.   -  person Tom Tregenna    schedule 04.09.2014
comment
Попробуйте это: github .com / AzureADSamples / WebApp-WSFederation-DotNet / blob /   -  person Tratcher    schedule 06.09.2014
comment
Спасибо, Трэчер, это был один из моих первоисточников благодаря индивидуальному блогу Витторио Берточчи. Но он все еще не дает окончательного объяснения, почему, например, для параметра AuthenticationType UseCookieAuthentication установлено значение cookie, а не wsfed, я видел оба варианта, использованные в различных примерах.   -  person Tom Tregenna    schedule 06.09.2014
comment
Каждому промежуточному программному обеспечению для аутентификации нужен свой уникальный AuthenticationType. Некоторое промежуточное программное обеспечение также имеет поле SignInAsAuthenticationType, используемое для указания AuthenticationType другого промежуточного программного обеспечения, которое они должны использовать для сохранения результатов своей аутентификации. SetDefaultSignInAsAuthenticationType устанавливает значение, которое промежуточное ПО должно использовать для SignInAsAuthenticationType по умолчанию.   -  person Tratcher    schedule 07.09.2014
comment
Итак, в случае с этим образцом, вот чем заканчивается каждое промежуточное ПО: CookieAuthMiddleware - AuthType: Cookies; WsFedAuthMiddleware - AuthType: WsFed, SignInAsAuthenticationType: файлы cookie.   -  person Tratcher    schedule 07.09.2014
comment
много противоречивой информации, что, я думаю, является результатом учащения обновлений кода - ›Полностью согласен! Некоторые сообщения в блогах следует исправить / удалить с сайтов Microsoft ...   -  person Matthieu    schedule 16.02.2016


Ответы (1)


Как сказал @Tratcher, параметр AuthenticationType используется Microsoft.Owin.Security в качестве ключа для поиска экземпляров промежуточного ПО для аутентификации.

В приведенном ниже коде будет использоваться следующий простой вспомогательный метод, чтобы требовать аутентификации всех запросов. На практике вы с большей вероятностью будете использовать атрибут [Authorize] на чувствительных контроллерах, но мне нужен пример, который не зависит от каких-либо фреймворков:

private static void AuthenticateAllRequests(IAppBuilder app, params string[] authenticationTypes)
{
    app.Use((context, continuation) =>
    {
        if (context.Authentication.User != null &&
            context.Authentication.User.Identity != null &&
            context.Authentication.User.Identity.IsAuthenticated)
        {
            return continuation();
        }
        else
        {
            context.Authentication.Challenge(authenticationTypes);
            return Task.Delay(0);
        }
    });
}

Вызов context.Authentication.Challenge(authenticationTypes) вызовет проверку подлинности каждого из предоставленных типов проверки подлинности. Мы просто собираемся предоставить один, наш тип аутентификации WS-Federation.

Правильный код

Итак, во-первых, вот пример «оптимальной» конфигурации запуска Owin для сайта, который просто использует WS-Federation, как и вы:

public void Configuration(IAppBuilder app)
{
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

    app.UseCookieAuthentication(new CookieAuthenticationOptions());

    app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions
    {
        AuthenticationType = "WS-Fed Auth (Primary)",
        Wtrealm = ConfigurationManager.AppSettings["app:URI"],
        MetadataAddress = ConfigurationManager.AppSettings["wsFederation:MetadataEndpoint"]
    });

    AuthenticateAllRequests(app, "WS-Fed Auth (Primary)");

    app.UseWelcomePage();
}

Обратите внимание на использование "WS-Fed Auth (Primary)" AuthenticationType для уникальной идентификации экземпляра промежуточного программного обеспечения WS-Federation, который мы настроили. Это означает, что вы могли бы, например, использовать "WS-Fed Auth (Secondary)" с отдельным сервером WS-Federation в качестве запасного варианта, если бы у вас было такое требование.

Эта конфигурация будет делать следующее:

  1. Сначала сообщите конвейеру безопасности Owin, что по умолчанию мы хотим аутентифицировать запросы с значением CookeAuthentication AthenticationType по умолчанию. (Это просто постоянная строка в этом классе CookieAuthenticationDefaults, и это значение по умолчанию, используемое свойством CookieAuthenticationOptions.AuthenticationType.)
  2. Затем зарегистрируйте экземпляр промежуточного программного обеспечения для проверки подлинности файлов cookie со всеми параметрами по умолчанию, чтобы он соответствовал ключу AuthenticationType, который мы установили по умолчанию на шаге 1.
  3. Затем зарегистрируйте экземпляр промежуточного программного обеспечения проверки подлинности WS-Federation с параметрами, которые мы определяем в файле Web.config, и с настраиваемым значением AuthenticationType, чтобы мы могли обратиться к нему позже.
  4. После того, как все регистрации промежуточного программного обеспечения аутентификации выполнены, мы говорим конвейеру аутентифицировать все запросы (с помощью нашего специального вспомогательного метода, который вызывает Microsoft.Owin.Security методы для выдачи вызовов любому неаутентифицированному запросу)
  5. Наконец, если пользователь прошел аутентификацию, покажите страницу приветствия!

Неверный код

Так что здесь есть несколько способов ошибиться.

Не указан тип аутентификации по умолчанию

Чтобы поэкспериментировать, я попробовал сделать это, и вы сразу поймете, в чем проблема:

public void Configuration(IAppBuilder app)
{
    var x = app.GetDefaultSignInAsAuthenticationType();

    app.SetDefaultSignInAsAuthenticationType(x);
}

Этот первый вызов даст вам исключение, о котором вы упомянули в своем первом комментарии:

«Значение по умолчанию для SignInAsAuthenticationType не найдено в свойствах IAppBuilder. Это может произойти, если промежуточное ПО для проверки подлинности добавлено в неправильном порядке или если оно отсутствует».

Верно - потому что по умолчанию конвейер Microsoft.Owin.Security ничего не предполагает о промежуточном программном обеспечении, которое вы собираетесь использовать (т.е. Microsoft.Owin.Security.Cookies даже не известно о его наличии), поэтому он не знает, что должно быть по умолчанию.

Использование неправильного типа аутентификации по умолчанию

Сегодня это стоило мне много времени, потому что я толком не знал, что делаю:

public void Configuration(IAppBuilder app)
{
    app.SetDefaultSignInAsAuthenticationType("WS-Fed AAD Auth");

    // ... remainder of configuration
}

Итак, он будет продолжать попытки аутентифицировать вызывающего с помощью WS-Federation при каждом вызове. Дело не в том, что это сверхдорогие, а в том, что промежуточное ПО WS-Federation на самом деле создает проблемы на каждый запрос. Таким образом, вы никогда не сможете войти, и вы видите, как множество URL-адресов для входа пролетает мимо вас. :П

Возможности

Итак, что здорово иметь всю эту гибкость в конвейере, так это то, что вы можете делать действительно классные вещи. Например, у меня есть домен с двумя разными веб-приложениями внутри него, работающими с разными подпутьями, такими как: example.com/foo и example.com/bar. Вы можете использовать функцию сопоставления Owin (как в app.Map(...)), чтобы настроить совершенно другой конвейер аутентификации для каждого из этих приложений. В моем случае один использует WS-Federation, а другой - клиентские сертификаты. Было бы ужасно пытаться сделать это в монолитном System.Web фреймворке. :П

person Lars Kemmann    schedule 08.10.2014
comment
Большое спасибо, Ларс, мне наконец удалось найти время, чтобы взглянуть на это еще раз (извините за задержку с принятием!), И вы, и Тратчер очень помогли в этом, я обобщил то, что, как мне кажется, я знаю, в своей ответьте здесь - stackoverflow.com/questions/23262471/ - person Tom Tregenna; 12.12.2014
comment
Спасибо, Том. Очень признателен. :) И ваше резюме точное. Когда вы говорите, что, насколько я понимаю, промежуточное программное обеспечение Federation использует промежуточное программное обеспечение Cookie для управления своими файлами cookie, связанными с аутентификацией, - я могу сказать несколько иначе. Промежуточное ПО Federation даже ничего не знает о файлах cookie, оно просто тупо и проверяет токен в каждом запросе, который его просят аутентифицировать. Как только запрос аутентифицируется промежуточным программным обеспечением WS-Fed, промежуточное программное обеспечение Cookie знает, что нужно выдать cookie (я не уверен, как это сделать, это некоторая возможность конвейера). Так что это просто перевернутая зависимость. - person Lars Kemmann; 30.12.2014
comment
На шаге 3 он не работает без набора свойств Wreply. Я устанавливаю то же значение, что и Wtrealm, и тогда он работает. - person Miguel; 12.03.2019
comment
--- Позвольте мне расширить свой предыдущий комментарий. Я обнаружил, что Wreply необходим, когда у вас есть несколько конечных точек, зарегистрированных для вашего Relaying Party Trust в AD FS. В этих обстоятельствах, если Wreply не установлен, AD FS будет отвечать, используя конечную точку по умолчанию, которая может отличаться от Wtrealm и вызывать проблемы. - person Miguel; 12.03.2019