Forms authentication & subdomain - asp.net-mvc

I'm trying to use forms authentication that will work for both my top level domain & sub domains.
for example, if I log in with this domain: mydomain.com and afterwards going to www.mydomain.com i want to have the ability to identify the user who logged on to mydomain.com (it's the same application).
i'm using the following in my web.config file:
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" domain="mydomain.com" timeout="2880" />
</authentication>
This is an mvc project, and i'm getting the user id with the following API:
HttpContext.Current.User.Identity.Name
The creation of form authentication cookie is done by the following api after performing openid logon to the user:
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
I can see that the authentication cookie is being sent to both domain but only the domain that the authentication was made against recognizes the user.
Am i doing something wrong?
Thanks,
Lior

Make sure you have the same machine keys setup for those two applications. If the authentication token is encrypted with the machine key of application 1 and application 2 has different key it won't be able to decrypt it.

This question isn't exactly the same as yours, but it looks like it's the solution your looking for.

You need to issue your ticket in the toplevel domain, in order to be recognized by subdomains. This is because of how cookies work:
If you set the cookie in domain.com it will be visible on sub.domain.com
However if you set it on sub.domain.com, it will not be visible on domain.com
This is a security issue because of cookies and you'll have to consider it, beyond the settings of the <form> element which have to do with validating/rejecting a authentication cookie, where you will need to have domain='domain.com', which you already do.
In addition to all this, if on the subdomain you have a different application, you will need to explicitly define the machine key to be the same. You can generate your self some keys here: http://aspnetresources.com/tools/machineKey

Related

Authenticate all Subdomains in Multitenant Application

I have built a Multitenant SAAS application. In this application the User can pick his preferred subdomain name during signup. When user logins to the main application i.e. app.example.com, I validate his credentials and then redirect him to his preferred domain i.e. client1.example.com
I am using Forms Authentication and trying to authenticate the user over the domain "example.com" by making following changes in the web.config.
<forms loginUrl="~/Login/Home/AuthenticateLogin" timeout="2880" protection="All" domain=".domain.com"/>
My understanding is that once authenticated over "example.com" user will be able to access any subdomain of (domain.com). But it seems this does not happen as expected. After successful login to app.example.com when I redirect him to client1.example.com it again shows the login page.
What am I missing here?
You need to configure the same machineKeyfor all applications that share the authentication cookie. See Generate a Machine Key for a Web Farm (IIS 7).
Also verify that the cookie is set when you log in, and that it flows to all the applications.
Okay, So after trying for so long I got to know what the real problem was.
Actually even after allowing subdomains to share authentication cookie it did not work because the SessionId was not being shared between the subdomains. My Application had outproc Session Configuration (Sql Server). To share SessionId between subdomains I had to make following entry in my web.config :
<httpCookies domain=".domain.com"/>
After this it worked like a charm.
Hope this helps someone in need.

Cookie expires or session timeout too soon

I have code like this which is run when a user is authorized:
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
email,
DateTime.Now,
DateTime.Now.AddMinutes(120),
true,
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
faCookie.Expires = authTicket.Expiration;
Response.Cookies.Add(faCookie);
I then redirect to a controller/Action that has the Authrize attribute:
[Authorize]
public class ProductsController : Controller
{
I have the following in web.config:
<authentication mode="Forms">
<forms loginUrl="~/Home/Unauthorized" timeout="2880" />
</authentication>
<sessionState timeout="120"></sessionState>
However users are complaining of session timing out or redirecting Home/Unauthorized after a couple of mins of inactivity.
what could be causing this, what else should i check?
A couple of thoughts before I go into a possible solution of why your logins are expiring. First, the FormsAuthentication cookie and SessionState are two different things completely. You can have one or the other, or both or neither. As a result, the timeouts for these two items are also not related.
The FormsAuthentication cookie is an encrypted cookie that contains some basic information such as the user name and an expiration value. The .NET application uses this cookie once a user has authenticated to know if the user is authorized for certain resources.
What controls the encryption and decryption of the FormsAuthentication cookie is the MachineKey for that web application on IIS. The MachineKey is a set of keys used to encrypt and decrypt the cookie. By default, a web application on IIS is set to AutoGenerate the machine key. What this means is that when an application starts, a random machine key is generated. If an application recycles, you get a new machine key. Additionally, if you are hosting on a shared provider, the web host will typically have your application load balanced, meaning hosted by more than one server. Each one of those servers will auto generate a machine key.
If your web application is on a load balanced scenario, then each machine in the web farm cannot decrypt the other's encrypted cookie. This will give the appearance of "being logged out". The example of this is logging in on web server A, then a subsequent request goes to web server B. Web server B does not share a machine key with web server A and cannot decrypt the cookie, sending the user back to the login page.
The solution is to define the MachineKey section in your web.config so each instance of IIS will use the same keys as well as if the application pool recycles, you still have the same machine key.
Here would be an example machine key (use the .NET 2.0 version) that you could place in your web.config
<system.web>
<machineKey validationKey="EBC1EF196CAC273717C9C96D69D8EF314793FCE2DBB98B261D0C7677C8C7760A3483DDE3B631BC42F7B98B4B13EFB17B97A122056862A92B4E7581F15F4B3551"
decryptionKey="5740E6E6A968C76C82BB465275E8C6C9CE08E698CE59A60B0BEB2AA2DA1B9AB3"
validation="SHA1" decryption="AES" />
</system.web>
Additional thoughts are that your expiration in your web.config (2880) and what you are actually setting the expiration to be (120) do not match. You may want them both to match.
If you are running behind a load balancer you will want to ensure that the web farm is using a consistent key as pointed out by Tommy's answer.
Other things to check will be that the IIS metabase settngs for each server are identical. They need to have the same path and ID.
You will also want to look at holding session out of proc (your web.config looks like in proc) which is susceptible to network outage and random app recycles.
Basically a summary of this link.
http://msdn.microsoft.com/en-us/library/vstudio/ms178586(v=vs.100).aspx
If you can post more of your config if possible and give more detail about your environment setup it will be easier to point you in a more focused direction.
Try This one:
web.config Code:
<system.web>
<httpRuntime maxRequestLength="40000000" useFullyQualifiedRedirectUrl="true" executionTimeout="600000" />
<authentication mode="Forms">
<forms loginUrl="~/Home/Unauthorized" timeout="2880" cookieless="UseCookies" />
</authentication>
</system.web>
This will help you.

Membership can't validate user after providing machineKey

I have a web site with two endpoints, let's say www.mydomain.com and mydomain.com.
I need my user stay loged in when he jumps from one domain to another.
For this task I could force my users to login on one of domain (let's call it the main) and if somebody visits another - just redirect him to the main domain.
But I have read that I can use Forms Authentication Across Applications and share the same authentication ticket accross multiple domains.
So I decided to give a try to this approach, but it doesn't work for me... the main question why?
What I did:
I generated new machineKey from this service.
Added it in my web.config.
After this step my old membership provider stoped working correctly. It doesn't validate users with right passwords.
I suppose it's because all passwords in my current database should be encrypted by values from machineKey section.
Could anybody point me at what I am doing wrong and is it possible to make shared authentication with machineKeys and existing membership database that contains passwords in hashed format?
I also experimented with addint protection="All" (I assume that it shouldn't work with hashed password because it forces its encryption by machineKeys) and domain="mydomain.com" attributes to my <forms/> section in web.config, but - no luck.

STS Authentication - MVC Site

I have two servers: STS and Web. On the STS server, I call:
FormsService.SignIn(model.UserName, false);
The next line, I check:
User.Identity.IsAuthenticated
This is set to TRUE. Then I redirect back to my Web server and in the controller I hit, I check:
User.Identity.IsAuthenticated
This is set to FALSE.
What could cause this?
UPDATE: I also just tried moving the STS web site to the Web server. I get the same error/issue
UPDATE: I forgot to mention that our DEV server works just fine. The configuration there is identical (except for the server name and cert thumbprints). The only thing different between these two servers is that one (DEV) is using a self-signed cert and is inside our firewall. The other (QA) is using an official (thawte) cert and is ourside our firewall. This cert's common name does not match the server name (so it can be shared in our farm). So when we access the site, we do so using https://[commonname].com/web as opposed to https://[servername]/web. I tried the latter approach (I get cert errors that there is a name mismatch) but still have the same result.
Also, I can access the STS site directly and login fine there.
ASP.NET authentication is based on cookie by default. Cookie lives inside web domain.
So if you have two servers installed like this:
http://www.web.com
http://www.sts.com
WEB server cannot read cookie set by STS
There are two possible solutions:
Implement both servers as sub-domains
Store authentication ticket in URL instead of cookie
For option 1
Move servers as follows:
http://www.web.yourdomain.com
http://www.sts.yourdomain.com
Update web.config to scope cookie to yourdomain.com:
<authentication mode="Forms">
<forms domain=".yourdomain.com"/>
</authentication>
For storing ticket in url check this article - http://www.codeproject.com/Articles/2796/Cookieless-ASP-NET-forms-authentication
Update: Seems that I did not get that STS stands for Security Token Service. My answer is not relevant. :(
While redirecting from your STS server you will have to redirect using the AutoPostform which will submit the token to the Relying party.
And when Relying party will receive the token it will create the cookie against that user.
So next time whnen you will check User.Identity.IsAuthenticated at Relying party it will return you True.
Go throung the following link to know more,
http://chris.59north.com/post/2013/03/27/Claims-based-identities-in-ASPNET-MVC-45-using-the-standard-ASPNET-providers.aspx
We had the same issue when moving the RP to a different server. It turns out that we needed to go into the application pool -> advanced settings -> Set 'Load User Profile' = true.
After that, everything worked as it should on the new server and User.Identity.IsAuthenticated was returning 'true' after it came back from the STS.

ASP.Net MVC Single-Sign On

We're in a period of moving all our applications to sub-domains of the same primary domain.
Once this is done we aim to move our entire set up to a Single Sign-On system. Currently, we use Forms authentication and set a cookie containing an encrypted token when the user is successfully logged in.
When it comes to setting this up for SSO - is it simply a matter of changing the domain to which the session cookie(s) are set? Or are there other matters that need addressing for this to work.
Set the Machine key in the system.web section of your we.config's to the same value, get that from your IIS config:
<machineKey validationKey="<from IIS>" decryptionKey="<from IIS>"
validation="SHA1" decryption="3DES" />
Then all the sites will see the cookie as valid. The domain names in your section should be subdomains, I think. Well, it works when they are subdomains, don't know what it will do if the actual domain names are different.

Resources