ASP.NET 2.0 Security, Membership and Roles Tutorials

Scott Mitchell recently published part 5 of his nice series on using the new ASP.NET 2.0 Membership and Roles features.  You can read the series here:

-- Part 1 - Learn about how the membership features make providing user accounts on your website a breeze. This article covers the basics of membership, including why it is needed, along with a look at the SqlMembershipProvider and the security Web controls.

-- Part 2 - Learn how to create roles and assign users to roles. This article shows how to setup roles, using role-based authorization, and displaying output on a page depending upon the visitor's roles.

-- Part 3 - See how to add the membership-related schemas to an existing database using the ASP.NET SQL Server Registration Tool (aspnet_regsql.exe).

-- Part 4 - Improve the login experience by showing more informative messages for users who log on with invalid credentials; also, see how to keep a log of invalid login attempts.

-- Part 5 - Learn how to customize the Login control. Adjust its appearance using properties and templates; customize the authentication logic to include a CAPTCHA.

The Microsoft Patterns and Practices Group also recently released a reference sample application that shows best practices on how to implement Internet based security with ASP.NET 2.0.  You can download the sample and associated documentation here.

For other great resources on ASP.NET 2.0 Security, please check out this ASP.NET Security Resources link that I regularly update with links to tutorials, how-to articles, and books.  I also highly recommend buying Stefan Shackow's ASP.NET Security, Membership and Role Management book:

Stefan works on the ASP.NET team and drove much of the design for the ASP.NET 2.0 Security features.  His book does an awesome job of diving into how to maximize them.  It is one of the books I pull down from my bookshelf to regularly consult when answering questions on the forums, and it contains a wealth of knowledge to leverage.

Hope this helps,

Scott

 

56 Comments

  • ScottGru,

    Your posts on Security, Membership, Roles, etc. have been incredibly helpful.

    I have two questions:

    1.  I'm curious why MS never added controls to change email addresses or security questions and answers.

    2.  I have an old ASP application with a database with 1800 registrations and a clear password.  I'd like to convert it to .NET 2.0 and use the builtin systems.  Do you know of any links that discuss this topic or do you have any advice?  From my perspective it seems that the passwordSalt is the biggest problem.

    Steve  

  • Posted some comments and questions this morning...what happened to it?

  • Hi Barry,

    I'm not really sure what is causing that. Is your web-site using the built-in web-server or IIS?

    Thanks,

    Scott

  • Hi Steve,

    Sorry for the delay in your comment showing up. Unfortunately due to (a lot of) spam I usually approve each comment before it shows up, and I sometimes only get to them in the evening. To answer your questions above:

    1) Unfortunately we didn't have time to build those controls in ASP.NET 2.0 -- which is why they aren't built into the box. However, you can get the functionality by creating your own UI that uses the Membership API directly. It provides all the functionality you are after.

    2) The built-in membership system supports a configuration property that allows you to store the passwords either in cleartext or hash-encoded. For security reasons we recommend (and set the default) to be hash encoded -- but if you change it to cleartext you can store passwords that way.

    Probably the easiest way to re-use the membership system might be to write a "migration.aspx" page that loops over all of the usernames/passwords from your old database, and then calls Membership.CreateUser() -- passing the appropriate values. This will then provision your database with all the same username/passwords. You can then choose whether to hash the password or keep it cleartext.

    Hope this helps,

    Scott

  • Hi Balaji,

    Yep -- you can configure multiple provides for your web-site. You can access a specific provider via the "Providers" collection on the Membership object like so:

    if (Membership.Providers["myprovider"].ValidateUser("scott", "test")) {
    // validate with second configured provider
    }

    Hope this helps,

    Scott

  • I wanted to implement a way for a user to get their userid for an email address, which is easy enough to do, but I also wanted them to provide the answer to their security question. There doesn't seem to be a way to validate ore get the answer from the default membership provider. I thought about Hijacking the PasswordRecovery control and labeling the UserName field Email, then behind the scenes i would look up the user by email asign the UserName input the real username value and go to the next step, which is verify the question. It all works, except that it changes the password, which i dont want.

    Is there any way to provide this type of funtionality, short of writing my own provider?

    Craig

  • I read the part about defining a provider at runtime, but I also need a way of defining a connectionstring at runtime also, is this not supported ? It seems the microsoft intends that all connection strings be defined in the element of the config file, is there any other options ? I want to store my connection strings somewhere else, such as properties of a custom class.

  • Hi Joe,

    I believe there is a way to configure the connectionstring dynamically at app startup. The connection properties are cached -- so you wouldn't want to try and change this on a per-request basis.

    If you wanted to-do that, you would probably need to build your own custom provider which could internalize that logic.

    Hope this helps,

    Scott

  • Hi Andrew,

    Are you looking to store the extra parameter being used? Or simply using it as part of the authentication process?

    If the Login control doesn't work well for your scenario, you can always drop-down and use the Membership APIs directly. This allows you to have whatever HTML UI you want (with whatever fields you need) to login.

    This article walksthrough how to use the Membership APIs directly: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/paght000014.asp

    Hope this helps,

    Scott

  • Hi Craig,

    Have you looked at using the Membership API directly to accomplish this? I believe you should be able to implement the password recovery scheme you describe above using that API directly.

    Thanks,

    Scott

  • Hi Scott,

    The 3rd parameter would need to be stored as it's used to determine the connection string needed (each department has their own membership database).

    I wrote a custom membership provider to give me the correct functionality but am having trouble using it.

    If I use the normal Login control, I have this code:

    protected void Login1_Authenticate(object sender, AuthenticatedEventArgs e)
    {
    e.Authenticated = Membership.ValidateUser(Login1.UserName, Login1.Password);
    }

    That works fine, and I know it uses the overridden ValidateUser in my custom
    provider as it hits the breakpoint there, but what I really want it to say
    is:

    protected void Login1_Authenticate(object sender, AuthenticatedEventArgs e)
    {
    e.Authenticated = MyMembership.ValidateUser(Login1.UserName, Login1.Password, Login1.Deparment);
    }

    But that generates an error. MyMembership doesn't exist in the current context. OK, so lets change it to Membership then... Another error. The Login control does not contain a definition for Department. OK, so I replace Login1.Department with "test" and try again. This time I get a No overload for ValidateUser takes 3 arguments. Drop the 3rd argument and I'm back to the working 2 parameter version.

    It's probably very simple, but even google doesn't find an appropriate example.

  • Hi Andrew,

    To access your specific Membership Provider implementation, you should be able to write this:

    MyMembership customMembership;

    customMembership = (MyMembership) Membership.Provider;

    customMembership.CustomValidateMethod(anyarg);

    Hope this helps,

    Scott

  • Yes!

    Your comment, plus the example included with the online help for the Login class has enabled me to create a custom Login control with 3 parameters, and a custom MembershipProvider that takes those 3 parameters.

    Thank you for your help Scott. Very much appreciated.

  • Thanks for the great set of articles on your blog : your blog has been a priceless resource for me

    The site I’m working on currently has some restricted content available only for subscribers. Subscribing to the site requires to do the following on registration

    user information submission
    online payment using credit card

    I’m planning to use ASP.NET 2.0 Membership, Roles and Profile approach for this site.

    But I don’t have a clear idea of how I’m going to insert the online payment part into the CreatwUser Wizard steps

    The payment system I’m connecting does not allow me to have the payment part on my application. I have to redirect my subscribers to their server and accept him on returning once the payment is complete.

    The registration process should not be considered over till I get the status code on return path as using this status code only I can verify whether the payment was successful or not

    If the payment is done successfully I should create the user otherwise I shouldn’t

    Do I have to write my own providers for this or can I get away with tweaking the default providers available with ASP.NET ?

    Thanks Again

  • Hi Dushan,

    Unfortunately I don't have too much experience with payment support. However, Rich Strahl has written up a great article here that you might want to take a look at: http://www.west-wind.com/presentations/aspnetecommerce/aspnetecommerce.asp

    Hope this helps,

    Scott

  • Thanks for the prompt reply and pointer to West-Wind…I can further simplify my requirement


    I want to redirect my visitor to an application running on another server (the bank’s IPG server) . He will do some form filling there and at the end of that process he will be redirected back to my application again. He will be taking 3-4 parameters from my site to that application and brining back 2 parameters to my site on his way back..


    So basically what I want to know whether I can insert this redirecting and coming back step in between the steps of ASP.NET 2. 0 CreateUser Wizards


    What is happening at the banks end is not going to affect my application. I’m supposed to sent some parameters ( transaction ID, amount, merchant ID ) to them and collect a few from them to check the status of the payment ( success/fail and reason for failure if failed, invoice number)

    hope everything is clear for you now...

  • Hi Scott,

    This article is very timely for one of my latest projects. Thanks for the valuable info.

    I have a question about interacting with LDAP or Active Directory. I'm creating an ASP.NET application to be installed on my customer's servers. I need to be able to authenticate against their Active Directory or LDAP in my login logic and store the user name and roles to identify their view/update security levels. Would a provider be useful in this case, or is a more customized method necessary?

    Taking it one step further, I'm trying to find a way to set it up so they can pass their own login credentials to my application so they can utilize a single signon feature of their intranet, if they have one. I'm not sure where to start on that idea.

    I appreciate any ideas you may have.

    Thanks!
    Drew

  • Hi Drew,

    The good news is that we actually have a built-in Active Directory provider that you can use for Forms Authentication in ASP.NET. This article describes more how to use it: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/paght000026.asp

    Hope this helps,

    Scott

  • Can I use multiple role providers and switch between them programmaticlly. So for example I have Staff users which can log in using the StaffMembershipProvider but it the users credentials do not match then it will check our Affiliates membership provider (AffiliateMembershipProvider).

    I have managed to authenticate (after reading your post to Balaji.) first the staff members and if that fails then the affiliate. This works fine and all the credentials are correct.

    The problem is with the Role provider which is defaulted to the StaffRoleProvider and needs to be set to the AffiliateRoleProvider

    Do you have any idea on how to switch Role provider during runtime?

  • I need to have two membership providers to login user from two different domains. One domain is for staging environment and could be pulled off the network completely. The login page contains a drop down to allow user to pick the domain and the domain name will be used to select the provider as Membership.Providers[domainName]. With both domain controllers online, all went well. While staging server is offline, trying to login to still online domain fails. It seems like Membership.Providers[myStillOnlineDomain] needs to instantiate all providers before returning anything. Since one of the domain controller is down, the connection will fail and the providers collection won't be available due to connection exception.

    Is it possible to skip the inaccessible membership provider and just loop through the online ones to validate the login? Please advise …

    Thanks a lot.

  • Dear all,

    how can i use Oracle database to build membership security tables ?
    shall i SQL securtiy tables through using aspnet_regsql to my Oracle database,and then use it directly using the membership classes ?

    if there's something else ? let me know ?

  • What is the best strategy using the provider model to administratively change a password?

    The ChangePassword method seems to require both old and new passwords. But, old password usually isn't known to a help desk technician trying to resolve a lockout problem.

  • Hi Tom,

    One trick you can use is to register two providers for Membership -- one for the login controls and other code that you use for end-users to the site. This would require the old password to change existing passwords.

    You can then register a separate "admin" provider -- either in the same application, or possibly in a special "admin" app that you build that is only for admins. With this provider you can configure it so that the old password is not required. You can then use this provider to change the password.

    Hope this helps,

    Scott

  • Hi there!

    I am trying to use Membership and Role Providers for my web site. The problem is: i authenticate using 2 parameters: a username and an account number.

    So, for the login, what i did was using my own login interface, and then, when the user is authenticated, i do:

    FormsAuthentication.RedirectFromLoginPage(textBoxUser.Text, false);

    Ok, so far so good. But then i looked at the other methods of Membership and Role Providers, and again they all use only the username to identify the user, so i would have to rewrite all those methods, and call them from my interface.


    My question is: is it worth doing this? I mean, maybe the great advantages in using this model are not being explored doing things this way...

    For example, if i wanted to use my custom Membership and Role providers in another site, i wouldn't be able to do that just changing in Web.Config the name of the providers; also if i wanted to change my application to use the default Membership/Role Providers, i would also have to write code, for the pages to call the default methods...

  • Hi Adam,

    I'd recommend using the Profile API to store additional user data. To use the email address of the user as the username, just enter this as the username and you should be good to go. You could also then optionally take the same value and pass it as the email property for the newly created user as well.

    Hope this helps,

    Scott

  • Hi Scott,
    I just went through your whole article. Thanks for writing great one. I still have a question after reading it.

    Q: I have a Native ASP web application which I'm trying to convert into ASP.NET 2.0. This application has registration module which registers users after several approval flow into SQL 2000 DB. Currently we have 9K users registered. I do not want to change registration module. But I want to convert rest of the application into .net (login,logout,displaying CRM data etc.)

    Is it possible to use ASP.NET Memberships with my existing user table? My first impression is no unless I migrate all the users into Membership.createuser() which I do not wish to do. I want to keep registration module in Native ASP as is.

    Please advice.
    Sarika

  • Hi Sarika,

    You could build a membership provider for .NET that points to the same database table schema that you are using today. This would then allow you to build new pages using .NET, but keep the old ones exactly the same.

    This article describes how to build a custom membership provider if you want: http://www.devx.com/asp/Article/29256

    Hope this helps,

    Scott

  • I have implemented custom AuthProvider in MOSS 2007 by implementing custom http Module and our custom Membership provider.

    Problem Case:
    With custom Membership Provider for LDAP, we are able to fetch specific mail group from LDAP Directory and we can add that mail group to that specific sharepoint site collection.

    Now let say one user who is not added to that specific share point site collection. But that user is part of email group which we have added in above step. Now if this user will try to access that site collection’s URL then he should get access of it.

    But currently he is getting access denied message screen.

  • Hi Scott,

    This is a great article. I am having one problem with membership -- when I create a username with a space in it -- I do not get an error, the website acts like the user is created -- but the user is not created in the database. Have you or anyone else seen this behavior?

    Thanks

  • Hi John,

    Can you send me an email with details about the username with the space? I will then loop some folks in from my team to help comment on it.

    Thanks,

    Scott

  • Hi Hrao,

    Can you send me email on this issue? I will then loop a few folks in from the SharePoint team to see if they can help.

    Thanks,

    Scott

  • Hi Scott,
    I am trying to create a login in for my users that is not using the login control. I just put a couple of text boxes and a button on my page. Then in the code behind I am trying to log the person in. I have:

    protected void LoginButton_Click(object _ sender, EventArgs e)
    {
    bool Authenticated = false;

    Authenticated = Membership.ValidateUser_(username.Text, password.Text);
    }

    but Authenticated always comes back as "false". Am I doing this right?

    p.s. The only reason I'm not using the Login control is because it always creates a table! I use Divs.

    Thanks,
    Michael.

  • Hi Scott,
    Is it possible to use ActiveDirectoryMembershipProvider and SqlRoleProvider together? That's to say, use FormsAuthentication against AD, but roles information are maintained in database.

  • Hi Xiaofeng,

    Yep -- you can definitely do this. You can mix and match Roles and Membership providers anyway you want.

    Hope this helps,

    Scott

  • I know that the has been covered here, but I am trying to find a way to set the default provider at runtime, so that i can use a production database in the production environment.

    basically i want to aslways use the proper DB for the enviroment so i want to set something up in Application_Start() to switch the fault provider.

    Is this possible?

  • I have a question that I cannot seem to find the answer to.

    I have been able to use the login control to programatically connect to an existing users table in a sql server database without any problem. I used the Login control's Authenticate event.

    In order for me to take advantage of the membership class, do I need to create the users after I retrieve the user info from my custom database?

    What I am trying to accomplish is to secure the subsequent pages the user sees when he/she logs in. I.e., If ValidateUser(xxx) is True, then Let Them Do What they Want...

    I feel like I am missing some piece of the puzzle.

    Thanks!

    Bonnie

  • Hi Bonnie,

    One approach you could take would be to add your own Membership Provider to your site. This example shows how: http://weblogs.asp.net/scottgu/archive/2006/10/13/Tip_2F00_Trick_3A00_-Source_2F00_Documentation-for-Simple-ASP.NET-2.0-SQL-Providers-Published.aspx

    Once you do this, then the Membership API and Login controls will just work for you.

    Thanks,

    Scott

  • Hi,

    I am using Custom Membership Provider of .net 2.0 with MOSS 2007.
    I am able to fill MembershipUser Class, but I want to add some more custom properties to this MembershipUser class which I am currently returning with GetUser Method of Membership Provider.

    To achieve this I have tried to make my own custom MembershipUser Class (by Inheriting Original MembershipUser Class).
    In this class I have added some of extra properties like,
    Account, LoginName, FirstName. etc… I am filling and returning this class in GetUser method to get all my custom properties with specific Member.

    But when I am seeing MOSS 2007’s Add User dialog box OR I am adding any member in specific site…I am not finding this properties value except some of basic properties of MembershipUser base class (name, email)…

    Can some one help me on this issue….Or any other knowledgebase article on Customizing MembershipUser class for MOSS 2007 will be great help,

    Thanks in advance.

    Himanshu Rao

  • Scott,

    In my application, there are two login screens. I am able to use custom membership provider which i created for one login page. However for second login page i want to use SqlMembership Provider.

    I tried by setting property MembershipProvider="SqlProvider" for second login page. Still its taking custom membership provider (which is default provider). If I set default provider as SqlProvider, the first login screen also takes SqlProvider.

    I can't really understand why this is happenning.

    Thanks,
    Prasanna
    prasanna.hiremath@fadv.com

  • Hi Prasanna,

    What you'll want to-do is to register multiple membership providers in your web.config file. As part of this you can then register which is your "default" provider.

    You can then reference a non-default provider by writing code like this:

    Membership.Providers["OtherProvider"].CreateUser()

    where "OtherProvider" is the string you specified in your element when registering the provider in the web.config file.

    Hope this helps,

    Scott

  • Hi Prasanna,

    Are you sure you have your type declared correctly? I suspect either you have a spelling error in the name of the provider (does the string in the Providers collection above exactly match that of the one in web.config?), or it might be that the provider type is not of type CustomMemProvider.

    The Login control uses the above API directly - so if it is working there it should be working via code too.

    Thanks,

    Scott

  • Hi Scott,
    I have membership working fine (so far) in the site I'm developing, but I want to set up a mock MembershipProvider in my unit tests for the classes that use Membership.

    I've created a MockMembershipProvider class, but I haven't found any way to set it as the default provider.

    I read above that I can access it by
    Membership.Providers["myMockProvider"].CreateUser(). I think I could make this work by creating a variable for the provider name:

    //In the fixture SetUp
    string myProviderName = "MockMembershipProvider";
    Membership.Providers.Add(new MockMembershipProvider());

    //In the code being tested:
    Membership.Providers[myProviderName].CreateUser()

    However, then I'd need to set myProviderName in the application somehow, and I'd lose the simplicity of simply calling Membership.CreateUser().

    I'd rather write something in the test fixture SetUp to set the default provider. Is this possible?

    thanks,
    Scott

  • Hi Scott,

    That is a good question. Any chance you could send it to me via email (scottgu@microsoft.com)? I don't know the answer for certain, and would like to loop in a few additional folks on my team to help comment.

    Thanks,

    Scott

  • I am having a bit of trouble configuring and using multiple Membership and Role providers.

    My assumptions:

    A MembershipProvider stores a set of users - the username is unique. By configuring more than one MembershipProvider I can have users from different sources. By configuring two providers it is possible that the same username is used in different providers - identifying different users.

    A RoleProvider stores a set of users with a set of roles, username and rolename are both unique. By configuring more than one RoleProvider I can have different sets of users within the site.

    Suppose I have a site with MembershipProvider 1 and 2 (MP1 & MP2) and RoleProvider 1 and 2 (RP1 & RP2). The members in MP1 have roles assigned in RP1 and the members in MP2 have roles in RP2. The same username exists in both MP1 and MP2 identifying different members.

    My site contains 2 logon controls - one for MP1 and one for MP2. The login for each works correctly.

    However it would appear that only the username is stored and it is impossible to tell what provider a given member actually logged in to. This then means I cannot get the right set of roles for a user.

    Have I got something wrong, if not how do I solve the problem?

    Thanks

    Ian

  • Hi Ian,

    A username needs to be unique in each provider. If you configure two membershipproviders to point to two different data stores, then in theory you could have two different users with the same username. In general I'd recommend against this if possible.

    One way to avoid it would be to append a store name before the username. For example: membership1/scottgu vs. membership2/scottgu or some other scheme.

    Alternatively when you log someone in could set the membershipprovidername in the "userdata" property of the FormsAuthenticationTicket that gets sent back to represent the cookie for the logged in user. This is encrypted, and would then allow you to check on the server which provider they came from.

    Hope this helps,

    Scott

  • Hi Scott,

    Thanks for your help.

    Ian

  • Hi Scott,

    I've setup a web site using the membership and roles. However, when I publish the db and site to production I don't have any users setup (clean db and ran aspnet_regsql). In development, I created users and roles using the ASP.NET Web Admin Tool. Obviously this tool cannot be run on a production server. I have an admin section on my web site to create and manage users, but I can't even log in to use it because no users exist initially. Is there an easy way of setting up a simple user in a role? Maybe I have to write an sql script that will create a user and a role then assign the user to the role?

    Thanks for any advice....

  • Hi Rino,

    You can use this blog post here to learn how to create a .SQL script for the contents of your membership and role database: http://weblogs.asp.net/scottgu/archive/2007/01/11/tip-trick-how-to-upload-a-sql-file-to-a-hoster-and-execute-it-to-deploy-a-sql-database.aspx

    Hope this helps,

    Scott

  • Hi Scott,

    I am trying to implement my own Custom Membership provider. In this I need to use a connection string for my database which i need to be able to configure from the web.config file in the application. So, When I am building the Provider, how do I access the connection string which is supposed to be present in the connection strings part of the site's web.config file?

  • Hi Scott,

    I am having almost the same issue Ian had on August 02, 2006.

    I have an application that needs to work with two sets of providers ( but not simultaneously). We have two sets of custom providers: Membership and Role providers using LDAP and using our own data store.

    If our customers have LDAP available, we need to switch to the LDAP providers. If they don't have LDAP, we provide our own data storage, with our own providers.

    At application start, I know if LDAP is enabled or not. How can I do to set the Providers to the correct values?

    I know I could go manually, open the web.config file, and change the defaultProvider attribute, but I am trying to do that dynamically.

    Thanks

  • Hi Luisetxe,

    What might be easiest to-do would be to create a third custom provider that wraps the two you already have. You could then dynamically call out to the appropriate provider based on whatever logic you want to pick between the two.

    Does that make sense?

    Thanks,

    Scott

  • hi scott,

    i am trying to use the membership sored procedures for creating a new member in an sql database via a back office procedure.

    the passwordformat is set to hashed in the web.config file.

    i created a password salt using:-

    Private Function CreateSalt(ByVal size As Integer) As String


    ' Generate a cryptographic random number using the cryptographic
    'service provider
    Dim rng As New System.Security.Cryptography.RNGCryptoServiceProvider
    Dim buff(size) As Byte
    rng.GetBytes(buff)
    'Return a Base64 string representation of the random number
    Return Convert.ToBase64String(buff)


    End Function


    and encrypted the password with th following:-
    Private Function encryptHashWithSalt(ByVal pwd As String, ByVal salt As String)

    Dim saltAndPwd As String = String.Concat(salt, pwd)
    Dim hashedPwd As String = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPwd, "sha1")
    Return hashedPwd

    End Function


    these values are then passed into the membershipcreateuser store procedure. the data is stored correctly in the db but does not validate via the login control.

    could you shed some light on the salting and hashing used by the create user wizard and login control as that works fine but my own does not.

  • Hi Scott -

    I'm trying to use the login/membership controls against novell eDirectory, which requires an authenticated bind. The MOSS2007 LDAP provider does everything I want *except* provide a way to authenticate to the LDAP server. Is there an easy way to extend the ldap provider to provide that without having to essentially re-write the entire provider?

    thanks!
    Eric

  • Hi Eric,

    I'm not 100% sure - but if you send me an email I can check with the MOSS team to see.

    Thanks,

    Scott

  • Hey Scott,

    first of all thanks for your tutorials, really helps me out a lot.

    My question is, for different type of users (different profile specifications), should i use multiple membershipproviders? or is it better to work with a single membershipprovider and use profile property groups to distinct the different usertypes?

    grtz

    Jack

  • Hi Jack,

    I'd probably recommend using a single MembershipProvider, and not try to automatically switch providers based on their profile group. Doing it this way will probably complicate your app considerably.

    Hope this helps!

    Scott

Comments have been disabled for this content.