I was initially under the misconception that I could not use the current DNNMembershipProvider and I would have to create a whole new Authentication Provider and collect the credentials and pass them to my partner organization.
What I have figured out is that you CAN use the existing DNNMembership provider, but you have to create the user before the request gets to the DNNMembership provider using the information provided by ADFS.
Note: This method is a straight pass-through from ADFS to DNN. No measures are taken to authenticate the user or to check any of the inputs from ADFS.
As an aside, this method works not only with ADFS but also any other external 3rd-party Authentication method that sends user information in headers or cookies. Change the context_AuthenticateRequest method to suit your requirements.
Here are the pre-conditions to this article. I expect:
* Your partner organization has ADFS up and running
* You have your ADFS proxy up and running and it talks to the partner organization.
* ADFS Web Agent is installed on the server you are running.
Let’s get started.
What you have to do is create an HTTPModule that will intercept the AuthorizeRequest events before DNN does. An over-simplified definition of an HTTPModule is, it is a piece of code that runs before any page gets hit. You can listen for a lot of different events. For more information, click here.
To create the HTTPModule you will need to:
* Open Visual Studio and create a new class library.
* Create a new class and copy the code attached to this blog.
Add References to the following DLLs
* Compile the solution
* The DLL that is created will need to be placed in the bin directory of your website.
* Make changes to your web.config (explained in a later section).
I will walk through a bit of the code. Here is the first snippet of code. We start listening for the AuthenticateRequest event. All other events pass through untouched.
1 public void Init(HttpApplication context)
3 //Start listening for each authentication request
4 context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest);
Now, what do we do when this event is fired off? To shorten the namespace I added the statement
1 using SSO = System.Web.Security.SingleSignOn;
First off, we need to get the information that ADFS has sent us by casting the User.Identity into the ADFS object SingleSignOnIdentity.
1 public void context_AuthenticateRequest(object sender, EventArgs e)
3 HttpApplication app = (HttpApplication)sender;
4 //By the time the request gets to here, it should have been authenticated
5 //against ADFS.
6 SSO.SingleSignOnIdentity id = (SSO.SingleSignOnIdentity)app.User.Identity;
At this point you will have access to the user’s Identity and any claims coming from the ADFS server. You can access them through id.SecurityPropertyCollection. You can use them to populate the new user account. You can iterate through the claims with the following code
1 foreach(SecurityProperty sp in id.SecurityPropertyCollection)
Next, we check to see if the use already exists in the database by using the DNN API function GetUserByName. If it doesn’t, then the user is created by the standard DNN API function CreateUser and logged in. If the user does exist already then we log them in automatically. The user will automatically be added to the Registered Users and Subscribers security groups.
01 //'See if user exists in DNN Portal user DB
02 UserInfo objUserInfo = UserController.GetUserByName(currentPortal.PortalId, id.Name);
03 //' user does exist - try to create on the fly
04 if (objUserInfo == null)
06 objUserInfo = new UserInfo();
07 objUserInfo.DisplayName = id.Name;
08 objUserInfo.FirstName = id.Name;
09 objUserInfo.LastName = id.Name;
10 objUserInfo.Username = id.Name;
11 objUserInfo.Membership.Password = "AReallyStrongPassword";
12 objUserInfo.PortalID = currentPortal.PortalId;
13 objUserInfo.Email = id.Name;
14 UserCreateStatus objUserCreateStatus = UserController.CreateUser(ref objUserInfo);
15 //See if the user was added successfully
16 if (objUserCreateStatus == UserCreateStatus.Success)
18 //We have created them successfully, so let them into the site
23 //This will send the error to the error log, but the user will experience an infinite loop
24 throw new Exception("User not created successfully: " + objUserInfo.Username + "- " + objUserCreateStatus.ToString());
Here is the LetsLogUserIn function:
01 private void LetsLogUserIn(UserInfo objUserInfo)
05 //Get the current portal
06 PortalSettings currentPortal = PortalController.GetCurrentPortalSettings();
07 //set the language to the default language of the portal
09 //Log the user in
16 catch(Exception ex)
We need to make several changes to the web.config. First we need to make the changes necessary for ADFS and then we need to make changes for our HTTPModule.
The ADFS changes are the standard web.config changes you would do for any ADFS claims-aware site. You first need to add the section groups to your web.config.
Then you need to add the actual section. The
If you would like to have logging (and who doesn’t like loggingJ) you will need to add the following section at the end of your web.config