I have an ASP.NET 6 WebAPI application.
I've implemented login functionality, which boils down to calling:
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal);
It sets a cookie with key .AspNetCore.Cookies and value of ID of the user session.
Somehow these sessions are persisted across WebAPI restarts. User agent with this cookie is still logged in when sending HTTP requests to WebAPI after restart. Where these sessions are persisted? Is there a way to disable this behaviour?
For clarity: I'm not using .AspNetCore.Session-related functionality, we're speaking solely on .AspNetCore.Cookies based user authentication.
Thanks in advance.
Related
The flow I am trying to figure out is this:
UserA is logs into ClientA
ClientA redirects to Idenitity Server to authenticate user
after authentication ClientA manages User info in its own system
UserA is found to be a "bad actor"
AdminUser goes into IdentityServer AdminTool (a different client application for managing the IdentityServer, including users).
AdminUser performs an action to "revoke" UserA
A call is made to the IdentityServer back-end from the admin tool where UserA has an "Enabled" property that is set to false.
At this point in the flow I want to kick the user out of ClientA from the back-end of the IdentityServer.
More context:
IdentityServer is using cookies in the client browser to keep the "session" (not sure if that is the right word cause there isn't actually any state being managed).
Also using cookies for remember-me.
Is there a way to remove the cookie for the IdentityServer from the back-end? Or notify the client that UserA should no longer have a valid authentication so that it can perform HttpContext.SignOutAsync()?
I was reviewing this link: https://docs.identityserver.io/en/latest/topics/signout.html for guidance but I am stuck on how to do this from the back-end as the AdminUser. Calling HttpContext.SignOutAsync() would sign out the AdminUser that made the request, not UserA that is causing havok in ClientA.
In a typical setup with identity server you have:
A JWT token with a short lifetime
A session cookie
The JWT token needs to be renewed frequently. The session cookie is used when there's no valid JWT. In this case the user will be redirected to the login page and if there's a session cookie the user will be automatically authenticated and redirected back to client app.
So you have some options for your logout:
Ensure the user cannot renew his JWT (= logout after a few minutes)
Ensure the user cannot login again
Really clear everything in the browser (and ensure he cannot login/renew again)
Back to your question
Is there a way to remove the cookie for the IdentityServer from the back-end?
The answer here is WebSockets which allows a two-way communication.
https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API
A common library for C# is Signal/R
https://dotnet.microsoft.com/apps/aspnet/signalr
You would create a Hob on the server side that allows you to send messages to the "bad user".
https://learn.microsoft.com/en-us/aspnet/core/signalr/hubs?view=aspnetcore-6.0
And listen for those messages in your client app:
https://learn.microsoft.com/en-us/aspnet/core/signalr/javascript-client?view=aspnetcore-6.0
Please note: Whatever you do on the client side, the important part is typically to block the server requests. It's not secure to delete the cookie on the client. You have to delete the session on the server side instead.
Additional notes:
The flows in your setup may be different from what I described above.
I know, this is just a partial answer, but it's too much content for a comment ;-)
We have a web application built with asp.net core, .net core 3.1, angular which uses asp.net core identity for user authentication management.
We have a need to implement the below scenario:
"If user A is logged in (this is an open session) and user B logs in with the same credentials (this is the 2nd concurrent session), after user B passes MFA, we will send an email to the email address of this customer to notify them that someone else just logged in. We will NOT end the session for the user A."
Our current implementation uses ASP.Net identity to authenticate users with Authentication Tickets being stored in cookies. Since authentication tickets are stored in cookies, the session is browser based, hence being able to track whether the user is logged in with an ongoing open session is not possible with this implementation.
I was leaning towards using custom store for storing auth tickets on server side with either database / redis, and then tracking token expiration thereby determining an existing ongoing session. Am I thinking along the right direction, or are there other mechanisms ? I would like some thougts and suggestions.
ASP.NET Core Identity use Cookie authentication . That means when user B login in your application , application doesn't know whether user A is active , only next time userA send request with cookie to application , then application could check whether user A is active(authentication ticket is not expire ) and create a email response . If user A doesn't send request to server , server won't know the state of user A since cookie is only sent with HTTP request .
You can use asp.net core signalr which enables server-side code to push content to clients instantly.
My application has an API part and a website-part.
On the website, the user can log in and gets a JWT bearer token from the API.
My question now is:
Where should I store that token?
Some say, store it in Cookie (while others say "don't, because CSRF"), some say HTML5 Web Storage, others say use Session (while other say, "don't use Sessions in ASP Net Core") and I saw an article where someone stored the auth-token in a database (??).
So, what's now the correct place?
MVC-web application with many controllers and a lot of views
If you have to use the token to authenticate every request to your MVC app I think the best option is store it in session cookie because, if not, the web browser are not going to send the token authomaticaly in every request and it will be a pain in the ass.
Now, to secure the cookie and requests:
Make session cookie (no expiring date)
Restrict the scope of the cookie all you can (domain and path).
Set Secure and HttpOnly attribures.
Set SameSite attribute.
If browser does not support SameSite use an anti-CSRF token.
Set restrictive X-Frame-Options.
Do not forget to verify the JWT signature on your server on every request.
Encrypt the JWT token to prevent leaking information that could lead to social engineering.
My ASP.NET MVC 4 application is protected by SSO (OAM) with an ISAPI filter running on IIS. When a request to my application is received, it is intercepted by ISAPI filter and redirected to SSO. User has to login at SSO and after that he is returned to my application.
The username of authenticated user (via SSO) is shared with my application in HTTP Request Headers.
Request.Headers["username"]
What I am trying to achieve is- after SSO authentication, setting FormsAuthentication within my application for username = Request.Headers["username"]. This way SSO remains transparent to my application and Identity of user is available in HttpContext object, plus, I (developer) could effectively utlize Authorize attribute for specific roles.
To achieve this- I hookup into Session_Start(), read Request.Headers["username"], Set FormsAuthentication cookie. And I get this SSO user Forms-Authenticated for my application.
But my problem is when I logout (FormsAuthentication.Signout), I redirect it to another page inside the application, which triggers a new Session (I can see Session_Start triggering when this happens)
Am I doing the right thing- FormsAuthentication after SSO? And if not, why not and then how do I make my application aware of SSO authenticated user?
It's entirely reasonable to use FormsAuthentication cookies to track the logged in user in your application after they have been authenticated using a Single-Sign-On provider. You don't show it but I'm hoping that you are also getting some ticket that you can use to verify the signed in user out-of-band with the SSO provider and not simply trusting the username header.
What you may be seeing, however, is that the user is not signed out from the SSO provider when you sign them out of your application. Because of that, as long as they have a valid cookie for the SSO provider, they will remain signed in, i.e., the user will get automatically bounced back to your application from the SSO provider without any required authentication.
That's unfortunate, but normal.
If you truly want the user to be signed out, you'll need to make use of the centralized logout functionality. I haven't worked with OAM, but it appears that it does support this: http://docs.oracle.com/cd/E21764_01/doc.1111/e15478/logout.htm
I had to explicitly kill the session inside Session_Start if requested URL is logout URL. And then with next request (like from logout to login page again), it generates a new session and runs smoothly.
protected void Session_Start()
{
if (!Request.IsAuthenticated && !IsSignoutURL)
AcceptSessionRequest(); //process local authentication
else if (IsSignoutURL)
RejectSessionRequest(); //kill the sessions
}
For background on how SSO passes authenticated user's identity to my application, read my comment to tvanfosson's post.
The post remains opened for a better idea.
We are having a discussion about how forms authentication really works.
Is all information that identifies the user as being logged in stored in the cookie, or is some information stored in the session?
Information about the user being authenticated is stored in the FormsAuthenticationTicket in a cookie, by default named .ASPXAUTH.
Information about a user's session is separate from information about authentication. The identifier for session can be stored in a cookie (a different cookie from the authentication cookie) or, as Henk has pointed out, in a cookieless session i.e. as part of the URL.
The problem with storing some information about authentication in a user's session is that session is not available until some time after the authentication event (5 events later IIRC) in the processing pipeline, in PostAcquireRequestState. This means you wouldn't have access to the authentication data in session until after authentication!
It's possible to store data in session and to overwrite the IIdentity and IPrincipal with that data, but this does means that the user identity will have some data for the events before session is available and different data for the events after session is available, which may or may not be a problem. Furthermore, you'll probably want to cryptographically secure that data in session in some way.
To answer your title question, forms authentication does not require session; they are distinct entities required for different purposes.
For how Forms Authentication works, you can check out the below links:
Explained: Forms Authentication in ASP.NET 2.0
Understanding the Forms Authentication Ticket and Cookie
Forms Authentication works in web farm scenarios where the server handling a request from a Forms authenticated user may be different than the server that actually authenticated the user and issued the Forms authentication ticket and the cookie unless cookieless forms authentication is configured. To make this work, according to Web Farm Scenario section of the first link:
To address this issue, the validationKey and decryptionKey values must be identical on all computers in the Web farm. For more information about configuring the machineKey element, see How To: Configure MachineKey in ASP.NET 2.0.
which suggests that the Forms Authentication does not store anything in ASP.NET session. Otherwise, you would need to set up some form of an out-of-process session management in-place as well.
I also had a sample Forms Authentication application on hand and wanted to prove this quickly. After getting authenticated via Forms Authentication and landing on the home page, I restarted the application pool that the sample application was running in which should kill the user session. I then clicked on one of the links requiring authentication on the home page and was able to go to that link without getting redirected to the login page.