ASP.NET Identity 2 with Google login... Logout doesn't work - asp.net

I want to be able to logout the currently logged in user, especially in the use case of current user closes browser, opens a new browser, heads to the login page.
Here is what I've been trying...
private ActionResult DoLogout()/// check this out https://dzone.com/articles/catching-systemwebowin-cookie the sytem.web cookie monster
{
var AuthenticationManager = HttpContext.GetOwinContext().Authentication;
AuthenticationManager.SignOut();
AuthenticationManager.SignOut( DefaultAuthenticationTypes.ApplicationCookie );
Session.Abandon();
var user = UserManager.FindByName( User.Identity.Name );
if (user != null)
{
UserManager.UpdateSecurityStamp( user.Id ); // remove the old cookie so it can't be reused to re-log in - EWB
}
AuthenticationManager.SignOut();
ClearCookies();
Request.GetOwinContext().Authentication.SignOut( DefaultAuthenticationTypes.ApplicationCookie );// https://stackoverflow.com/questions/28999318/owin-authentication-signout-doesnt-seem-to-remove-the-cookie - stralos s answer
// https://stackoverflow.com/questions/43675904/asp-net-identity-2-logging-out-other-sessions-using-security-stamp-after-pa
AuthenticationManager.SignOut( DefaultAuthenticationTypes.ApplicationCookie );
return Redirect("https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=https://"+ Url.Action( "Index", "Home", new { target = "_blank" } ) ); //https://stackoverflow.com/questions/27515518/asp-net-identity-external-login-wont-log-out - f belihocine answer
}
but when I log back in this code gets called
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("LogOut"); // <--- here
}
Because the user is in a broken state, because I think ASP.net is logged out, but Google is still logged in....
Any help is appreciated

You need to call Google API to get this done , please see this for more information ASP.net identity - external login - won't log out

this is what finally did the trick
Request.GetOwinContext().Authentication.SignOut( DefaultAuthenticationTypes.ApplicationCookie );// https://stackoverflow.com/questions/28999318/owin-authentication-signout-doesnt-seem-to-remove-the-cookie - stralos s answer
Request.GetOwinContext().Authentication.SignOut( DefaultAuthenticationTypes.ExternalCookie ); // https://stackoverflow.com/questions/43675904/asp-net-identity-2-logging-out-other-sessions-using-security-stamp-after-pa
I noticed that most places used app cookie, but in a few it was external.. .I converted all to app cookie and it stopped working, then I tried this next.
Here is the code in StartupAuth where you can see both cookies are being used
app.UseCookieAuthentication(
new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
SlidingExpiration = true,
ExpireTimeSpan = TimeSpan.FromMinutes( 1 ),
CookieName = "SP3GGS-ID2-cookie",
//CookieSecure = CookieSecureOption.Always, // TODO: turn this on for prod/qa so only ssl is allowed - EWB - per https://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes( 1 ),
regenerateIdentity: ( manager, user ) => user.GenerateUserIdentityAsync( manager )
)
},
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);// HERE EWB

Related

User unauthorized after Azure AD login to different application simultaneously

I have two MVC applications AppA and AppB, and implemented Azure AD authentication for login.
I am able to sign-in successfully to both applications.
But the issue is, after I login to AppA and then to AppB, after sometime when I return back to AppA I am facing the issue where user has been logged out, and it again redirects to login screen (in AppA).
After I login to AppA (second time) and go back to AppB (user in AppB is logged out).
Client IDs are different ; TenandID is same. Both apps are hosted in same server.
Startup file:
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
SlidingExpiration = true,
Provider = new CookieAuthenticationProvider
{
OnResponseSignIn = context =>
{
context.Properties.AllowRefresh = true;
context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddDays(1);
},
OnValidateIdentity = MyCookieValidateIdentity
},
ExpireTimeSpan = TimeSpan.FromDays(2)
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = appId,
//CookieManager=new SameSiteCookieManager(new SystemWebCookieManager()),
Authority = "https://login.microsoftonline.com/xxxxxx/v2.0",
Scope = $"openid email profile offline_access {graphScopes}",
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectUri,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = (context) =>
{
context.ProtocolMessage.DomainHint = "xyz.com";
return Task.FromResult(0);
},
// SecurityTokenValidated = OnSecurityTokenValidated,
AuthenticationFailed = OnAuthenticationFailedAsync,
AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
}
}
);
}
actionContext.RequestContext.Principal.Identity.IsAuthenticated is returning False
I am assuming it has to do something with the cookie. Can someone please help resolve this ?
Edit:
Debugged further and found:
Initially if the cookies for AppA are set as:
.AspNet.Cookies = A_abc123 ; ASP.NET_SessionId = A_def456
And for AppB .AspNet.Cookies = B_mno123 ; ASP.NET_SessionId = B_pqr456
Then after I click any link in AppA, the cookie's values are updated with AppB's cookies, i.e. .AspNet.Cookies = B_mno123 ; ASP.NET_SessionId = B_pqr456
.AspNet.Cookies ASP.NET_SessionId
AppA A_abc123 A_def456
AppB B_mno123 B_pqr456
AppA B_mno123 B_pqr456
One thing that you need to do is to configure the Data Protection API so that both services uses the same cookie protection key. Out of the box each service creates its own unique key, and a cookie from one service is not valid in a different service.
I also did a blog post about the data protection API here.
See
How to: Use Data Protection
Get started with the Data Protection APIs in ASP.NET Core
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
//AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,// DefaultAuthenticationTypes.ApplicationCookie,
CookieName = ".AspNet.AppA.Cookies",
SlidingExpiration = true,
CookieManager = new SystemWebCookieManager(),
Provider = new CookieAuthenticationProvider
{
OnResponseSignIn = context =>
{
context.Properties.AllowRefresh = true;
context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddDays(1);
},
},
ExpireTimeSpan = TimeSpan.FromDays(2)
});
//... code removed for brevity //
}
The Default Cookie Name set by the application was: .AspNet.Cookies
And when I modified the default cookie name, the issue got resolved. Each application was generating its own cookiename and hence the other application was not signing out the user.

ASP.NET CORE 3.1 Authentication Cookie but store Username Only

I have created the code below to enable authentication on my ASP.NET CORE 3.1 site that is not using full blown Identity framework but instead just UseAuthentication in startup.
Startup.cs cookie settings:
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(cookieOptions => {
cookieOptions.Cookie.Name = "UserLoginCookie";
cookieOptions.LoginPath = "/Login/";
cookieOptions.ExpireTimeSpan = TimeSpan.FromMinutes(1);
cookieOptions.SlidingExpiration = true;
});
services.AddRazorPages().AddRazorPagesOptions(options => {
options.Conventions.AllowAnonymousToFolder("/Login");
options.Conventions.AuthorizeFolder("/");
});
The indexmodel for my razor login page utilized the following cookie related code:
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, UserName)
};
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
if (RememberMe)
{
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
new AuthenticationProperties
{
IsPersistent = RememberMe,
ExpiresUtc = DateTimeOffset.UtcNow.AddDays(30)
});
}
else
{
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity));
}
return RedirectToPage("/index");
I allow the user to select remember me or not on the login page and if they do then it creates a persistent cookie. Therefore, if the user selects this option and leaves the site they are not required to login in again as long as the cookie has not expired. My question is can a cookie only store the username such that if the user leaves the site/closes the browser they must login again but the username is stored in the login form from the cookie? If this is possible is there a secure way to implement this using a hash and salt with the username stored in the cookie?
If this is not possible does the current method I am using for authentication securely hash the username and password by default or do I need to do some additional settings for this? When i look into the browser application tab for the cookies it looks to be hashed but not sure what sure to what extent the hash is being secured with. Any insight on this would be great.

Asp.NET Identity setting persistent cookie to expire after specific time

I have written a following code like below to refresh user roles after they subscribed to my website like following:
private void RefreshUserRoles()
{
var AuthenticationManager = HttpContext.GetOwinContext().Authentication;
var Identity = new ClaimsIdentity(User.Identity);
Identity.RemoveClaim(Identity.FindFirst(ClaimTypes.Role));
Identity.AddClaim(new Claim(ClaimTypes.Role, "Subscriber"));
AuthenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(
new ClaimsPrincipal(Identity),
new AuthenticationProperties { IsPersistent = true}
);
}
Please note this line of code:
AuthenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(
new ClaimsPrincipal(Identity),
new AuthenticationProperties { IsPersistent = true}
);
After user comes back to my website I set the cookie to be persistent, but I forgot to set the expiration for this cookie. I should set this cookie to last for 30 minutes, after which user should be asked to re-log onto the system.
Since some users never re-log on website, this leaves me with an issue, now I need to reset all users cookies in their browsers when they access the website and change their role if they cancelled the subscription. I noticed some users cancelled their subscription and never relogged but yet they still are able to use features on my website...
So my questions are:
How to set expiration of cookie to 30 minutes after which user will be asked to re-log onto the system.
How to Setup to re-check users cookies if they haven't expired in a long time so that I can reset their cookies to regular user if they cancelled subscription?
Here is the ConfigureAuth method I was talking about:
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Controller/Action"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
That's how I have it set and it works for me.

Make custom request when auth session is expired or user logged out

In one MVC project, I implemented asp.net identity based on cookies. Now I have a requirement to make a request to remote service when auth session is expired or when user logged off.
Is there any natural way to accomplish that? For now I managed to set two delegate properties from CookieAuthenticationProvider like below:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Login"),
CookieSecure = CookieSecureOption.SameAsRequest,
ExpireTimeSpan = TimeSpan.FromMinutes(expireInMinutes),
CookiePath = cookiePath,
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = c =>
{
if (c.Properties.ExpiresUtc.HasValue && c.Properties.ExpiresUtc.Value < c.Options.SystemClock.UtcNow)
{
c.RejectIdentity();
c.Request.Context.Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
return Task.FromResult(0);
}
if (c.Options.SlidingExpiration)
{
// Reissue the auth cookie
}
return Task.FromResult(0);
},
OnResponseSignOut = c =>
{
// Make a custom request
}
}
});
At first glance it looks like it works but I don't like the idea of checking expiry date in here. Problem is that OnResponseSignOut is not called when auth cookie is simply expired but is called only when I explicitly call IAuthenticationManager.SignOut.
Is creating a custom CookieAuthenticationProvider the best option in here, or maybe there is another clean and natural solution for that case?

Identity cookie loses custom claim information after a period of time

I am storing custom claims, such as the user's real name, in the ASP.NET Identity cookie to avoid unnecessary database queries on every request. At least that's what I assume this code is doing:
var identity = await user.GenerateUserIdentityAsync(UserManager);
identity.AddClaim(new Claim(ClaimTypes.GivenName, user.FirstName)));
// etc.
AuthenticationManager.SignIn(new AuthenticationProperties {IsPersistent=true}, identity);
This works fine, and I can retrieve these claims with:
private static string GetClaim(string claimType)
{
var identity = (ClaimsPrincipal) Thread.CurrentPrincipal;
var claim = identity.Claims.SingleOrDefault(o => o.Type == claimType);
return claim == null ? null : claim.Value;
}
The identity.Claims property contains the following claims, as expected:
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: ced2d16c-cb6c-4af0-ad5a-09df14dc8207
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: me#example.com
http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider: ASP.NET Identity
AspNet.Identity.SecurityStamp: 284c648c-9cc7-4321-b0ce-8a347cd5bcbf
http://schemas.microsoft.com/ws/2008/06/identity/claims/role: Admin
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname: My Name
The trouble is that after some time (usually several hours), my custom claims seem to disappear - in this example, givenname no longer exists in the enumeration. The user is still authenticated, and all the default claims are still there.
What's going on, and how can I fix this? The only thing I can think of is that the cookie is expiring and being re-issued behind the scenes, but I don't know why (or if) that would happen.
Yes, the issue is most likely the cookie getting expired. Since you didn't add the custom claims to the user's claims in the database, they are lost on refresh since you aren't adding the claim inside the method being called. You can either add the claim via:
userManager.AddClaim(user.Id, new Claim(ClaimTypes.GivenName, user.FirstName));
or you can move this inside of the method that's called when the cookie is regenerated (by default its user.GenerateUserIdentityAsync).
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider {
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
In Net5 you can get old cookie Custom Claim and add to new cookie like this,
builder.Services.Configure<SecurityStampValidatorOptions>(options =>
{
// set time how oftern the cookie is invalidated
options.ValidationInterval = TimeSpan.FromMinutes(10);
options.OnRefreshingPrincipal = context =>
{
// Get my custom claim from old cookie
var guidClaim = context.CurrentPrincipal.FindFirst("GUID");
// Add value to new cookie
if (guidClaim != null)
context.NewPrincipal.Identities.First().AddClaim(guidClaim);
return Task.FromResult(0);
};
});

Resources