Search code examples
asp.net-mvcauthenticationauthorizationowinws-federation

OWIN WsFederation authentication with in-app authorization


The scenario:

  • A ASP.NET MVC Web app for a company's internal users, configured for authentication against the company's ADFS, using Microsoft.Owin.Security.WsFederation
  • The company's ADFS contains several users, but only a few of them should be able to log in to the application.
  • I therefore have a database table containing these users' email addresses
  • The web app should check if the email claim received from ADFS exists in the DB table, and only issue a log in token for those users.
  • Other users should be redirected to a "Sorry you are not authorized to use this application"-page.

My question:

  • Where is the correct place to put the authorization logic that checks if an user should be allowed in?

Here's the code in my Startup.Configuration method:

app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseWsFederationAuthentication(
    new WsFederationAuthenticationOptions
    {
        MetadataAddress = "https://.../FederationMetadata.xml",
        Wtrealm = "...",                        
    }
);

Solution

  • You have two options to achieve what you want:

    1. One is to configure this at the very AD FS. I personally think this is the right way to do this, since the AD FS is the IdP and it should be the one controlling whether or not its users have access to the application. In this case the company should or should not allow somebody to use some of its resources (of course there are anti-arguments). This can be easily done at the Domain Controller, through the AD FS Management GUI. The following answer greatly describes this: https://serverfault.com/a/676930/321380

    2. Second is to use the Notifications object at the OWIN WSFed middleware in this way:

                Notifications = new WsFederationAuthenticationNotifications()
                {
                    SecurityTokenValidated = (context) =>
                    {
                        //extract claims' values and check identity data against your own authorization logic
                        bool isAuthorized = CheckForUnauthorizedAccess();
                        if (!isAuthorized)
                        {
                            throw new SecurityTokenValidationException("Unauthorized access attemp by {some_identifier}");
                        }
                        return Task.FromResult(0);
                    },
                    AuthenticationFailed = (context) =>
                    {
                        if (context.Exception is an unauthorized exception)
                        {
                            context.OwinContext.Response.Redirect("<unauthorized_redirect_url>");
                        }
                        context.HandleResponse(); // Suppress the exception
                        //exception logging goes here
                        return Task.FromResult(0);
                    }
                }