Custom Sign In and Sign Out page

It’s been awhile since my last blog post. It’s been awhile that I have been developing SharePoint solutions. Lately I had to write a functional design for a new project, so I used Word and Balsamiq very often… But, good times are here again!

The problem

One of my customers has implemented an F5 Firewall and that firewall does the authentication for all user’s that access SharePoint sites. For some user’s RSA code authorization is in place. Once authentication is done by the F5 Firewall, a session is created and the user is redirected to the SharePoint site. If the SharePoint site is set up for Claims and Forms Based Authentication, the default sign in page is shown with the annoying drop down for choosing the authentication provider. A second login was required.

The request

The customer did not want users to login twice. This should be done automatically. The web application has been set up for FBA and Windows Authentication, since both employees and external users (such as customers) need to login using the same url.

The solution

I have analyzed how the F5 firewall was configured, what features it has and how authenticated credentials are passed on to SharePoint. Basically there were 2 options: NTLM and Forms. If the corporate employee is authenticated against their ActiveDirectory the credentials are passed with NTLM. If an external user is authenticated against Lightweight Directory Services (LDS), the credentials are passed with Forms.

I started to build a solution with a custom login page.The login page could be set in the Web Application’s Authentication Provider setting.

WebAppSettings

The default login page has a control to show a dropdown with multiple authentication providers. If the Forms Authentication option is selected, the user is redirected to a second login page for entering username and password.

The _login/default.aspx page with the dropdown:

DefaultSignInSelector

This file is located in the [SharePoint Root]/Template/IdentityModel/Login. Analyzing this ASPX file you’ll notice the page is inherited from Microsoft.SharePoint.IdentityModel.Pages.MultiLogonPage and it contains a line of code with:

<SharepointIdentity:LogonSelector ID=”ClaimsLogonSelector” runat=”server” />

When choosing Forms Authentication in the LogonSelector, the user is redirected to _forms/default.aspx for entering his credentials:

DefaultSignInForms

This file is located in the [SharePoint Root]/Template/IdentityModel/Forms. This page is inherited from Microsoft.SharePoint.IdentityModel.Pages.FormsSignInPage   This page contains a Login control:

<asp:login id=”signInControl” .. >

Exploring the all code behinds with .NET Reflector or ILSpy you’ll be understanding what happens. Basically the process is as follows:

  

  • Load _login/default.aspx
  • Select Forms Authentication
  • Redirect to _forms/default.aspx
  • Enter user credentials  
  • Get SecurityToken For Forms Authentication
  • Establish Session with Token
  • Redirect to Success Url (requested site by user)
  •     

So, to login automatically I had to combine these two pages and their functionality. I created a new Visual Studio solution and created a new login.aspx that I deploy to the SharePoint Root somewhere.

LoginAspx

In the code behind, the Page_load method will have all the code needed. First of all, the retrieve the Request information. If the F5 authenticated a Windows user, the credentials are passed with the NTLM protocol, otherwise the (external) user is authenticated with Forms and the credentials are passed as Forms.

HttpRequest request = HttpContext.Current.Request;
 
bool isWindowsAuth = false;
string username = request["username"];
string password = request["password"];
 
// If no username is provided by F5, it'll probably be Windows Authentication (NTLMv2 protocol)
if (String.IsNullOrEmpty(username))
{
    isWindowsAuth = true;
}

Then you can use the SPIisSettings class to communicate with the different kinds of AuthenticationProviders.

SPIisSettings iisSettings = SPContext.Current.Site.WebApplication.IisSettings[SPUrlZone.Default];
 
if (isWindowsAuth)
{
     // Windows Authentication it is
 
    if (null != iisSettings && iisSettings.UseWindowsClaimsAuthenticationProvider)
    {
         SPAuthenticationProvider provider = iisSettings.WindowsClaimsAuthenticationProvider;
         RedirectToLoginPage(provider); // This should cause automatic sign in
    }
}

And if it is not Windows Authentication, we perform the authentication for Forms.

// FBA authentication it is.

SPFormsAuthenticationProvider formsClaimsAuthenticationProvider = iisSettings.FormsClaimsAuthenticationProvider;

SecurityToken token = SPSecurityContext.SecurityTokenForFormsAuthentication(new Uri(SPContext.Current.Web.Url), formsClaimsAuthenticationProvider.MembershipProvider, formsClaimsAuthenticationProvider.RoleProvider, username, password, false);

if (null != token)
{
    EstablishSessionWithToken(token);
    base.RedirectToSuccessUrl();
}


Now, all this code does not work if you do not reflect, grab and borrow code from the used Microsoft assemblies by the original Login and Forms ASPX files. You will need to copy the code from the following methods:

// Borrowed from Microsoft.SharePoint.IdentityModel.LogonSelector class
private void RedirectToLoginPage(SPAuthenticationProvider provider)
{ }

// Borrowed from Microsoft.SharePoint.Utilities.SPUtility class
private string EnsureUrlSkipsFormsAuthModuleRedirection(string url, bool urlIsQueryStringOnly)
{ }

// Borrowed from Microsoft.SharePoint.IdentityModel.Pages.IdentityModelSignInPageBase
private void EstablishSessionWithToken(SecurityToken securityToken)
{ }

When you deploy your solution you can change the web application setting to use the custom sign in page.

WebAppSettingsCustom

Custom Sign Out page

Although you cannot set a custom sign out page through Central Admin like we did for the Sign In page, you can do so by code. The SPWebApplication class has a method called UpdateMappedPage(). With this method you can map several type of pages to your custom ones. E.g. the sign out page looks like this:

currentWebApp.UpdateMappedPage(SPWebApplication.SPCustomPage.Signout, "/_login/octavie/SignOut.aspx");
currentWebApp.Update(true);
 

Just add a feature with an eventreceiver to your solution. On FeatureActivated add the above code.

On MSDN you can reed more about the UpdateMappedPage method.

Summary

With SharePoint you can define your own custom login page for your Claims Based web application. You can use the default login page for starters, but for more complex requirements you will need tools such as Reflector or ILSpy to analyze what really is going on behind the scenes.

Share