How can I use a Guid for implementing single sign on the same domain? I can't use sessions as the different web apps would open in new windows hence loosing the session.
Technology used: ASP.net 3.5, MVC2 architecture, C#.
You should be able to use a cookie and access it from whatever application is running under the same domain. If the other web applications sit on a subdomain, you need to set the Domain of the cookie like:
Response.Cookies("CookieName").Domain = ".mydomain.com"
If the sites exist with in an Intranet and the users are all logged into Windows with a unique user account, you can turn on Windows Authentication and read their Windows User Name from their web request to determine the user.
Edit to elaborate:
Have each site read the cookie. You can determine if the user is logged in or not based on the existence of the cookie, which can be managed by setting the cookie expiration.
If you wanted to make this more sophisticated (there are probably security concerns with relying solely on the cookie), you could store the GUID in the database and have each page do a look up to insure the GUID they're passing in is valid. From here, however you want to manage the GUID's validated in the database is up to you (compare time stamps, etc).
You might want to store additional information in the Cookie to use for validation. For instance, you could generate a random string and store that with your GUID in the database. Perform one-way encryption on that string and store it in the Cookie when you initially save it. This way, you can compare that value when checking to see if the cookie is valid.
Related
I have searched all over for an answer to this, and not found anything that seems to answer my question. Which feels like it should be an easy one (but clearly isn't).
I have an API which authenticates using a token. This token I generate from my application - more specifically, I have a new Token Generation web call that will return a token. Currently, I pass in a cookie with the user and password information, and it uses this to identify who I am and what I should be allowed to do. This is all working absolutely fine and hunky-dory.
I am achieving this process by making the Token Generation use OWIN Cookie Authentication, which means that the cookie is read and the Identity is set. I am then able to use this identity to confirm whether the user is allowed to access the system.
What I now want to do is replace this Cookie Authentication process by authenticating against a Windows User (everything is windows based, and this will be an option so non-windows users can still use the cookie authentication route). But I cannot discover how to straightforwardly do this.
Note that I don't actually need to validate that the user is genuine or refer back to the AD at all. If you provide a windows user that matches a user in the system, you can log in.
So how can I - easily - get the requesting user into the Identity Name? Or is this not possible?
If you are looking for information on the current user accessing your program, assuming the program is running on the user's machine and is windows based, you can simply query windows for the user's username or any other publicly available information about the user.
Refer to https://learn.microsoft.com/en-us/dotnet/api/system.environment?view=netframework-4.8 for information on the Enviroment class and what it's features are.
If you could provide some code or further clarity I could help you further.
We are currently starting to use MVC and are now looking at authentication. .net Authentication isn't necessarily our strongest point, so looking for some advise or pointers.
Our current set up:-
Basic Windows authentication
system uses the authenticated user to query a 3rd party system to get their current roles
these roles are then stored in session variables and used when ever authorisation is required
Any additional user details are called upon as and when needed from various tables
What we'd like to achieve :-
Basic Windows authentication (perhaps create a forms authentication cookie on the back of it)
System users the authenticated user to query 3rd party system to get their current role/s,
These roles are stored within the cookie, and can be accessed via User.Roles etc
Any additional user details (i.e. user favourite colour) will be called on authentication and store against the user profile. The additional user details will be stored in a single table as key value pairs.
Is this the correct way to go about this? we're struggling to find any samples etc to match the scenario we are after.
unfortunately, we need to use this 3rd party system to access the roles, this is achieved via a web service call.
Are there any new advances with MVC 4 which could greater handle authentication with additional user details?
any help, or advise would be greatly appreciated. :)
Sounds like a perfect candidate for federated authentication. You could even use WIF (Windows Identity Foundation) which is now part of the Base Class Library.
In general, federated authentication consist of following parts: delegating the authentication to an external identity provider, consuming identity provider's response, persisting the identity locally (in a cookie perhaps).
WIF has solutions for all these concerns, it is built around the WS-Federation protocol. The really, really great benefit of this is that you can switch between different identity providers easily. This is something that you could consider useless, until you see it in action and immediately you start to create complicated business scenarios in your head.
Using WIF requires some knowledge and specific questions can be answered easily. However, until you get at least some basic knowledge, this sounds like a mumbo-jumbo. You should definitely start by reading a free ebook, Claims-Based Identity and Access Control from here
http://msdn.microsoft.com/en-us/library/ff423674.aspx
Just download it and start reading. I promise you'll immediately find answers to many of your questions and page by page you'll feel this constant "wow, so that's how it should be done!".
Just to provide a specific answer to one of your questions: user data can be persisted in the authentication cookie. If you stick with WIF's model of Claims, expressing arbitrary data is natural: a claim is a pair (claim type, claim value). This requires however to switch to SessionAuthenticationModule as forms authentication module could possibly produce cookies that are too large:
http://www.wiktorzychla.com/2012/09/forms-authentication-revisited.html
(the session authentication module has a special "session" mode where the large part of the identity is stored locally at the server in the session container so that the cookie is really small)
And yes, the federated identity model works with MVC authorization tags. Claims of type role are interpreted as user roles. The remote identity provider can then even set user roles and you can guard your MVC controllers in the usual way.
If you are lucky your 3rd party component might bring a Claims provider with it so you could use Claims based authentication and let the Claims provider supply the additional user data in form of Claims that you can use in your application. For a tutorial see this link. If you cannot access a Claims provider, the known security building blocks still work for MVC. So for your additional roles, you could create a RoleProvider that requests the roles and configure it in your application. You can then secure your controllers or actions with the Authorize-attribute.
In order to optimize the request for roles so that you do not have to request it from the 3rd party system over and over again, there are some alternatives:
As you propose in your question, you can store them in the cookie. But be aware that cookies are stored on the client computer and could be tampered with. So if you have a Forms authentication cookie that you can use, you could store it in the UserData of this cookie. This cookie is already encrypted so that users cannot change it easily. As you want to use Windows authentication at least in the first step, you do not have a Forms authentication cookie that you could use. In the context of security, it is always advisable to set up upon a widely used and well tested framework, so I'd not recommend to create a cookie of your own and store the roles there (though it wouldn't be a too daunting task in this specific case to encrypt/sign the cookie data).
You could also store the roles in a Session variable. Downside is that the session times out after a while and you'd have to be prepared for this case. On the other hand, session memory is located on the server so that it is not that easy for users to tamper with (and if they could, you'd have lots of other problems).
Another component you could use is the Cache on the server; though you'd have to be careful not to mix data for various users as it is shared among users, it is also located on the server and provides a more fine grained control on when the data are invalidated. So you could configure a time frame after that any user would be authorized with a new role set in case it was changed.
Your RoleProvider would need to implement the caching technology (Cookie, Session or Cache).
As for your last point regarding the user profiles, I can imagine that the User Profiles of ASP.NET 2.0 still work. I don't have any experience with it, so I can't give you a recommendation on whether to use it or not. On the other hand, these data don't seem to be too security critical so you can also store them in a cookie or session memory once the user has been authenticated.
I'm currently looking for a nice solution for the problem above. We'll probably run form authentication on the .NET one.
I have an ASP.NET MVC app running on a.mydomain.com and a Java based app running on b.mydomain.com.
What is the best approach so that I don't have to log in to each app. Say, when I log into the a.mydomain.com and then open the Java b.mydomain.com, and it will check and see that I'm already logged in?
Would the WCF AuthenticationService class work for this? Could I do an AJAX request from the JavaScript of b.mydomain.com to check if I'm logged in already in the .NET app?
As long as mydomain.com is not in the public suffix list ( http://publicsuffix.org/list/ ), a.mydomain.com can put a domain cookie for .mydomain.com
( note that you can only go down one level in putting cookie : a.b.mydomain.com can not put a .mydomain.com cookie )
The cookie will be sent to b.mydomain.com (as well as *.mydomain.com and mydomain.com) and can be used as a token to open a session. So be sure to control the whole *.myDomain.com subdomain and make it httpOnly and secured (https)
Response.SetCookie(new HttpCookie("myCookieName", "myCookieValue") { HttpOnly = true, Domain = ".myDomain.com", Secure=true });
Some parts of the Atlassian Crowd solution http://www.atlassian.com/software/crowd/overview are based on this cookie mechanism
So you might :
Enable forms authentication on a.domain.com
upon successfull login build a myToken cookie which value contains userId and hashed userId with hashing key known by a.myDomain.com and b.myDomain.com
set the cookie with domain .myDomain.com
when user enters b.myDomain.com, check the cookie server side (in java) for matching between userId and hashed value
if the cookie is correct, open session for user userId
Note that you won't be able to access the cookie client side (so no js cookie handling, except if it is server side js, for example nodejs)
Using a Java or .NET existing solution is not likely to function on the other platform. You need several capabilities:
Tracking the client with an identifier for recognition (session, cookie).
Have both the Java and .NET application be able to get the related information.
How can you do these?
This is actually quite easy. You're using the same domain so you can place a cookie on the browser for all domains, meaning that requests to a* and b* will both have the cookie sent to the server. Both Java and .NET have excellent facilities for cookie placement.
This is dependent on your back-end. What are the systems using for persistent storage? If you have something like a MySQL database which both systems are connected to, you can make a table with login information for each stored identifier for authentication. If you take this route, have some sort of time-out as well to invalidate old authentications.
If you have both those pieces of information, you can do the authentication on each system.
I recommend using one of enterprise sso protocols, Oauth2 or ws-federation. This gives you maximum flexibility in composing your services, you can not only federate these two but then, later, easily expand your application environment. Both protocols do not need apps to be on the same domain.
Although this could sound overcomplicated for your simple needs, you do it once and have the sso problem solved forever, no matter what happens in future to your applications.
Here is the situation:
C# Windows Forms application
ASP.NET web application
Both authenticate with a custom user table in the same database (usename/password) and create a User object that is used throughout both applications
A user is logged into the Windows Forms application and we want to launch a URL to open a page in the ASP.NET web application in the default browser (IE, Chrome, Firefox, etc.). We want to pass the current username/password from the Windows Forms application to the ASP.NET web application in order to keep the user from having to log into the web application separately.
Based on our research, here are some options we have found (and the drawbacks):
Pass username/password in URL as QueryStrings and create the User object in the web application
Not secure (password visible in URL)
Create a temporary HTML page on the client machine that includes a JavaScript OnLoad function that POSTs username/password to the target URL and create the User object in the web application
(Could not find a way to POST data directly to a URL and display URL in default browser using C#)
Not secure (password visible in temporary page)
Create a "Handoff" table to store username/password with a key that gets passed to the page via QueryString and deleted from the table when the page loads and create the User object in the web application
Small potential for key to be intercepted (hackers)
Have a separate MongoDB that stores the User object and retrieve it in the web application
Separate software (MongoDB) running - additional point of failure
All of this is so that the user doesn't have to type their username/password twice to log into both applications.
Which one of the above options above would work best (most secure, least overhead/maintenance)?
OR
Is there a way to create a Forms Authentication ticket (cookie?) in the C# application that could be used by the default browser?
OR
Is there a better, secure method for handling this?
(edit)
OR
Is there a good argument for requiring the user to enter the username/password again to access the web application if they're already authenticated from the Windows Forms application? If so, can you provide links to references? Best practices, web security standards, etc.
You could salt+MD5 the password and send it simply with the URL.
However, you should point to a script on the server first, which authenticates the user and creates the appropriate cookies, and redirects to the desired page, now without the credentials in the URL.
edited: or basically do whatever you want to preserve the users' session
Unfortunately, as long as passwords are involved, you can't be 100% secure. Still, hashing a salted (salting is when you concatenate the password with some other string before hashing) password might be your best bet if somebody can get a visual on the passwords.
You generate the password hash, with salt.
You send it to be processed (I usually just put it into the URL of a separate script, but it's a matter of preference.)
You generate a hash with the same salt on the server and check it against the submitted one.
Authenticate the user and redirect to the original location.
In additional to what Máté Gelei has contributed, you could also include a timestamp in the Url and check to make sure the timestamp falls within a few seconds of current time. This is a little added protection and ensures the login attempt becomes invalid very quickly. Of course, you would want to somehow hide the purpose of this to make it a bit more secure.
This does not make it 100% secure, but it does add one more level of protection.
I was wondering if anybody could give advice on a secure way to implement a global login. I have an admin page that accesses active directory admin groups after typing in your username and password.
current logged in account (on computer) does not matter
user in web browser goes to web app, redirects to global login page with query string of app name
types user name and password of an account in AD (not necessarily current computers logged in user)
authenticates (looks up user, pass etc and authentication is valid)
redirects back to original web app.
Once redirection happens, how do I securely tell the original web app that this user is ok until the original web session dies?
The way I'm thinking of implementing it:
My original thought was to pass the session ID of original app to the login page as well as the app
name. Store that session in a DB once authentication is checked. Master page of the other app validates on page load that the session ID matches. On session close, remove current session ID from DB.
You cannot depend on sessionID accurately in some cases. SessionID only becomes a constant value after a (any) page makes a request for a session variable, if you dont have Session_Start not defined in global.asax. If you log the user in and the default page does not access session, you will end up with a different session id for the subsequent requests until a request to session is made. Usually it is always constant as there is a default empty session_start event in global.asax.
But similar to your model, you could generate a GUID (or make sure you access session on login/authentication) and store it in the user table with an expiration. Your web sites can check this key and if currently valid, auto sign the user in.
You also cannot depend on session_end event since there is no real accurate way of detecting it (eg: user closing browser). So, you should store this ID with an expiration time along with it, preferably the same as session timeout. Just like session, you will need to extend this, something like a sliding expiration. This way, this id will be expired after a period of inactivity.
also, this Claims-Based Single Sign-On for the Web may be of interest to you.
What you're describing sounds like it would be better implemented using Windows Identity Foundation and Active Directory Federation Services 2.0. I don't know the extent of all your requirements, but it might be valuable to check out what these will give you out of the box.
You could use a cookie. If you pass the name of the application to the login page, you can set that application name to the PATH property of the formsauthentication cookie. By setting the PATH property, you're effectively limiting the readability of the cookie to the pages within that path. Because it's a common login interface, this may require some code being done perhaps in a common page base class that handles the parsing of the cookie information.
You can share authentication tokens between .NET applications, even between .NET CLR's if you want to. I think this will give you the single sign on you're looking for.
At a high level you need to share a machine key between the applications. You can generate the machine key using the key generator app code example found on this link, and providing you then reference the same key in each application the sign on can be shared:
http://msdn.microsoft.com/en-us/library/ms998288.aspx
There are some consideration when looking at things across domains or accross machines/web farms etc, but if all apps are on the same box it's not too hard.
The harder side of things is sharing things like session state which I don't believe can be done accross app pools. (I ended up recreating the session object on the new app manually last time I did it :( but that was between 1.1 and 2.0 apps )
EDIT: I did a rough write up of it last year and was using it as a test for a demo article on my site, might be worth a read through if you want things broken down a bit more (Ignore the unfinished site!):
http://www.dougmcdonald.co.uk/test/html5/v5/articles/2010/05/10/Sharing-forms-authentication-between-applications/