Monday, June 30, 2008

MOSS 2007 : Access Denied exception even when using SPSecurity.RunWithElevatedPrivileges Method

Problem :

if you implement my previous post which is MOSS 2007 : Implement Task - Task Activities (Parent-Child Relationship) on the same List and after attach the mentioned list event handler on ItemAdded, you will get an "Access Denied Exception" if the current loged in user is not one of the MOSS site's owners (if he is not included in the site's owners group) even if you use SPSecurity.RunWithElevatedPrivileges WSS 3.0 API Method. let me show you the code.

//////////////////////////////////////////////////////////////////////////

public override void ItemAdded(SPItemEventProperties properties)
{
using (SPWeb web = properties.OpenWeb())//Open the web you want to use
{
SPContentType TaskCT = web.ContentTypes["TaskCT"];

if (TaskCT != null)
{
// Check if the Added Item Belongs to Task Content T ype
if (properties.ListItem.ContentType.Name == TaskCT .Name)
{
SPList TaskList = web.Lists[properties.ListId];

// Get folder in the list and a content type.
SPFolder TaskFolder = TaskList .RootFolder.SubFolders[properties.AfterProperties["Title"].ToString()];
SPContentType TaskActivityCT = TaskList .ContentTypes["TaskActivityCT"];
List contentTypes = new List();
contentTypes.Add(TaskActivityCT);

// Set the content type order for the Task Folder and update
TaskFolder.UniqueContentTypeOrder = contentTypes;
TaskFolder.Update(); // The Exception Will Occur Here (Access Denied)
}
}
}
}

//////////////////////////////////////////////////////////////////////////


The above code will generate an exception TaskFolder.Update(); line which marked with red color. why?

Becos as we said, the loged in user is not a member of the site's owner group.

What we can do?? do I have to use SPSecurity.RunWithElevatedPrivileges Method that will Execute my method with Full Control rights even if the user does not have?

Solution:

if you use SPSecurity.RunWithElevatedPrivileges method with the above code, the exception will still raising again and again when your code executed by a normal user (not site owner) ! that will make me lose my mind!!! why ?

lets try it

//////////////////////////////////////////////////////////////////////////

public override void ItemAdded(SPItemEventProperties properties)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{

using (SPWeb web = properties.OpenWeb())//Open the web you want to use
{
SPContentType TaskCT = web.ContentTypes["TaskCT"];

if (TaskCT != null)
{
// Check if the Added Item Belongs to Task Content T ype
if (properties.ListItem.ContentType.Name == TaskCT .Name)
{
SPList TaskList = web.Lists[properties.ListId];

// Get folder in the list and a content type.
SPFolder TaskFolder = TaskList .RootFolder.SubFolders[properties.AfterProperties["Title"].ToString()];
SPContentType TaskActivityCT = TaskList .ContentTypes["TaskActivityCT"];
List contentTypes = new List();
contentTypes.Add(TaskActivityCT);

// Set the content type order for the Task Folder and update
TaskFolder.UniqueContentTypeOrder = contentTypes;
TaskFolder.Update(); // The Exception Will Occur Here (Access Denied)
}
}
}

});
}

//////////////////////////////////////////////////////////////////////////
we will take now about the reason, why we still get that exception even after using SPSecurity.RunWithElevatedPrivileges method.

from the above code we are using properties.OpenWeb() Method which returns SPWeb object that refer to the current web which our code execute in, but that object was created in a context of a non-administrative user. lets solve it now :


//////////////////////////////////////////////////////////////////////////

public override void ItemAdded(SPItemEventProperties properties)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{

SPWeb webInContext = properties.OpenWeb();
SPSite siteInContext = webInContext.Site;
Guid _webGuid = webInContext.ID;
Guid _siteGuid = siteInContext.ID;

using (SPSite site = new SPSite(_siteGuid))
{
using (SPWeb web = site.OpenWeb(_webGuid ) )//Open the web you want to use
{
SPContentType TaskCT = web.ContentTypes["TaskCT"];

if (TaskCT != null)
{
// Check if the Added Item Belongs to Task Content T ype
if (properties.ListItem.ContentType.Name == TaskCT .Name)
{
SPList TaskList = web.Lists[properties.ListId];

// Get folder in the list and a content type.
SPFolder TaskFolder = TaskList .RootFolder.SubFolders[properties.AfterProperties["Title"].ToString()];
SPContentType TaskActivityCT = TaskList .ContentTypes["TaskActivityCT"];
List contentTypes = new List();
contentTypes.Add(TaskActivityCT);

// Set the content type order for the Task Folder and update
TaskFolder.UniqueContentTypeOrder = contentTypes;
TaskFolder.Update(); // The Exception was gone :)
}
}
}

}
});
}

//////////////////////////////////////////////////////////////////////////

in this way, the SPWeb is created in a context of an administrative user( site.OpenWeb(_webGuid ) )

enjoy :) and don't forget to include a reference to System.Configuration namspace to have the Guid available.

Thanks,
Mohammed Barakat Kharboush

1 comment:

Anonymous said...

Create a new object SPWeb !!
That works for me ;-)

Thanks Mo!