ASP.NET Core clear session issue - asp.net-core

I have an application where I save some information on the session that later I assign to the model when I save it to the DB.
For example I have the following model saved by User1:
...
MyModel model = new MyModel();
model.name = mypostedModel.name;
model.type = HttpContext.Session.GetString("UniqueTypeForThisUser");
...
After I save the model in my DB, at the end of the post method, I clear the session with this line:
HttpContext.Session.Clear();
Let's say at the same time there's a User2 creating a new model and I have saved another value in the session with a unique key for User2. Same way as before, at the end of the post method I clear the session with the Clear() method.
Does this clear session method clear the session for all users, or only for one user. If for example User1 saves the model first and clears the session for all users, then the User2 will get his session variable cleared (lost) and will assign a null value to my 'type' column for the model.
For the documentation this was not clear for me. Thanks

You Can remove specific keys
HttpContext.Session.Remove("YourSessionKey");

The session object that you can access for example through HttpContext.Session is specific to a single user. Everything you do there will only affect the user that belongs to this session and there is no mix between sessions of other users.
That also means that you do not need to choose session configuration key names that are somewhat specific to a user. So instead of using GetString("UniqueTypeForThisUser"), you can just refer to the values using a general constant name:
var value1 = HttpContext.Session.GetString("Value1");
var value2 = HttpContext.Session.GetString("Value2");
Each user session will then have these values independently. As a result, calling Session.Clear() will also only clear the session storage for that session that is specific to its user.
If you actually do need different means for storing state, be sure to check out the docs on application state. For example, things that should be stored independently of the user can be stored using an in-memory cache.

Does this clear session method clear the session for all users, or only for one user.
The HttpContext is the one for the current request. Since every user has a different request, it follows that clearing the session on the current request only clears it for that request's user, not all users.

Related

Removing a user from backend created by IdentityServer4

I am debugging confirmation email flow when signing up a new User in Asp.Net Core web application with Identity Server 4.
Since I had already signed up with my actual email, to reuse it, I modified the UserName and Email in AspNetUsers table using SQL Update to some random value.
Now when I am signing up with the original email again. I am getting a duplicate user error
result = await _userManager.CreateAsync(user, model.Password);
I have already:
Cleared browser cache.
Closed local IIS Express
Restarted Visual Studio.
Used_userManager.DeleteAsync() after updating the UserName and Email back to original values but this gives an Microsoft.AspNetCore.Identity.IdentityError with description Optimistic concurrency failure, object has been modified.
On running this query on Sql Server
select * from INFORMATION_SCHEMA.COLUMNS where COLUMN_NAME in ( 'UserName' , 'Email')
I get the following:
I know that this is not a good practice to mess with backend, but this is development environment and I could continue my work with another email.
I would request readers to help in understanding how the User could be safely scorched to be able to reuse the email.
Appreciate your time
I agree with Kyle's comment and to further speed up your debug process you should note that if you use gmail to do this you can debug this process using one email.
from google/gmails perspective myaccount#gmail.com == my.acount#gmail.com == m.y.a.c.c.ount#gmail.com etc etc just try it out, google disregards all period characters in the email. you can enumerate/exhaust ~2^8 emails (in this example) if you just enumerate through the local-part of the e-mail address. but from your applications side, myaccount#gmail.com is not the same as my.account#gmail.com, ie they are different user accounts. Basically you can use one email to test out this feature of yours without having to delete the user.
Here is how I did it and finally got passed the pesky "concurrency failure" error message... This works in ASP.NET CORE 2.2
Obtain the user object through the FindByName method first.
Remove the user from their assigned Role (in this case I hard coded "Admin" because that is the role I'm interested in but fill in your own), then delete the user.
//Delete user.
//Obtain the user object through the FindByName method first.
//Remove the user from their assigned Role, then delete the user.
var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
ApplicationUser delAppUser = new ApplicationUser
{
Email = "SomeEmailForindividualAdminUser",
UserName = "SomeUsernameindividualAdminUser"
};
Task <ApplicationUser> taskGetUserAppUser = userManager.FindByNameAsync(delAppUser.UserName);
taskGetUserAppUser.Wait();
Task<IdentityResult> taskRemoveFromRoleAppUser = userManager.RemoveFromRoleAsync(taskGetUserAppUser.Result, "Admin");
taskRemoveFromRoleAppUser.Wait();
Task<IdentityResult> taskDeleteAppUser = userManager.DeleteAsync(taskGetUserAppUser.Result);
taskDeleteAppUser.Wait();

The User.IsInRole("Administrators") with IClaimsTransformer always false

I add the role administrators to user claims after authentication with an IClaimsTransformer impelimentation like this:
(principal.Identity as ClaimsIdentity).AddClaim(new Claim(ClaimTypes.Role, "Administrators"));
But when i call User.IsInRole("Administrators") in my Razor view it return false.
I'm doing something similar in an API-based solution, but I set the role claim when I create the user, instead of in a transformer.
After looking at the User.IsInRole() documentation it appears that this method is designed to pull from a cache first.
IsInRole first checks the IsRoleListCached property to determine
whether a cached list of role names for the current user is available.
If the IsRoleListCached property is true, the cached list is checked
for the specified role. If the IsInRole method finds the specified
role in the cached list, it returns true. If IsInRole does not find
the specified role, it calls the GetRolesForUser method of the default
Provider instance to determine whether the user name is associated
with a role from the data source for the configured ApplicationName
value.
I suspect since ClaimTypes.Role is a common claim and not a custom domain-specific claim (which I believe is the use-case for a ClaimsTransformer), the application is using a default, cached, pre-transform value.
Much of this is speculation, though. You may try setting the claim when you create the user. I do it using the UserManager class.
var claimsResult = await _userManager.AddClaimAsync(applicationUser, new Claim(ClaimsIdentity.DefaultRoleClaimType, "Administrator"));
I had the exact same problem - when I added the claim to the already-existing identity User.IsInRole always returned false (even though I could see that the identity had that role), but when I added a second ClaimsIdentity with the claim it worked just fine:
var id = new ClaimsIdentity();
id.AddClaim(new Claim(ClaimTypes.Role, role.RoleName));
// I actually returned a clone of the principal every time, not the original principal
clone.AddIdentity(id);
I admit that I don't completely understand why yet, but it worked for me.

Laravel, get currently logged-in users

I want to display a list of currently logged-in users in an app. I want to use Laravel Auth method. I'm looking at the API and I cannot find anything like it.
I would probably need to loop through the sessions store and then match it to a user ID. Am I right?
UPDATE: Forgot to mention, I'm storing sessions in the DB.
"Currently logged in" is something you can't do with plain old sessions. Let me explain why:
A session is a bunch of data stored at server side which is assigned to an user through a cookie. That cookie remains on user browser and so it keeps the session active. Sessions can stay "alive" months without the user even logging in.
But, it's possible to store sessions on database.
As you can see, Laravel keeps a field called last_activity and, through that field, you should be able to retrieve all sessions that had activity within the last 15 minutes (or something else, you call it).
When your retrieve those records, the data field is a serialized representation of session data. You can unserialize($session_record->data) and retrieve the user id.
Depending on your Auth driver, session's user id may have different names:
For eloquent driver, it should be eloquent_login.
For fluent driver fluent_login.
For your Custom\AuthClass, it should be called custom_authclass_login.
Assume that all http requests from logged in users are passing auth middleware, we can override terminate function like following:
public function terminate($request, $response)
{
Auth::user()->save();
}
Then a query like User::where('updated_at', '>', Carbon::now()->subMinutes(12))->get(); will bring all logged in user, where 12 is the lifetime of session.
Of course, for real time, we should use ajax calls every 5 seconds or websockets via pusher or other.
First create a table where the logged in user's id will be inserted
Schema::create('active_users', function(Blueprint $table)
{
$table->increments('id')->unsigned();
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')
->onUpdate('cascade')->onDelete('cascade');
$table->timestamps();
});
Then in yourcontroller insert data while logging in
if (Auth::attempt($credentials)) {
DB::table('active_users')->insert(array('user_id' => Auth::id()));
}
and delete the data while logging out
DB::table('active_users')->where('user_id', '=', Auth::id())->delete();
Print the online users list in your view
<ul><strong>Online Users</strong>
<?php $online_users = DB::table('active_users')->where('user_id','!=',Auth::id())->get(); ?>
#foreach($online_users as $online_user)
<li>{{User::find($online_user->user_id)->first_name}}</li>
#endforeach
</ul>

DropboxUnlinkedException but the session already had token inside and user didn't revoke the access

My problem is I have existing user in database which store the key and secret from the first authentication. I wish to reuse it again when I come back. For the first time authentication, everything working fine. I can use every method call from Dropbox API and the Token(key and secret) was stored in database.
I come back to app and get the Token from database, set it to the session, link current session with API.
session = new WebAuthSession(appKeys, ACCESS_TYPE);
api = new DropboxAPI<WebAuthSession>(session);
String userKey = dropboxUserObj.getUserKey(); //Key from database
String userSecret = dropboxUserObj.getUserSecret();//Secret from database
AccessTokenPair userAccessTokenPair = new AccessTokenPair(userKey, userSecret);
session.setAccessTokenPair(userAccessTokenPair);
It return DropboxUnlinkedException to me when I want to get user data from api using
String userDisplayName = api.accountInfo().displayname;
I have checked on debug mode. Api was linked with the current session. The current session stored Appkey and user's token and correct access type. The point that I doubt is I saw "client = null". I maybe forgot something but I check them all, try every possibilities I can think of but it still return me "DropboxUnlinkedException" which mean I haven't set an access token pair on the session and I didn't revoke access for sure.
Please help me figure out...
I added a screenshot maybe it can illustrate my problem

nhibernate 'save' -> 'get' problem

HEllo,
I'm using nhibernate and have problems regarding user registration on my site.
When user wants to register I create new user record in the database and immidiatelly after that the system is logging the user in.
Well here lies the problem... When creating user record I'm using
NHibernateSession.Save(entity); //does not saves user object immediately to the database. It's kept in the session.
And when I want to log the user in, i load the user by his user name, and then I get null user object.
Why am I getting a null object and how can I make it work?
Thanks
Ok, I just tested this :
ISession session = s.CreateSession();
User user = new User();
user.Number = 122;
user.UserName = "u";
user.Id = 1;
session.Save(user);
User user1 = session.CreateCriteria<User>().Add(Restrictions.Eq("UserName", "u")).UniqueResult<User>();
session.Flush();
First the Select is being executed from the CreateCriteria and then on Flush the insert. So that's why it's not finding anything.
I also tested with Get<User>(1) and it returns the entity passed to the Save method - no query is executed.
Still - why query the database since you have the entity right there ?
Also, you say you use Get and then say you want to load by the UserName - is the UserName the primary key ? Get tries to load by the primary key.
If your Save and Get are done from different sessions then the Get will return null because the object only exists in the other sessions internal cache until it is flushed.
I'm not sure if an L2 cache would make a difference (I don't if L2 cache is written at Save or Flush).