Using ASP.Net Identity on multiple web applications - asp.net-mvc

I've got several applications hosted on the same IIS (different context roots), that are all protected using the Microsoft.ASPNet.Identity 2.1 NuGet packages. At the moment however, when I log in to one of the applications, the next visit to any of the other applications prompts me to log in again. I can't be logged in to more than just one of the applications at once.
I'm guessing that they are all using the same cookie to store the login token, so when you log in on one app, it resets the cookie which becomes invalid for requests to the other applications.
What are my options for resolving this? I don't mind having to log in to each app individually, so can each app be configured to use a different cookie?
Alternatively, each app does in fact share the same User table in the DB, so it might be possible to configure it so that when you log in to one of the applications, the others also become logged in.

Have a different cookie name for each app:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
CookieName = "CookieNameHere",
});
As shown on this page http://tech.trailmax.info/2014/07/rename-authentication-cookie-name-of-asp-net-identity/

Yes, this is because on 'localhost' you are sharing the same cookie.
This will not happen on production, because cookies are domain only. (unless, of course, all applications are deployed to same domain).
This is kinda annoying on localhost but easy to solve. Just change the name of the cookie for each application.
This varies from identity version to version but something like this is what you are looking for :
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
CookieName = "MyApp1", // <-- add this, with different names for each app
// ...
});
normally found on Startup.Auth.cs or Startup.cs file.
As of using the same cookie on all applications (if they share subdomain.domain) you need to get MachineKey (validationKey, and decryptionKey) AND same cookie name on all your applications.
something like this on web.config:
<machineKey
validationKey="..." <-- some valid validation key
decryptionKey="..." <-- some valid decryption key
validation="SHA1"
decryption="AES"/>

I think Single Sign-On could be your solution. Search for it on Google.
For your start up, you can refer couple of links below:
Single Sign-On Asp.Net
Claim base Single Sign-on for Web and Azure
Single Sign-on for existing MVC App
Hope this is what you are looking for and will resolve your problem.

Related

Claims Identity anti-forgery exception with brand newly templated website with Individual User Authentication

I used the MVC5 web template to create a new site with Individual User authentication and when I try to run it I get:
System.InvalidOperationException: 'A claim of type
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier'
or
'http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider'
was not present on the provided ClaimsIdentity. To enable anti-forgery
token support with claims-based authentication, please verify that the
configured claims provider is providing both of these claims on the
ClaimsIdentity instances it generates. If the configured claims
provider instead uses a different claim type as a unique identifier,
it can be configured by setting the static property
AntiForgeryConfig.UniqueClaimTypeIdentifier.'
I haven't changed anything in the code since it was generated. What could be causing this?
So the answer to this turned out to be to clear the cookies for the site.
As far as I can tell, the issue occured because I was also developing another MVC5 app at the same time, and that one was using a different set of authentication code (Active Directory based).
I worked out that the two apps were interfering with each other by commenting out the #Html.AntiForgeryToken() line in the _LoginPartial class and then the home page loaded without the error. What I then saw was that I was already logged in, even though this was the first run of the app.
Clearing the cookies sorted that issue, but I definitely wasn't expecting two different MVC apps to share a cookie. However, that is actually the expected behaviour, because by default the ASP.NET Cookie Authentication will create a cookie named .AspNet.ApplicationCookie for every app. If you inspect the cookies for your ASP site you can see this:
That's actually very easy to change, just modify the code in Startup.Configuration to set a specific CookieName:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie",
LoginPath = new PathString("/Account/Login"),
CookieName = "yourCookieName"
});
}
}
Then, clear the cookies for the site, run it up again and you should see the Cookie has now been renamed.

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.

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.

Setting up a private beta for a website

I'm trying to setup a "private beta" for a site that I'm working on. The site uses open id. I don't want anyone to even browse the pages if they aren't part of the beta. What's the best way to implement this? Any suggestions?
For example:
When the site goes live, users will go to http://www.mydomain.com which will not require them to log in.
For the beta I want to restrict access. Users that go to http://www.mydomain.com will be redirected to a login page. Anyone attempting to access ANY PART OF THE SITE who is not authenticated will be redirected back to the login page.
I could stick [Authorize] attributes all over my controller actions, but that seems stupid.
If you're using ASP.NET MVC, it comes with authentication/authorization out of the box. You should be able to use that to setup authentication on your site.
Alternatively you could setup app server settings - IIS lets you setup username/password on a specific site it's serving, regardless of what the actual application may do. If you have access to the app server this might be the best solution.
If you're using IIS6, you can setup authorization easily. Right-click on your site > Properties > Directory Security Tab > Authentication and Access Control > Edit, and enter a username/pwd of your choice. Done.
The real question is how are they being invited to the private beta?
You could setup a password which drops a cookie much like serverfault.com does.
OR
If you know who you are inviting: you could add them to the system before hand using the email/login information that you already know about them (assuming you are inviting them via email)
I have implemented a function in a web application a while ago where we go the possibility to block access to the full website unless the user was an administrator (which in our case meant that the user account was a member of a specific group in Active Directory).
It was based on two things. First, all pages in the web application inherited not directly from the Page class, but from a custom page class in our web application. Second, we had a value like this in the appSettings section of web.config file:
<add key="adminaccessonly" value="0" />
The custom page class would check that value when loading. If it was not 0 it would redirect to a page (that did not inherit the same custom page class, though) informing the user that "the site is not available right now". If the value was 0 the page would load as usual.
In that application we used this to be able to take the site "offline" when we deployed a new version, giving us some time to verify that all was good before we let in the users again.
Best way are invitation system (based on invitation code) or manually confirmation access after create profile in your system. imho
Or you could host the site on a private server, and set up a VPN to use it. Depending on your resources and needs this may be the easiest and most secure way to do what you want without modifying your codebase.
OR alternatively you could use Apache or IIS to force authentication on access to the website directory. Keeping the authentication info in .htaccess for a while.
Even though you use open id authentication, you may still need some form of authorization mechanism. The simplest form would be a user-roles system in your database that assigns different roles to users
In your case, just assign the private_beta role to your private beta invitees and ensure you your authorization mechanism that all users have private_beta privilege before they may continue.
If you don't want to provide authorization for the public site (where everyone can do everything, once authenticated), then, you may only need to do a quick-and-dirty post-processing (for private beta only) on your open_id authenticated users to check them off a short list (which you can store on a text file.

Resources