Skipping home realm discovery with Ws-Federation O

2019-01-28 07:17发布

问题:

Our Mvc/WebAPI solution currently has four trusted identity providers which we have registered in ADFS3. Each of these identity providers can be used by our users by direct links, effectively working around any home-realm-cookies that ADFS may have created (eg: www.ourportal.com/accounts/facebook or www.ourportal.com/accounts/twitter). Currently we are migrating from WIF to OWIN but will keep using WS-Federation protocol for the time being by implementing wsfederation and cookie authentication middleware. When using WIF, we did the following in order to go directly to a known identity provider:

var signInRequest = new SignInRequestMessage(stsUrl, realm) { HomeRealm = homeRealm };
return new RedirectResult(signInRequest.WriteQueryString());

This seems to have two concerning behaviors, it does not pass the WsFedOwinState parameter, and on the return back to the Relying Party, the Home.cshtml is built (with a windows principal) before the the Owin authentication middleware is fired. The Home.cshtml being fired before the Owin middleware is the most concering as this view relies on Claims that would is provided in the transformation done by the authentication pipeline, which is fired afterwards and thus our view does not work. It works in the correct order when going to the portal in the normal way (eg www.ourportal.com)

I understand that in order to provide the Whr parameter, you do the following when configuring the ws-federation middleware:

RedirectToIdentityProvider = (context) =>
{
    context.ProtocolMessage.Whr = "SomeUrnOfAnIdentityProvider";
    return Task.FromResult(0);
}

but this sets a single identity provider for the whole solution and does not allow our users to go directly to one of a list of identity providers.

The non-working method which builds the sign-in-request is currently:

private RedirectResult FederatedSignInWithHomeRealm(string homeRealm)
{
    var stsUrl = new Uri(ConfigurationManager.AppSettings["ida:Issuer"]);
    string realm = ConfigurationManager.AppSettings["ida:Audience"];

    var signInRequest = new SignInRequestMessage(stsUrl, realm)
    {
        HomeRealm = homeRealm
    };
 HttpContext.Request.GetOwinContext().Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
        return new RedirectResult(signInRequest.WriteQueryString());
    }

The ws-federation and cookie middleware are configured as the first middleware in OWIN startup and the default authentication is set to app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

回答1:

I think I found a solution. The new method for skipping the home realm screen would be like this :

private void FederatedSignInWithHomeRealm(string homeRealm)
{
    HttpContext.Request
               .GetOwinContext()
               .Authentication
               .SignOut(CookieAuthenticationDefaults.AuthenticationType);
    var authenticationProperties = new AuthenticationProperties { RedirectUri = "/" };
    authenticationProperties.Dictionary.Add("DirectlyToIdentityProvider", homeRealm);
    HttpContext.GetOwinContext().Authentication.Challenge(authenticationProperties);
}

And the OWIN WS-Federation middleware would be configured like this :

app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions
{
    Notifications = new WsFederationAuthenticationNotifications()
    {
        RedirectToIdentityProvider = notification =>
        {
            string homeRealmId = null;
            var authenticationResponseChallenge = notification.OwinContext
                                                              .Authentication
                                                              .AuthenticationResponseChallenge;
            var setIdentityProvider = authenticationResponseChallenge != null 
                                      && authenticationResponseChallenge.Properties
                                                                        .Dictionary
                                                                        .TryGetValue("DirectlyToIdentityProvider", out homeRealmId);
            if (setIdentityProvider)
            {
                notification.ProtocolMessage.Whr = homeRealmId;
            }
            return Task.FromResult(0);
        }
    },
    MetadataAddress = wsFedMetadata,
    Wtrealm = realm,
    SignInAsAuthenticationType =     CookieAuthenticationDefaults.AuthenticationType,
    TokenValidationParameters = new TokenValidationParameters
    {
        ValidAudience = realm
    }    
});


标签: owin