I recently had a shared hosting provider customer contact me
about a problem with non-administrators deploying using Web Deploy. The
specific issue he was running into was that the deployment would work if the
user deployed to a sub-application (e.g. mywebsite/myapp) but not if he
deployed to the root of the site (e.g. mywebsite). I want to walk through how
to debug issues with Web Deploy delegation rules.
First things first โ let's take some steps to make debugging
easier. Read here about how to enable Web Management Service (wmsvc)
tracing โ you can read about IIS tracing in general here. Don't forget to
restart wmsvc once you enable tracing! This will start recording all sorts
of useful information every time a request comes to wmsvc.
Once the customer did that, I looked at his tracing logs
files. I generally search for the names of common Web Deploy providers, such as
createApp, setAcl and recycleApp, that require non-standard permissions. Sure
enough, I found the culprit:
<EventData>
<Data Name="ContextId">{00000000-0000-0000-517F-0080020000F6}</Data>
<Data Name="Uri">/msdeploy.axd</Data>
<Data Name="eventData">Tracing
deployment agent exception. Request ID ''. Request Timestamp: '09/23/2010 18:47:04'. Error Details:
System.UnauthorizedAccessException: Attempted to perform an unauthorized
operation.
at
System.Security.AccessControl.Win32.SetSecurityInfo(ResourceType type, String
name, SafeHandle handle, SecurityInfos securityInformation, SecurityIdentifier
owner, SecurityIdentifier group, GenericAcl sacl, GenericAcl dacl)
at System.Security.AccessControl.NativeObjectSecurity.Persist(String
name, SafeHandle handle, AccessControlSections includeSections, Object
exceptionContext)
at
System.Security.AccessControl.NativeObjectSecurity.Persist(String name,
AccessControlSections includeSections, Object exceptionContext)
at
Microsoft.Web.Deployment.FileSystemSecurityEx.Persist(String path)
at
Microsoft.Web.Deployment.SetAclProvider.Add(DeploymentObject source, Boolean
whatIf)
at
Microsoft.Web.Deployment.DeploymentObject.Update(DeploymentObject source,
DeploymentSyncContext syncContext)
at
Microsoft.Web.Deployment.DeploymentSyncContext.HandleUpdate(DeploymentObject
destObject, DeploymentObject sourceObject)
at
Microsoft.Web.Deployment.DeploymentSyncContext.SyncChildrenOrder(DeploymentObject
dest, DeploymentObject source)
at
Microsoft.Web.Deployment.DeploymentSyncContext.ProcessSync(DeploymentObject
destinationObject, DeploymentObject sourceObject)
at
System.Security.AccessControl.Win32.SetSecurityInfo(ResourceType type, String
name, SafeHandle handle, SecurityInfos securityInformation, SecurityIdentifier
owner, SecurityIdentifier group, GenericAcl sacl, GenericAcl dacl)
at System.Security.AccessControl.NativeObjectSecurity.Persist(String
name, SafeHandle handle, AccessControlSections includeSections, Object
exceptionContext)
at
System.Security.AccessControl.NativeObjectSecurity.Persist(String name,
AccessControlSections includeSections, Object exceptionContext)
at
Microsoft.Web.Deployment.FileSystemSecurityEx.Persist(String path)
at
Microsoft.Web.Deployment.SetAclProvider.Add(DeploymentObject source, Boolean
whatIf)
at
Microsoft.Web.Deployment.DeploymentObject.Update(DeploymentObject source,
DeploymentSyncContext syncContext)
at
Microsoft.Web.Deployment.DeploymentSyncContext.HandleUpdate(DeploymentObject
destObject, DeploymentObject sourceObject)
at
Microsoft.Web.Deployment.DeploymentSyncContext.SyncChildrenOrder(DeploymentObject
dest, DeploymentObject source)
at
Microsoft.Web.Deployment.DeploymentSyncContext.ProcessSync(DeploymentObject
destinationObject, DeploymentObject sourceObject)
at
Microsoft.Web.Deployment.DeploymentObject.SyncToInternal(DeploymentObject
destObject, DeploymentSyncOptions syncOptions, PayloadTable payloadTable,
ContentRootTable contentRootTable)
at
Microsoft.Web.Deployment.DeploymentAgent.HandleSync(DeploymentAgentWorkerRequest
workerRequest)</Data>
</EventData> at
Microsoft.Web.Deployment.DeploymentObject.SyncToInternal(DeploymentObject
destObject, DeploymentSyncOptions syncOptions, PayloadTable payloadTable,
ContentRootTable contentRootTable)
at
Microsoft.Web.Deployment.DeploymentAgent.HandleSync(DeploymentAgentWorkerRequest
workerRequest)</Data>
</EventData>
Notice that one of the lines mentions the SetAclProvider.
This told me that Web Deploy was failing to set file system permissions. I then
asked him for the output of icacls.exe on the folder where the website's files
are stored. I saw something like this:
C:UsersAdministrator>icacls
C:hostingspacesfoobarfoobar.comwwwroot
C:hostingspacesfoobarfoobar.comwwwroot NT AUTHORITYSYSTEM:(OI)(CI)
BUILTINAdministrators:(OI)
machinesomeuser:(OI)(CI)(R)
machinesomeuser:(OI)(CI)(M)
machinesomeuser:(OI)(CI)(RX)
Successfully processed 1 files; Failed processing 0 files
From this, I can tell that the customer hasn't given the
local user account (someuser) Full Control over the wwwroot directory. SetAcl
is failing because Modify permissions are not enough to change the permissions
on a directory, they're just enough to set permissions on child objects (such
as sub-folders and files underneath the directory). Giving this user Full
Control fixed the problem!
I hope this blog post helps you debug Web Deploy delegated
deployments.