How to allow multiple authentication methods in ASP.NET? - c#

I'm building a new ASP.NET MVC application (in C#) and one of the requirements is to create a new database of members. For this, we'd need roles to manage the different types of members and profiles to manage the additional metadata attached to each member. So far so good, just use the standard MembershipProvider, RoleProvider and ProfileProvider provided as part of the .NET Framework.
However, the catch is that I'd like to allow different authentication methods. I'd like Accounts and Login Credentials to have a one-to-many relationship (one account can have a number of login credentials attached). A user for example, might have both an OpenID and ActiveDirectory account attached to their account.
However, after experimenting with a few ways we opted for the MembershipProvider route (explained how it was achieved as an answer below).
My question is, how have people done this before and how would people suggest I approach it? It appears to be something that is achieved on quite a number of sites, yet a search on here doesn't return anything solid to play around with.
EDIT: After looking around for a good period of hours overnight and this morning - I'm still not convincinced that butchering a single MembershipProvider would have been the easiest option. Does having multiple MembershipProviders give the same effect?
BOUNTY EDIT: With no responses, I am assuming that there is no more optimal solution that the one I posted as an answer. Is this really the case? I'm offering a bounty to try and see if anyone has any further thoughts on this and whether there are better alternatives.
BOUNTY ACCEPT EDIT: I think that WIF is the answer as accepted below, for a .NET 4 release and maybe other versions as it probably works with 3.5. Other than that, maybe a butchered MembershipProvider or adapted one may still be relevant.

In my opinion, the "real way" of doing this is to use federation with WIF (Windows Identity Foundation, formerly Geneva framework).
The idea is that you separate authentication from authorization. The authentication is performed by a so-called STS (Security Token Service) and it manages all the possible login mechanism that you want to support. When a user has been authenticated the STS issues a token containing a set of claims and the user's identity.
This token is sent to the web site (called a relying party in this lingo), and the website determines which parts of the site the user has access to based on the claims in the token. WIF supplies both membership and role providers that extract information from token.
You can read about creating a claims aware website here.
One of the pros of this approach is the separation of concerns between authentication and authorization. You do not need any complex membership and roleproviders in your website. Furthermore the STS can be reused to authenticate users to other applications you might have without them having to register more than once (effectively achieving single sign-on)
The downside is that you will have to spend some time studying these concepts and coding your STS. Mind you, it is not hard to code an STS with WIF, but it is not a 100% trivial task either.
If I have managed to tickle your interest I would recommend that you start out by reading this whitepaper.
Kind regards,
Klaus

One idea we've followed is to create a custom Membership / Role / Profile provider. We customised the login / authentication methods significantly and have an additional table of logins. This table basically just contained:
LoginID (Auto-Incremental ID, PK)
UserID (FK)
LoginSystemID (FK)
...blah blah
Within the above, the LoginSystemID was a link to a foreign lookup table which helped the system to determine which authentication service to use (e.g. Standard, AD, OpenID, FacebookConnect - etc).
The problem we ran into was that the Username field in the MembershipProvider couldn't be empty and while in our schema everyone had a UserID (it was their account name), they didn't have a Username that was unique. We had to get around this by generating a GUID and using that. This of course is hidden from the user and a DisplayName attribute from our Users table can be displayed instead.
This was all done via FormsAuthenication (the AD checks were done via LDAP checks). However, an additional layer (a webform) was added with appropriate settings within IIS that provided a means for automatic WindowsAuthentication - we redirect to there in the instance that we feel the user is likely to be internal (based on IP address).

Use standard framework stuff. See http://blogs.teamb.com/craigstuntz/2009/09/09/38390/
You can have an unlimited number of authentication methods attached to one account, the magic is in the FormsAuthentication.SetAuthCookie(userName, createPersistentCookie); statement

Related

ASP.NET Single Sign On

We have two servers that run on the same machine under the same domain.
Both written in ASP.NET and uses the Identity framework.
I need to implement Single Sign-On (and single sign out) between them.
Actual sign-in is done in AJAX (I POST the username and password, the server authenticate the user and sets the session, then sends the redirect data URL to the client).
I found overwhelming amount of information about OWIN, the Identity framework, Claims, etc.
I found tutorials explaining how to create projects using just about any modal dialog and any Wizard there is in Visual Studio, which I tried to understand but really is useless to me, as I already have authentication system up and running.
I even found some demos claiming to implement SSO in all kinds of ways, and some Stackoverflow questions that said to simply put this and that values in the web.config and you're done, which seemed strange to me and I figured out I'm missing some basic understanding of how it works.
Still, I can't understand how SSO works in ASP.NET Identity.
Can someone please explain it to me in a simple manner, or refer me to some kind of such explanation?
Again: I have two authentication systems up and running. What code and/or configuration changes I need to make to get Single Sign-On working?
First, if you want them to share authentication, they need to be working on the same user store. In other words, you should factor out the Identity initialization code (ApplicationUser, ApplicationDbContext, ApplicationUserManager, and ApplicationSignInManager) into a class library that both applications share. Trying to mantain and share two separate databases with user data is going to be an impossible and insurmountable task.
Then, you need only ensure that both applications utilize the same machine key. The auth cookie is encrypted, and since the encryption is based on the machine key, both applications need to use the same key to encrypt/decrypt that cookie.
Since you've already stated that they will both be hosted on the same domain, that's all there is to it.

MVC authentication with additional user details

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.

Options for single sign-on between ASP.NET and MVC.NET solutions?

I have an ASP.NET solution that acts as the primary customer portal for my customers. On this website the users can log-in access their important financial information and more. The website uses a custom authentication scheme that checks the user's username (their email) and their password (salt-hashed) against a Users table in a local database.
I am building a new MVC.NET solution that is more of a web-app tool to be used by these same customers for ordering. I want to re-use the sign-on mechanism of the ASP.NET portal to authenticate users. The goal is to save the user from remembering two log-ins or even having to supply the same log-in twice.
What are my options for allowing users who sign on to the ASP.NET solution to then be auto authenticated to the MVC.NET solution? I've listed some ideas below but are these "bad" or is there a more elegant solution? I'd love your input.
Common Cookie I could create a common cookie that the ASP.NET site creates and the MVC.NET site looks for. But is that secure enough?
Token in Query String I could create a token id on the ASP.NET site that is stored in the local database and is then passed in the query string of the link to the MVC.NET site which takes the token id and validates it against the same database.
Hybrid A bit of both?
Other? Got a better idea?
I've recently done something quite similar (the major difference being that it was internal to the company rather than for external customers) using OpenId.
The implementation of OpenId for .NET is called DotNetOpenAuth which should be suitable for your purposes.
It did take me a while to implement; but it works very well, is very flexible, and extremely secure.
More information about openid (from Wikipedia):
OpenID is an open standard that allows users to be authenticated by certain co-operating sites (known as Relying Parties or RP) using a third party service, eliminating the need for webmasters to provide their own ad hoc systems and allowing users to consolidate their digital identities.
Users may create accounts with their preferred OpenID identity providers, and then use those accounts as the basis for signing on to any website which accepts OpenID authentication. The OpenID standard provides a framework for the communication that must take place between the identity provider and the OpenID acceptor (the "relying party").2 An extension to the standard (the OpenID Attribute Exchange) facilitates the transfer of user attributes, such as name and gender, from the OpenID identity provider to the relying party (each relying party may request a different set of attributes, depending on its requirements).
The OpenID protocol does not rely on a central authority to authenticate a user's identity. Moreover, neither services nor the OpenID standard may mandate a specific means by which to authenticate users, allowing for approaches ranging from the common (such as passwords) to the novel (such as smart cards or biometrics).
Oh, and if you'd like further encouragement, Stack Exchange uses it!
#Jmrnet: in response to your last comment:
Perhaps I was unclear. OpenId in and of itself is simply for validating credentials from one location to another (more or less). It's entirely possible to implement as an SSO model where users do nothing different whatsoever - they don't have to choose a provider, or register, or anything like that. For example, in my setup, the user enters a username and password in a web portal, and then clicks a button to launch another site being automatically logged in by OpenId. Nothing different for the user at all! OpenId can be used with any initial authentication model you can think of (note the bolded section in the snippet from wikipedia).
Take a look at SAML:
http://en.wikipedia.org/wiki/Security_Assertion_Markup_Language
It works using XML and supports encryption.
I am currently implementing two SSO solutions for the same project.
In one, we are interfacing with an external partner and are using SAML.
In the other, we are allowing logged in users access to our Sharepoint and using the "Token in Query String" approach, since we trust Sharepoint to access our membership tables. This approach is much easier than dealing with SAML tokens.
There are many methods you can use, Mansfied described OpenID and RandomUs1r described SAML. Also, you can store relevant information in localStorage or in the session. I believe you should store relevant information with session.
It is not safe to put this in the query string, because if I register and log in, I will see something like UserID=1234 in the URL. If I change that to UserID=1235 and the ID is existent, then I can do some things in the name of the other user. This is called identity theft, which should be prevented by any means possible. So you should never have this kind of info in your URLs. Also, if you store the id of the user, you should obfuscate it somehow. For instance if you store the value in local storage and instead of 1234 you store encrypt(1234, salt), then the consistency of user action will be maintained.

C# 4 ASP.net *NON MVC* Custom Authentication

I know this question as been asked countless times, but believe me I've searched Google for hours and got nothing. Whatever is out there, it's for MVC, which I'm not using.
My requirement is simple. I do not want to use the default authentication provided in asp.net. I would store the username/password/role in my custom SQL Server table. I'll provide 2 inputs for username/password and a button to validate. On validation, he is allowed access to the admin areas. This will only be used by admin guys at my subdomain "admin.*.com". They will use this page to add content to the website on daily basis.
How do I implement it. A tutorial link would suffice.
Is it safe for Production? I don't want some newbie hacker getting in to my site and mess it up. If not safe, what else option do I have.
Thanks,
Dev
As per our comments, given your reluctance to implement an ASP.Net Membership provider (and it is worth the time to investigate - you may not feel that it is right now, but it can be handy. I felt the same way at first, but the cost of maintaining your own code and infrastructure soon proves to be false economy) you have at least two other choices:
1) Straightforward Forms Authentication
Put all of your admin pages under a single folder, for example, /Admin, then use Forms Authentication to protect access to this folder. Only users defined in the database or Web.Config will have access to these pages. This is less flexible than ASP.Net membership, but may give you most of what you want. In terms of security, this will be as secure as your website is, is well tested, and is well documented.
2) Use Facebook OAuth
You mentioned that your use has access to Facebook. You could use Facebook to do the authentication for you. Although you wont be able to grab the username and password, you can get a token back, that you can then validate against a known permission set. This is a lot more work than 1) though and will tie you to potential future changes in the Facebook API. However, it also benefits from being well tested, and secure, but you have little to no control over the actual user information.
As an aside, please also consider being nicer to Google!
You can create your own custom membership provider which has the features you are looking for.asp.net membership provider
Its best to use the tried and tested method for security purposes. Remember you can customise any providers including role providers or even create your own unique providers.
Here is an example how to LDAP authentication using ASP.NET 1.1. The logic may still be applicable or can be adapted to later versions of ASP.NET, although I have not tested it.
Using the built-in membership providers, or implementing your own, is no guarantee that a hacker can't get access to your system. Things you'll have to consider:
encrypting data between client and server
don't store passwords in the database, not even encrypted. Hash each password its own salt, if you can.
enforce strong password entropy.
make sure session and authorization cookies are marked HttpOnly and Secure
for admin passwords, have a policy to change them frequently (like once a month)
provide means to notify administrators when someone signs in to their accounts
temporarily lock out ip address who exceeds number of requests per second and failed to authenticate
temporarily lock out users when they enter their password more then x (e.g. 10) number of times in an y number of minutes (e.g. 10).
These are just a handful of things to look for. You'll also have to concern yourself with session highjacking, javascript attacks and so forth.
Its not a trivial matter.
Writing a custom authentication handler is very dangerous. There are many ways to get it wrong and leave your website vulnerable to attack.
I also understand your complaint that Forms Authentication is extremely complicated. I was faced at a similar cross roads and decided to build my own authentication system called FSCAuth. It's BSD licensed. It's designed to be super simple and to allow for just about any database format you can image. All that must be done to set it up is implement a small 4 function interface into your database and populate a few configuration fields.

What is the best way to send custom ACS Claims across programs?

I've got two programs, a "login" program that uses the a foreign STS (Google, Facebook, etc.) to log the user in and returns the type of security access that user has. I then want to send that information off to a separate program that takes that security access and gives the user privileges based on that.
What is the best way to send that information across?
I've read some things about the Custom Authorization Manager Service, but I'm not sure if that is what I need here. Is it possible to just POST the security info across and the web.config turns that into a claim? Should I be making a new token and sending that?
I am hopelessly lost. If someone could provide a helpful tutorial somewhere on the web, that would be immensely appreciated (as my googling has only turned up long-winded articles that either do much more than I need or much less).
Specific code snippets would make my day.
Thanks!
EDIT: I am trying to avoid making the login system into an STS. But I am starting to feel I need to. Is there some halfway point between STS and relying party? Like a relying party that can generate its own claims?
You have several options:
The simplest one is the ClaimsAuthorizationManager, which might be what you're looking for. http://msdn.microsoft.com/en-us/library/ee748497.aspx The CAM is a step in the ASP.NET authentication pipeline that runs right after your application has validated the security token incoming from ACS. Here is where you define your custom authorization logic, and you can add additional claims to the IClaimsPrincipal that gets delivered to yor application. Instead of centralizing authorization logic in a service, you could for example implement your CAM in a library that's shared accross various relying party applications.
If your authorization rules are simple, i.e., you're not querying any external user attribute store, then one option would be to use ACS claims transformation rules to do this. Then your applications would consume the token issued by ACS directly. http://msdn.microsoft.com/en-us/library/gg185955.aspx
If however your architecture absolutely requires a separate login service that consumes tokens and populates new tokens with user attributes and such, then it will need to be an STS. Building your own STS can be tricky, but there are prefabricated STSes available to do this. If your applications live in an AD domain for example, ADFS 2.0 would be an ideal choice because of it's close integration with AD and ACS, and it's powerful claims transformation capabilities.

Categories