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/
Related
We have a SPA application that makes use of cookie-based authentication. The cookie is validated on the app server by checking the expiration time of the user's stored session in a database.
The client requirement is that each new tab/browser opened should force the user to log in on that new tab/browser instance, thus allowing the user to have multiple sessions open for concurrent work purposes. Closing a tab or signing out needs to expire the user's session for that specific tab and still keep the other sessions active. Refreshing a tab should obviously still keep the user logged in on that specific tab.
At the moment, we make use of a unique identifier to identify the specific tab with its accompanying cookie, in order to only clear the relevant cookie when the user logs out or closes the tab. This unique identifier is stored in Session Storage and gets passed as a header with each server request. This unique identifier is visible in the the browser URL, for the reason that when the tab is refreshed, that identifier is used to get the relevant cookie and authenticate it.
This whole process feels clunky and prone to bad security practice.
What type of authentication would be best to facilitate the client requirements?
It feels like a very old-fashion and outdate requirement, to have separate sessions per tab. One approach is to let the backend redirect each new request to it, to its own unique per-tab sub-domain, so that each sub-domain can get its own independent set of cookies.
like
session1.mysite.com
session2.mysite.com
session3.mysite.com
session4.mysite.com
session5.mysite.com
I have an application that uses APS.NET as the middle tier. One of the features for administrators is to allow them to popup another browser window logged in as a non-admin user, so they can provide support.
I use a javascript function "openWindowWithPost." The application takes credentials from a DB and forces a login so the support staff does not need to know the user credentials. Unfortunately when it does that the original session is reused and hence all of their application variables are shared, causing havoc with the original Admin login.
What I would like the ability to do is to force a second browser window to popup and when it talks to IIS have it create a new session and keep the original one active. Is this possible? If so where can I find how to do this?
From your post, it looks like you are using the Session object in ASP.Net to store data.
By default the Session ID is stored by the browser in a cookie. See MSDN
for a description of how it works. You could setup your application to use query strings to store the session id, but that is really old fashion and can become messy and hard to deal with.
Your best bet is to find a solution at the browser level. For example, Firefox has an extension called Multifox that would do what you want. Other browsers have similar extensions.
I have two website consider it as website1 and website2.
In website2 there is a login page .When a user click on the login button it will call a HTTPhandler in website1 to authenticate user.On successful authentication user information will be stored in a Session variable from handler.
Then it will redirect to a page page1.aspx in website1.But the previously set session is not available in the page1.aspx .What will be the issue?
I checked the session id in first request(when calling handler in website 1 from webiste 2) and Second request( redirecting to the page1.aspx from the handler) the session id is different.
How can i retain the session data?
You need to store session data in another process shared to both web site.
You can do it intwo different ways:
Configure an SQL server
Configure SessionState service, a Windows service used to share informations.
In both cases you have to change both web.config files to support the new session mode.
I.e. to use SQL:
Prepare a database (from command prompt):
cd \Windows\Microsoft.NET\Framework\v4.0.30319
aspnet_regsql.exe -ssadd -E -S localhost\sqlexpress
Modify web config as following:
<sessionState mode="SQLServer"
sqlConnectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=Test" allowCustomSqlDatabase="true"/>
You don't need to change your code.
Correct me if I an wrong, AFAIK different domains cannot share a single session. One way to handle this is to carry the data to the other site through cookie [encrypt the values for security], then copy this cookie value to the session in the other site receiving it and destroy the cookie.
And if the sites are in different servers you need to handle the "sticky session" so that servers share the session.
This situation sounds kind of similar to one I have experienced and worked on before, where one web application acts as the login page while another is the actual app where all your work is done. I can describe what I did in the hope that you find it useful.
Like you I had one web app which had the login page (so in your example this would be website2). When the login form submitted I then redirect to a fake Login.aspx page in website1 - this is where we differ I think as I'm not sure of your specific reason for using a HttpHandler.
In my case the website2 Login.aspx page is actually just the way into the web application; it has no markup, just code-behind which will authenticate the user, perform setup (e.g. set session variables) and then redirect to another page such as Homepage.aspx. This particular scenario has worked for me, so maybe your problem revolves around the use of a HttpHandler though I would not be able to tell you why.
In order to retain the same session date across two different servers running ASP.NET web applications you must configure your session state to be managed out of process. This means the actual session state data variables will be stored outside of worker process and in another process that is able to make the session data available to other machines.
To achieve this you can configure your application to use SQL Server to store session state and make it available to multiple servers in your farm. The TechNet article Configure a SQL Server to Maintain Session State (IIS 7) provides details on hor this is done in IIS 7.
If you are using IIS 6 then the steps to configure are somewhat different and I can provide further details on this if needed.
In order for this to work you do need to ensure that both servers are running applications within the same domain, e.g. myapp.com, otherwise the ASP.Net session cookie will not be passed between the two servers. ASP.Net uses the cookie to lookup the session state stored in SQL Server and will therefore not find any matching session if the cookie is not passed on requests between the two servers.
i think IRequiresSessionState will not help because context is different.
once we had the same problem but that was passing asp session varibles to .net. How ever you can do it here also.
on both website create a page setsession.aspx
now if you are on page say web1/page5.aspx and want to go to web2/page3.aspx
you redirect to web1/setsession.aspx?togo1=web2/page3.aspx
in both setsession.aspx logic in to extract sessiondata and place them in querystring
so the web1/setsession will redirect to web2/setsession.aspx?sess1=value1&sess2=value2&togo=page3.aspx
web2/setsession.aspx will check for togo querystring and if found will extract all querystring name and value will set them in session and will then redirect to togo value.
you need to differentiate togo1 and togo carefully.
Session sharing between websites is going to require hand-coding. You could hack the asp.net framework to get this working, but I feel that this is not a clean way of achieving what you set out.
If user authentication is all you are doing from website, is it possible to use alternative? Single Sign On mechanisms will help you out here.
Something like SAMLSSO could help you in this case.
You have two websites which are hosted on different servers, it means you have two different processes running on separate machines, so sessions will be definitely different. Same session can't be shared across processes because by default asp.net support in-memory session.
Here you would need to think about storing sessions information which can be shared between two processes (i.e. out of process). Ideal way to store sessions information in databases. For this you can consider Stefano Altieri code sample above.
I don't think you really want to share session information between two websites at all. From what I can gather from comments, what you're really trying to do is have a user authenticate in one website (give you a username and password which are validated) and then have that "logged in" state transferred to another website which doesn't handle authentication for itself.
What you are describing is the Delegated Authentication model.
In this model, your application hands-off authentication to other systems which it trusts to provide information about users.
There are two well-known protocols which provide this mechanism:
OpenID
This is intended to facilitate users logging in with their own identity providers (Google, Facebook, Microsoft Account). It's a very good choice if you're running a public-facing website, as most users will already have an account they can log in with.
WS-Federation
This is intended to facilitate users logging in with identity providers which are managed by known trusted parties, such as partner organisations.
From version 4.5, the .NET Framework has built-in support for WS-Federation via the Windows Identity Foundation component (and is also available for earlier versions as a separate download). This automates the task of delegating your authentication to an Identity Provider.
It also provides components for you to write your own Identity Provider, should you want to create your own, but you shouldn't have to; you can find various existing implementations to perform this job for you.
The problem you're trying to solve is a very difficult one, especially trying to make it secure enough to be reliable. The good news is that smarter people than you or I have spent years working out very clever ways of doing this. You should use what they have done and not try to cobble together something out of Session state.
In the long-run it's best to let the smarter men do the hard work for you.
I'm enabling an windows identity foundation on an existing webapp.
I want to mess as little as possile with the existing code so I would like to the login page which uses formsauthentication left in the application and I just connect with the STS if the user enters the application via a specific page e.g "im_comming_from_some_other_site.aspx".
in the "im_comming_from_some_other_site.aspx" the code would be like:
Page_Load(...)
{
if(verifyAgainstSTS()
{
FormsAuthentication.SetAuthCookie(<some_STS_Userid), ...)
Response.Redirect("default.aspx")
}
else
{
Response.Redirect("http://<STS_server_name/<STS_service...etc>")
}
}
Is there someone who knows if this may be done and how? Any links to example code (if available) deeply appreciated.
(Of course some code would be needed when to determine what to do when the authentication is timed out; either go to local login page or goto STS-login page)
I know this may seem like a bad design, not going all the way with STS, but I need to implement this ASAP and I want to keep the original site as untouched as possible.
It is not a bad design, it's your requirement and you try to fulfill it. We have working system built like that and it's not a rocket science. The only difference is that we switch it to forms/sam statically (via global settings), not dynamically.
Anyway, you keep your forms authentication in web.config so that when there's no authorization for current user, forms redirects the request to the login page.
In the login page you have two options. One creates the forms cookie somehow.
The other option involves WIF's FederatedPassiveSignIn control.
If a user follows forms authentication, the cookie is set and you are done.
If a user follows the STS login control, sooner or later he/she will come back with valid SAML token. The FederatedPassiveSignIn will pick it up automatically and you just handle the redirect in the SignedIn event.
You will even not need the if you mention in your question.
There's one caveat from what I remember. When a user is authenticated by STS, the WS-Federation cookie is created, you can read claims etc. Everything works.
However, if a user is authenticated by forms, the SAM (SessionAuthenticationModule) will REPLACE forms cookie by the WS-Federation cookie in ASP.NET pipeline upon EACH request (I guess it's because the SAM is later in the pipeline that forms authentication module).
This will NOT blow up your context.User.Identity.IsInRole(...) also authorization works correctly because SAM will copy user roles to corresponding claims.
However, if at any place in your code you try to extract information directly from the forms cookie (instead of using general APIs), you could find out that the forms cookie is not present even if the user was authenticated by forms in first place (and the cookie is not present because it will be replaced by the WS-Federation cookie).
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.