My ASP.Net app uses OWIN/Katana/Claims, and allows login using:

  1. Traditional username/password (exists for all users)
  2. Google
  3. Azure AD

It works perfectly, and all the necessary redirects/claims transfers work well (the user NameIdentifier/Provider(/tenant) details are passed back to my app so the unique id values can be linked up). Note that users do not sign up/register for the app - access is provisioned by their organisation's super-user, and a username/password sent to them which they can then hook up with Google/Azure.

However, I now need to extend this functionality to allow users to hook up to their organisation's ADFS provider. The only working example for this that's remotely close is here (tutorial/code), but it is strictly based on ADFS-only. When I adapt this into my project, it doesn't work.

My entire StartupAuth file is shown below. I appreciate that there may be configuration errors, but based on the scraps of samples I've found over the last six weeks, this is the best I've had.

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); });
    }
}

Here is the code I use to issue an 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();

This is webforms, but please don't let that stop MVC pro's from contributing. The code is virtually identical anyway and I'm using routes.

The problem I have is that when the user clicks on the "sign-on with ADFS" link, e.g. URL becomes https://myapp.com/SSO/Login/CompanyA/ADFS I get an 401 Unauthorized error, instead of the user being redirected to the ADFS login page.

In web.config, I allow unauthorized access to path "SSO", so I don't get why this happens (OWIN shouldn't check for the ADFS cookie until the user comes back to the app (e.g. "Go" is appended on the URL).

I've been sturggling with this now for six weeks, so this is getting maximum bounty at the first opportunity, and a crate of beer delivered to your chosen address when it is solved.

Related posts

Recent Viewed