While walking another IT user through the SSP admin interface the other day I discovered that even though the user was a Farm Administrator that user was not able to get into certain pages within the SSP admin site (such as the profile properties page). Turns out that there's additional permissions that must be granted via the "Personalization Service Permissions" page located under the "User Profiles and My Sites" section. As my goal is to make all changes necessary for our upgrade scriptable I ended up having to create a new command to give our admin group the appropriate permissions: gl-setsspacl. The challenge with this one is that the API to manipulate this information is not a public interface - almost everything is marked internal. I have no idea why this is the case - it's really annoying (what should have been about 40 lines of code turned into about 110 lines because of all the reflection calls). I continue to be frustrated when trying to programmatically manipulate the SSP - why on earth they made so much internal is beyond me. The code to set the permissions is below (avert your eyes if you're easily scared - using reflection is such a pain!):
1: public override int Run(string command, StringDictionary keyValues, out string output)
2: {
3: output = string.Empty;
4:
5: InitParameters(keyValues);
6:
7: string sspname = Params["sspname"].Value;
8: string username = Params["user"].Value;
9: SharedServiceRights rights = GetUserRights(Params["rights"].Value.Split(','));
10:
11: ServerContext current = ServerContext.GetContext(sspname);
12:
13: //SharedServiceAccessControlList acl = SharedServiceAccessControlList.GetInstance(current);
14: Type sharedServiceAccessControlListType = Type.GetType("Microsoft.Office.Server.Infrastructure.SharedServiceAccessControlList, Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
15:
16: MethodInfo sharedServiceAccessControlListMethodInfo =
17: sharedServiceAccessControlListType.GetMethod("GetInstance",
18: BindingFlags.NonPublic |
19: BindingFlags.Public |
20: BindingFlags.Instance |
21: BindingFlags.InvokeMethod |
22: BindingFlags.FlattenHierarchy |
23: BindingFlags.Static,
24: null,
25: new Type[] { typeof(ServerContext) }, null);
26: object acl = sharedServiceAccessControlListMethodInfo.Invoke(null, new object[] { current });
27:
28: //SharedServiceAccessControlEntry aclEntry = acl[username];
29: PropertyInfo itemProp = acl.GetType().GetProperty("Item",
30: BindingFlags.NonPublic |
31: BindingFlags.Instance |
32: BindingFlags.InvokeMethod |
33: BindingFlags.GetProperty |
34: BindingFlags.Public);
35: SharedServiceAccessControlEntry aclEntry = (SharedServiceAccessControlEntry)itemProp.GetValue(acl, new object[] { username });
36:
37: if (aclEntry == null)
38: {
39: if (rights == SharedServiceRights.None)
40: {
41: output += "User does not currently have any rights assiged - nothing to do.";
42: return 0;
43: }
44:
45: // Adding a new user
46: aclEntry = new SharedServiceAccessControlEntry(username, rights);
47:
48: MethodInfo add =
49: acl.GetType().GetMethod("Add",
50: BindingFlags.NonPublic |
51: BindingFlags.Public |
52: BindingFlags.Instance |
53: BindingFlags.InvokeMethod |
54: BindingFlags.FlattenHierarchy,
55: null,
56: new Type[] { typeof(SharedServiceAccessControlEntry) }, null);
57:
58: //acl.Add(aclEntry);
59: add.Invoke(acl, new object[] { aclEntry });
60: }
61: else
62: {
63: if (rights == SharedServiceRights.None)
64: {
65: // Remove an existing user
66: MethodInfo remove =
67: acl.GetType().GetMethod("Remove",
68: BindingFlags.NonPublic |
69: BindingFlags.Public |
70: BindingFlags.Instance |
71: BindingFlags.InvokeMethod |
72: BindingFlags.FlattenHierarchy,
73: null,
74: new Type[] {typeof (string)}, null);
75:
76: //acl.Remove(username);
77: remove.Invoke(acl, new object[] { username });
78: }
79: else
80: {
81: // Modifying an existing user
82: aclEntry = new SharedServiceAccessControlEntry(username, rights);
83:
84: MethodInfo updateAccessControlEntry =
85: acl.GetType().GetMethod("UpdateAccessControlEntry",
86: BindingFlags.NonPublic |
87: BindingFlags.Public |
88: BindingFlags.Instance |
89: BindingFlags.InvokeMethod |
90: BindingFlags.FlattenHierarchy,
91: null,
92: new Type[] {typeof (SharedServiceAccessControlEntry)},
93: null);
94:
95: //acl.UpdateAccessControlEntry(username, aclEntry);
96: updateAccessControlEntry.Invoke(acl, new object[] {aclEntry});
97: }
98: }
99:
100: MethodInfo update =
101: acl.GetType().GetMethod("Update",
102: BindingFlags.NonPublic |
103: BindingFlags.Public |
104: BindingFlags.Instance |
105: BindingFlags.InvokeMethod |
106: BindingFlags.FlattenHierarchy,
107: null,
108: new Type[] {}, null);
109: // acl.Update();
110: update.Invoke(acl, null);
111:
112: return 1;
113: }
And just to show how much simpler this would have been if the classes were marked as public:
1: public override int Run(string command, StringDictionary keyValues, out string output)
2: {
3: output = string.Empty;
4:
5: InitParameters(keyValues);
6:
7: string sspname = Params["sspname"].Value;
8: string username = Params["user"].Value;
9: SharedServiceRights rights = GetUserRights(Params["rights"].Value.Split(','));
10:
11: ServerContext current = ServerContext.GetContext(sspname);
12:
13: SharedServiceAccessControlList acl = SharedServiceAccessControlList.GetInstance(current);
14: SharedServiceAccessControlEntry aclEntry = acl[username];
15:
16: if (aclEntry == null)
17: {
18: if (rights == SharedServiceRights.None)
19: {
20: output += "User does not currently have any rights assiged - nothing to do.";
21: return 0;
22: }
23:
24: // Adding a new user
25: aclEntry = new SharedServiceAccessControlEntry(username, rights);
26: acl.Add(aclEntry);
27: }
28: else
29: {
30: if (rights == SharedServiceRights.None)
31: {
32: // Remove an existing user
33: acl.Remove(username);
34: }
35: else
36: {
37: // Modifying an existing user
38: aclEntry = new SharedServiceAccessControlEntry(username, rights);
39: acl.UpdateAccessControlEntry(username, aclEntry);
40: }
41: }
42: acl.Update();
43:
44: return 1;
45: }
C:\>stsadm -help gl-setsspacl
stsadm -o gl-setsspacl
Set the personalization services permissions for an SSP. Specify 'None' for rights to remove an existing user.
Parameters:
-sspname <SSP name>
-rights <comma separated: All | None | CreatePersonalSite, ManageAnalytics, ManageAudiences, ManageUserProfiles, SetPermissions, UsePersonalFeatures>
-user <DOMAIN\name>
Note that the user parameter can refer to a group or a user. Here's an example of how to give a group all permissions:
If you wish to remove a user or group then simply specify "None" for the rights. You can specify multiple rights by comma separating the values:stsadm -o gl-setsspacl -sspname SSP1 -rights All -user "domain\group1"
stsadm -o gl-setsspacl -sspname SSP1 -rights "UsePersonalFeatures, CreatePersonalSite" -user "domain\group1"



17 comments:
Hi Gary,
Thanks for sharing this stuff it's great.
I am running into this error when running this extension.
Do you know what may be the issue?
C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN>stsa
dm -o setsspacl -sspname "Prod_SSP2" -rights none -user "NT AUTHORITY\Authenticated Users"
Exception has been thrown by the target of an invocation.
That error is actually just hiding the actual error - I need to wrap the code in a try/catch(TargetInvocationException) and throw the inner exception so you can see what the real error is. I have a build with this change made but I'm in the middle of something so I can't push it out at the moment without breaking another command. If you have a machine in which you can compile the code then just wrap the code in the try/catch - otherwise I'm hoping to have a build out today or tomorrow.
I've just pushed a new build out - if you try again with the latest you should be able to see the actual error message.
New build worked like a champ, thanks a bunch Gary.
There is so many great utilities here I really appreciate you sharing them.
I will be checking in from time to time to see if you add one to enhance the extendvsinwebfarm operation :)
Regards,
Dennis
Minor bug: if you enter an invalid SSP name, you get an "Object reference not set to an instance of an object" instead of a more specific error message.
p.s. Thanks for the fix to gl-createwebapp and the schedule audience recompilation commands.
Thanks for the feedback - I just fixed it locally and will try to get it out with the next build.
Unfortunately, whenever I attempt to run this command I get an error regarding attempting an unauthorized command.
The account under which context I am running the command is a member of the farm administrators group and has full control (via web app policy) over the SSP.
Any clue what is going on?
The SSP has it's own set of permissions you need to configure via the personalization services permissions link.
I thought the gl-setsspacl command was supposed to be setting the personalization services permissions. Are you saying I need to set the permissions before I can set the permissions?
If you are using the account that you used to create the SSP then you will have the rights you need to set the permissions. If not then you will need to grant your current user rights to manage permissions.
Gary
Can you please tell me where I can get or download this extension for adding/removing personalized permission for mysite?
You can find it on the downloads page.
What is the file name to download
Ani
I installed setsspacl command and tested with windows user name, it works perfectly.
But when I added with form based user, it give me error "The specified user ro group not found". It seems it wont support for formbased users, it support only windows based users?
Please confirm
Ani
I've not done any FBA testing so it's a good chance it won't work.
Hi Gary,
Thanks for this site, it is invaluable to any SharePoint deployment.
I am using the deployment batch files from your site, and I am running the install from start to finish using the SPAdmin account with the permissions you specify, and everything goes smoothly until I get to this command. Then I get this error.
Cannot open database "SharePoint_SSP1_Content" requested by the login. The login
failed.
Login failed for user MyDomain\SPAdmin'.
This user does not have any rights in that database (should it?), but I can update the SSP permissions through central admin with this account without any issues. I am using NTLM, not kerberos if it makes any difference.
Any thoughts? I can always do this step through the UI, but I'd hate to break a perfect streak of scripting everything [made possible with the help of this site]
mjcarrabine - I've seen this issue with SP2+ deployments and have not yet found a solution beyond just manually granting the rights and then rerunning the script from the point where it failed. Not sure if a CU fixes the issue or not as I haven't had time to look into it.
Post a Comment