Search code examples
asp.net-mvcoauth-2.0asp.net-mvc-5asp.net-identityopenid-connect

Mixing cookie external login using Azure AD and individual account in MVC5


I am getting problems with application cookie and external cookie that are integrated login with Azure AD to my web app using MVC5. Currently, my local account work correctly but external account (Google and Azure AD) cannot map external cookie to local cookie. My code get userId return incorrect user Id.

IIdentity ident = HttpContext.Current.GetOwinContext().Request.User.Identity;
ident.GetUserId()

Below is my startup.cs

public partial class Startup
    {
        // The Client ID is used by the application to uniquely identify itself to Azure AD.
        string clientId = System.Configuration.ConfigurationManager.AppSettings["ClientId"];

        // RedirectUri is the URL where the user will be redirected to after they sign in.
        string redirectUri = System.Configuration.ConfigurationManager.AppSettings["RedirectUri"];

        string postLogoutRedirectUri = System.Configuration.ConfigurationManager.AppSettings["PostLogoutRedirectUri"];

        // Tenant is the tenant ID (e.g. contoso.onmicrosoft.com, or 'common' for multi-tenant)
        static string tenant = System.Configuration.ConfigurationManager.AppSettings["Tenant"];

        // Authority is the URL for authority, composed by Microsoft identity platform endpoint and the tenant name (e.g. https://login.microsoftonline.com/contoso.onmicrosoft.com/v2.0)
        string authority = String.Format(System.Globalization.CultureInfo.InvariantCulture, System.Configuration.ConfigurationManager.AppSettings["Authority"], tenant);

        // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
        public void ConfigureAuth(IAppBuilder app)
        {
            // Configure the db context and user manager to use a single instance per request
            app.CreatePerOwinContext(AppIdentityDbContext.Create);
            app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);
            app.CreatePerOwinContext<AppSignInManager>(AppSignInManager.Create);
            app.CreatePerOwinContext<AppRoleManager>(AppRoleManager.Create);


            // Enable the application to use a cookie to store information for the signed in user
            // and to use a cookie to temporarily store information about a user logging in with a third party login provider
            // Configure the sign in cookie
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                AuthenticationMode = AuthenticationMode.Active,
                LoginPath = new PathString("/"),
                Provider = new CookieAuthenticationProvider
                {
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<AppUserManager, AppUser>(
                        validateInterval: TimeSpan.FromHours(1),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                },
                ExpireTimeSpan = TimeSpan.FromHours(1),
                //Samesite secure
                CookieSameSite = SameSiteMode.Lax,
                CookieHttpOnly = true,
                CookieSecure = CookieSecureOption.Always,
                CookieManager = new SameSiteCookieManager(new SystemWebCookieManager())
            });

            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

            //Open Id Connect
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ExternalCookie,
                CookieManager = new SameSiteCookieManager(new SystemWebCookieManager())
            });
            app.UseOpenIdConnectAuthentication(CreateOpenIdOptions());

            // GOOGLE
            app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
            {
                ClientId = ConfigurationManager.AppSettings["GoogleClientID"].ToString(),
                ClientSecret = ConfigurationManager.AppSettings["GoogleClientSecret"].ToString()
            });
        }

        private OpenIdConnectAuthenticationOptions CreateOpenIdOptions()
        {
            var options = new OpenIdConnectAuthenticationOptions
            {
                Authority = authority,
                ClientId = clientId,
                RedirectUri = redirectUri,
                AuthenticationMode = AuthenticationMode.Passive,
                // PostLogoutRedirectUri is the page that users will be redirected to after sign-out. In this case, it is using the home page
                PostLogoutRedirectUri = postLogoutRedirectUri,
                Scope = OpenIdConnectScope.OpenIdProfile, // a basic set of permissions for user sign in & profile access
                                                          // ResponseType is set to request the id_token - which contains basic information about the signed-in user
                ResponseType = OpenIdConnectResponseType.IdToken,
                TokenValidationParameters = new TokenValidationParameters
                {
                    // In a real application you would use ValidateIssuer = true for additional checks and security.
                    ValidateIssuer = false,
                },
                Notifications = new OpenIdConnectAuthenticationNotifications()
                {
                    AuthenticationFailed = OnAuthenticationFailed,
                },
                // Handling SameSite cookie according to https://learn.microsoft.com/en-us/aspnet/samesite/owin-samesite
                CookieManager = new SameSiteCookieManager(
                                 new SystemWebCookieManager()),
            };

            return options;
        }

        private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
        {
            // Handle any unexpected errors during sign in
            context.OwinContext.Response.Redirect("/Error?message=" + context.Exception.Message);
            context.HandleResponse(); // Suppress the exception
            return Task.FromResult(0);
        }
    }

Below is sign out method which is called before sign in

var authenticationTypes = new string[] {
                DefaultAuthenticationTypes.ApplicationCookie,
                DefaultAuthenticationTypes.ExternalCookie,
            };

            AuthManager.SignOut(authenticationTypes);

I also already tried apply many fixed posts related to this but it does not work. How can we resolve external cookie map to local cookie?


Solution

  • Finally, I found workaround solutions below: First if you don want to use Open id connect use the link below