Application to check cascade access rights for a particular user or anonymous user in SharePoint

Don’t you hate when you have access denied and you don’t know where it is coming from? It is even worse when it is related to anonymous access where a single detail can prevent a page from being rendered (IIS authentication, broken inheritance, you name it). The application will show the detailed cascade rights for anonymous, current user and given user for a given item in url. In the example below it will show all details from site to page item:

 

image

image

The output will look like it:

 

Object Type: File
**** Start Miscellaneous for Site https://rviana-moss-w28
IIS Allow Anonymous: [True]
IIS is impersonating: [False]
Zone: [Default]
Host Name: [rviana-moss-w28]
Write Locked: [False]
**** End Miscellaneous for Site
**** Start Miscellaneous for Web https://rviana-moss-w28
Web Allow Anonymous: [True]
Anonymous Access to Lists and Libraries: [On]
********* Start of List of Rights to anonymous in this web
Perm Mask - Hex: 1000031041 Binary 1000000000000000000110001000001000001
ViewListItems Hex [00000001] Binary [1]
ViewVersions Hex [00000040] Binary [1000000]
ViewFormPages Hex [00001000] Binary [1000000000000]
Open Hex [00010000] Binary [10000000000000000]
ViewPages Hex [00020000] Binary [100000000000000000]
UseClientIntegration Hex [1000000000] Binary [1000000000000000000000000000000000000]
FullMask Hex [1000031041] Binary [1000000000000000000110001000001000001]
********* End of List of Rights to anonymous in this web

********* Start of List of Rights for User CONTOSO\alanew
Perm Mask - Hex: 1b03c4312ef Binary 11011000000111100010000110001001011101111
ViewListItems Hex [00000001] Binary [1]
AddListItems Hex [00000002] Binary [10]
EditListItems Hex [00000004] Binary [100]
DeleteListItems Hex [00000008] Binary [1000]
OpenItems Hex [00000020] Binary [100000]
(... lines removed for space ...)
CreateAlerts Hex [8000000000] Binary [1000000000000000000000000000000000000000]
EditMyUserInfo Hex [10000000000] Binary [10000000000000000000000000000000000000000]
FullMask Hex [1b03c4312ef] Binary [11011000000111100010000110001001011101111]
********* End of List of Rights

********* Start of List of Rights for Current User CONTOSO\rviana
Perm Mask - Hex: 7fffffffffffffff Binary 111111111111111111111111111111111111111111111111111111111111111
ViewListItems Hex [00000001] Binary [1]
AddListItems Hex [00000002] Binary [10]
EditListItems Hex [00000004] Binary [100]
DeleteListItems Hex [00000008] Binary [1000]
(... lines removed for space ...)
EditMyUserInfo Hex [10000000000] Binary [10000000000000000000000000000000000000000]
EnumeratePermissions Hex [4000000000000000] Binary [100000000000000000000000000000000000000000000000000000000000000]
FullMask Hex [7fffffffffffffff] Binary [111111111111111111111111111111111111111111111111111111111111111]
********* End of List of Rights

**** End Miscellaneous for Web

**** Start Miscellaneous for List Pages at /Pages/Forms/AllItems.aspx
Access to Template List is Restricted : [False]
Users Access Limited to Items they Created: [False]
Anonymous can access : [True]
Everyone can view List : [False]
********* Start of List of Rights to anonymous in this List
Perm Mask - Hex: 1000031041 Binary 1000000000000000000110001000001000001
ViewListItems Hex [00000001] Binary [1]
ViewVersions Hex [00000040] Binary [1000000]
ViewFormPages Hex [00001000] Binary [1000000000000]
Open Hex [00010000] Binary [10000000000000000]
ViewPages Hex [00020000] Binary [100000000000000000]
UseClientIntegration Hex [1000000000] Binary [1000000000000000000000000000000000000]
FullMask Hex [1000031041] Binary [1000000000000000000110001000001000001]
********* End of List of Rights to anonymous in this List

********* Start of List of Rights for User CONTOSO\alanew
Perm Mask - Hex: 1b03c4312ef Binary 11011000000111100010000110001001011101111
ViewListItems Hex [00000001] Binary [1]
AddListItems Hex [00000002] Binary [10]
EditListItems Hex [00000004] Binary [100]
DeleteListItems Hex [00000008] Binary [1000]
OpenItems Hex [00000020] Binary [100000]
ViewVersions Hex [00000040] Binary [1000000]
(... lines removed for space ...)
EditMyUserInfo Hex [10000000000] Binary [10000000000000000000000000000000000000000]
FullMask Hex [1b03c4312ef] Binary [11011000000111100010000110001001011101111]
********* End of List of Rights

********* Start of List of Rights for Current User CONTOSO\rviana
Perm Mask - Hex: 7fffffffffffffff Binary 111111111111111111111111111111111111111111111111111111111111111
ViewListItems Hex [00000001] Binary [1]
AddListItems Hex [00000002] Binary [10]
(... lines removed for space ...)
EditMyUserInfo Hex [10000000000] Binary [10000000000000000000000000000000000000000]
EnumeratePermissions Hex [4000000000000000] Binary [100000000000000000000000000000000000000000000000000000000000000]
FullMask Hex [7fffffffffffffff] Binary [111111111111111111111111111111111111111111111111111111111111111]
********* End of List of Rights

**** End Miscellaneous for List

**** Start Miscelaneous for List Item default.aspx at Pages/default.aspx
Anonymous has access to list item : [True]
Permission Inheritance is broken : [False]
********* Start of List of Rights for User CONTOSO\alanew
Perm Mask - Hex: 1b03c4312ef Binary 11011000000111100010000110001001011101111
ViewListItems Hex [00000001] Binary [1]
AddListItems Hex [00000002] Binary [10]
EditListItems Hex [00000004] Binary [100]
(... lines removed for space ...)
UpdatePersonalWebParts Hex [20000000] Binary [100000000000000000000000000000]
UseClientIntegration Hex [1000000000] Binary [1000000000000000000000000000000000000]
UseRemoteAPIs Hex [2000000000] Binary [10000000000000000000000000000000000000]
CreateAlerts Hex [8000000000] Binary [1000000000000000000000000000000000000000]
EditMyUserInfo Hex [10000000000] Binary [10000000000000000000000000000000000000000]
FullMask Hex [1b03c4312ef] Binary [11011000000111100010000110001001011101111]
********* End of List of Rights

********* Start of List of Rights for Current User CONTOSO\rviana
Perm Mask - Hex: 7fffffffffffffff Binary 111111111111111111111111111111111111111111111111111111111111111
ViewListItems Hex [00000001] Binary [1]
AddListItems Hex [00000002] Binary [10]
EditListItems Hex [00000004] Binary [100]
(... lines removed for space ...)
EnumeratePermissions Hex [4000000000000000] Binary [100000000000000000000000000000000000000000000000000000000000000]
FullMask Hex [7fffffffffffffff] Binary [111111111111111111111111111111111111111111111111111111111111111]
********* End of List of Rights

********* Item Xml
<z:row xmlns:z='#RowsetSchema' ows_ContentTypeId='0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF390064DEA0F50FC8C147B0B6EA0636C4A7D400B86BB823B4EF734998C6CF97A89029EE' ows_FileLeafRef='1;#default.aspx' ows_Modified_x0020_By='SHAREPOINT\system' ows_File_x0020_Type='aspx' ows_Title='Search Center' ows_PublishingPageLayout='https://rviana-moss-w28/_catalogs/masterpage/searchmain.aspx, Search Page' ows_ContentType='Welcome Page' ows_ID='1' ows_Created='2010-10-22 20:43:50' ows_Author='1073741823;#System Account' ows_Modified='2010-10-22 20:43:50' ows_Editor='1073741823;#System Account' ows__ModerationStatus='0' ows_FileRef='1;#Pages/default.aspx' ows_FileDirRef='1;#Pages' ows_Last_x0020_Modified='1;#2010-10-22 20:43:50' ows_Created_x0020_Date='1;#2010-10-22 20:43:50' ows_File_x0020_Size='1;#739' ows_FSObjType='1;#0' ows_PermMask='0x7fffffffffffffff' ows_CheckedOutUserId='1;#' ows_IsCheckedoutToLocal='1;#0' ows_UniqueId='1;#{B9F29A82-3E82-4817-B8A5-77CED27512E8}' ows_ProgId='1;#' ows_ScopeId='1;#{037929C6-B73A-4F2B-BD14-07003EADB4CD}' ows_VirusStatus='1;#739' ows_CheckedOutTitle='1;#' ows__CheckinComment='1;#' ows__EditMenuTableStart='default.aspx' ows__EditMenuTableEnd='1' ows_LinkFilenameNoMenu='default.aspx' ows_LinkFilename='default.aspx' ows_DocIcon='aspx' ows_ServerUrl='/Pages/default.aspx' ows_EncodedAbsUrl='https://rviana-moss-w28/Pages/default.aspx' ows_BaseName='default' ows_FileSizeDisplay='739' ows_MetaInfo='1;#vti_modifiedby:SR|SHAREPOINT\\system
vti_parserversion:SR|12.0.0.6545
vti_cachedhastheme:BR|false
vti_cachedcustomprops:VX|ContentType vti_title PublishingPageLayout
ContentType:SW|Welcome Page
vti_title:SR|Search Center
vti_cachedtitle:SR|Search Center
vti_charset:SR|utf-8
ContentTypeId:SW|0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF390064DEA0F50FC8C147B0B6EA0636C4A7D400B86BB823B4EF734998C6CF97A89029EE
PublishingPageLayout:SW|/_catalogs/masterpage/searchmain.aspx, Search Page
vti_author:SR|
vti_setuppath:SX|SiteTemplates\\SRCHCEN\\default.aspx
vti_cachedneedsrewrite:BR|false
' ows__Level='1' ows__IsCurrentVersion='1' ows_SelectTitle='1' ows_SelectFilename='1' ows_Edit='0' ows_owshiddenversion='2' ows__UIVersion='512' ows__UIVersionString='1.0' ows_Order='100.000000000000' ows_GUID='{5FAA46F1-443E-4FF7-A60B-7A229EBD9C03}' ows_WorkflowVersion='1' ows_ParentVersionString='1;#' ows_ParentLeafName='1;#' ows_Combine='0' ows_RepairDocument='0' ows_ServerRedirected='0'/>

********* End of Item XML

********* Role Assignments Xml
<permissions><permission memberid='3' mask='9223372036854775807' />
<permission memberid='4' mask='756052856929' />
<permission memberid='5' mask='1856436900591' />
<permission memberid='6' mask='206292717568' />
<permission memberid='7' mask='1856438737919' />
<permission memberid='8' mask='4611688150860241903' />
<permission memberid='9' mask='1856436900863' />
<permission memberid='10' mask='206292848673' />
<permission memberid='11' mask='206292717568' />
<permission memberid='13' mask='756052856897' />
<permission memberid='1073741823' mask='206292717568' />
</permissions>
********* End of Role Assignments Xml

**** End Miscellaneous for List Item

*** File default.aspx content:

???<%@ Page Inherits="Microsoft.SharePoint.Publishing.TemplateRedirectionPage,Microsoft.SharePoint.Publishing,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" %> <%@ Reference VirtualPath="~TemplatePageUrl" %> <%@ Reference VirtualPath="~masterurl/custom.master" %>

<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"><head>

<!--[if gte mso 9]><xml>
<mso:CustomDocumentProperties>

<mso:ContentType msdt:dt="string">Welcome Page</mso:ContentType>

<mso:PublishingPageLayout msdt:dt="string">/_catalogs/masterpage/searchmain.aspx, Search Page</mso:PublishingPageLayout>

</mso:CustomDocumentProperties>
</xml><![endif]-->

<title>Search Center</title></head>

*** End File
*** Anonymous has rights on File default.aspx: [True]

 

The code core is below. The cascade walking class was based on Sanjay’s class defined at https://blogs.msdn.com/b/sanjaynarang/archive/2009/04/07/find-sharepoint-object-type-from-url.aspx .

You can download code and executable here: https://rodneyviana.codeplex.com/releases/view/19103

It works for SharePoint 2010 but you have to change the references and recompile using 14.x assemblies.

 

 

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Deployment;

namespace CheckEffectiveProperties
{
public class SPObjType
{
public Guid objectGuid;
public object obj;
public string url;
public string siteRelativeUrl;
public SPDeploymentObjectType objType;
public StringBuilder message = new StringBuilder(2000);
public SPBasePermissions currUserRights;
public SPBasePermissions testUser;
public SPBasePermissions anonymousMask;
public bool? isAnonymousEnabled = null;

       
public static string EnumeratePermission(SPBasePermissions Mask)
{
StringBuilder sb = new StringBuilder(100);
sb.AppendFormat("Perm Mask - Hex: {0} Binary {1}\n", ((ulong)Mask).ToString("x8"), Convert.ToString((Int64)Mask, 2));
foreach (string permName in Enum.GetNames(typeof(SPBasePermissions)))
{
ulong i = (ulong)Mask & (ulong)(Enum.Parse(typeof(SPBasePermissions), permName));
if (i > 0)
{
sb.Append(String.Format(" {0} Hex [{1}] Binary [{2}]\n", permName, i.ToString("x8"), Convert.ToString((Int64)i, 2)));
}
}
return sb.ToString();
}
public void GetFile(SPFile File, SPBasePermissions Mask)
{
try
{
byte[] binFile = File.OpenBinary();
ASCIIEncoding asc = new ASCIIEncoding();
string fileContent = asc.GetString(binFile);
message.AppendFormat("\n*** File {0} content:\n\n{1}\n\n", File.Name, fileContent);
message.Append("\n*** End File");
if (File.Item != null)
{
message.AppendFormat("\n*** Anonymous has rights on File {0}: [{1}]\n\n", File.Name, File.Item.DoesUserHavePermissions(Mask));
}
else
{
message.AppendFormat("\n*** Unable to test Anonymous rights on File {0}\n\n", File.Name);
}
}
catch (Exception ex)
{
message.AppendFormat("\n\n*************** Error opening file {0}: {1} ************\n\n", File.Name, ex.Message);

}

        }
}

    // The class below was originally created by Sanjay Narang to identify the object type from a URL
// The code for this intent is found here: https://blogs.msdn.com/b/sanjaynarang/archive/2009/04/07/find-sharepoint-object-type-from-url.aspx
    //
// It was modified to check properties and cascade access (Anonymous | Current User | GivenUser)
// for an object pointed by Rodney Viana
// You have to agree with this license to use this code/application: https://rodneyviana.codeplex.com/license
    // Details of the implementation can be found at: https://blogs.msdn.com/rodneyviana
    // This project can be downloaded at: https://rodneyviana.codeplex.com/releases/view/19103

    class SanjayMossUtilities
{
public SPObjType GetObjectTypeFromURL(string passedUrl, string User)
{
SPObjType oType = new SPObjType();
oType.objType = SPDeploymentObjectType.Invalid;

            oType.objectGuid = Guid.Empty;

            SPSite site = null;
SPWeb web = null;
SPList list = null;
oType.obj = null;
oType.url = null;
oType.siteRelativeUrl = null;
NameValueCollection queryParams = null;

            oType.url = GetModifiedUrl(passedUrl, out queryParams);

            try
{
site = new SPSite(oType.url);
oType.message.AppendFormat("**** Start Miscellaneous for Site {0}\n", site.Url);
oType.message.AppendFormat("IIS Allow Anonymous: [{0}]\n", site.IISAllowsAnonymous);
oType.message.AppendFormat("IIS is impersonating: [{0}]\n", site.Impersonating);
oType.message.AppendFormat("Zone: [{0}]\n", site.Zone.ToString());
oType.message.AppendFormat("Host Name: [{0}]\n", site.HostName);
oType.message.AppendFormat("Write Locked: [{0}]\n", site.WriteLocked);
oType.message.Append("**** End Miscellaneous for Site\n");

                web = site.OpenWeb();
oType.message.AppendFormat("**** Start Miscellaneous for Web {0}\n", web.Url);
oType.message.AppendFormat("Web Allow Anonymous: [{0}]\n", web.AllowAnonymousAccess);
oType.message.AppendFormat("Anonymous Access to Lists and Libraries: [{0}]\n", web.AnonymousState.ToString());
if (web.AllowAnonymousAccess)
{
oType.message.Append("********* Start of List of Rights to anonymous in this web\n");
oType.message.Append(SPObjType.EnumeratePermission(web.AnonymousPermMask64));
oType.message.Append("********* End of List of Rights to anonymous in this web\n\n");
}

                if (!String.IsNullOrEmpty(User))
{
oType.message.AppendFormat("********* Start of List of Rights for User {0}\n", User);
oType.message.Append(SPObjType.EnumeratePermission(web.GetUserEffectivePermissions(User)));
oType.message.Append("********* End of List of Rights\n\n");

                }
string curUser = Environment.UserDomainName + "\\" + Environment.UserName;
if (User.ToLower().Trim() != curUser.ToLower().Trim())
{
oType.message.AppendFormat("********* Start of List of Rights for Current User {0}\n", curUser);
oType.message.Append(SPObjType.EnumeratePermission(web.GetUserEffectivePermissions(curUser)));
oType.message.Append("********* End of List of Rights\n\n");
}
oType.message.Append("**** End Miscellaneous for Web\n\n");
               

                if (oType.url.Equals(site.Url, StringComparison.OrdinalIgnoreCase))
{
oType.objectGuid = site.ID;
oType.objType = SPDeploymentObjectType.Site;

return oType;
}

                if (oType.url.Equals(web.Url, StringComparison.OrdinalIgnoreCase))
{
oType.objectGuid = web.ID;
oType.objType = SPDeploymentObjectType.Web;
return oType;
}

                oType.siteRelativeUrl = oType.url.TrimStart(web.Url.ToCharArray());

                try
{
list = web.GetList(oType.url);
}
catch(Exception ex)
{
oType.message.AppendFormat("\n\n ******* Error trying to retrieve List : {0} ***** \n\n", ex.Message);
list = null;
}
     

                if (null != list )
{
oType.objectGuid = list.ID;
oType.objType = SPDeploymentObjectType.List;

                    oType.message.AppendFormat("**** Start Miscellaneous for List {0} at {1}\n", list.Title, list.DefaultViewUrl);
oType.message.AppendFormat("Access to Template List is Restricted : [{0}]\n", list.RestrictedTemplateList);
oType.message.AppendFormat("Users Access Limited to Items they Created: [{0}]\n", (list.ReadSecurity==2));
oType.message.AppendFormat("Anonymous can access : [{0}]\n", list.DoesUserHavePermissions(list.AnonymousPermMask64));
oType.message.AppendFormat("Everyone can view List : [{0}]\n", list.AllowEveryoneViewItems);

                    oType.message.Append("********* Start of List of Rights to anonymous in this List\n");
oType.message.Append(SPObjType.EnumeratePermission(list.AnonymousPermMask64));
oType.message.Append("********* End of List of Rights to anonymous in this List\n\n");

                    if (!String.IsNullOrEmpty(User))
{
oType.message.AppendFormat("********* Start of List of Rights for User {0}\n", User);
oType.message.Append(SPObjType.EnumeratePermission(list.GetUserEffectivePermissions(User)));
oType.message.Append("********* End of List of Rights\n\n");

                    }
if (User.ToLower().Trim() != curUser.ToLower().Trim())
{
oType.message.AppendFormat("********* Start of List of Rights for Current User {0}\n", curUser);
oType.message.Append(SPObjType.EnumeratePermission(list.GetUserEffectivePermissions(curUser)));
oType.message.Append("********* End of List of Rights\n\n");
}
oType.message.Append("**** End Miscellaneous for List\n\n");

                    if (oType.siteRelativeUrl.Equals(list.RootFolder.Url, StringComparison.OrdinalIgnoreCase))
{
return oType;
}
}

                // if we are here, it means URL is none of these:
// site, web, list
// So, it can be either file, folder or a list item.
// Finding that is intricated.

                oType.obj = web.GetObject(oType.url);

                if (null != oType.obj)
{
SPListItem item = (oType.obj as SPListItem);
if (item != null)
{
if (!String.IsNullOrEmpty(User))
{
oType.message.AppendFormat("**** Start Miscellaneous for List Item {0} at {1}\n", item.Name, item.Url);
oType.message.AppendFormat("Anonymous has access to list item : [{0}]\n", item.DoesUserHavePermissions( list.AnonymousPermMask64));
oType.message.AppendFormat("Permission Inheritance is broken : [{0}]\n", item.HasUniqueRoleAssignments);

                            // oType.message.Append(SPObjType.EnumeratePermission(web.AnonymousPermMask64));

                            oType.message.AppendFormat("********* Start of List of Rights for User {0}\n", User);
oType.message.Append(SPObjType.EnumeratePermission(item.GetUserEffectivePermissions(User)));
oType.message.Append("********* End of List of Rights\n\n");

                        }
if (User.ToLower().Trim() != curUser.ToLower().Trim())
{
oType.message.AppendFormat("********* Start of List of Rights for Current User {0}\n", curUser);
oType.message.Append(SPObjType.EnumeratePermission(item.GetUserEffectivePermissions(curUser)));
oType.message.Append("********* End of List of Rights\n\n");
}
oType.message.AppendFormat("********* Item Xml\n", curUser);
oType.message.AppendFormat("{0}\n", item.Xml);

                        oType.message.Append("********* End of Item XML\n\n");
oType.message.AppendFormat("********* Role Assignments Xml\n", curUser);
oType.message.AppendFormat("{0}\n", item.RoleAssignments.Xml);

                        oType.message.Append("********* End of Role Assignments Xml\n\n");

                        oType.message.Append("**** End Miscellaneous for List Item\n\n");

}
if (oType.obj is SPFile)
{
// Generally, we get here for Forms Pages,
// such as DispForm.aspx, AllItems.aspx
// so, a SPFile object could be a list item Or
// a folder in a list or a Folder

                        // Pages in root of the web are also returned as
// SPFiles e.g. https://moss/default.aspx

                        // The URLs that point to a file in doc lib are
// returned as SPListItem by GetObject method
//

                        SPFile file = oType.obj as SPFile;

                        if (null != queryParams)
{
// The logic to identify folder or item has
// been explained in ValidateQueryString
string idValue = queryParams["ID"];
string folderValue = queryParams["RootFolder"];
if (null != idValue)
{
item = list.GetItemById(int.Parse(idValue));
oType.objectGuid = item.UniqueId;
oType.objType = SPDeploymentObjectType.ListItem;
return oType;
}
else if (null != folderValue)
{
SPFolder folder = web.GetFolder(folderValue);
oType.objectGuid = folder.UniqueId;
oType.objType = SPDeploymentObjectType.Folder;
return oType;
}
else
{
// Deployyment Object Type is: Invalid, so no need
// to do anything
}
}
else
{
oType.objectGuid = file.UniqueId;
oType.objType = SPDeploymentObjectType.File;
oType.GetFile(file, web.AnonymousPermMask64);
return oType;
}
}
else if (oType.obj is SPFolder)
{
SPFolder folder = oType.obj as SPFolder;
oType.objectGuid = folder.UniqueId;
oType.objType = SPDeploymentObjectType.Folder;
return oType;
}
else if (oType.obj is SPListItem)
{

                        item = oType.obj as SPListItem;

                        // item can contain a folder of file also. e.g.
// https://moss.litwareinc.com/Documents/folderinlibrary
                        // https://moss.litwareinc.com/Documents/FolderInLibrary/File2.doc

                        if (null != item.Folder)
{
oType.objectGuid = item.Folder.UniqueId;
oType.objType = SPDeploymentObjectType.Folder;
return oType;
}
else if (null != item.File)
{
oType.objectGuid = item.File.UniqueId;
oType.objType = SPDeploymentObjectType.File;
oType.GetFile(item.File, web.AnonymousPermMask64);

                            return oType;
}

                        oType.objectGuid = item.UniqueId;
oType.objType = SPDeploymentObjectType.ListItem;
return oType;
}
}

            }
finally
{
if (web != null)
{
web.Dispose();
}
if (site != null)
{
site.Dispose();
}
}
return oType;
}

        private string GetModifiedUrl(string url, out NameValueCollection queryParams)
{
string modUrl = url; //modified url
string querystring = string.Empty;
queryParams = null;

            // if it's a site or web or folder, user can pass '/' at
// the end, which we need to trim
if (url.EndsWith("/"))
{
modUrl = url.TrimEnd(new char[] { '/' });
}

            // we need to get the URL without query string as it creates
// problem getting the parent folder
if (url.Contains("?"))
{

                int tmp = url.IndexOf("?");
modUrl = url.Substring(0, tmp);
querystring = url.Substring(tmp + 1);

                queryParams = HttpUtility.ParseQueryString(querystring);
// apply custom rules
ValidateQueryString(queryParams);
}

            return modUrl;
}

        private void ValidateQueryString(NameValueCollection queryParams)
{
// when there's query string in the URL, the URL can point to a
// list item (in a list) or a folder.
// For example if an item is a folder
// 'FolderInTasksList' the URL of item would look like this
// https://moss.litwareinc.com/Lists/Tasks/DispForm.aspx?ID=2&RootFolder=/Lists/Tasks/FolderInTasksList OR
// https://moss.litwareinc.com/Lists/Tasks/DispForm.aspx?ID=2&RootFolder=%2fLists%2fTasks%2fFolderInTasksList
            //
// And if we need Url of the folder, it would be like this:
// https://moss.litwareinc.com/Lists/Tasks/AllItems.aspx?RootFolder=%2fLists%2fTasks%2fFolderInTasksList&FolderCTID=&View=%7bD8E1251D%2d829B%2d4FCE%2d9127%2d5E4FC6E6A5C4%7d
            //
// From the above two examples, I'm applying the following
// rules on the query string
// 1. It can contain only these keys: ID, RootFolder, FolderCTID, View
// If there's any other key, i would treat that as invalid query string
//
// 2. ID and RootFolder should never be empty
// otherwise, raise exception here rather than hitting that later
//
// 3. the query string has to contain at least one of the following
// a. ID, b. RootFolder

            // Build a string collection with possible values. For comparison,
// we'll use lower case only
StringCollection strColl = new StringCollection();
strColl.Add("ID".ToLower());
strColl.Add("RootFolder".ToLower());
strColl.Add("FolderCTID".ToLower());
strColl.Add("View".ToLower());

            // Apply the Rules
bool hasID = false;
bool hasRootFolder = false;

            Console.WriteLine();
foreach (string str in queryParams.AllKeys)
{
// can be used for debugging
// Console.WriteLine("Name: " + str + " | Value: " + queryParams[str]);

                // Rule 1
if (!(strColl.Contains(str.ToLower())))
{
throw new ArgumentException("Invalid argument in passed query string");
}
// Rule 2
if (str.Equals("id", StringComparison.OrdinalIgnoreCase))
{
hasID = true;
if (queryParams[str].Equals(String.Empty))
{
throw new ArgumentException("Query string parameter \"" + str + "\" can not be empty.");
}
}
// Rule 2
if (str.Equals("rootfolder", StringComparison.OrdinalIgnoreCase))
{
hasRootFolder = true;
if (queryParams[str].Equals(String.Empty))
{
throw new ArgumentException("Query string parameter \"" + str + "\" can not be empty.");
}
}
}
// Rule 3
Console.WriteLine();
if (!(hasID || hasRootFolder))
{
throw new ArgumentException("Query string must have at least one parameter from these: ID and RootFolder");
}
}

    }
}