Sharepoint: How to programmatically manage SPFolder and SPListItem permissions - security

I want to know if I'm missing something.
Here's how I would do it:
For SPFolder I would change the associtaed item's permissions (SPFolder.Item).
So I suppose managing SPFolder permissions boils down to managing SPListItem permissions.
For SPListItem I would frist break role inheritance with SPListItem.BreakRoleInheritance() and then work with RoleAssignments collections adding and removing roles there.
I wonder if RoleAssignments is the only way to manage SPListItem's permissions (besides inheritance) and is there a way to manage individual permissions without roles.
There is also EffectiveBasePermissions property but I'm not sure.
So the question is
is there other ways (besides inheritance) to manage SPListItem permissions apart from the RoleAssignments collection?
#Edit: there's also AllRolesForCurrentUser, but I guess you can get the same info from the RoleAssignments property, so this one is just for convenience.
#Edit: As Flo notes in his answer there is a problem with setting
folder.ParentWeb.AllowUnsafeUpdates = true;
And using BreakRoleInheritance with argument of 'false' (i.e. without copying permissions of the parent object).
folder.Item.BreakRoleInheritance(false);
BreakRoleInheritance simply won't work on GET request as you'd expect after allowing unsafe updates. Presumably the method resets AllowUnsafeUpdates back to 'false'.
One workaround I know for this is to manually delete the inherited permissions after you BreakRoleInheritance(true), like this:
folder.Item.BreakRoleInheritance(false);
while(folder.Item.RoleAssignments.Count > 0) {
folder.Item.RoleAssignments.Remove(0);
}
Thanks!

You have it pretty much right. I believe that RoleAssignments are indeed the only mechanism for managing permissions directly. Here's a post that shows a quick example of how to do it. I also used these two posts when I did some more complicated things.

This post will be interessting, too, when working with the BreakRoleInheritance() method. It's about a problem you might run into when using BreakRoleInheritance(false).

Related

Liferay: How to get List of friendlyUrl using groupID

Is there any API where I can get All the friendlyURL related to particular groupID from group table.
Please help.
Precaution upfront: Do not think in terms of database: This will lead you to manipulating the database sooner or later, which is a recipe for disaster. Never manipulate the database.
That being said, you can use GroupLocalService (or GroupService) to obtain a Group object that has the method you're looking for. If you have a themeDisplay object where you are, e.g. in a portlet request handler, you can obtain the current group from it as well.

Extending AccessInfo to Include Roles

I'm looking to extend the base Singleton "AccessInfo" to include additional information pertaining to the current user (such as roles.)
Is there a most favorable path to do this? I can see how to extend a Graph, Cache, but not seeing any documentation how to extend this area.
Unfortunately due to the way it has been implemented, there is not a way to add fields to that DAC and have them populated on instantiation, and since it's not selected from the DB like a normal DAC, I do not think events would fire for it.
If you would like to access Roles related to the current Users, this should suffice.
PXSelect<UsersInRoles,
Where<UsersInRoles.userName, Equal<Current<AccessInfo.userName>>>>.Select(this /*Or Base if it's a Graph Extension*/);
As there will likely be multiple Roles per user, you will need to loop.
foreach (UsersInRoles role in PXSelect<UsersInRoles, Where<UsersInRoles.userName, Equal<Current<AccessInfo.userName>>>>.Select(this /*Or Base if it's a Graph Extension*/))
{
//Some thing here
}

instantiate SPSite and SPWeb objects

I want to know whats the best method of Instantiating SPSite and SPWeb objects . As there are no. of ways by which you can do this.Some of the ways I know
1.
SPSite mySite = SPControl.GetContextSite(Context);
SPWeb myWeb = SPControl.GetContextWeb(Context);
//Why we use second method as in first method there is no need to write the hardcoded url and also no need to dispose too as recommended by Microsoft.
2.
SPSite mySite=new SPSite("http://abc");
SPWeb myweb= mySite.RootWeb;
//Dispose
mySite.Dispose();
myweb.Dispose();
or difff. way of disposing for it by having using( )
/
3. Similar to first.. SPSite mySite = SPContext.Current.Site;
SPWeb myweb = SPContext.Current.Web;
Let me know if there is any other best approach or means out of these which should be the best approach to instantiate objects.....
Thanks,
You should do something like this:
using(SPSite oSPsite = new SPSite("http://server"))
{
using(SPWeb oSPWeb = oSPSite.OpenWeb())
{
// do stuff
}
}
You should also take a look into this: SharePoint Dispose Checker Tool, as it can inspect your code and to point where you're missing best practices.
EDIT: Yes, you can to use Context (and it's way I always do) but it shouldn't be used in some scenarios, like inside a SPSecurity.RunWithElevatedPrivileges. So, I recommend:
1 method for normal operations
2 for RunWithElevatedPrivileges and
3 should not be used, as it probably will mess your request if disposed.
Basically, creating a new SPSite object is "expensive" in terms of memory it requires. This is why you have to Dispose() them whenever you can - to free up resources you have taken.
So, whenever such method is available, you should call methods which use "singletons" built into SharePoint. For instance, in your 3rd example, you call SPContext.Current.Web. Internally (you can see it, if you load the code in Reflector) it stores a reference to the SPWeb object and returns you the same object, every time you call it. It means that different web controls in the same page use one single SPSite object and one SPWeb object. Your second example, however, creates a new SPSite object and that costs you 2Mb of memory (information taken from Robert Lamb's article).
In my opinion, the 1st and the 3rd method are equivalent. One of the methods calls the other one internally (I don't have access to microsoft.sharepoint.dll at the moment, so I cannot verify).
The 2nd example is different.
There is no one best way, it depends on what you're doing. If you're writing code where you know you have access to a current/implicit context such as a web part, option #1 is preferable. This "piggy backs" on the current context, is faster and saves resources. Rubens Farias' post offers some additional details regarding limitations.
Sometimes you don't have a current/implicit context such as in a command line utility. Sometimes you want to access objects outside of the current context such as in another web app. In these cases you are left with option #2 which spins up its own context.
I tend to view option #3 as a redundant and less expressive version of option #1. Someone else may be able to offer a compelling case for it's use but I have not run into it.
Both approaches (current vs. explicit context) work well and should be in your toolbox. The key is knowing why and how to employ one approach vs. another in a given situation.
Method 1 and 3 are equivalent. In fact SPContext (method 3) is using method 1 itself.
I prefer to use SPContext.Current because it gives a nice consistency when you also want to use SPContect.Current.List and so on which isn't available from SPControl
Method 2 is for use when you're not running your code inside the site in question so if you're creating a console/WPF app or an extension to stsadm.
If you need to run with elevated privileges then use the variant of method 2 with Guid and SPUserToken as parameters
To sum it all up my recommendation is: Use method 3 if you can and method 2 when you need to

Clean document roles in a Doc Library

I have been developing an event handler to clean up the RolesAssignments of the new item of a document library in MOSS. I’ve searched for a method that could clean all the RolesAssignments efficiently, although the best way I found seams to be loop through the RolesAssignments and delete one by one? Is there another way to clean all the RolesAssignments for an item?
The code I’m using for cleaning the RolesAssignments look like this:
for (int i = ListItem.RoleAssignments.Count - 1; i >= 0; --i)
{
ListItem.RoleAssignments.Remove(i);
}
Does anyone have any ideas on how to deal with this?
The example you've given within the body of your question is the most correct way to do this. ResetRoleInheritance and BreakRoleInheritance may do what you need, but this is the side-effect of the operations they perform. Their purpose is not to remove RoleAssignments, but rather operate on role inheritance. From MSDN:
ResetRoleInheritance - "Removes the local role assignments and reverts to role assignments from the parent object."
BreakRoleInheritance - "Creates unique role assignments for the item rather than inheriting them from a parent."
If role inheritance is already broken and you are using specific role assignments, you should remove them using a loop as you have in your question.
I have the answer, put the propertie SPListItem.BreakRoleInheritance(false) to break the role inheritance and remove the role assignments.
How about ResetRoleInheritance? This should clear out all of the RoleAssignments.

Regarding MOSS or WSS 3.0, What parts of the API might have been implemented better?

Such as:
Sealed Methods you might have liked to extend
Exceptions thrown are more vague than is helpful
Elimination of Connected Content which was a major feature in MCMS 2002
HTML is stripped from fields when stored and returned. No easy option to work around this problem
Creating an SPWeb takes an eternity.
Nonexistant migration path from MCMC 2002
I wish that the Sharepoint object model was purely managed code. Although having .NET wrappers is convenient, having to worry about disposing the many objects that implement IDisposable is a pain. It's so easy to run into memory issues when dispose does not get called in a WSS app. And I thought the reason for moving to .NET was to free developers from having to deal with memory management...
How about refactoring Properties that result in additional database calls to methods instead, for example the Items property on SPList.
Any of the SPList API could use a complete rewrite. Trying to deal with libraries with nested folders is a complete nightmare with the list being completely flattened with no obvious hierarchical structure.
Another wonderful addition would be adding interfaces to SPWeb, SPList and other Sharepoint classes to aid testing.
Has anyone seen this method:
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spsecurity.runwithelevatedprivileges.aspx This method shows the unbelievable nonsense that Sharepoint exposes to developers.
My personal favourite is the SPField.GetFieldValue Method. I have no idea why they designed it the way they did, but to me it does hardly make sense. To get a object out of a ListItem you have to do somethine like:
SPField field = ((SPList)list).Fields.GetField("FieldName");
object fieldValue = field.GetFieldValue(((SPListItem)item)[field.Title].ToString());
Getting an object out of a ListItem is IMO a basic operation, so this should not be that complicated.
Inconsistencies when passing field names to methods or arrays. For example:
SPFieldCollection.ContainsField(): Internal name or display name
SPFieldCollection.GetField(): Internal name or display name
SPFieldCollection.GetFieldByInternalName(): Internal name
SPFieldCollection.Item: Display name
SPListItem.Item: Internal name or display name
SPListItem.GetFormattedValue(): Internal name or display name
SPViewFieldCollection.Exists: Internal name
To put the icing on the cake, there is usually no documentation about whether a method takes internal and/or display name.

Resources