Owin authentication sign-out is not invalidating Identity in asp.net MVC - asp.net-mvc

I am connecting to QBO (Quickbooks Online) app using OAuth. QBO has it's own Auth Server and Auth Client.
I am using single sign-on. So after successfully connecting to QBO I am setting Cookie using following code:
var id = new ClaimsIdentity(claims, "Cookies");
Request.GetOwinContext().Authentication.SignIn(id);
My Startup.cs contains:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
AuthenticationMode = AuthenticationMode.Passive,
LoginPath = new PathString(Paths.LoginPath)
});
To signout I used :
HttpContext.GetOwinContext()
.Authentication
.SignOut(HttpContext.GetOwinContext().Authentication.GetAuthenticationTypes().
Select(o => o.AuthenticationType).ToArray());
But User.Identity remain valid after sign-out. I have tried different solutions from SO but no success.
Any idea?

When you call SignOut it would delete the cookie in order to invalidate user identity, but the User would be still authenticated during that request.
You can put [Authorize] attribute on the action that is signing the user out, so it will be redirected to login page.

Related

Why log out sooner than ExpireTimeSpan in asp.net identity?

I am working on an asp.net mvc application that used asp.net identity.
In Startup.Auth.cs file I set ExpireTimeSpan to 20 days but when I log in to my app, sooner than 20 days my app is logged out and I have to log in agian!
Startup.Auth.cs
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/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, User>(
validateInterval: TimeSpan.FromMinutes(0),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
},
ExpireTimeSpan = TimeSpan.FromDays(20),
SlidingExpiration = true
});
And in Login action:
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);
Update
When I log in, .AspNet.ApplicationCookie is generated and it's expire date is set to "20" days later, And when I open site next day, I am logout but the cookie is exist.
What is the cause of this problem?
Thanks in advance.
Here are the few reasons for logging out sooner than expected:
Having multiple web apps on the same domain and all of them have the same cookie name (cookie name collisions). In this case app A overwrites app B's cookies.
When validateInterval is set to zero/TimeSpan.FromMinutes(0), all calls to UpdateSecurityStamp will force the user to logout and login again immediately, including UserManager.CreateAsync, UserManager.RemovePasswordAsync, UserManager.UpdatePassword, UserManager.RemoveLoginAsync, UserManager.ChangePhoneNumberAsync/SetPhoneNumberAsync, UserManager.SetTwoFactorEnabledAsync, UserManager.SetEmailAsync. Which means if you update the user's properties, UpdateSecurityStamp will be called.
If you update the .NET framework on the server, it will overwrite the machine-key too. changing that will mark all of the issued cookies as invalid. The Machine-Key is a set of keys used to encrypt and decrypt the cookies. If you are running behind a load balancer you will want to ensure that the web farm is using a consistent machine-key.
If you are storing too many user-claims with your cookies, they will become large (larger than ~5K) and some browsers will reject them. so check out the size of the issued cookie.
Users can set their browser to delete the cookies when they close it (private browsing).

Sharing .AspNet.ApplicationCookie between two MVC projects

I have a Web project to login our users. It signs a user in, creates the ".AspNet.ApplicationCookie" cookie and then redirects to a page "~/Views/../Redirect.cshtml" that will choose, based on some rules, what will be the Website user will be redirected to. Very simple, a "redirecting..." message and a setTimeout function.
The problem is...website 2 does not recognize cookie created by site 1 and just moves the user back to site 1.
Some information:
1 - Works running both sites locally
2 - Site 1 and 2 are in the same server running on the same domain, just different ports.
3 - Both sites share the same ApplicationUserManager.Create call since I moved this class to a Domain project.
Startup.cs is as follows:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(AccountDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.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,
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, DefaultAuthenticationTypes.ApplicationCookie))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
It turns out that the problem was the Application Pool. All sites sharing the same cookie need to run on the same Application Pool. Once I set them all to use the same, it worked just fine.

Context.User is null in self-hosted SignalR hub when called from IIS-hosted MVC app

I'm have an IIS hosted MVC 5 app that uses Asp.Net Identity and OWIN for authentication via .AspNet.ApplicationCookie. From one of its views, I make calls to long-running methods on a self-hosted SignalR hub (running on the same server) via a SignalR JS client. These calls all work as expected. I now wish to decorate my hub with [Authorize(Roles = "Administrator")]. This has proved problematic. Setting a breakpoint in a hub method reveals that the Context.User is null, even though the .AspNet.ApplicationCookie is clearly in the Context.RequestCookies.
Here is the bootstrap for the hub (self-hosted in a windows service):
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie
});
var hubConfiguration = new HubConfiguration();
map.RunSignalR(hubConfiguration);
});
Here is the auth config for the web app (hosted in IIS):
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(UserAccountContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.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,
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))
}
});
Question 1: Is the use of [Authorize] possible in the scenario described above? If so, how?
Question 2: Would it be better to just merge the self-hosted hub into the IIS hosted app? If so, are there any issues with long-running hub methods under IIS?
Update 1
I've tried adding TicketDataFormat = new TicketDataFormat(new MachineKeyDataProtector("ASP.NET Identity")) to the CookieAuthenticationOptions on my hub config, but that didn't help. Sure seems like this should be easier than it is.
I ended up moving my self-hosted hub into my ASP.Net application and it worked just fine. This seemed easier and more maintainable than implementing the workaround in this SO question, OWIN Self-Host CookieAuthentication & Legacy .NET 4.0 Application / FormsAuthenticationTicket

Double authentication with Web app & Web API needed?

I'm stuck on how to solve following problem.
I'll start with describing what my app looks like in a general context.
[ ASP MVC (Angular App) ]
Uses Owin cookie
[ WEB API 2 ]
Uses Oauth Token Bearer
This scenario is happening:
User visits app and authenticates with a login form which lies in ASP MVC app and generates a cookie.
Now I've decided to use AngularJs to add a couple features which made me use $resources and Web API 2. However, those features are only available if user is authorized.
To the problem: Now I must use a token for each request to the Web Api 2 to access different methods within controllers. This means I must login the user again but this time through AngularJs. Using /token route.
How would I do this?
Should I take the cookie, check credentials in it and send it as a authentication request?
Can I do something within the form authentication, in the same method, in the Asp MVC app?
Please help me, this gave me a lot of overhead. Walking from a simple app to this in 30min. Can't even get my head around all stuff in the authentication.
Regards!
My WebAPI supports both token and cookie auth.
During startup I register the authentication like this:
private void ConfigureAuth(IAppBuilder app)
{
//Token
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
});
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnApplyRedirect = ctx =>
{
// this is to ensure that a 401 response is sent if the
// user is not authenticated, rather than redirecting to
// a logon page.
}
},
CookieDomain = ".example.com" //might not need to set this
});
}

Owin + DefaultAuthenticationTypes.ApplicationCookie + Windows Authentication

My MVC5.1 application uses OWIN authentication based on http://www.khalidabuhakmeh.com/asp-net-mvc-5-authentication-breakdown
The user persistence in db and login validation is handled by my custom UserService class. This works perfectly fine when using individual accounts for users to login into the system.
I also need to make this work with Windows Authentication (Active Directory). So if Windows auth is turned on (on IIS & a flag in my web.config) the AD user will be validated against my DB to see if the logged in user has access to my web application and if yes log him in (set the application cookie).
I enabled Windows Auth in IIS, disabled Anonymous Auth in IIS, and removed <authentication mode="None" /> from my web.config file. This makes OWIN think the user is already authenticated even though in the startup I configure it to use ApplicationCookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
Well this is fine, I could write a wrapper around AuthenticationManager.User.Identity.IsAuthenticated property and add the check to validate the user against my db. But then I am not able to add custom claims as OWIN doesnt seem to be using an Application Cookie but directly uses the WindowsClaimsIdentity.
My login function (the one that tries to add additional claims) is as follows:
_authenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
var identity = new ClaimsIdentity(
new[] {
new Claim(ClaimTypes.NameIdentifier, user.UserID.ToString()),
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.UserData, user.CurrentDomainID.ToString())
},
DefaultAuthenticationTypes.ApplicationCookie,
ClaimTypes.Name,
ClaimTypes.Role);
_authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
Now If I add the line <authentication mode="None" /> in web.config it seems to be working, meaning OWIN only looks for claims inside its cookie and doesnt authenticate the user until the user exists in the DB.
But in both these cases, I am stuck in a redirect loop on the login page unless i remove login path from the startup. I tried setting Response.SuppressFormsAuthenticationRedirect=false in my login controller but no change.
Another problem I am facing is, the browser doesnt show me the login page until I enter a valid username/password in the basic auth popup even if i am logged in with my AD account in windows. Is there a way to hide this popup?

Resources