Wednesday, November 30, 2011

Being Ignored By the SQL Membership Provider

SQL Membership Provider in SharePoint 2010

Those of you who have worked on SharePoint 2010 sites that use Forms Based Authentication (under the umbrella of Claims Based Authentication), won’t act surprised when I start talking about the SQL Membership Provider. It’s one of the most common providers that gets used in SharePoint 2010 FBA sites. The fact that it’s a free, very flexible, and pretty straight forward way to set up FBA in SP 2010 have helped spur its popularity.
Those who have also worked with the SQL Membership Provider in environments where claims based authentication wasn’t in play, may very well have noticed some changes in its behavior. While the code is of course the same, the additional complexity of a claims environment, means that some properties may not behave as they normally would.

The Computer Isn’t Listening to Me

On two separate occasions now we’ve had developers set properties on the SQL Membership Provider in the web.config expecting it to change the behavior of their SP 2010 site. In both these cases a lack of understanding in how claims authentication works has left them scratching their heads when the properties didn’t take effect.
An example of this might be:
  • Developer wants to change one of the authentication options of the membership provider (say increase the MaxInvalidPasswordAttempts property), and does so in the web.config of the chosen web application.
  • After the change to the provider settings, the developer notices that the web application behaves no differently than before.
  • After a series of cuss words and IIS resets, developer starts aimlessly searching the internet (or an empty bottle) for the answer.
It’s important to remember that once claims based authentication is introduced, the web application doesn’t perform any of the authentication anymore. Even though those settings for the provider in the web.config speak to authentication behavior, in Sharepoint 2010 claims auth scenarios the actual authentication is most often performed by the SharePoint Secure Token Service.
Those web.config settings (in the web application) that don’t speak to authentication are still fair game and will behave as expected, but the properties that change auth behavior like MaxInvalidPasswordAttempts or PasswordAttemptWindow won’t have any effect (unless their made in the Secure Token Service web.config).
To be clear, you need to make those changes to the web.config of the STS, normally hosed at: C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\WebServices\SecurityToken\web.config.
In most scenarios, the authentication exchange looks like the picture below (with steps 3-8 being performed by the STS).
Claims Authentication Steps for Browser and Secure Token Service
Once the relationship between the user, the STS, and the web application become clear the reasoning behind this behavior starts to make a lot more sense.
Since knowing is half the battle, it’s probably worth keeping an eye on claims based authentication technologies and how they behave. With how many systems are now using shared/claims auth both in and outside the enterprise, these are troubleshoots that are going to become increasingly common in future years.
My Best,
Tyler

Tuesday, October 18, 2011

SharePoint People Picker Filters Strike Back

Yay, Free Integration

One of the benefits of rolling out SharePoint in intranet environments is that it marries pretty well with Active Directory (and other LDAPs). An example of this is the People Picker. It allows you resolve (or look up) any user in the LDAP that you’re authenticating against.

Since LDAPs often get pretty dated/polluted there’s often a need to filter out certain sections of the LDAP or a certain genre of results. These might be old employees who have left the company, or users from a section of the organization that just aren’t relevant to the web application at hand.

An example of a filter at the Organizational Unit is below. The following filter ensures that the people pickers in the given web application only pull users from the Employees organizational unit (OU).

stsadm -o setsiteuseraccountdirectorypath -url http://webApplicationUrl -path "OU=Employees,DC=fullly,DC=quallified,DC=domain,DC=com"

Should you change your mind later, the following removes the filter above. In general, no application pool recycle or IISReset is required.

stsadm -o setsiteuseraccountdirectorypath -url http://webApplicationUrl -path ""

It’s worth mentioning that these filters don’t affect existing accounts in the site collection that have already been added. They only stop future users additions that would collide with the give filter.

There are some pretty expressive filters available out there. Many can target specific LDAP properties like title, name, organization, etc… or other fields. Examples can be found at:

The Resulting Errors

The problem with these filters is that its easy to forget about them and remember that they’re still in play. Specifically when adding users to a group, administrators/site owners are sometimes greeted with:

The user does not exist or is not unique. at Microsoft.SharePoint.Library.SPRequestInternalClass.UpdateMembers(String bstrUrl, Guid& pguidScopeId, Int32 lGroupID, Int32 lGroupOwnerId, Object& pvarArrayAdd, Object& pvarArrayAddIds, Object& pvarArrayLoginsRemove, Object& pvarArrayIdsRemove, Boolean bSendEmail) at Microsoft.SharePoint.Library.SPRequest.UpdateMembers(String bstrUrl, Guid& pguidScopeId, Int32 lGroupID, Int32 lGroupOwnerId, Object& pvarArrayAdd, Object& pvarArrayAddIds, Object& pvarArrayLoginsRemove, Object& pvarArrayIdsRemove, Boolean bSendEmail)

Which is an awfully confusing error. When you get the above, make sure that there aren’t any filters in play that would normally preclude the given user from resolving as they can cause this error.

You can check the existence of a directory path filter by running the following stsadm command:

stsadm -o getsiteuseraccountdirectorypath -url https://webApplicationUrl

If there are, remove them first and then try again. This is a step that should often be done before getting too far into a troubleshoot.

Hope that helps.

My Best,
Tyler

Friday, October 7, 2011

Customizing SharePoint 2007 Welcome and Site Actions Menus

Can We Trim That Down?

A good portion of a SharePoint branding implementation is discerning which out of the box features are working and those that need to be customized. Especially in branding engagements where we’re trying to write as little code as possible, being able to provide customizations w/out opening Visual Studio is a huge win.
Below are two very common modifications that can be done to both the Site Actions and the Welcome menu to restrict the options that appear.

Removing Options from the Site Actions Menu

There are two ways to declare a SiteActions menu, the very terse:
<SharePoint:SiteActions runat="server" />
Or the more verbose style like that found in the default.master:
<SharePoint:SiteActions runat="server"
AccessKey="<%$Resources:wss,tb_SiteActions_AK%>" id="SiteActionsMenuMain"
PrefixHtml="&lt;div&gt;&lt;div&gt;"
SuffixHtml="&lt;/div&gt;&lt;/div&gt;"
MenuNotVisibleHtml="&amp;nbsp;">
<CustomTemplate>
<SharePoint:FeatureMenuTemplate runat="server"
FeatureScope="Site"
Location="Microsoft.SharePoint.StandardMenu"
GroupId="SiteActions"
UseShortId="true">
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_Create"                    
Text="<%$Resources:wss,viewlsts_pagetitle_create%>"
Description="<%$Resources:wss,siteactions_createdescription%>"
ImageUrl="/_layouts/images/Actionscreate.gif"
MenuGroupId="100"
Sequence="100"
UseShortId="true"
ClientOnClickNavigateUrl="~site/_layouts/create.aspx"
PermissionsString="ManageLists, ManageSubwebs"
PermissionMode="Any" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_EditPage"
Text="<%$Resources:wss,siteactions_editpage%>"
Description="<%$Resources:wss,siteactions_editpagedescription%>"
ImageUrl="/_layouts/images/ActionsEditPage.gif"
MenuGroupId="100"
Sequence="200"
ClientOnClickNavigateUrl="javascript:MSOLayout_ChangeLayoutMode(false);"/>
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_Settings"
Text="<%$Resources:wss,settings_pagetitle%>"
Description="<%$Resources:wss,siteactions_sitesettingsdescription%>"
ImageUrl="/_layouts/images/ActionsSettings.gif"
MenuGroupId="100"
Sequence="300"
UseShortId="true"
ClientOnClickNavigateUrl="~site/_layouts/settings.aspx"
PermissionsString="EnumeratePermissions,ManageWeb,ManageSubwebs,AddAndCustomizePages,ApplyThemeAndBorder,ManageAlerts,ManageLists,ViewUsageData"
PermissionMode="Any" />
</SharePoint:FeatureMenuTemplate>
</CustomTemplate>
</SharePoint:SiteActions>
Although there’s some testing that needs to be done, you can for the most part use either the PermissionsString/PermissionMode properties to conditionally hide menu items OR you can remove them in entire (by simply removing the menu item markup [above]).

Even when we start to work with publishing sites, it’s worth mentioning that the PublishingSiteAction menu (like that found in blueband.master) is really just a control template which pretty much does the above but adds additional controls to the menu. You can find said control at:

C:\Program Files\Common Files\microsoft shared\Web Server Extensions\12\TEMPLATE\CONTROLTEMPLATES\PublishingActionMenu.ascx.

See something you don’t like? Change it. Its worth mentioning that we typically don’t recommend altering any of the controls in the ControlTemplates folder themselves (since it has farm wide impact). If you can, either make your changes in the masterpage (using selective declarative markup like the above), or create a copy of an existing control, make your alterations in the copy and reference it from your master page.

Either way, keep your footprint as small as possible.

Removing Options from the Welcome Menu

The welcome menu works in pretty much the same way. Typically it’s declared looking like:
<%@ Register TagPrefix="wssuc" TagName="Welcome" src="~/_controltemplates/Welcome.ascx" %>
...
<wssuc:Welcome id="IdWelcome" runat="server">
Notice that similar to the PublishingSiteAction menu (above) it simply references a control template found in:

C:\Program Files\Common Files\microsoft shared\Web Server Extensions\12\TEMPLATE\CONTROLTEMPLATES\Welcome.ascx

The easiest way to work with a reduced version of the welcome menu is to replace your existing welcome menu control (above) with the actual control markup/template, and then selectively remove what you don’t want (and test). An example of such a trimmed control (which only shows the “Sign In as a Different User” and “Logout” options) would look like:
<SharePoint:PersonalActions AccessKey="<%$Resources:wss,personalactions_menu_ak%>" ToolTip="<%$Resources:wss,open_menu%>" runat="server" id="ExplicitLogout">
<CustomTemplate>
<SharePoint:FeatureMenuTemplate runat="server"
FeatureScope="Site"
Location="Microsoft.SharePoint.StandardMenu"
GroupId="PersonalActions"
id="ID_PersonalActionMenu"
UseShortId="true">
<SharePoint:MenuItemTemplate runat="server" id="ID_LoginAsDifferentUser"
Text="<%$Resources:wss,personalactions_loginasdifferentuser%>"
Description="<%$Resources:wss,personalactions_loginasdifferentuserdescription%>"
MenuGroupId="200"
Sequence="100"
UseShortId="true"/>
<SharePoint:MenuItemTemplate runat="server" id="ID_Logout"
Text="<%$Resources:wss,personalactions_logout%>"
Description="<%$Resources:wss,personalactions_logoutdescription%>"
MenuGroupId="200"
Sequence="300"
UseShortId="true"/>
</SharePoint:FeatureMenuTemplate>
</CustomTemplate>
</SharePoint:PersonalActions>
And voila, this:

Original, unmodified welcome menu.

Becomes this:

Customized Welcome Menu w/out authoring a feature or changing any controls in the controltemplates folder.

This can sometimes be super helpful, not only can you selectively pick links (and still hide the whole control with a <Sharepoint:SPSecurityTrimmedControl/> if need be), but you also don’t have to author a feature to change the menu or start messing with controls in the ControlTemplates folder (which can have a farm wide impact).

Hope this helps someone.

My Best,
Tyler

Monday, September 19, 2011

SharePoint 2007’s Most Common and Confusing Error

That Seems Misleading

Today I ran into an error that I was positive I’d dealt with before. When we tried to visit any System pages (those that use the default.master) in a SharePoint 2007 application, we got the following error.

The DataSourceID of 'TopNavigationMenu' must be the ID of a control of type IHierarchicalDataSource. A control with ID 'topSiteMap' could not be found.

More formally, it looked like this:

Common SharePoint 2007 Error

When we tried to load other pages (where we were loading custom user controls from disk) we got another misleading error.

An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.

Another symptom and misleading error message.

Believe it or not, this is one of SharePoint 2007’s most well known red herrings. I post this in part because:

  1. A lot of the existing content on the web doesn’t fully document this error and how to troubleshoot it (misleading).
  2. I’ve run into it enough times (and forgotten the solution) that I feel a need to document it somewhere that I can easily look it up.

The Solution

The first thing to know about this error is that it gets thrown for a wide variety of reasons. While most often it has something to do with the web.config of a SharePoint 2007 web application, the root cause can get pretty tangential to a simple web.config parser error.

The first step to troubleshooting this, is to get an error message that actually speaks to the error at hand (the two above don’t, so don’t try to troubleshoot off of them). This genre of error seldom puts helpful details into the event log and so you should:

  1. Open up the latest log file in the 12 hive (C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\Logs).
  2. I usually go to the end of the file and search up for terms like “error” or “exception”.
  3. You should be able to find some error. These can be quite varied from type/assembly resolution errors to parsing in the web.config.
  4. From here troubleshoots typically go one of two routes.
    • Either the error itself will inform you of what to do (e.g. a file is missing somewhere).
    • You still have no idea and need to manually merge back in a working web.config.
  5. If you can’t figure out what to do based on the error, 99% of the time you can repair the error by merging in (use a diff tool, don’t blindly stomp) a stock SharePoint web.config. To do this…
  6. Backup your failing web.config.
  7. Create a blank web application in some test farm.
  8. Diff in (we use Beyond Compare) the newly provisioned stock web.config into your failing one (preferably line by line to determine root cause).
  9. After you bring a line/section over feel free to save the file and refresh your browser. Every time you change the web.config (and save) the application pool should recycle, so don’t worry about needing to reset IIS.

This “baby steps” process has always yielded a quick troubleshoot down to root cause for us.

Troubleshooting SharePoint errors is often the beginning of a frustrating afternoon, so hopefully this helps someone out there.

My Best,
Tyler

Tuesday, August 23, 2011

Convenient, Yet Confusing Elements of Windows Integrated Authentication

Windows Integrated Authentication

If you’ve written an application the intranet, you’ve likely used Windows Integrated Authentication at some point. When it works, it’s pretty slick. Not only is it flexible in the authentication protocols you can use, but users (if set up right) don’t even need to enter in their username/password.
Windows Integrated Authentication can use any of NTLM, Kerberos, Negotiate, or Digest. So if you’re picky about your security protocols (performance, client availability, hack-ability) there’s probably something in that list that will float your boat.
For those that haven’t had the pleasure yet, WIA is a way for users to authenticate (establish an identity) with an application in a Windows environment. The identity they’re usually establishing is one from from Active Directory or a local Windows credential.

Why’s It Useful

As it turns out, people don’t like logging in. Most users don’t even like typing in general, and the rest can’t be bothered to remember their password. When WIA works well, the user doesn’t do anything. They simply access a resource, and in the background a challenge/response ballet establishes their identity. All they see is a page that knows who they are treats them accordingly.
The equivalent of this happening to you in real life would be people just (seemingly) knowing who you are and treating you accordingly. If you were to arrive at a fancy restaurant (and you had reservations) you could just show up and be led to you table (no need to check in).
On the other side of things, if you showed up somewhere you weren’t supposed to be (no permissions) they’d immediately throw you into the street. The moral of the story here; regardless of how you get treated, you don’t need to type.

A Day In The Life

Here’s a look into what some WIA challenge/responses looks like in against a SharePoint 2007 site using NTLM and Internet Explorer 8 as a client. The important note here is that the user didn’t do anything beyond visit the site. All this happens in the background when WIA behaves appropriately.
Request/Response 1
Request1
This is the first of a series of requests and responses to a web server that requires the user to authenticate via WIA (in this case, NTLM).
RequestResponse1The user types in the address of an end point they’re trying to visit (say http://server:81) and the browser sends the first request with the following request headers (request and response headers courtesy of Fiddler).
The server looks at the request, notices that there’s no cookie or any kind of identity sent with it, and kindly tells the browser (401) that not just anyone can visit this URL. In the response headers, the web server asks the browser to establish the users identity using the NTLM protocol.
 
Request Response 2
This is the second and final request/response in the WIA handshake. Its of note that the user still hasn’t done or seen anything, s/he’s still waiting on the screen to load…
Request2
RequestResponse2
The browser sends a 2nd request with the identity of the user according to the NTLM protocol. The server inspects the request, processes the NTLM response and decides that this user is indeed who s/he claims to be.
The server issues a response with a token that the client can use to identify themselves.
Request Response 3 (Not Shown)
Finally, the client makes the last request using the token just obtained, to identify themselves. The server authenticates them and hands back a cookie associating the user with a logged in session. The client is finally authenticated.
Its worth mentioning that this handshake takes place extremely quickly and the user is often none the wiser. All the user truly notices (if anything at all) is that the page they just requested recognizes who they are.
As mentioned earlier, when it works it offers a great user experience, but there’s a couple things that can get in the way.

Internet Explorer

Internet Explorer is the only browser that works with WIA “out of the box”. Any browser that supports the required authentication protocol (NTLM, Kerberos, Negotiate, Digest) can authenticate against the server, but there are some special conditions that need to exist.
For IE to send an encrypted identity over the wire, WIA has to be enabled (it is by default). You can check to see whether WIA is enabled under Tools-> Internet Options->Advanced Tab.
In addition to WIA being enabled, one of the following needs exist:
  • The site needs to be in the “Intranet Zone”. IE has a pretty simple test to verify this. Effectively it looks to see if there’s any periods/dots in the host name. For instance, http://someserver is in the intranet zone, but http://someserver.fullyqualified.com however is not (even thought they may both resolve to the same IP. As a result any IP address (e.g. 192.168.132.155) also won’t be in the intranet zone either.
  • If the site isn’t in the intranet zone, it needs to be a trusted site for IE to send the user’s identity over the wire w/out prompting. You can see/manage trusted sites by going to: Tools->Internet Options->Security->Trusted Sites
Once the above is handled (either access to the server takes place with a “intranet” URL, or its put in a trusted zone) WIA usually behaves itself pretty well.

FireFox

Firefox has no ideas of intranet zones like IE. If you want FireFox to trust a site and send over the user’s identity, you need to enlist the site as a trusted NTLM site (and ensure that NTLM is a usable protocol for WIA in IIS).
You do this by:
  • Opening FireFox
  • Type “about:config” into the address bar
  • Edit the Network.automatic-ntlm-auth.trusted-uris property and add the URL of the site you’d like to trust. You can enter multiple URLs delimited by commas.
Firefox-NTLM
This browser should now be able to authenticate via NTLM.

Chrome

At the time of writing, Chrome doesn’t have have a way to seamlessly integrate with WIA (the current browser does support NTLM though). Unfortunately for the time being, Chrome users will always need to enter in their credentials.

Summary

Windows Integrated Authentication can be pretty slick in certain environments. While some if its protocols aren’t rock solid security wise, and many are proprietary, it provides one of the cheapest solutions for authentication that balances both maintenance and ease of use for the user.
My Best,
Tyler

Wednesday, June 29, 2011

Troubleshooting Blue Screens

How is that supposed to be helpful?

Anyone who’s used Windows long enough has eventually ran into the quintessential Microsoft error, the Blue Screen of Death (BSoD). Not that other operating systems don’t have their own versions, those that have played with their share Unix flavors know all to well about kernel panic.

Nevertheless, someone usually needs to troubleshoot these, especially if you own the machine. The tricky thing about BSoDs is that they:

  • Can be hard to reproduce
  • The error messages are seldom helpful
  • Can be driver related OR hardware related
  • Don’t always wait for user feedback before disappearing (sometimes the machine will restart right away depending on OS settings).

I recently did a new build at home. Latest gear. Full of promise. That is, until the machine (running Windows Server 2008 x64) started to BSoD when restoring sizeable databases (8 GB) on SQL Server 2008 R2 x64.

Picture of blue screen while restoring database.

Even though the error messages themselves are usually useless, it still helps to see them (even the appearance of a useless error messages is evidence of failure). This isn’t always the default behavior with system faults in all versions of Windows. So for many, the first step is to acquire/witness the blue screen itself (instead of your system sitting at a login prompt, when 30 min ago it was restoring a database).

Disabling Automatic Restart

First ensure that you’ve disabled the Automatic Restart checkbox in Startup and Recovery. This is typically found in:

  1. System Properties (Control Panel->System)
  2. Click Advanced System Settings
  3. Click on the Advanced tab.
  4. Click on Settings under the Startup and Recovery section.
  5. Ensure that the Automatically restart checkbox is unchecked and its usually not a bad idea to Write an event to the system log (checked).Click on Settings under Startup and RecoveryAutomatically Restart

Reproducing the Error and Narrowing the Field

If you’re like 99% of users, you can’t infer what the problem is from a BSoD error or analyze a memory dump. If that’s the case, the next steps are reproducing the error, and trying to figure out root cause.

If you can’t easily reproduce the error (or if it’s a new build), then all your components are suspect. It could be anything from hard drive, to your video card. If you’ve recently installed new hardware or drivers, those are likely the culprit.

For testing many components at once I’d suggest a product like PassMark’s Burn In Test, a tool we used to use back in my tech days. There are many similar products available (assuming you have a preference), essentially you just want to be able to selectively test many components at once and get either a:

  • BSoD (in which case you reduce the number of components you’re testing until you isolate the culprit)
  • A fail from the testing software which will usually tell you what component is causing the trouble

The next step (once the component is identified) is either:

  • Replacing drivers for that component, or failing that
  • Replacing the component all together (hopefully its not something that’s integrated into your motherboard)

Lather, rinse, repeat. That is, after you’ve identified (what you think is) the issue, and either swapped out a component or device driver, you need to run the tests again to see if you’ve actually improved anything. Once the errors start going away you can start to have some confidence in your fix.

Resolution

These take time. Running a full burn in test alone usually takes 20 min. In my case, my issue ended up being a faulty hot swap bay, which is unfortunate because its likely the last device you’d suspect. More often than not, its memory, a video card, or some other kind of removable component. Assuming you can’t narrow it down, power supplies can also be suspect.

Hardware’s great, especially when it works. But with increasingly complex computers these days, DOA’s and semi faulty components seem to be more common. Ideally this saves someone some out there some time, or even better, a tech bill.

My Best,
Tyler

Sunday, May 15, 2011

SharePoint Health Rules Modifying Your Web.Config

Is That a Web.Config Ninja?

One of the new feature in SharePoint 2010 is the Health Analyzer. At its core, it’s a set of rules that perform checks and/or repairs executed by timer jobs. When a rule executes, the output gets rolled up into a Health Analyzer Report that helps inform SharePoint Administrators about any potential issues with their farm configuration.

Even if you don’t have any interest in Health Rules/Reports, its something you should know about. The rules (including those that ship out of the box) don’t all just harass you into maintaining a cleaner farm, some of them actually “correct” possible issues without asking first. Having a series of timer jobs that can modify your farm adds complexity, and you should know what possible modifications can be made while you’re off the clock.

If you’re curious as to where these rules live, they can be found in the Central Administration site under Monitoring->Review Rule Definitions.

Central Administration Health Rule Definitions

Case In Point

In a recent engagement we were using the stock ASP.NET Membership Provider for user management (for FBA accounts) in a Claims Based Authentication site. It became important to be able to decrypt users password for retrieval which meant that we had to modify the encryption/decryption settings. For the stock provider, these are housed in the <machineKey> setting in the web.config.

Then things got weird.

Across many of our machines, the settings kept getting rolled back. Every night at 12:00am (midnight) parts of the web.config would get reverted to the old machine key settings. It got to the point where we were considering making the web.config read only.

Then we did some snooping around and found out about a particular Health Rule that takes syncing web.config files pretty seriously. There’s one in particular called Web.config Files are not identical on all machines in the farm which out of the box will repair automatically. This can be a huge help if your web.config settings have unintentionally fallen out of sync, but if its rolling back intentional changes, then its downright troublesome.

Web.config files are not identical on all machines in the farm.

There’s nothing wrong with this rule per se, but if you ever find yourself having similar issues, I’d recommend unchecking the Repair Automatically check box. This will hopefully help you both find closure, and move on to the next SharePoint woe in your life. Hope it helps someone.

My Best,
Tyler

Sunday, April 17, 2011

Access Denied With Linq to SharePoint (SPMetal)

Access Denied

SPMetal (Linq to SharePoint) is kind of a mixed bag. On one had it’s great addition to what used to be a very anemic toolset for SharePoint. On the other hand it has some pretty remarkable shortcomings that aren’t really advertised all that well in the documentation.
Two of the more notable ones:
  • No support for anonymous users (at least at the time of writing)
  • No support for RunWithElevatedPrivileges
These two shortcomings are actually very intimately related. If you’re using SPMetal (Linq to SharePoint) and you find that code inAccess Denied when trying to RunWithElevatedPrivileges RunWithElevatedPrivileges still yields Access Denied errors (or doesn’t seem to run in any kind of elevated context) you’ve potentially encountered a very awkward shortcoming of SPMetal.
The good news is that there are some very functional workarounds to these issues but for you to troubleshoot these (and discern where they’re appropriate) it helps to know why these errors happen.

What’s Going On?

For those who have worked with RunWithElevatedPrivileges before you know that certain “shapes” of code don’t work. An example of this would be running some code with RunWithElevatedPrivileges context but then using an object you’d previously created outside the elevated context. Here are two examples of RunRunWithElevatedPrivileges, one which still throws an Access Denied and another that works.
The astute observer will recognize that the below will throw an Access Denied error
//Doesn't work, still yields access denied.
SPSecurity.RunWithElevatedPrivileges(delegate()
{
  using (SPSite site = SPContext.Current.Site)
  {
    using (SPWeb web = site.RootWeb)
    {
      web.AllowUnsafeUpdates = true;
      SPList list = web.Lists["ListName"];
      SPListItem item = list.AddItem();
      item["Property"] = "Property Value";
      item.Update();
    }
  }
});

The reason the above fails is that the SPContext.Current.Site gets created relatively early in the request lifecycle. By the time you call it from some page/webpart/etc… the SPSite object has long since been constructed, and at the time the SPSite WAS constructed, the application was NOT running in a RunWithElevatedPrivileges security context.

The below DOES work since a new SPSite (and all other objects) are created in the RunWithElevatedPrivileges security context.

//Works because the SPSite, SPWeb etc... are created in the new elevated security context.
SPSecurity.RunWithElevatedPrivileges(delegate()
{
  using (SPSite site = new SPSite("http://servername"))
  {
    using (SPWeb web = site.RootWeb)
    {
      web.AllowUnsafeUpdates = true;
      SPList list = web.Lists["ListName"];
      SPListItem item = list.AddItem();
      item["Property"] = "Property Value";
      item.Update();
    }
  }
});

The moral of the story is that objects you’re working with need to be recreated within your RunWithElevatedPrivileges code block.

The Problem with SPMetal

The two problems we kicked off this post with:

  • No support for anonymous users (at least at the time of writing)
  • No support for RunWithElevatedPrivileges

Actually stem from the same class of problem as the incorrect “shape” of code shown in the RunWithElevatedPrivileges example above. When the Linq to SharePoint Provider goes to create a connection to the given SPSite/SPWeb, it’ll take the current SPSite object out of the SPContext.Current context. The problem with this is that there’s no (easy) way to have that SPSite object constructed with an elevated security context.


Here’s a look at the reflected code.
SPServerDataConnection.png

The solution that most people have taken for the anonymous access issues also works for the RunWithElevatedPrivileges issues.

The trick is to set the HttpContext to null temporarily just prior to creating creating the DataContext in a RunWithElevatedPrivileges block. This bullies the Linq to SharePoint provider into creating a new SPSite, and this one is created with the correct context.

Below is a helper method which follows the RunWithElevatdPrivileges pattern which allows you to create a DataContext that will indeed run with elevated privileges.

/// <summary>
/// Runs with elevated priviledges after setting the HttpContext temporarily to null prior to doing so. This allows linq to sql 
/// to create a DataContextManager based on the RunWithElevatedCredential (farm account) instead of the current user.
/// Otherwise the linq2sql DataContextManager would take its SPSite off of the SPContext.Current.Site which is already cached
/// with the priviledges of the current user.
/// 
/// NOTE: This should ONLY BE CALLED by code creating Linq to SharePoint SharePointDataContexts. It's also of note that any
/// SharePointDataContext created using this code WILL BE ABLE TO DO ANYTHING the farm account can.
/// </summary>
protected static void RunWithElevatedPrivilegesAndContextSwitch(SPSecurity.CodeToRunElevated secureCode)
{
  HttpContext backupContext = HttpContext.Current;

  HttpContext.Current = null;
  SPSecurity.RunWithElevatedPrivileges(secureCode);

  HttpContext.Current = backupContext;
}
Usage might look something like the following:

SharePointDataContext context = null;
string url = SharePointHelper.WebApplicationRoot;

RunWithElevatedPrivilegesAndContextSwitch(delegate()
{
  context = new SharePointDataContext(url);
});

//Do something you normally wouldn’t be able to with this elevated linq to SharePoint context.
List<ListName> items = context.ListName.ToList();

It’s worth mentioning that if your data access is consolidated in to a formal data access layer you may need to centralize this kind of code so that it doesn’t get placed all over the site, but above is the central idea behind getting Linq to Sharepoint DataContexts to run with Farm Account privileged access.


I hope the above makes sense, and helps.


My Best,
Tyler

Wednesday, March 16, 2011

Awkward Usernames Courtesy of Claims Authentication (FBA)

Who’s i:0#.f|membership_providerName|userName?

If you’re one of the many people who have set up Forms Based Authentication in SharePoint 2010, you’ve likely enjoyed dealing with the awkward usernames that can come with claims authentication and FBA (Forms Based Authentication).
In a recent engagement, we’d provisioned an ASP.NET Membership schema (aspnet_regsql.exe), populated it with a stock SQLMembershipProvider and then added the users to the site collection using the Site Settings->People and Groups screens.
What we ended up with, were a lot of SPUsers with "unfriendly" SPUser.Name properties set. Since the Name field wasn’t assigned it ended up getting set to the equivalent of the SPUser.LoginName property which looks a lot like:
i:0#.f|fba|administrator
The problem with leaving these cryptic display names in their native format is that they can seep all over a farm. Not only will they show up in stock SharePoint controls that display user names, but those same display names will also start to show up in other service applications like search.
There's also the fact that your users will likely ask you to set them to something more sensible.

Resting the SPUser.DisplayName Property

Assuming you have some other name that you’d prefer instead of the awkward native claims format, you can explicitly set these display names by using either PowerShell or the stock SharePoint API.
Below are two examples, both involve you iterating over everyone in the authentication store (think SQL, LDAP, AD, etc…) and updating the SPUser.Display/Name property after fetching the SPUser out of the site collection. See below:


PowerShell
$user = Get-SPUser -Web "http://wss2k10tholmes:81" -Identity "i:0#.f|providerName|userName"
$user.DisplayName = "FriendlyName";
$user.Update();
C# (API)
//We use ensure so that the given user will be added if they don't exist. They need to be resolved
//via their claims name.
SPUser spUser = web.EnsureUser(string.Format("i:0#.f|providerName|{0}", fbaUser.UserName));
spUser.Name = "FriendlyName";
spUser.Update();

Alternatives

You don’t necessarily need to go through the API or PowerShell, if you have a connection to an LDAP store or a BCS connection to your auth store. You can also map the properties yourself and leave it to the User Profile Synchronization service. That being said, if you’re dependent on BCS then you’ll also need to have SharePoint Enterprise Server license which isn’t available to all customers.
Once you’re done you should be
Administrator Claims FBA username able to visit any of the users in your site collection and see their “Name” property set to something that is less likely to confuse your user base. Once the value is set, it helps to make sure that it doesn’t get stomped with any User Profile Synchronization (UPS) that may be in place in your farm.

Hope that Helps,

Tyler

Saturday, January 22, 2011

Getting a Public Key Blob From 3rd Party Assemblies

The Return of Code Access Security

Working with SharePoint sometimes takes you to some pretty weird places. Code Access SecurityThere’s a lot of .NET’s surface area that I’m pretty sure I’d never have explored on my own if I hadn’t been tasked to do so via some SharePoint engagement.

One of these explorations has involved authoring custom CAS policies, the reasons for which I’ve blogged about in the past. Granted with the advent of SharePoint 2010 and sandboxed solutions it’s not as common a task these days, but it still comes up.

When authoring a custom CAS policy you’re taxed with obtaining the Public Key Blob from a Strong Name Key. This helps the .NET runtime identify assemblies (via their Strong Name) that you’d like to run with a particular code access security profile.

Now obtaining a public key blob is pretty straight forward if you have the .snk, but it gets a little more awkward if all you have is some 3rd party assembly. This is often the case when you want 3rd parties assembly (for us it was a bunch of Telerik Controls) to run in full trust. After all you don’t have their key and they’re super unlikely to give it to you.

Getting a Public Key Blob from a 3rd Party Assembly

1) First open up the Visual Studio Command Prompt (or optionally any command prompt, but have access to sn.exe which is typically found in Visual Studio’s SDK->BIN folder).

2) Run the following command:

sn -e [ThirdPartyAssembly.dll] publicKey.snk

This extracts the public key (and public key blob) into a file.

3) Then run:

sn -tp publicKey.snk

Which should display the public key blob and public key token (the blob is the long one).

Public Key Blob

At this point you can throw it in your own custom CAS file or resume whatever would make you seek out these awkward little strings in the first place.

Hope that helps. Had stare at the sn.exe docs for a good 10 minutes to find this and the web wasn’t all that helpful.

Happy CASing,
Tyler