Thursday, April 6, 2017

Problem with SPWeb.EnsureUser method and FBA users with claims based authentication in Sharepoint

If you need to perform some action on FBA user in your Sharepoint site where claims authentication is used from outside of Sharepoint context (e.g. from console application) you may face with the following issue: when you will call web.EnsureUser(userName) method it will throw exception:

Specified user ‘username’ not found

There are several things which have to be done in order to make it possible to work with FBA users without Sharepoint context with claims based authentication:

1. Fake HTTP context after you get instance of SPWeb:

   1: HttpRequest request = new HttpRequest("", web.Url, "");
   2: HttpContext.Current = new HttpContext(request,
   3:     new HttpResponse(new StringWriter()));
   4: HttpContext.Current.Items["HttpHandlerSPWeb"] = web;

2. Use user name in full claims format, i.e.:

   1: var user = web.EnsureUser("i:0#.f|mymembershipprovider|username");

where instead of mymembershipprovider and username you should use your own membership provider name and user name.

3. The most tricky thing: from web.config of your FBA site zone you need to copy the following sections to the app.config of your console application:

  • connectionStrings
  • system.web/membership
  • system.web/roleManager

e.g.:

   1: <connectionStrings>
   2:   <add name="MyConnStr" connectionString="..." />
   3: </connectionStrings>
   4: <system.web>
   5:   <membership defaultProvider="i">
   6:     <providers>
   7:       <add name="i" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider,
   8: Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
   9:       <add connectionStringName="MyConnStr" name="MyMembershipProvider" ... />
  10:     </providers>
  11:   </membership>
  12:   <roleManager defaultProvider="c" enabled="true" cacheRolesInCookie="false">
  13:     <providers>
  14:       <add name="c" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthRoleProvider,
  15: Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
  16:       <add connectionStringName="MyConnStr" applicationName="/" name="MyRoleProvider" ... />
  17:     </providers>
  18:   </roleManager>
  19: </system.web>

Here is the full working C# code which allows to get FBA user from console application:

   1: using (var site = new SPSite("http://example.com"))
   2: {
   3:     using (var web = site.OpenWeb())
   4:     {
   5:         web.AllowUnsafeUpdates = true;
   6:         HttpRequest request = new HttpRequest("", web.Url, "");
   7:         HttpContext.Current = new HttpContext(request,
   8:             new HttpResponse(new StringWriter()));
   9:         HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
  10:  
  11:         var user = web.EnsureUser("i:0#.f|mymembershipprovider|username");
  12:         ...
  13:     }
  14: }

2 comments:

  1. Hi Alexey, why does this happen?

    ReplyDelete
    Replies
    1. Gary, if user didn't login to site yet SPUser object is not created for such user in Sharepoint and EnsureUser needs to call all registered membership providers in order to check whether such user really exists in the users store. In order to do that mentioned configuration is config file is needed. I think this is the reason.

      Delete