Метод OWIN Challenge() не выполняется при использовании нескольких файлов ADFS + Cookies

Мое приложение ASP.Net использует OWIN/Katana/Claims и позволяет войти в систему, используя:

  1. Традиционное имя пользователя/пароль (существует для всех пользователей)
  2. Google
  3. Azure AD

Он работает отлично, и все необходимые передачи перенаправлений/утверждений работают хорошо (данные пользователя NameIdentifier/Provider(/tenant) передаются обратно в мое приложение, поэтому уникальные значения идентификатора могут быть связаны). Обратите внимание, что пользователи не подписываются/не регистрируются в приложении — доступ предоставляется суперпользователем их организации, и им отправляется имя пользователя/пароль, которые они затем могут подключить к Google/Azure.

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

Весь мой файл StartupAuth показан ниже. Я понимаю, что могут быть ошибки конфигурации, но, основываясь на обрывках образцов, которые я нашел за последние шесть недель, это лучшее, что у меня было.

public void Configuration(IAppBuilder app)
    {
        // STANDARD CODE FOR APP COOKIE AND GOOGLE - WORKS PERFECTLY

        CookieAuthenticationOptions coa = new CookieAuthenticationOptions {
            AuthenticationMode = AuthenticationMode.Active,
            CookieName = "MyAppName",
            ExpireTimeSpan = TimeSpan.FromMinutes(60),
            SlidingExpiration = true,
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/login.aspx"),
            CookieHttpOnly = true,
            CookieSecure = CookieSecureOption.SameAsRequest,
            Provider = new CookieAuthenticationProvider { OnValidateIdentity = context =>
            {
                dynamic ret = Task.Run(() =>
                {
                    // Verify that "userId" and "customerId" claims exist, and that each has a valid value (greater than zero) - removed for brevity
                    return Task.FromResult(0);
                });
                return ret;
            } }
        };
        app.SetDefaultSignInAsAuthenticationType(coa.AuthenticationType);
        app.UseCookieAuthentication(coa);

        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
        app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions {
            ClientId = "84***********************k3.apps.googleusercontent.com",
            ClientSecret = "jue*****************Ppi"
        });



        // NEW CODE THAT FAILS TO WORK - SPECIFYING EACH CUSTOMER'S ADFS AS A NEW WSFED AUTH OPTION


        WsFederation.WsFederationAuthenticationOptions Adfs_CompanyA = new WsFederation.WsFederationAuthenticationOptions {
            AuthenticationMode = AuthenticationMode.Passive,
            MetadataAddress = "https://CompanyA.net/FederationMetadata/2007-06/FederationMetadata.xml",
            AuthenticationType = AdfsAuthenticationTypes.CompanyA,
            Wtrealm = "https://www.CompanyA.co.uk/MyAppName"
        };

        WsFederation.WsFederationAuthenticationOptions Adfs_CompanyB = new WsFederation.WsFederationAuthenticationOptions {
            AuthenticationMode = AuthenticationMode.Passive,
            MetadataAddress = "https://CompanyB.net/federationmetadata/2007-06/federationmetadata.xml",
            AuthenticationType = AdfsAuthenticationTypes.CompanyB,
            Wtrealm = "http://www.CompanyB.co.uk/azure/MyAppName"
        };

        // User (who is logged in), route for hyperlink "Link my account with ADFS"
        app.Map("/SSO/LinkUserAccount/ADFS/process", configuration => { configuration.UseWsFederationAuthentication(Adfs_CompanyA); });

        // CompanyA ADFS - single sign-on route
        app.Map("/SSO/Login/CompanyA/ADFS/Go", configuration => { configuration.UseWsFederationAuthentication(Adfs_CompanyA); });

        // CompanyB ADFS - single sign-on route
        app.Map("/SSO/Login/CompanyB/ADFS/Go", configuration => { configuration.UseWsFederationAuthentication(Adfs_CompanyB); });
    }
}

Вот код, который я использую для запуска OWIN Challenge:

string provider = MyApp.SingleSignOn.GetCustomerAdfsAuthenticationType(customerName);
string redirectUrl = string.Format("{0}/SSO/Login/{1}/ADFS/Go", Request.Url.GetLeftPart(UriPartial.Authority), provider); // creates https://myapp.com/SSO/Login/CompanyA/ADFS/Go for CompanyA users
Context.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = redirectUrl }, provider);
Response.StatusCode = 401;
Response.End();

Это веб-формы, но, пожалуйста, не позволяйте этому мешать профессионалам MVC вносить свой вклад. В любом случае код практически идентичен, и я использую маршруты.

Проблема, с которой я сталкиваюсь, заключается в том, что когда пользователь нажимает ссылку «Вход с ADFS», например. URL становится https://myapp.com/SSO/Login/CompanyA/ADFS. Я получаю ошибка 401 Unauthorized вместо того, чтобы пользователь перенаправлялся на страницу входа в ADFS.
В web.config я разрешаю несанкционированный доступ к пути «SSO». По какой-то причине метод Challenge() никогда не перенаправляет пользователя, он просто игнорируется, и код достигает точки, в которой он возвращает 401. Значение строки provider точно соответствует значению WsFederationAuthenticationOptions.AuthenticationType, определенному в Startup.Auth.

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


person EvilDr    schedule 02.12.2015    source источник


Ответы (2)


Я решил проблему. Удивительно, но это было так просто, как я пропустил это в конце StartupAuth:

app.UseStageMarker(PipelineStage.Authenticate);
person EvilDr    schedule 09.12.2015

Вы настроили ведение журнала OWIN? Есть какие-нибудь подсказки?

Кроме того, Тестирование WS- ПО промежуточного слоя аутентификации федерации для Katana.

Взгляните на код в IdentityServer 3. Там есть плагин WS-Fed, а документация находится здесь (внизу).

person rbrayb    schedule 02.12.2015
comment
Образец кода, по-видимому, настраивает один экземпляр ADFS, что я встречал во многих других проектах в Интернете. Однако я не вижу никакого использования ADFS в тандеме с другими поставщиками. Сегодня я посмотрю на ведение журнала, хотя раньше я этого не делал. - person EvilDr; 03.12.2015
comment
IdentityServer 3 поддерживает социальные сети (Google и т. д.), OpenID Connect, OAuth2 и WS-Fed. - person rbrayb; 03.12.2015