Switch to SQL membership provider from AD membership provider runtime - asp.net

In my asp.net application admin functionality, I am trying to combine AD authentication and form authorization for creating the users, roles and Assign users to roles etc. I have configured MembershipADProvider and AspNetSqlMembershipProvider in my web.config with MembershipADProvider as the default one. After user logs in using AD authentication, I need to switch/assign my membership object to use AspNetSqlMembershipProvider in order to get all the users from membership object (from dbo.aspnet_Users table). How do I switch the provider during run time? I have tried different approaches after searching for this issue and none of that seem to work for me so far.
Here are couple of approaches I tried:
1. foreach (MembershipProvider mp in Membership.Providers)
{
if (mp.Name == "MembershipADProvider")
{
Membership.Providers.Remove(MembershipADProvider");
MembershipUserCollection users = Membership.GetAllUsers();
ddlUsers.DataSource = users;
ddlUsers.DataBind();
break;
}
}
Membership.Providers.Remove(MembershipADProvider"); - doesn't work as it's not supported..
Also, tried to clear the Membership.Providers and then add only the type of AspNetSqlMembershipProvider which are also not supported.
I can't set Membership.Provider with value from
Membership.Providers["AspNetSqlMembershipProvider"] as Membership.Provider is a read only property.
I tried to swtich the connection string between 2 providers, which didn't swtich the provider, as both are different types of providers..if both were sqlserver providers this would have worked I believe.
Please let me know if anybody has successfully implemented or if at all this is a plausible approach. Thank You!

You would pass an explicit provider to your code, rather than taking a dependency on Memebership directly (which just wraps the one flagged as default in the config). There is no need to swap them in and out at runtime, think how this would affect thread safety.
So rather than saying Membership.GetAllUsers(); you would do something like (I don't have a compiler to hand):
public UserSerivce : IUserService
{
private MembershipProvider provider;
public UserService(MembershipProvider provider)
{
this.provider = provider;
}
public IEnumerable<MembershipUser> GetUsers()
{
return provider.GetAllUsers();
}
public void DoSomethingElseUseful()
{
...
}
}
And then to use it for a particular provider:
var service = new UserService(Membership.Providers["mySqlMembershipProvider"]);
var users = service.GetUsers();
Or if using AD specific code:
var service = new UserService(Membership.Providers["myADMembershipProvider"]);
var users = service.GetUsers();
Using DI in this way also helps keep code testable.

If all you need a list of users in the aspnet_Users table, just connect to your database with System.Data.SqlClient objects and query the table. There is no reason (that you mentioned) you need to use a membership provider to get that data.
Having said that, your membership/authentication scheme sounds like it may have some design issues, perhaps best tackled in a different question, but I think it might be useful to you if you sought comment on what you are trying to accomplish overall with the multiple membership providers.
Edit: I found some potentially useful posts on using multiple membership providers. It looks like the general idea is to implement custom code handling the Login.Authenticate event on your Login control, and use Membership.Providers["ProviderName"].ValidateUser to attempt authentication with each provider.
http://www.stevideter.com/2008/03/20/using-two-membership-providers-for-aspnet-logins/
http://forums.asp.net/p/1112089/1714276.aspx

Related

ASP.NET Identity - Steps for custom authentication

Envrionment: Visual Studio 2013, ASP.NET MVC 5
On the new MVC5-based project I will be working on, I need to use a custom database that stores usernames, passwords, and roles in its own way. I am searching the Internet to look for an example for custom authentication. Looks like the old-style "membership provider" classes have been replaced by the new "Identity" mechanism.
However, finding a good step-by-step example has proven to be futile. There are a few links (published this year) that talk about implementing custom IPrincipal and DbContext classes. Some other links talk about implementing IUserLoginStore and IUserPasswordStore. A few others hinted on implementing IUser, IUserStore interfaces.
Maybe the last option is what is needed. Can someone please guide me with the steps or point me to any link that has a simple example? Something like:
Implement MyUser based on IUser
Implement MyUserStore based on IUserStore
Modify web.config to use MyUserStore
Remove DefaultConnection from web.config as it is not required
Regards.
First, stop. Stop thinking about "custom authentication". You don't need custom authentication, you just need custom storage of authentication data.
ASP.NET Identity has abstracted out the storage mechanism of authentication from the process of authentication. There are several interfaces that follow the pattern IxxxStore.. Such as IUserStore, IRoleStore, etc...
You can find more information about this here, along with custom implementations for various databases which you can probably convert to your own needs.
http://odetocode.com/blogs/scott/archive/2014/01/20/implementing-asp-net-identity.aspx
As an example, here is a RavenDB implementation that uses all the various interfaces in a single class.
https://github.com/tugberkugurlu/AspNet.Identity.RavenDB/blob/master/src/AspNet.Identity.RavenDB/Stores/RavenUserStore.cs
However, all this assumes you really truly a need to store data totally differently. If you just need to store the data in different columns, then it may simply be as easy as overriding OnModelCreating in your IdentityContext and changing the names of the columns in use.
ad.1.
public class ApplicationUser :IUser
{
public string Id
{
get;
set;
}
public string UserName
{
get;
set;
}
}
ad.2.
public class MyStore : IUserStore<ApplicationUser>, IUserPasswordStore<ApplicationUser>, IUserSecurityStampStore<ApplicationUser>, IUserEmailStore<ApplicationUser>
{
... //implement all interfaces here
}
ad. 3.
Now you can create your applicationUserManagerService (you will need IdentityMessageService, and IDataProtectionProvider):
var applicationUserManagerService = new ApplicationUserManagerService(new MyStore(), emailService, dataProtectionProvider);
Try to use IoC and register your IUserStore (I did it this way - link below):
unityContainer.RegisterType<IUserStore<ApplicationUser>, MyStore>();
check also my answer here (i'm using int as UserId there):
AspIdentiy ApplicationUserManager is Static, how to extend so it participates in my IoC framework?

Custom fields in ASP.Net Login/Register?

I have to edit the Login/Registration that ASP provides to include a custom dropdown ("BranchID") menu that saves to the database so each user has its own Branch. I am using ASP Membership system, and of course it saves to the ASPNETMDF database it creates. Googling has net me some results but I am quite confused. I know there are "User Profiles", and I I can save this Profile data, but what I am not quite sure is if its a temporary measure or if it does record to the database.
I could make my own custom membership system, use the built it and adapt it or use the user profiles. What is the best course of action? I'd vastly prefer to adapt/edit the built in Membership system and add the data I require to it but I still don't haven't a clear answer to what I should do or what's best.
You have two choices:
Create a CustomMembershipProvider , and if you need to a CustomRoleProvider, you can do this by implementing .NET's MembershipProvider. Sample: http://www.codeproject.com/Articles/165159/Custom-Membership-Providers
Create a separate table that stores additional user information, i.e., "BranchID", and add a one-to-one relationship between your table and .NET's Membership
It's really up to you which one you choose.
MembershipProvider is pretty easy to extend. Assuming the branch is something they have to select to authenticate? You should be able to extend authenticate to do something like:
public class MyCustomMembershipProvider : MembershipProvider
{
/*
....
*/
public bool ValidateUser(string username, string password, string branch)
{
return (::ValidateUser(username, password) && MyCustomRoutine(username, branch));
}
}

ASP.NET MVC, Account Model : How to make relations to it?

I've created a new MVC 3 Internet Application, and it comes with the Account model/controller, etc.
Those are stored in a MDF database.
I'd like to create new models for my application, and make relations from these to my account model.
I did not find anything about it, maybe I looked for the wrong thing... So I was wondering, is there anybody who could point me in the right direction about how to do so?
Thanks!
Ah there in lies a problem with using the built in providers and aspnet default db.. In that database there is a unique id for each row - you in theory CAN use that to link to your databasse - but realize this is completely separate. One alternative many people do is to use a Custom Membership Provider (for example custom sql membership provider)
There are tons of articles/blogs out there on that - for starters see:
http://blogs.syrinx.com/blogs/dotnet/archive/2007/12/14/a-simple-custom-sql-membership-provider-part-1.aspx
This enables you to keep everything in your own database and its fairly easy to implement.
I found this as well:
https://github.com/anderly/SimpleMembership.Mvc3
I guess it's another alternative.
The answer I was looking for is exactly this:
In your model, link to the Membership User like this:
public virtual Guid UserGuid { get; set; }
public virtual MembershipUser User
{
get
{
return Membership.GetUser(UserGuid);
}
}

ASP.NET Provider with Different Types of Roles

I have different types of Roles to take into account when authorizing a user.
For example: John must have Position Manager and be part of the Office Supplies Department to order a new computer.
Problem with Roles is Roles.GetRolesForUser("John") can only return a string array.
Should I go with a custom roleProvider and custom roleManager?
or should I develop a custom ProfileManager to add methods like GetUsersWithProfileProperties()?
Any suggestion is welcome!
Thibaut
EDIT: the above example is simplified I could have a much as 4 types of roles which are 4 different collections.
EDIT: I found a very similar question
From what you write; I believe that everything you need is currently available out of the box:
// Return all Users in a Role
string[] users;
users = Roles.GetUsersInRole("RoleName");
// Return all Roles for a User
string[] roles;
roles = Roles.GetRolesForUser();
// Search through Membership store locating users with a role
MembershipUserCollection mu;
mu = Membership.GetAllUsers();
// Loop through all membership users looking for users in a role
foreach(MembershipUser m in mu){
if(Roles.IsUserInRole(m.UserName, "Role Name")){
// Do something
// We can even nest to x levels
if (Roles.IsUserInRole(m.UserName, "Another Role")){
// Do something else
}
}
}
Please clarify if I have misunderstood your question.
why not create a "CompositeRoleProvider" with a Path-To-Level typew convention for accessing each subordinate role provider. You will still have to create multiple role providers, but your Composite or Top-Level Provider does all of the work for you.
I plan to do a similar thing with ProfileProvider
I'm studying how to solve a pretty similar problem and I've come to a conclusion that the best thing to do is to implement a custom role provider.
I'm using this (http://msdn.microsoft.com/en-us/library/317sza4k(v=vs.100).aspx) as a base and I will implement my methods like (IsManager, GetDepartment, ecc).
Data will be stored in custom tables that are joined to the aspnet_users table.
Hope it may help someone in the future :)
I think there is a method GetUsersInRole.
http://msdn.microsoft.com/en-us/library/system.web.security.roles.getusersinrole.aspx

Which authentication and authorization schemes are you using - and why?

We're beginning to design a whole bunch of new services to create (WCF, ADO.NET Data Services, possibly in the cloud at some point) and one question that pops up is what authentication and authorization scheme to use - there are quite a few!
We basically need to be able to identify users (actual people, and "virtual" application/service users) on a wide variety of protocols - HTTP, HTTPS, TCP - and we need to assign them at least a bunch of roles / permission to see certain data and/or do certain operations.
We definitely can't use Windows group membership alone - we have plenty of external consumers of our services and we don't want to have to set up a domain account in our internal domain for everyone of them.
So there's mainly three options, I think:
Using the ASP.NET membership system - create users and assign roles there
Use AzMan (Authorization manager) which seems to be a more granular, more mature, more elaborate system (with users, tasks, groups - three levels, not just user + roles)
Roll our own
First of all - which of these three would you recommend? Any why?
Secondly - are there more options that I'm missing?
Thanks for any hints, pointers, opinions!
Marc
PS: seeing the answers so far, I'm amazed at the amount of folks voting for option #3. I would have thought that MS would be able to design something reusable that could handle all of these requirements....
Actually, the answer is probably a combination of 1 and 3.
You can take advantage of a lot of the tools and features that the framework provides for you by writing a membership, role or profile provider if the default options don't quite go as far as you'd like.
We've done just that on a number of client sites - for example one of our clients has most of their users stored as Commerce Server users, and use the Commerce Server profile system, so we wrote a membership and profile provider to talk to those datastores - a fairly simple excercise.
Most people are probably going for 3 because of the need to authenticate over raw TCP - this introduces a layer beyond that of the standard ASP.NET membership providers.
Most of what MS produce is "ok" or "good enough", but there will always be edge cases where you want to do something "not quite standard" that mean you end up rolling your own. I guess to have something beyond "Basic Auth" or "Windows Auth" that was simple for your average developer to understand, they took the sensible option of "lets just build this for the web".
If you take a look at the numerous ways you can authenticate against a WCF service, you'll see what I mean - these are designed to handle different transport mechanisms, and are therefore much more complex.
That said, the default roles and profile providers are fairly limited (roles: no hierarchy, so you need to check for each possible role, or explicitly assign each role to the user; profiles: all stored in one field as comma seperated values - not easy to find all users who've got a value set).
We use (3). Actually that helped us in an integration scenery to have accounts in sync with
business processes
Other systems (not all on the same technology stack (ASP.NET))
On a recent project we extended the ASP.NET membership provider (wrote a custom provider) with the intent of using some of the role based controls for managing permissions. Now that the project has matured sufficiently, we're finding that the controls are not flexible enough for our requirements, and to some extent we're regretting going down the MS membership path. Rolling your own authentication if you have the time to architect it correctly is going to be the best option.
It sounds like your app is a bit of a hybrid in that you're serving internal and external customers, but perhaps also give some consideration to integrating OpenID for your external customers. There are some great ASP.NET OpenID controls that really makes handling new accounts for external customers a no brainer. This of course depends on how 'public' your application is.
Ldap anyone? It's free, cross-plaftorm, easy to use and administer remotely, has bridges to other auth schemes, and bindings in more languages that you knew existed...
Isn't AZMan from 2003?
I would recommend 1 or 3. Personally I've always gone for 3. There's a lot of functionality that 1 has that I don't use or care to use.
I would stay away from AzMan. We went down that road once and didn't like the section of town we broke down in. We've always done AD-based logins that use the SID of the current user to link to a user in the database, then taken the permissions from there. Given your setup this may not be possible (or practical), but I'd stay away from AzMan in any event.
I'm not an ASP or .NET developer, but my gut says (3). You really don't want a public-use web-app to have any sort of access to your corporate network, much less be able to put auth credentials anywhere near AD.
You seem to provide too much and too extensible to stick to one technological solution
Solution 3.
I would base the whole application around a User class
You would just simply have to model it so that it will provide you with the needed flexibility and extensibility
Something like:
[ClassAttribute ( "Yordan Georgiev", "1.0.2", "20090302", "20090415" , false )]
public class User
{
#region DomainName
private string _DomainName;
public string DomainName
{
get { return _DomainName; }
set { _DomainName = value; }
} //eof property DomainName
#endregion DomainName
#region Status
private int _Status;
public int Status
{
get { return _Status; }
set { _Status = value; }
} //eof property Status
#endregion Status
#region Password
private string _Password = Resources.GV.Pass;
public string Password
{
get { return _Password; }
set {
_Password = GenApp.Utils.Security.Encryptor.Encrypt ( value,
GenApp.Conf.GenAppSettings.Instance.EncryptionAlgorithm );
//debug_Password = value; //unencrypted
}
} //eof property Password
#endregion Password
#region ListUserRoles
private List<UserRole> _ListUserRoles;
public List<UserRole> ListUserRoles { get { return _ListUserRoles; } set { _ListUserRoles = value; } }
#endregion ListUserRoles
#region UserSettings
private GenApp.Conf.UserSettings _UserSettings;
public GenApp.Conf.UserSettings UserSettings
{
get {
if (_UserSettings == null)
_UserSettings = (GenApp.Conf.UserSettings)GenApp.Conf.GenAppSettings.Instance;
return _UserSettings;
}
set { _UserSettings = value; }
} //eof property UserSettings
}

Resources