In SharePoint 2007 writing a custom login page for a forms based authentication (FBA) site was not too terribly hard. There were a few things to know, most of which weren’t SharePoint specific, and some tips to have your login form take on the look and feel of a standard SharePoint layouts page. Overall though, if you knew ASP.NET and the FormsAuthentication class you were good to go. As luck would have it, things get somewhat more complicated in SharePoint 2010.
In this post we’ll walk through one scenario of a custom login page. In this example we decide that we need an entirely custom login page – we’re not just changing the look and feel, we require an entirely different UI. For example, maybe we need to grab the Membership credentials that are used to log in, and then maybe we need someone to enter a secondary authentication ID, like you might have with SecurID. In that case we’re going to have a couple of text boxes on an ASP.NET page for username and password and we’ll need to take those and programmatically log our user in.
The most important point to remember here is that your old friend, the FormsAuthentication class, will no longer be used. The reason for that is because in SharePoint 2010, FBA users are actually claims users. So while you may think you’re working with a standard ASP.NET Membership user and Role provider, under the covers those objects have a shiny claims authentication shell. Because of that, we need to use some of the SharePoint claims classes to work through the FBA login process.
I need to add one caveat here! Normally through one way or another, before I post something on my blog I either know or validate as best I can with someone that yeah, this is the right / blessed / supported way of doing something. In this case, I tried repeatedly to get this approach vetted but was unable to do so. I have used this code for a project I was working on and it does work, but I don’t want someone going into cardiac arrest if the code police tell you at a later date that you need to modify it to meet some other better / more appropriate way of doing things. So enough with the CYA, let’s just look at some code.
Before we get started there’s a couple of references we’re going to need that you probably haven’t used before. The first one is Microsoft.SharePoint.Security.dll, and it’s in the 14 hive in the ISAPI folder. The other one is trickier, and primarily why I gave my caveat above. You need a reference to Microsoft.SharePoint.IdentityModel.dll. However, if you go to add references you won’t readily find this assembly, and thus my source of being slightly embarrassed and wary at the same time. As I described in another post, the best thing I found to do is find it on the file system, copy it to an easy to find location, and add your reference to the copied version. The way I usually do that, ‘cause I’m old school I guess, is I go to a command prompt, change to the root of the drive and do a “dir Microsoft.SharePoint.IdentityModel.dll /s” and find it that way. Once you have that, you’ll probably want to add a little gaggle of using statements:
So now that we have that bit of awkwardness out of the way, when I call into the claims class to validate the FBA user credentials the user typed in I need to tell it what Membership and Role provider it should use. It just needs a name is all. In my particular case I had written a custom Membership and Role provider for what I was doing, so I just enumerated through all the providers my web application knew about until I found mine:
//get the provider names for our type
string userProviderName = string.Empty;
string roleProviderName = string.Empty;
//get the membership provider name
foreach (MembershipProvider p in Membership.Providers)
userProviderName = p.Name;
//get the role provider name
foreach (RoleProvider rp in System.Web.Security.Roles.Providers)
roleProviderName = rp.Name;
Okay, great, I got my provider names. Now we need to take the username and password and get back a SecurityToken. In order to do that, we’re going to use the SPSecurityContext class. It has a method designed just to do this forms based auth login for us; if it’s successful it returns a SecurityToken – if not it returns null. Here’s what it looks like when we authenticate the user credentials:
SecurityToken tk = SPSecurityContext.SecurityTokenForFormsAuthentication(
new Uri(SPContext.Current.Web.Url), userProviderName, roleProviderName,
So I’ve passed in a Uri for the site I’m trying to authenticate against, I’ve told it the name of my membership and role providers, and I’m passing in the username and password values that were typed in the textboxes in my login page. Now I need to check to make sure that my SecurityToken is not null, and if it isn’t I need to write a session token. That is done with the SPFederationAuthenticationModule. Once I’ve written my session token then I can go ahead and redirect the user to whatever page or resource it was that they requested. Here’s the rest of the code that does that:
if (tk != null)
//try setting the authentication cookie
SPFederationAuthenticationModule fam = SPFederationAuthenticationModule.Current;
//look for the Source query string parameter and use that as the redirection
string src = Request.QueryString["Source"];
StatusLbl.Text = "The credentials weren't valid or didn't work or something.";
Now you see when I’ve successfully done everything then I just grab the Source query string parameter because it tells us where the user was originally headed. Once I have that I just send them on their way.
I have done all above steps & working fine now but I have a little requirement. I would like to take some decision on source querystring parameter witn in the membership class, you can say within the validate method. So how I can get that with the membership class?
A perhaps simpler, and less "awkward" way of getting the forms provider would be:
var settings = site.WebApplication.IisSettings[site.Zone];
MembershipProvider fbaProvider = Membership.Providers[settings.FormsClaimsAuthenticationProvider.MembershipProvider];
Hope this is of some help.
I require the functionality i.e
Hi, when I use the correct user and pass I get "Object reference not set to an instance of an object" error. However when I use an incorrect user and pass the token is always NULL. It seems that method recognize the user and pass as valid but cannot issue the security token. Could you please help.
Hi, In addtion to my last post, I noticed that when i browse to
192.168.15.27/.../securitytoken.svc I get the following error:
System.InvalidOperationException: An exception was thrown in a call to a policy export extension.
Error: Security policy export failed. The binding contains a TransportSecurityBindingElement but no transport binding element that implements ITransportTokenAssertionProvider
when i browse to http://localhost:32843/SecurityTokenServiceApplication/securitytoken.svc I get the following error:
An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is:
Error: Security policy export failed. The binding contains a TransportSecurityBindingElement but no transport binding element that implements ITransportTokenAssertionProvider. Policy export for such a binding is not supported. Make sure the transport binding element in the binding implements the ITransportTokenAssertionProvider interface. ----> System.InvalidOperationException: Security policy export failed. The binding contains a TransportSecurityBindingElement but no transport binding element that implements ITransportTokenAssertionProvider. Policy export for such a binding is not supported. Make sure the transport binding element in the binding implements the ITransportTokenAssertionProvider interface.
at System.ServiceModel.Channels.TransportSecurityBindingElement.System.ServiceModel.Description.IPolicyExportExtension.ExportPolicy(MetadataExporter exporter, PolicyConversionContext policyContext)
at System.ServiceModel.Description.MetadataExporter.ExportPolicy(ServiceEndpoint endpoint)
--- End of inner ExceptionDetail stack trace ---
at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.InitializationData.InitializeFrom(ServiceMetadataExtension extension)
at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.TryHandleDocumentationRequest(Message httpGetRequest, String queries, Message& replyMessage)
at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.ProcessHttpRequest(Message httpGetRequest)
at SyncInvokeGet(Object , Object , Object )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object inputs, Object& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
Hi, thanks for this article. It's helped me alot. I was wondering if you could possibly answer a question I have. I'm planning on running mixxed authentication (windows and forms based) adn would like to add to your solution, however, I'm having troubles figuring out how to issue the SecurityToken when authenticating against a WindowsClaimsAuthenticationProvider.
You provide the way to get a SecurityToken when authenticating a FormsClaimsAuthenticationProvider. Could you shed light on how to get one when using a WindowsClaimsAuthenticationProvider please? Thank you if you can! :-)
Any idea how to create a custom login form that doesn't use simple.master? I've been banging my head on the desk for hours attempting this. It seems like FormsSignInPage is calling something in simple.master in it's OnLoad because I get an object reference error when I don't use simple.master. I would like to completely control the branding of the login form.
Good article. How to do same for Windows Authentication. Thanks in advance.
What is "Microsoft.SE.AnonProvider" as this line is throwing error.
where to find lib dll for Microsoft.SE.AnonProvider ? thanks
I used below code and can't find my custom membership provider. It only find default provider. Any idea? From sharepoint central admin, it can access my custom membership provider and I have assigned some users to my web application. I can use these users to login using default form login. But my custom login page is not working. thanks. Gary
userProviderName = p.Name;