SharePoint Internals – Hristo Pavlov’s Blog

29 September, 2008

Monitoring web service calls under SharePoint

Filed under: ASP.NET, SharePoint — Tags: , , , — hristopavlov @ 7:57 am

I had this third party web part today that was calling some web services and we were suspecting that the calls were taking a lot of time and were slowing down the response of our SharePoint pages. Running a profiling session with the help of Fiddler we could only see the requests to SharePoint and to the default.aspx page which was taking 30+ seconds to complete but we were not seeing any calls to the suspected web services that may have been happening in the code behind of the default.aspx.

Knowing that Fiddler is actually an HTTP proxy that changes the system configuration and as a result all web browser request get redirected through it I realized that I could probably redirect all .NET HTTP requests to use the Fiddler proxy and this way could identify and monitor them. The ASP.NET web.config file provides a way for the proxy settings to be defined for the whole web application (in our case this is SharePoint). To do this add the section below to your SharePoint’s web.config file:

<system.net>

      <defaultProxy>

            <proxy usesystemdefault = false proxyaddress=http://127.0.0.1:8888 bypassonlocal=false />

      </defaultProxy>

</system.net>

As Fiddler will start on the local machine on port 8888 the lines above will define this proxy to be always used by all HTTP calls made by SharePoint and all web parts and this includes web service calls.

After doing this change I could now see in Fiddler the calls to the web service done from this web part and see that they were actually taking the 30+ seconds delay in which the default.aspx page was waiting for the web service call to complete.

Well now I need to figure out why this is happening and can it be fixed but at least it is now clear which web method is being called as this information is displayed under the “Text View” inspector in Fiddler !

22 September, 2008

SharePoint Code Acceptance Checklist

Filed under: SharePoint — Tags: , , , , — hristopavlov @ 1:24 am

Microsoft have released and recently updated the ‘Sample code acceptance checklist for IT organizations’. This is a checklist with things to look for when doing a code review of SharePoint applications. It can be used as a best practices guide. The article also contains various links to other SharePoint related “Best Practices” documents so bookmark this link now:

http://technet.microsoft.com/en-us/library/cc707802.aspx

18 September, 2008

Implementing Custom Security Rights in SharePoint

Filed under: SharePoint — Tags: , , , , , — hristopavlov @ 11:55 pm

This is a blog entry about a customization that some of you will call a ‘hack’ but which power in my opinion is far greater that the support issues it poses. However before I start I want to make a disclaimer that if you follow my article you do it on your own risk and I am not going to provide support other than what you can find in this article. What I describe below has been implemented successfully in at least one large enterprise project I’ve worked on and works great!

What is the whole fuss about

Well you know how in SharePoint you have those users that can be granted various permission levels, which permission levels contain predefined user rights such as: Manage Lists, Override Check out, Add Items, Edit Items … etc … all those different rights that exist in SharePoint OOB. Those user rights are pretty much fixed and defined by Microsoft. Imagine you are building a custom application on the top of SharePoint and you want to define your own custom user rights. You can always do this in alternative ways but what if you wanted to extend the user rights in SharePoint by defining your own rights and this way keeping the security centralized? This would allow the new user rights to be managed by SharePoint the same way it manages the rest of the permissions. You would be able to grant the custom rights via the SharePoint Permission Levels from the UI and from the object model. You will be able to use the object model to test whether any of your custom rights are granted to a user and most improtantly you will have your custom rights and permissions going togather with the SharePoint permissions. And if anyone has the “Full Control” access granted they will also automatically get your new custom rights. Wouldn’t that be nice? Well this article is about how you can implement this!

How the user rights work

The rights used by SharePoint when defining Permission Levels are all defined in the Microsoft.SharePoint.SPBasePermissions enum. The enum is a flags enum each member of which is a 64 bit integer number that has one of its bits set. This allows a total of 64 different rights to be defined. The permissions granted to a SharePoint user is a single 64 bit permission mask represented as a SPBasePermissions object which corresponding bits/flags will be set for the user rights that have been granted to the user. You can cast this SPBasePermissions object to a 64 bit integer and check whether a specific bit = flag = user right is set.  At the moment the number of flags used by SharePoint is only 33 or 64, which means there is enough room for us to define an extra 31 custom user rights!

Our plan will be:

– Find a free enum value for our new user right
– Define a new Permission Level (using code) that contains our new user right
– Grant the new user right from the SharePoint UI
– Write code that checks whether a user has the new user right granted

How we implement custom user rights

The first step of our plan is to find a free enum value that is not already in use. We pretty much need to go through the existing members of the SPBasePermissions enum and pick one which is not used and which we don’t use already. The complete list of all possible values is shown below.

[Flags]

public enum SPBasePermissions

{

    EmptyMask =                 0x0000000000000000,

    ViewListItems =             0x0000000000000001,

    AddListItems =              0x0000000000000002,

    EditListItems =             0x0000000000000004,

    DeleteListItems =           0x0000000000000008,

    ApproveItems =              0x0000000000000010,

    OpenItems =                 0x0000000000000020,

    ViewVersions =              0x0000000000000040,

    DeleteVersions =            0x0000000000000080,

    CancelCheckout =            0x0000000000000100,

    ManagePersonalViews =       0x0000000000000200,

    UNUSED-VALUE =              0x0000000000000400,

    ManageLists =               0x0000000000000800,

    ViewFormPages =             0x0000000000001000,

    UNUSED-VALUE =              0x0000000000002000,

    UNUSED-VALUE =              0x0000000000004000,

    UNUSED-VALUE =              0x0000000000008000,

    Open =                      0x0000000000010000,

    ViewPages =                 0x0000000000020000,

    AddAndCustomizePages =      0x0000000000040000,

    ApplyThemeAndBorder =       0x0000000000080000,

    ApplyStyleSheets =          0x0000000000100000,

    ViewUsageData =             0x0000000000200000,

    CreateSSCSite =             0x0000000000400000,

    ManageSubwebs =             0x0000000000800000,

    CreateGroups =              0x0000000001000000,

    ManagePermissions =         0x0000000002000000,

    BrowseDirectories =         0x0000000004000000,

    BrowseUserInfo =            0x0000000008000000,

    AddDelPrivateWebParts =     0x0000000010000000,

    UpdatePersonalWebParts =    0x0000000020000000,

    UNUSED-VALUE =              0x0000000040000000,

    UNUSED-VALUE =              0x0000000080000000,

    UNUSED-VALUE =              0x0000000100000000,

    UNUSED-VALUE =              0x0000000200000000,

    UNUSED-VALUE =              0x0000000400000000,

    UNUSED-VALUE =              0x0000000800000000,

    UseClientIntegration =      0x0000001000000000,

    UseRemoteAPIs =             0x0000002000000000,

    ManageAlerts =              0x0000004000000000,

    CreateAlerts =              0x0000008000000000,

    EditMyUserInfo =            0x0000010000000000,

    UNUSED-VALUE =              0x0000020000000000,

    UNUSED-VALUE =              0x0000040000000000,

    UNUSED-VALUE =              0x0000080000000000,

    UNUSED-VALUE =              0x0000100000000000,

    UNUSED-VALUE =              0x0000200000000000,

    UNUSED-VALUE =              0x0000400000000000,

    UNUSED-VALUE =              0x0000800000000000,

    UNUSED-VALUE =              0x0001000000000000,

    UNUSED-VALUE =              0x0002000000000000,

    UNUSED-VALUE =              0x0004000000000000,

    UNUSED-VALUE =              0x0008000000000000,

    UNUSED-VALUE =              0x0010000000000000,

    UNUSED-VALUE =              0x0020000000000000,

    UNUSED-VALUE =              0x0040000000000000,

    UNUSED-VALUE =              0x0080000000000000,

    UNUSED-VALUE =              0x0100000000000000,

    UNUSED-VALUE =              0x0200000000000000,

    UNUSED-VALUE =              0x0400000000000000,

    UNUSED-VALUE =              0x0800000000000000,

    UNUSED-VALUE =              0x1000000000000000,

    UNUSED-VALUE =              0x2000000000000000,

    EnumeratePermissions =      0x4000000000000000,

    FullMask =                  0x7FFFFFFFFFFFFFFF,

}

We need to pick one unused value and let this be 0x0000000000002000. This 64 bit number is actually the decimal 8192 presented in hex. Let’s call our new user right “My Custom {SharePoint Internals} User Right” and grant it to users that will be allowed to use ‘tricks’ when developing SharePoint applications. The best way to grant our new right would be if we can add it as an extra check box to the editrole.aspx page. Doing this may or may not be possible and will definitely require very serious customizations to this SharePoint page. An easier alternative is to create a new Permission Level and setup its permission mask to contain only our new user right. This way we can grant this new permission level to everyone that we want to allow to use ‘tricks’.

To create our special Permission Level we will need to use code and we can “install” it for example as a feature receiver. One of the reasons for our ‘trick’ to work is because the permission levels are actually created from unmanaged code and the permission masks from managed SharePoint object model code are passed as 64 bit integers rather than as an enum values.  The function that will create any Permission Level of our liking is the AddRoleDef method of the SPRequest unmanaged object associated with every SPWeb. In order to call this method we will need to use Reflection though. In this case we already have the rootWeb SPWeb object and are going to add this new SPRoleDefinition to the root web, which will make it available for the whole site collection if we don’t break the role definitions. The code below does the job:

 

PropertyInfo propRequest =

      typeof(SPWeb).GetProperty(“Request”, BindingFlags.NonPublic | BindingFlags.Instance);

 

object spRequest = propRequest.GetValue(rootWeb, null);

 

MethodInfo mthAddRoleDef = spRequest.GetType().GetMethod(“AddRoleDef”);

 

mthAddRoleDef.Invoke(spRequest, new object[]

{

    rootWeb.Url,

    “My Custom {SharePoint Internals} User Right”,

    “Can use ‘tricks’ when coding”,

    false,

    1000,

    (ulong)0x2000, /* The mask of our custom right */

    (byte)5, /* Use ‘5’ so editing is not allowed */

    0

});

 

Well we completed most of our plan. Now the new Permission Level will show up in the central administration. Its checkbox will be disabled, which is done on purpose, because the editrole.aspx page will not know how to show the custom right. However it will be there and SharePoint will know about it even that you don’t see it from the UI. Next steps would be to actually grant this new Permission Level to some users. This can be done via the SharePoint administration pages or using the object model. Once we have some users that are allowed use ‘tricks’ we will possible want to check in various ocasions whether the curent user is allowed to use tricks in the current web or not i.e. to check whether our custom user right is granted to the user or not. This is done by the standard DoesUserHavePermissions method you usually use, but the permission mask is passed a little differently:

 

(web as ISecurableObject).DoesUserHavePermissions((SPBasePermissions)0x2000)

 

Well that’s it! You have successfully defined a new user right and have integrated it in the SharePoint security model.

What are the risks

Well Microsoft may decide to add a few more user rights themselves and use some of the flags we’ve taken already. Even that this sounds possible actually it will require a bigger change in the object model and such a change is very unlikely to be done in SharePoint 2007 i.e. without a major version release. Even if this happens remember we have 31 extra flags to choose from so that’s plenty.

Another thing that could go wrong is if you are using any third party tools to replicate permissions across servers or site collections and those third party tools use a conservative approach in the replication. Depending on how exactly the replication is implemented there is a chance the special permission masks to be lost after the replication. However this may only happen to the permission mask of the custom Permission Level we created at the root web. Now if you simply don’t replicate this Permission Level (because it will not change) then you won’t have any other issues.

16 September, 2008

The Id attribute of a ListInstance feature is ignored by SharePoint

Filed under: SharePoint — Tags: , , , — hristopavlov @ 7:22 am

A developer asked me today why SharePoint doesn’t use the Id specified in the ListIntance feature manifest for the guid of the list to be created. I checked the MSDN documentation and found out that the Id should be actually an integer number rather than a Guid: http://msdn.microsoft.com/en-us/library/ms476062.aspx

Looking at the SharePoint code with reflector revealed that the class that is responsible for activating a ListInstance feature is Microsoft.SharePoint.SPListInstanceElement which actually completely ignores the Id attribute. It creates the list the “normal” way and the list instances will always come with a different and unique guids.

internal SPList Microsoft.SharePoint.SPListInstanceElement.EnsureListExists(SPWeb web)

{

    SPList list2;

    try

    {

        return web.Lists[this.Title];

    }

    catch (ArgumentException)

    {

        Guid guid;

        int num;

        string str;

        string documentTemplate;

        SPListTemplate.QuickLaunchOptions off = SPListTemplate.QuickLaunchOptions.Off;

        if (string.IsNullOrEmpty(this.TemplateType))

        {

            return null;

        }

 

     

 

        num = int.Parse(this.TemplateType, NumberFormatInfo.InvariantInfo);

        str = base.FeatureDefinition.Id.ToString();

        documentTemplate = null;

      

        guid = web.Lists.Add(this.Title, this.Description, this.Url, str, num, documentTemplate, off);

        if (!(guid != Guid.Empty))

        {

            return null;

        }

        return web.Lists[guid];

 

    }

}

8 September, 2008

SharePoint Coding Best Practices

Filed under: SharePoint — Tags: , — hristopavlov @ 12:59 am

Mark Harison blogged few days ago about the great new Best Practices for SharePoint site coming directly from Microsoft:

http://markharrison.co.uk/blog/2008/09/sharepoint-best-practices-series.htm

Make sure you check the Common Coding Issues When Using the SharePoint Object Model article.

Blog at WordPress.com.