By Chris R. Chapman at October 20, 2010 14:51
Filed Under: claims based auth, sharepoint2010

I just got a ping from StackOverflow on a query I posted there when I was first wrasslin’ with SharePoint 2010’s really awful claims authentication scheme back in early May. Mike Vallotton responded with a link to his blog where he’s written up a three entry how-to guide for configuring claims and getting a custom login form stood up.

Well worth the read as he bears the scars of one who has been there – his first paragraph gives you the tenor (emphasis mine):

Setting up Claims Authentication in Sharepoint proved to be a difficult process. There are a huge variety of configuration options, and unless the planets align and you set everything properly, it simply won’t work.

I’ve covered this rather extensively here, including my frustration with three web apps behaving differently based on their URLs and getting a rather unsatisfying explanation after running it up to Premier Support and then on to an Escalation Engineer.  A really troubling issue is that Microsoft and the PG team, for whatever reason, decided to go opaque on providing clear, concise documentation on what was touted as a first-class feature for SharePoint 2010.  Almost all knowledge you will ever glean on FBA/CBA is going to be on a blog, some posts likely written when 2010 was in beta.

If you’re setting up Claims Based Auth, you’re in for a world of pain, son.  Best to strap on your helmet and just dive in.  Accept that you’re going to be banging your head against a wall for some time.  And take solace in that there are folks like Mike Vallotton who have written about their experiences so you don’t have to.

By Chris R. Chapman at July 27, 2010 02:47
Filed Under: claims based auth, sharepoint2010

If you’ve been following this series (Part 1, 2, 3) you know the issue:  I’ve got a SharePoint 2010 VM with three web applications, each enabled for Claims Authentication using three separate ASP.NET Membership SQL Databases.  One out of the three works reliably (ie. login/off/as another user) while the other two require a weird hokey-pokey of authenticating in using Windows credentials before letting the FBA credentials work.

Today, I was on a call with “D”, the Escalation Support Engineer assigned to my customer’s case.  He demonstrated to me how he was able to get three 2010 web apps, each with their own SQL Membership Database all working.  Up and down, left and right, no questions asked.  Baffling to me.

So, we do an EasyShare on my VM and I demonstrate the problem once more:  Port 80, works fine.  Port 85 and 90, only work after using Windows credentials.

“Could you try using the machine name in the browser address bar instead of ‘localhost’ ?”, “D” asks.

“Sure.”

And dammit.  It worked.  Each of the three web apps allowed me to sign-in/out and in again as another user.

“D” isn’t done, however.  He tries using ‘localhost’ on his end.

“They all work on my VM whether I use ‘localhost’ or the machine name,” says “D”.

Raising More Questions than Answered

Well, ain’t that just peachy.  So, the apparent “fix” for my environment is to not use ‘localhost’.  But even that’s not quite right as the port 80 web app works up and down irrespective of the means I put into the addressbar.  So, I’m left even more confused:  Why on Earth is there no consistency in a vanilla environment?

I’ve got homework to do, before I can come to a closer definitive resolution.  “D” has asked me to re-build my web apps using his recommended web.configs – that will take an hour or so.  Then I need to ping him again to see where this goes.

What. Fun.

By Chris R. Chapman at July 20, 2010 19:07
Filed Under: claims based auth, sharepoint2010

A short post to summarize the state of the matter revealed in my prior two posts (Part 1, Part 2) on the bizarre behaviours I've been encountering on behalf of my customer, Envision IT, with respect to SharePoint 2010 Claims Based Authentication. As indicated in my last post, we have initiated a support ticket with Microsoft to explore the issues we've seen (captured in a screencast that can be found in Part 2). This was sent to Premier Support, along with corresponding ULS logs: In the end, they had no explanation for what was causing the problems. 

So, I asked for an escalation to the next level which should be initiated some time today - I have no preconceived expectations here, but it would be nice to know why, precisely, FBA/CBA is such an untameable monster. In the interim, my customer opened a second support ticket to walk through setting up FBA on one of their integration servers that was acting ornery and not allowing the setting of permissions for Forms Based Users.

A bizarre (to me) outcome of this was the discovery that you don't need to add FBA users via User Policy in Central Administration for them to access a site collection. That's really, really, really interesting. Because just about every ounce of documentation that I've ever come across for setting up Claims requires this step to allow your FBA/Sql users into your web app. Even my first level of support indicated this as a required step. So what gives with that?

All this underscores a wide amount of confusion and lack of concise documentation from Microsoft on how to configure these environments successfully and repeatedly. Additionally, there is also the matter of IIS 7 integration when it comes to configuring the environments - effectively, you're better off modifying the web.config files for Central Admin, the Security Token Service and the target Web App manually rather than through IIS Manager. Part 4 should come later today or tomorrow.

Ongoing…

By Chris R. Chapman at May 08, 2010 02:47
Filed Under: claims based auth, sharepoint2010

While recently helping out my friends at Envision IT with their SharePoint 2010 FBA configuration, I came across an unsurprisingly frustrating aspect of using a custom ASP.NET form to handle the authentication.  From most of the sparse documentation that is available on this topic (re: custom FBA forms – there’s tons on OOTB FBA), you’d think that all that’s required is to provide an URL to your form in Central Administration and Bob is your father’s brother.

Centraladmin_customform
  Ta-da!  Ready to go home now!

Um, noooo.

The Bad News:  It Ain’t Gonna Work

It’d be great if things worked so easily as just slapping in an URL and the back-end wiring itself up automagically like it came out of Hogwarts – not so fast.  Say you have a basic ASP.NET form and you’ve configured it thus with standard <asp:Login> control:

<%@ Page Language="c#" AutoEventWireup="false" Inherits="System.Web.UI.Page" Trace="false" %>
<form id="fbaLoginForm" runat="server">
<asp:login id="signInControl" runat="server" displayrememberme="False"></asp:login>
<asp:checkbox id="chkRememberMe" runat="server" cssclass="RememberMe" text="Remember me and my language preference" tooltip="Tooltip goes here" visible="False" /> <br />
<span style="margin-left: 4px">
  <
a href="../ForgotPass/default.aspx" class="Label">
    <asp:label id="lblForgotPass" runat="server" text="Forgot Password?"></asp:label>
  </a>
</
span> </div> <script type="text/javascript" language="javascript">
// This Script focuses on the Username field (or the password field if the username was remembered)
if (document.getElementById("ctl00_ContentPlaceHolder1_Login1_UserName").value != "") {
document.getElementById(
"ctl00_ContentPlaceHolder1_Login1_Password").focus();
}
else {
document.getElementById(
"ctl00_ContentPlaceHolder1_Login1_UserName").focus();}
</script> </form>

Assuming that you’ve already set up the ASP.NET Membership SQL database, configured the Membership and Role providers, made the commensurate changes in the web app, Secure Token Service and Central Admin web.configs and gone into Central Administration to configure Forms Based authentication, you’d find that all your efforts would have been for nought:  This form would dutifully validate your credentials against the Membership database, but then unmercilessly given you a 403 HTTP error when the form attempted to redirect to /_layouts/Authenticate.aspx. (See my “How-To” FBA links on Delicious for reference if you’re lost in what I just said)

Why? 

Because a vanilla ASP.NET form has no idea how to create the required claims based authentication token to pass along to SharePoint’s doorman to say that you really are on “the list” and that you know this guy inside who can vouch for you.  This form inherits from System.Web.UI.Page – you are a nobody as far as Club SharePoint 2010 is concerned.  Move along.

The Good News:  You Can Make It Work

There is another way, but it is top-secret.  Well, at least it seems that way given the rigamarole I had to go through to put it together – there’s no API documentation on this, you see.  The solution is to go in-cognito:  In this case, to set your login form page to inherit from the same class that the out-of-the-box SharePoint FBA login form implementsMicrosoft.SharePoint.IdentityProvider.FormsSignInPage (this can be found in the /_forms sub folder of any SharePoint 2010 web application that has been set for FBA).

Ootb_login
  Our target:  The OOTB SharePoint 2010 FBA Form

Now through the magic of polymorphism, you too can access all the SharePoint FBA/Claims Auth token creation goodness out-of-the-box FBA forms get for “free”.  Please, hold your applause.

Ootb_fba_defaultaspx
  /_forms/default.aspx – You want to rip this code off

Using the default.aspx page as a guide, you can adapt your own custom login .aspx page and master page to implement the required <asp:Content> areas – you might want to keep them all or put the ones you don’t plan to use inside an <asp:Panel> control with the Visible property set to false.  Here’s what my revised login page default.aspx looks like – note the Assembly and Import directives and the Inherits property for the <% Page %> directive, and the <asp:Content> controls – these are required by the FormsSignInPage.

    1 <%@ Assembly Name="Microsoft.SharePoint.IdentityModel, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

    2 <%@ Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

    3 <%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

    4 <%@ Import Namespace="Microsoft.SharePoint.WebControls" %>

    5 <%@ Import Namespace="Microsoft.SharePoint" %>

    6 

    7 <%@ Page Language="c#" AutoEventWireup="false" MasterPageFile="DefaultGoodMasterPage.master"

    8     Inherits="Microsoft.SharePoint.IdentityModel.Pages.FormsSignInPage" Trace="false" %>

    9 

   10 <%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"

   11     Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

   12 <%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities"

   13     Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

   14 

   15 <asp:Content ID="Content2" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">

   16     <SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" ID="ClaimsFormsPageTitle" />

   17 </asp:Content>

   18 <asp:Content ID="Content3" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea"

   19     runat="server">

   20     <SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" ID="ClaimsFormsPageTitleInTitleArea" />

   21 </asp:Content>

   22 <asp:Content ContentPlaceHolderID="PlaceHolderSiteName" runat="server" />

   23 <asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server" />

   24 

   25 <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">

   26     <SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" ID="ClaimsFormsPageMessage" />

   27     <div style="text-align: left; margin-top: 10px;">

   28         <asp:Login ID="signInControl" runat="server">

   29         </asp:Login>

   30         <asp:CheckBox ID="chkRememberMe" runat="server" Text="Remember me"

   31             ToolTip="Tooltip goes here" Visible="False" />

   32         <br />

   33         <span style="margin-left: 4px"><a href="~/forgotmypassword/default.aspx">

   34             <asp:Label ID="lblForgotPass" runat="server" Text="Forgot Password?">

   35             </asp:Label>

   36         </a></span>

   37     </div>

   38     <script type="text/javascript" language="javascript">

   39         // This Script focuses on the Username field (or the password field if the username was remembered)

   40         if (document.getElementById("ctl00_ContentPlaceHolder1_Login1_UserName").value != "") {

   41             document.getElementById("ctl00_ContentPlaceHolder1_Login1_Password").focus();

   42         } else {

   43             document.getElementById("ctl00_ContentPlaceHolder1_Login1_UserName").focus();

   44         } 

   45     </script>

   46 </asp:Content>

   47 

Below is the master page code for my demo login form.  Note the <asp:Panel> control I’ve placed at line 32 that contains the <asp:ContentPlaceHolder> controls that are required by the FormsSignInPage class, but I don’t want to implement right now so I’ve hidden them.  This is an old trick I’ve borrowed from creating minimal master pages for SharePoint 2007 (nod to Heather Solomon;  what?  you don’t know who she is?  For shame…)

    1 <%@ Master Language="c#" %>

    2 

    3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    4 <html xmlns="http://www.w3.org/1999/xhtml" runat="server" id="html">

    5 <head id="Head1" runat="server">

    6     <title>Good SharePoint 2010 FBA Login</title>

    7     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    8     <meta name="keywords" content="" />

    9     <!-- Head Content Ends here -->

   10     <asp:ContentPlaceHolder ID="ContentPlaceHolderHead1" runat="server">

   11     </asp:ContentPlaceHolder>

   12     <!-- Head Content Ends here -->

   13 </head>

   14 <body onload="if (typeof(body_onload) == 'function') window.setTimeout('body_onload();', 500);">

   15     <form id="form1" runat="server">

   16     <h1 style="color: Green">

   17         Good SharePoint 2010 FBA Login Form</h1>

   18     <div>

   19         This form will process and validate credentials for an FBA user and successfully

   20         redirect them to the SharePoint Site.

   21         <p>

   22             Specifically, it inherits from <b>Microsoft.SharePoint.IdentityModel.Pages.FormsSignInPage</b>

   23         </p>

   24     </div>

   25     <div>

   26         <!-- Page Content Starts here -->

   27         <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">

   28         </asp:ContentPlaceHolder>

   29         <!-- Page Content Ends here -->

   30     </div>

   31     <!-- Required ContentPlaceHolders for parent page object -->

   32     <asp:Panel runat="server" Visible="false">

   33         <asp:ContentPlaceHolder ID="PlaceHolderPageTitle" runat="server">

   34         </asp:ContentPlaceHolder>

   35         <asp:ContentPlaceHolder ID="PlaceHolderPageTitleInTitleArea" runat="server">

   36         </asp:ContentPlaceHolder>

   37         <asp:ContentPlaceHolder ID="PlaceHolderSiteName" runat="server">

   38         </asp:ContentPlaceHolder>

   39         <asp:ContentPlaceHolder ID="PlaceHolderMain" runat="server">

   40         </asp:ContentPlaceHolder>

   41     </asp:Panel>

   42     </form>

   43 </body>

   44 </html>

   45 

Custom_login_good
  Behold:  This login form has actually been nominated for several design awards.

Using this technique, you can now adapt your pre-existing FBA login forms to conform with the claims based auth requirements for SharePoint 2010.  As far as I can tell, as of this writing there is no documentation around doing this – I had to use Reflector to determine what was going on inside the FormsSignInPage object as the API has no corresponding entries.

It’s a little more involved than just slapping down an ASP.NET page and setting the Sign In Form URL – but not that much more.

Please enjoy responsibly!

By Chris R. Chapman at April 23, 2010 01:26
Filed Under: sharepoint2010, claims based auth

Recently I was contacted by an attendee from the SharePoint 2010 Ignite training I delivered in January to help out his firm, Envision IT, with a baffling problem.  His team was under a lot of pressure to deliver a SharePoint 2010 portal that would allow extranet access – Forms Based Authentication is a natural fit.  So they thought.

My former attendee, Mike, explained the problem:  “We’re getting strange 500 internal errors when we try to log-in and there’s nothing in any of the event logs on the server.”

Strange.  When I arrived on-site, Mike and his boss Peter walked me through the issue.  They set up a basic 2010 web app and site, and were leveraging IIS7’s .NET Users and Roles providers to store credentials in a SQL database.  All that was running fine – here’s what they demonstrated:

Exhibit A:  The FBA Form

Envsionit_fba_login_fbauth_clean

Exhibit B:  The Fail

Envsionit_fba_login_fbauth_fail_clean

Strange.  I enabled ASP.NET tracing on the login default.aspx page and saw the following details of the exception that was being thrown:

Claims Authentication Tag(fsq7) Request for security token failed with exception:

System.ServiceModel.FaultException: The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.
  at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel.ReadResponse(Message response)
  at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel.Issue(RequestSecurityToken rst, RequestSecurityTokenResponse& rstr)
  at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel.Issue(RequestSecurityToken rst)
  at Microsoft.SharePoint.SPSecurityContext.SecurityTokenForContext(Uri context, Boolean bearerToken, SecurityToken onBehalfOf, SecurityToken actAs, SecurityToken delegateTo) 0.0353631536969084 0.018933

This began to suggest that something in the configuration was amiss.  Mike scared up a clean 2010 VM for me to play with and we started from scratch to build a “vanilla” 2010 FBA site.  We reproduced the issue, so it wasn’t any of the customizations or settings they had on their original dev box.  I was beginning to think that given the error message, something with the Secure Token Service wasn’t working as advertised – this, of course, is an integral part of SharePoint 2010’s Claims Based Authentication system which FBA sites now use to authenticate/authorize.

I sent a ping to a colleague who suggested I have a look at a recent post by Bil Baer on Claims Based Identity in SharePoint 2010 – specifically the section around how the STS is configured. The solution:  We needed to add entries for the Role and Membership providers to the STS web.config and add a User Policy to the SharePoint web application to allow FBA user access.  Also missing was a corresponding entry for the Membership provider in the Central Admin web application’s web.config.

Once this was done, authentication worked like a charm – case closed!

Envsionit_fba_login_fbauth_success_clean

 

About Me

I am a Toronto-based software consultant specializing in SharePoint, .NET technologies and agile/iterative/lean software project management practices.

I am also a former Microsoft Consulting Services (MCS) Consultant with experience providing enterprise customers with subject matter expertise for planning and deploying SharePoint as well as .NET application development best practices.  I am MCAD certified (2006) and earned my Professional Scrum Master I certification in late September 2010, having previously earned my Certified Scrum Master certification in 2006. (What's the difference?)