Writing your First Custom Authorization Provider

Intro

There are several people who are experts in the area of Custom Authorization Providers in MOSS. I want to thank each one of them who have helped me over the last year on my authorization provider. First and foremost I would like to thank Steve Peschka in relation to the base structure and more recently Mitch Prince both from MSFT. What I would like to demonstrate in this post is writing a brand new Custom Authentication Provider for MOSS for the beginner. I will make mention that in a different Post I will be addressing Site Minder integration with the custom provider, however, what you need to know here is that this provider will work regardless.

I will be utilizing a basic SQL table structure although you will see that it is not necessary, however, for simplicity sake, I figure it will be the easiest to demonstrate.

Creating the Data Structure

The first thing we are going to do is just set up some simple tables that we are going to store our users and roles (groups) in.

CREATE TABLE dbo.spUser(

    username VARCHAR (50) NOT NULL,

    email VARCHAR (200) NOT NULL,

)

   

GO

   

CREATE TABLE dbo.spRole(

    spRole VARCHAR (200) NOT NULL

)

   

GO

   

CREATE TABLE dbo.spRole_spUser(

    username VARCHAR (50) NOT NULL,

    spRole VARCHAR (200) NOT NULL,

)

   

Normally, you would add identities, primary keys, foreign keys with relationships etcetera but you get the point. We have a table to store users a table to store roles and an association between the two. Once again, this could be whatever data store you wish and have whatever other attributes like telephone number, password, hair color….

Understanding the Methods (Membership)

Now that we have the base data structure we are going to open up .NET and build our role Provider. In this case, I will be hooking each critical method up to a SQL Stored Procedure simply because I am more comfortable with this approach.

The first thing we will do is have an understanding of the methods and what they are used for. I will be only going over the necessary overloads that you must implement and correctly write for your provider to work. There will be several other properties and methods that you must override, but we will simply throw an exception on these.

public override void Initialize(string name, NameValueCollection config)

   

Initialize simply will set the properties of the provider. Usually these properties are set in the web.config and read in as a NameValueCollection.

public override bool ValidateUser(string name, string password)

The Validate User method simply takes in a user name and password and returns true or false based on your credential cache. Here is where you would authenticate. Your login page then would check this method first and based on the result do something.

public override MembershipUser GetUser(object userId, bool userIsOnline)

 This Overload of the Get User method will simply return a Membership User object based on an object. The way that I normally implement this is to actually take the ID, and pass to the other Get User Method as a .ToString(). This way there is only one code base.

public override MembershipUser GetUser(string name, bool userIsOnline)

   

Here we will be getting the Membership User based on name. Use intellisense on the new MembershipUser(

public override string GetUserNameByEmail(string email)

I have searched and searched but cannot find where this method is actually called, however, easy enough to implement and so just get the string that you would pass to the GetUser method based on the email passed in.

public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)

This method is called on the people picker and will be hit when searching for a person. Simply pass in the email and set the totalRecords (you can do this with your MembershipCollection.Count property and you are good to go.

public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)

This method is also hit as part of the people picker. It is the most important people picker method in my opinion and you can write your own wildcard characters. So something like:

SELECT username, Email FROM spUser WHERE UserName LIKE %userNameToMatch%

   

The following methods we will not implement even though "must override" is on. We will set Booleans to false or throw not implemented exceptions here.

public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)

public override bool DeleteUser(string name, bool deleteAllRelatedData)

public override int GetNumberOfUsersOnline()

public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)

public override bool ChangePasswordQuestionAndAnswer(string name, string password, string newPwdQuestion, string newPwdAnswer)

public override string GetPassword(string name, string answer)

public override bool ChangePassword(string name, string oldPwd, string newPwd)

public override string ResetPassword(string name, string answer)

public override void UpdateUser(MembershipUser user)

public override bool UnlockUser(string userName)

public override bool EnablePasswordRetrieval

public override bool EnablePasswordReset

public override bool RequiresQuestionAndAnswer

public override string ApplicationName

public override int MaxInvalidPasswordAttempts

public override int PasswordAttemptWindow

public override bool RequiresUniqueEmail

public override MembershipPasswordFormat PasswordFormat

public override int MinRequiredPasswordLength

public override int MinRequiredNonAlphanumericCharacters

public override string PasswordStrengthRegularExpression