I've moved my blog to!. Please update your links. This blog is no longer in use--you can find all posts and comments at my new blog; I will no longer be posting to this site and comments have been disabled.

Monday, December 3, 2007

Add User Policy for Web Application

I needed to create this command in order to solve an odd permissions problem that I was experiencing. I had a web application (http://teamsites) which I'd setup and needed to start migrating sites to. When I went to create the site collection using createsite I got the following error: "Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))" (I got the same "Access is Denied" error when I attempted this via central admin). After doing some digging I found that I could successfully create the site collection from the web application itself (not central admin or stsadm) (the site owner was the logged in user in this case). I also found that I could create the site via stsadm and central admin as long as the owner account was the same as my currently logged in admin account. If I specified an account other than the current user then an access denied error would come up. I then assigned the current user "Full Control" via the policy for web applications in central admin and found that I could now create sites collections and specify any user as the owner. So for some reason assigning my admin account the Full Control policy for the web application is what allows me to create a site collection and specify a user other than the logged in user. I find this really odd as it seems like a farm admin account should be able to do this just fine. Now that I knew how to solve the problem I needed a command to make this setting so that it would be part of my upgrade script: gl-adduserpolicyforwebapp. To make this change it's a simple matter of grabbing an SPPolicyCollection object and calling the Add() method passing in the user login and display name. Once the policy object is created (SPPolicy) you can then bind the permissions to it using the PolicyRoleBindings property and calling the Add method (passing in the SPPolicy object created previously):

   1: public override int Run(string command, StringDictionary keyValues, out string output)
   2: {
   3:  output = string.Empty;
   5:  InitParameters(keyValues);
   7:  string url = Params["url"].Value.TrimEnd('/');
   8:  string login = Params["userlogin"].Value;
   9:  string username = Params["username"].Value;
  11:  SPWebApplication webApp = SPWebApplication.Lookup(new Uri(url));
  12:  SPPolicyCollection policies = GetZonePolicyCollection(Params["zone"].Value, webApp);
  13:  login = Utilities.TryGetNT4StyleAccountName(login, webApp);
  15:  List<SPPolicyRole> roles = new List<SPPolicyRole>();
  16:  foreach (string roleName in Params["permissions"].Value.Split(','))
  17:  {
  18:   SPPolicyRole role = webApp.PolicyRoles[roleName.Trim()];
  19:   if (role == null)
  20:    throw new SPException(string.Format("The policy permission '{0}' was not found.", roleName.Trim()));
  22:   roles.Add(role);
  23:  }
  24:  SPPolicy policy = policies.Add(login, username);
  26:  foreach (SPPolicyRole role in roles)
  27:   policy.PolicyRoleBindings.Add(role);
  29:  webApp.Update();
  31:  return 1;
  32: }

The syntax of the command can be seen below:

C:\>stsadm -help gl-adduserpolicyforwebapp

stsadm -o gl-adduserpolicyforwebapp

Adds a user policy for a web application.

        -url <web application url>
        -zone <default | intranet | internet | custom | extranet | all>
        -userlogin <DOMAIN\user>
        -username <display name>
        -permissions <comma separated list of policy permissions>
Here's an example of how to add a policy giving a SharePoint administrators group full control to a web application:
stsadm -o gl-adduserpolicyforwebapp -url "http://intranet" -zone all -userlogin "domain\spadmins" -username "SharePoint Administrators" -permissions "Full Control"


LinuxInductee said...

Is there a trick to enumerating, updating or deleting user policies for the web application?

Gary Lapointe said...

Not really - take a look at the code I pasted. You should be able to follow it through to figure out how to enumerate, delete, etc.

HenrikD said...

Hi Gary,

First of all thanks for your excellent tools. Is there a way so set "Account operates as System" using gl-adduserpolicyforwebapp ?

Gary Lapointe said...

I didn't expose that capability through the command so I'd recommend using PowerShell to do it.