0

After spending days googling around reading various articles and looking through the Katana source code I'm struggling to understand what feel like fairly basic concepts of how OWIN/Katana/Identity work.

In particular, I've been looking at using Azure Active Directory for authentication of employees, local accounts for authentication of other users external to the company and controlling authorisation through roles in the app.

     //I don't understand what this line of code is for
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
//this appears to be needed for SSO via AAD to work and by default has an authentication type of "Cookies" and cookie name of "ASP.Net.Cookies"
//it is required for SSO via AAD to work and the cookie created appears to be the one required to keep track that a user is logged in
                    app.UseCookieAuthentication(new CookieAuthenticationOptions());
        //This bit sets up the AAD connection
                    app.UseOpenIdConnectAuthentication(
                       new OpenIdConnectAuthenticationOptions
                       {
                           ClientId = clientId,

                           Authority = aadInstance + tenantid,

                           PostLogoutRedirectUri = postLogoutRedirectUri,

                           Notifications = new OpenIdConnectAuthenticationNotifications
                           {
                               AuthenticationFailed = context =>
                               {
                                   context.HandleResponse();
                                   context.Response.Redirect(postLogoutRedirectUri);
                                   return Task.FromResult(0);
                               }
                           }
                       });

//now comes the second call to using cookies - this cookie as an authenticationtype of "ApplicationCookie" and cookie name of "ExternalUser"
                    app.UseCookieAuthentication(new CookieAuthenticationOptions
                    {
                        CookieName = "ExternalUser",
                        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                        LoginPath = new PathString("/Account/Login"),
                        SlidingExpiration = true,
                        ExpireTimeSpan = TimeSpan.FromHours(24),
                        Provider = new CookieAuthenticationProvider
                        {
                            // Revalidate user every 30 mins  
                            OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ExternalUserManager, ExternalUser>(
                                validateInterval: TimeSpan.FromMinutes(30),
                                regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                        }
                    });

Reading through the source code app.Use appears to simply add object types and options to a queue in OWIN to be called at some later point when invoked. I'm therefore struggling to understand the order of requests and where cookies are specifically created. I can see that the OwinContext.Authentication appears to control logins by creating an AuthenticationResponseGrant but I can't see where these are then used to then create cookies or where the cookies are read.

I have managed to get everything working using above and then adding claims for Roles manually using:

var identity = HttpContext.User.Identity as ClaimsIdentity;
                identity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));
                HttpContext.GetOwinContext().Authentication.SignIn(new AuthenticationProperties() { IsPersistent = false },new ClaimsIdentity[] { identity });

However, I would like to understand how this all integrates together much better than I do. What role does the AuthenticationType play? What reads this and differentiates between ApplicationCookie, Cookies, ExternalCookie etc.? How does 1 cookie get read when Azure AAD is being used but another for the ExternalUsers?

As an aside previous to this we were using 2 user databases, 1 for employees and 1 for external users but we struggled to get it to work successfully. The problem being that the authenticationprovider validator seemed to get overridden by the second use of app.UseCookieAuthentication and log-out other users after 30 mins as it failed. We tried to create a Custom SecurityStampValidator to cope with this but couldn't get this to work. It feels like all this is tied together.

All thoughts and links on how this all fits together appreciated. I've seen lots of bits and pieces but nothing seems to go into the detail of what is happening when and where.

Thanks.

Edit

In response to Juan's comment the previous approach using 2 databases had 2 usermanagers to handle the different types of user. The OWIN set-up then had 2 calls to app.UseCookieAuthentication. The second call being something like:

app.UseCookieAuthentication(new CookieAuthenticationOptions
                        {
                            CookieName = "InternalUser",
                            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                            LoginPath = new PathString("/Account/Login"),
                            SlidingExpiration = true,
                            ExpireTimeSpan = TimeSpan.FromHours(24),
                            Provider = new CookieAuthenticationProvider
                            {
                                // Revalidate user every 30 mins  
                                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<InternalUserManager, InternalUser>(
                                    validateInterval: TimeSpan.FromMinutes(30),
                                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                            }
                        });

i.e. identical bar the different user classes. The problem was that OnValidateIdentity always failed after 30 mins for 1 user type.

Edit2:

Here's the full code of the setup of the old problem (but note my main issue is understanding how these various cookie options all work and interact as I am no longer using the below as we've moved to using Azure AD for internal users):

public void ConfigureAuth(IAppBuilder app)
        {

            app.CreatePerOwinContext(ExternalContext.Create);
            app.CreatePerOwinContext(InternalContext.Create);
            app.CreatePerOwinContext<ExternalUserManager>(ExternalUserManager.Create);
            app.CreatePerOwinContext<InternalUserManager>(InternalUserManager.Create);
            app.CreatePerOwinContext<InternalSignInManager>(InternalSignInManager.Create);
            app.CreatePerOwinContext<ExternalSignInManager>(ExternalSignInManager.Create);

                     app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                CookieName = "InternalUser",
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                SlidingExpiration = true,
                ExpireTimeSpan = TimeSpan.FromHours(24),
                Provider = new CookieAuthenticationProvider
                {

                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<InternalUserManager, InternalUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                }
            });

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                CookieName = "ExternalUser",
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                SlidingExpiration = true,
                ExpireTimeSpan = TimeSpan.FromHours(24),
                Provider = new CookieAuthenticationProvider
                {

                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ExternalUserManager, ExternalUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                }
            });
        }
    }

Any logins of InternalUser would be auto logged out after 30 mins.

Edit3:

After reading around some more it seemed that the AuthenticationType was the key parameter. I therefore took that old code above and change the AuthenticationType to "InternalUserCookie" and "ExternalUserCookie" - I also added to the constructor of the signin managers a line to set the AuthenticationType here to these as well thinking this would match up. Making this change though just means the login isn't retained at all and no cookies...

Mark007
  • 345
  • 1
  • 4
  • 8
  • You shouldn't be needing to "understand" this. That is the whole point behind using components like this. Also, I am not sure why you are adding claims manually to the identity. Claims should be coming down to you from the authentication endpoint and you should be making authorization decisions based on that. Hard to tell what went wrong with your previous attempt. Not enough details. – JuanR Sep 25 '17 at 13:07
  • Here is the PDF for the full lifecycle https://www.asp.net/media/4071077/aspnet-web-api-poster.pdf – Filix Mogilevsky Sep 25 '17 at 13:08
  • @Juan Not sure I could ever agree that understanding is not important. The whole point of such components is to make life easier, not use things completely blindly in all cases. As per the description the roles are to be managed locally rather than coming from Azure. They can then be managed directly in the app rather than needing extra permissions within Active directory and can be shared with External users. Authentication and Authorisations are 2 things and I am using Azure AD for Authentication but managing Authorisations locally. – Mark007 Sep 25 '17 at 13:15
  • @Juan I've added extra info on previous attempt at 2 databases. We are no longer using this having moved to Azure AD for internal users but looking to understand how this works and why previous attempt failed. As an aside, if only the ExternalUser cookieoptions version is set but I called SignIn on the InternalUser user manager this used the ExternalUser cookie even though the other default cookieoptions were set-up too. What made it pick this one? – Mark007 Sep 25 '17 at 13:28
  • @FilixMogilevsky thanks for that useful PDF. However, it's not really what I'm looking for as it doesn't cover the OWIN and identity aspects. – Mark007 Sep 25 '17 at 13:29
  • Possible duplicate of [Mixed authentication for OWIN](https://stackoverflow.com/questions/21029192/mixed-authentication-for-owin) – JuanR Sep 25 '17 at 14:00
  • @Juan that's a useful post to show how to do windows authentication in a totally different way but doesn't entirely help. It does make me wonder why the first call to use cookies isn't to use an external cookie. Azure AD is surely external but all examples are set up as per my code above. Again need to understand what is going on with the cookies to understand what the best approach/why things work/don't work. – Mark007 Sep 25 '17 at 15:54
  • It looks to me like you may need to implement your own `CookieAuthenticationProvider` or a `UserManager` class that can handle both users. – JuanR Sep 25 '17 at 16:01
  • @Juan that's sort of where I got to with the old problem. Struggling with some fundamentals though. What causes the cookie to get created. It seems to be a combination of the OwinContext having an AuthenticationResponseGrant and also the cookie middleware being set-up but what is wiring this all up? Is it the cookie middleware that checks the GrantAuthenticationResponse? Is so when does it do it and why would one CookieMiddleWare pick it up and not the other. How does it link together? – Mark007 Sep 25 '17 at 16:38
  • I think I may have an idea of what is going on. Which user type fails the authentication after 30 minutes? AD or local? – JuanR Sep 25 '17 at 18:04
  • @Juan I've added another edit to give detail of the original problem. However, note I'm no longer doing this as now using Azure AD for internal users. I still need to understand what is going on with multiple cookie middlewares set. – Mark007 Sep 26 '17 at 08:46
  • Found a great article on CookieMiddleware for .Net core. Can't find an equivalent but it's still helped a little: https://andrewlock.net/exploring-the-cookieauthenticationmiddleware-in-asp-net-core/ – Mark007 Sep 26 '17 at 09:27

0 Answers0