Use OWIN Ws-Federation package to authenticate aga

2019-03-12 18:10发布

问题:

I have an MVC intranet site that needs to use AD accounts for authentication.

I setup ADFS 3.0 (Win Server 2012 R2) and followed this to setup the ADFS Relying Party Trust.

This other post introduces the Ws-Federation OWIN components and I'd like to use it. It mentions how to connect to an Azure AD but nothing regarding ADFS.

I tried setting the configuration properties "MetadataAddress" and "Wtrealm" to match what I configured in ADFS but at runtime I get an error:

A default value for SignInAsAuthenticationType was not found in IAppBuilder Properties. 
This can happen if your authentication middleware are added in the wrong order, or if one is missing.

I am looking for the proper way remove this error

回答1:

Yeah.. I came across the same issue. Just do the following and it should work:

    app.SetDefaultSignInAsAuthenticationType(WsFederationAuthenticationDefaults.AuthenticationType );

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


回答2:

I've been trying to get my head around this for a while now, and with thanks specifically to Lars Kemmann and Tratcher, I believe the accepted way of doing this is as follows:

app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

app.UseCookieAuthentication(
    new CookieAuthenticationOptions { }
);

app.UseWsFederationAuthentication(
    new WsFederationAuthenticationOptions
    {
        Wtrealm = ConfigurationManager.AppSettings["ida:Wtrealm"],
        MetadataAddress = ConfigurationManager.AppSettings["ida:FedMetadataURI"]
    }
);

It seems counter-intuitive that you're configuring the default authentication type as 'Cookie Authentication' to get WsFederation to work, however these are really just strings used to identify each piece of middleware (this allows you to register the same type of middleware multiple times, for example), they evaluate as follows:

  • CookieAuthenticationDefaults.AuthenticationType = "Cookies"
  • WsFederationAuthenticationDefaults.AuthenticationType = "Federation"

What's happening here is that we're telling OWIN that the middleware labelled "Cookies" should be used by default to authenticate requests, we then add the CookieAuthentication middleware (by default this is labelled "Cookies" from the CookieAuthenticationDefaults.AuthenticationType value, so we don't have to write any additional code to set it up), finally we add the FederationAuthentication middleware (this is labelled by WsFederationAuthenticationDefaults.AuthenticationType - i.e. "Federation"), my understanding is that the Federation middleware utilises the Cookie middleware to manage its authentication-related cookies.

All that's left it to do is configure your app to invoke the middleware at a time of your choosing, this can be achieved in a number of ways, some of which are as follows:

  • By returning a HTTP 401 response
  • By using the [Authorize] attribute on an MVC Controller
  • By calling the OWIN Context IAuthenticationManager's Challenge method (passing in the label of your Federation middleware)

When I asked this question here, Lars answered with a neat example of how to request authentication for all requests, I then bundled it in to the OWIN pipeline as follows:

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(WsFederationAuthenticationDefaults.AuthenticationType);

            return Task.Delay(0);
        }
    }
);

Note that in the first example above, I moved the Wtrealm and MetadataAddress values into my config file for ease of maintenance, they are just simple application settings:

<appSettings>
    <add key="ida:Wtrealm" value="[app-uri]" />
    <add key="ida:FedMetadataURI" value="https://[adfs-server]/federationmetadata/2007-06/federationmetadata.xml" />
</appSettings>

I hope this helps.



回答3:

Actually, you are just missing this line that is usually before the UseCookieAuthentication method call.

app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

in your case it would be

app.UseExternalSignInCookie(WsFederationAuthenticationDefaults.AuthenticationType);

This is what actually gets executed when you call UseExternalSignInCookie(...), externalAuthenticationType is what you pass in as the string parameter.

app.SetDefaultSignInAsAuthenticationType(externalAuthenticationType);
CookieAuthenticationOptions options = new CookieAuthenticationOptions();
options.AuthenticationType = externalAuthenticationType;
options.AuthenticationMode = AuthenticationMode.Passive;
options.CookieName = ".AspNet." + externalAuthenticationType;
options.ExpireTimeSpan = TimeSpan.FromMinutes(5.0);
app.UseCookieAuthentication(options);

So, if all you are setting is the AuthenticationType, you can safely just call UseExternalSignInCookie as it does it for you.