Best way to track a user on a site? - c#

I was reading on session state, application state, cookies, profiles.. and i wondered way would i adapt to my site.
I am building a forum, and i need to check whether the user is logged in or not. If he is not logged in, he wont have the choices a logged user has (e.g. pressing the reply/start thread/submit messages buttons). Basically, i thought to plant a cookie onto the users pc..but some browsers dont allow cookies, then i thought i would follow with a session state for users who dont allow cookies. I looked at the modes of the session configuration that session state has got, and there was one that i liked.. it was mode="sqlServer", but then i read that it has a disadvantage of being slow, and that i need to install a few more components to make it work.. in other words it looks cumbersome. I also looked at profile option, and i think it is a solution.. as soon as the user logs in, i can set his name. Something along those lines:
protected void updateProfileButton_Click(object sender, EventArgs e)
{
Profile.Name = nameTextBox.Text;
Profile.Age = Int16.Parse(ageTextBox.Text);
}
Whats the best option that i have got,? i am thinking of using cookies in a combination with profiling!!

If you just need to have a mechanism to allow a user to access additional functionality when they are logged in then have a look at ASP.NET Forms Authentication:
ASP.NET Forms Authentication Overview
Update:
In answer to the two questions in the comment below:
should i set this user identity to the
cookie? User.Identity.Name;
No, once you've authenticated the user ASP.NET's Forms Authentication provider configures the cookie for you.
will it add an automatic password to
the web.config?
No it won't, you need to write your own mechanism to store a user's details which would typically be captured from a user registration page (e.g. username, password, name, age, etc) For example you can use a SQL or Access database or you could use the ASP.NET Membership provider:
Introduction to Membership

Related

IdentityServer3 requiring a role when the user logs in (as additional credential)

I have a system where if the user logs in as Joe with the role "Readonly" then he will be granted access only to read things (fairly obviously) however if he logs in as Joe with the role "Administrator" then he will have access to do administrative functions. However I want him to have to relogin if he wishes to change from the Readonly role to the Administrator role so that he could potentially leave his account logged in as Readonly on a display screen or something without fear of someone hijacking his Administrator priviledges.
Now I also need to be able to log in a Web client via an implicit grant or another server via a code grant and have that service be able to use the same roles as well (while still requiring Joe to log in as the particular role if he isn't already authenticated.)
Now I have been trying to do this with IdentityServer3 but I cant seem to get the role information to be part of the authentication for the user, I tried adding an acr_value of role:ReadOnly to the token request (which then turns into an authentication request if the user is not logged in) but if they log in with the acr_value of ReadOnly and then come back to log in with the acr_value of Adminstrator it just lets them on in because they are already authenticated as the user.
Any tips on what I should be using instead of what I am doing or how I might be completely off base in this OAuth2/OpenID Connect world?
I finally figured it out so for others who might want to do the same thing here is what I did.
First you have build a custom UserService that looks in the acr_values for extra information. Then create a claim for that extra information in the AuthenticateResult.
Second you have to override the ClaimProvider to include your custom claim set in step one in the tokens generated.
Next you need a CustomRequestValidator in order to check if a new acr_value is being set compared to the one you have stored in token being currently used. If it has changed and you want to force the user to reauthenticate you can set 'request.PromptMode = "login";'
And that is it, using that set of steps I can now authenticate a user using 3 values (username, password, and role) and if the role requested changes I can require them to reauthenticate.
Works swimingly.

How can I register a new user with a user-defined unique identifier when leveraging OAuth code flow?

I'm building a sign-up / login flow for a web site. I plan to use Facebook as my identity provider instead of rolling my own.
I have a good feel for the server-side login flow with Facebook:
Call FB login API to get a code
Exchange the code for a user access token
Inspect the user access token
Validate the user access token details
After these steps, I'd like to check if the authenticated user is already registered in my system. If yes, simply return a newly generated bearer token, so the user can make subsequent requests to resource servers to access protected data.
If the user is not registered in the system, however, then I'd like to register them by creating a database entry. Before creating this entry though, I'd like to collect one piece of information from the user. Namely, I'd like for them to tell me their desired 'username'. I will use this unique username as my database primary key.
I'm not 100% sure on how to securely ask the user for their desired username before creating the database entry. This is my question. :)
One thought I had was to create a "redemption code". This code would be encrypted and contain the user initialization details, a secret only the server would know, and a timestamp. Something like this:
code: {
mySecret: "super-secret-value",
expirationDate: "date-value",
user: { ... },
}
After seeing the user is not in my system, I'd respond with the code + redirect the client to a page where they'd be able to specify their username. Upon submitting their username + code back up to the server, I could decrypt the code, and validate mySecret to determine the code is not tampered. If all is good, create the user in the database with the user information from the redeemed code. Lastly, I'd generate a new bearer token for the user and send it to the client.
Questions
Is my proposed redemption code strategy a secure way of requesting a username before creating the backend DB entry?
If not, what would be?
If yes, what is a secure encryption/decryption routine to use for this purpose in C#?
Flow Sequence
Steps 1-4 from above correspond to "Login" through "Validate" arrows.
My proposed redemption code strategy corresponds to the purple arrows.
Red text corresponds to Facebook specific nomenclature.
Note, Stack Overflow does something very similar to what I want to do. Before creating your account on SO, it will ask you for your desired Display Name (this happens after authenticating via Facebook, Google, etc.). After submitting your display name, your account is registered.
Use open source IdentityServer3.
Whatever flow you choose its already standardized in their server. Including (if you want or need) OpenID, OAuth2 etc.

Allow only one concurrent login per user in ASP.NET

Is it possible to allow only one concurrent login per user in ASP.NET web application?
I am working on a web application in which I want to make sure that the website allows only one login per user at a time. How to check that the current user already logged in or not?
Please suggest proper login method by which we can handle this problem. I think we should use SQL Server session state to handle this problem. What do you suggest?
I thought of one solution for it. We can do something like:
When the user logs into the system then we insert session id in user column. (We will use database session so that we can get all session related data like isexpired, expiredatetime etc easily).
When the same user tries to login a second time then we will check for that session id column and check that session is already expired or not. If session is not expired then we will not allow user to login.
Update user session ID every time when user logs out.
Please suggest whether this is the proper way or not.
Please refer to:
When the same user ID is trying to log in on multiple devices, how do I kill the session on the other device?
Out of the box, .NET does not support this. .NET allows for concurrent log-ins, as I'm sure you're aware.
I had this same exact requirement, and came up with a pretty slick solution, demonstrated in the link above. In a nutshell, my requirement was to only have one user log-in happening at one time. If that same user ID tried to log in elsewhere, then it killed the session for the first log-in by checking for an existing log-in under a different Session ID (this enabled the user ID to be logged in from multiple instances of their web browser on their computer [same Session ID], which is common, but not from a different computer [different Session ID] (possibly due to someone that stole their credentials, for example)). Through modification of the code you could probably change the behavior of this - i.e., prevent the second log-in attempt instead of killing the first log-in that's already active and in use.
Of course, it may not fit 100% to what you're needing, so feel free to modify it to fit your needs.
You can create a cache entry per user and store their session ID in it. Session ID will be unique per browser session. In your login page, you can create that cache entry when they successfully login:
if(Cache.ContainsKey["Login_" + username])
// Handle "Another session exists" case here
else
Cache.Add("Login_" + username, this.Session.SessionID);
(Code typed in textbox without syntax check. Assume "pseudo-code".)
In global.asax you can then hook into the Session_End and expire that cache entry of the user. See this for the global.asax events.
if(Cache.ContainsKey["Login_" + username])
Cache.Remove("Login_" + username);
You could add a flag column in the user table that indicates that a user is currently logged in.
When a users attempts to log in you check the flag if it's true (that users account is already currently used) then you don't allow the new user to log in, if the flag is false the users is allowed to log in as there account is not being used by anyone else at this time.
Be aware though that unless the uses actively logs out, you cannot know when the users moves on to something else (goes to different website or closes the browser, etc.) so you need to set some kind of session timeout that will automatically log out the user if there are no new requests within a specified time period.
This means that if a users closes his/her browser and try to log in on a mobile device for example, he/she will be unable to log in until your specified session timeout runs out, so give the timeout a bit of thought as you don't want the user to get logged out to quickly (if he/she is reading a long page, etc.) and you don't want the users to be unable to log in on another device for hours if he/she forgot to log out before leaving the home.
The login credentials are stored on the cookie, so to know if the user is logged in you need to keep this informations on server, prefered on a database because the database can be the only common place among web garden or web farm.
What you can keep, is on a table, that the user A is logged in or not, flag it that is logged out, maybe last user interaction to have a timeout, etc...
So let say that the User A, is logged in, then you open a flag on the database for that user, that is now logged in, and if is try to logged again, you keep him out.
To make this work you need to either say to your users to log out, or to keep a time out, similar to the time out of the credentials.
If You are using identity system this link will help you how to single user login on multiple device.
Prevent Multiple Logins in Asp.Net Identity
I have tried they work fine in my Asp.net Mvc Project.
Solution can be this way:
Add new column in your login table GuidCode.
Step 1 : When logging in check if the GuidCode in database is null.
Step 2 : Update GuidCode by new guid and also store it in the session.
Step 3 : If it is not null then take guid from the session and compare with database GuidCode value.
Step 4 : If it is same then allow login:

ASP.NET single page authorization

I have an ASP.NET application where most of the pages are accessible to all authenticated users via a single sign on module that sets the username into the Session array variable. Now I have one folder A containing one page B.aspx and a list of usernames who are allowed to access this page B.aspx.
My question: how do I elegantly authorize only these users for this one page, or better, for this one folder. Can it be done with the location tag in a Web.config file inside folder A ? If so, how do I connect that config with custom code to check whether the username stored in the session variable is one of the authorized for that folder or page ? Can I use a custom membershipprovider ?
Thanks in advance !
First, you scrap the kludged security methodology, as user name in a session cookie is not a good way to handle this. Okay, maybe a bit too overboard, as low security may be fine for you. If so, you can write a custom handler for the page that examines user name and compares to an updateable list.
NEW: With Session object, you are a bit more security, as the session token is sent over and the name is kept in session, but the Membership bits (below) handle translation of a particular session to a user without rewriting with your custom "this user is using this session" methodology. Yeah, ultimately you can argue Microsoft does something very similar to your software, but you leave the maintenance to them.
Going back to my original direction, there is the concept of roles and membership built into ASP.NET. If you use these bits, you can security trim the page (or even better folder so you can additional pages) to certain users (not as good) or roles (better) by setting up a new web.config with the security constraints.
The cool thing about the built in stuff is you can declaratively set up security and have the pipeline determine whether a user is valid or not without any heavy lifting on your part.
There is plenty of information on Membership and Roles on the various ASP.NET oriented sites.
that can be achieved specifying the user's name that can access the directory separate by commas.
As your username is not defined in web.config rather defined in some session variable you have to create a Form Authentication Ticket for this e.g.
FormsAuthenticationSupport formsAuthenticationSupport = new FormsAuthenticationSupport();
formsAuthenticationSupport.SignIn(UsernameInSession, RoleName, true);
Now you can set authentication rules and location tag in web.config for UsernameInSession.

Should I use Membership for this unusual account system

My asp.net mvc site needs some kind of authorization but it is rather different than the usual concept of users and thus membership.
It will be used more for preferences then for authentication actually. Accounts without any password should be possible (and will initially be the only type) and an account can also be used by multiple users at once. Depending on the user group it could be for example that all users of a certain region get a shared account.
This is a decision from the client('s marketing division) and is not up for discussion.
A certain landing page takes (only) a userId in the url that will load up an account which in turn has some preferences linked to it that can be used throughout the rest of the site.
If a user doesn't start at the landing page or the sent accountId doesn't match a record in the system, he/she will be assigned the default account that has default preferences.
I was thinking of not re-inventing the wheel (somebody should find a new expression for this) and use the asp.net Membership system.
But the whole system is based around required passwords, email and single sessions per user, which are all things I can't provide.
Because the situation is a bit unconventional I thought a custom MembershipProvider etc would be in place. But it seems the gist of this is inheriting from the regular Membership classes. The methods of these classes all require things I am not needing.
Any suggestions
You could use the standard Membership provider and using the Built in .Validate() method sending the Username and a Password that is "standard" for all accounts without authentication.
Have 2 different User Controls 1 for "Validated Login with Password" and one for "Share Account without password", each uses Membership-login but the latter needs to have a bit set on the field of the member that says "Public Account = True / 1 "
Good luck, seems like a fun project, would be cool to see the outcome ;)
By the way, you don't need to share the session, or you could, just stored the session in the database and map the session to a user instead of a cookie, might work?
As requested i'll elaborate on different user controls. Briefly i would have 2 Controls, one maybe called GlobalLogin and one called UserLogin, where GlobalLogin displays a Form which only has the Username, when submitted this will trigger a function that uses, as i stated before, a function which calls the Validate method in the Membership provider, with a pre-set password.
As a reflection, see all "Not logged in with password"-users as anonymous and treat them the same way, the only thing that is different is that they can access user-specific areas. This control also needs to check that a certain field in the database is set, such as a "Allows Globally Used Account Without Password"-field, where in this case, the bit / boolean needs to be true for this login to be accepted.
Now to the other part, the Control which handles Password Protected Accounts, this requires both Username & Password and this calls the Validate with these settings. Now, remember that when logged in with password, you can change your password, this SHOULD NOT be possible with a Global Account, because then your global password wouldnt work :)
There is detailed information on the Membership Provider at http://msdn.microsoft.com/en-us/library/f1kyba5e.aspx. Basically you need to create new provider, or derive from the existing, and overload the ValidateUser method to always return true.

Categories

Resources