views:

763

answers:

4

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.

+3  A: 

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).

Amadiere
+2  A: 

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

TFD
I'm not really sure how this works. I get that I can authenticate people happily, but I'm not sure how all the roles would be manageable and maintainable. Maybe I'm missing something..?
Amadiere
Use Forms authentication, and then have an another table to hold the keys for the other authentication methods linked to a form auth login. e.g. OpenID, AD etc. And check those and do the FormsAuthentication.SetAuthCookieThe login page can have username/password, openID, xyz fields/buttons on it to support all the differtn methods of signing onSee http://stackoverflow.com/questions/1406021/asp-net-mvc-windows-authentication-question
TFD
+5  A: 

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

klausbyskov
Wow, I was just beginning to type my own answer with WIF as you posted this. I'm using a combination of SQL and Active Directory to authenticate my users using several different methods.WIF is cool though, because once your STS (logon page) is set up, it issues "tokens" to the users in the form of cookies. The tokens identify the users and specify strings of information (claims) about the users.The STS decouples authentication from your application's logic.The user's claims may be read programmatically, or you can use a special `ClaimsAuthorizationManager` class to manage access.
Rice Flour Cookies
WIF certainly seems to solve the problem from what I can tell, but can't quite scope out it's pricing. There was no apparent mention of cost (http://msdn.microsoft.com/en-us/security/aa570351.aspx), but they elude to it being available for download for me to evaluate. If not free (or available with the not-most-recent AD server - I may have some issues. However, still an extremely good answer, so +1
Amadiere
@Amadiere WIF is going to be released together with the .net framework when 4.0 is released in april this year, and it is of course free. It's already available for download, and I use it on a daily basis and have found no issues with it whatsoever.
klausbyskov
@Amadiere you can download it from here: http://msdn.microsoft.com/en-us/evalcenter/dd440951.aspx
klausbyskov
Cool - spotted the download, but the wording was misleading. But this is good enough news for me. Thanks for the answer. :)
Amadiere
A: 

I hope I'm not hjacking this thread? but I can't figure out where to comment on one of the answers?

But I was wondering if anyone ever figured out how to have separate authentication from authorization?

Like the initial question, I want to have my ADFS server authenticate the users, however, I want my application to authorize them by doing a DB look up and then storing their roles to the session object or cookie? However, I don't know how to manually set the user's role?

I've tried: HttpContext.User = new System.Security.Principal.GenericPrincipal(User.Identity, roleName);

but when I hit a controller with [authorize(Roles="Admin")], it always fails authorization. Debugging shows that the "User" object doesn't save the rolename and hence it always authenticates to false for User.IsInRole("Admin"). Does someone know how to save the rolename to the "User" object so that User.IsInRole("Admin") will evaluate to true?

TriFu