IIS WebDav hosting using IIS Manager Users to authentication

Enabling IIS WebDav functionality by using IIS Manager Users

Setting up IIS WebDav functionality is pretty trivial if one to rely on Windows user accounts for authentication but this architecture causing massive issues, namely:

  1. Accounts have to be precreated in Windows and are in fact real Windows accounts with permissions through system. I frequently see people while troubleshooting WebDav authentication issues adding those users to various group (in addition to default Users group) including Administrators account.
  2. It’s difficult to maintain since those users accounts are specific to machine where they live and hence not trivial to extend setup to several servers without keeping all accounts in sync.
Instead we can rely on IIS Manager to store and maintain users which was designed to allow hosting providers to provide remote IIS management functionality to customers. This setup remove all the drawbacks of using Windows users as authentication provider. It’s easily scalable (since IIS shared configuration can be used) and do not provide any sort of access to underlying operating system.
Solution consists of 2 DSC scripts below. Instead of using UI to set this up DSC was chosen since it’s easily replicated at scale and provide reproducible and consistent behavior.
Prerequisites.ps1 which performs following:
  1. Install basic IIS features
  2. Enabled remote management to enable IIS Manager User features
  3. Install Nuget and chocolatey providers to pull required DSC resources to create website and manipulate NTFS permissions

Startup.ps1 which performs following:

  1. Enables WebDav and neccessary features
  2. Configured IIS Manager to accept both Windows and IIS Manager credentials
  3. Modifies permissions to allow IIS_IUSRS users to read configuration file
  4. Creates website and bindings it to default ports
  5. Create IIS manager users with the password
  6. Modifies IIS configuration to allow WebDav publishing based off IIS Manager credentials provider
  7. Assigns WebDav permissions to newly created users to access website

Prerequisites.ps1

Configuration BasicIIS
{
Import-DscResource ModuleName 'PSDesiredStateConfiguration'
node localhost {
WindowsFeature IIS
{
Ensure = "Present"
Name = "Web-Mgmt-Service"
}
WindowsFeature WebRequest-Monitor
{
Ensure = "Present"
Name = "Web-Request-Monitor"
}
Service WebManagementService
{
Name = "WMSVC"
StartupType = "Automatic"
State = "Running"
DependsOn = "[WindowsFeature]IIS"
}
WindowsFeature WebMgmtConsole
{
Ensure = "Present"
Name = "Web-Mgmt-Console"
}
Registry RemoteManagement
{
Key = "HKLM:\SOFTWARE\Microsoft\WebManagement\Server"
ValueName = "EnableRemoteManagement"
ValueData = 1
ValueType = "Dword"
DependsOn = "[WindowsFeature]IIS"
}
Script NugetPackageProvider
{
SetScript = {Install-PackageProvider Name NuGet MinimumVersion 2.8.5.201 Force}
TestScript = {if ((Get-PackageProvider listavailable name nuget erroraction SilentlyContinue).Count -eq 0) {return $false
} else {return $true
}}
GetScript = {@{Result = "true"}}
}
Script ChocolateyPackageProvider
{
SetScript = {Register-PackageSource Name chocolatey ProviderName Chocolatey Location http://chocolatey.org/api/v2/ force}
TestScript = {if ((Get-PackageProvider listavailable name Chocolatey erroraction SilentlyContinue).Count -eq 0) {return $false
} else {return $true}}
GetScript = {@{Result = "true"}}
}
Script xWebAdministration
{
SetScript = {Install-Module xWebAdministration}
TestScript = {if ((get-module xwebadminstration ListAvailable).Count -eq 0){return $false
}else {return $true
}}
GetScript = {@{Result = "true"}}
DependsOn = "[Script]NugetPackageProvider"
}
Script cNtfsAccessControl
{
SetScript = {Install-Module cNtfsAccessControl}
TestScript = {if ((get-module cNtfsAccessControl ListAvailable).Count -eq 0){return $false
}else {return $true
}}
GetScript = {@{Result = "true"}}
DependsOn = "[Script]NugetPackageProvider"
}
}
}
BasicIIS OutputPath .\BasicIIS
Start-DscConfiguration Wait Verbose Path .\BasicIIS Force

view raw
PreRequisites.ps1
hosted with ❤ by GitHub

Startup.ps1

Configuration IIS {
# SSL Thumbprint to bind
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string] $sslThumbprint
)
Import-DscResource ModuleName "PSDesiredStateConfiguration"
Import-DSCResource moduleName "xWebAdministration", "cNtfsAccessControl"
node localhost {
WindowsFeature WebDAVPublishing {
Ensure = "Present"
Name = "Web-DAV-Publishing"
IncludeAllSubFeature = $true
}
WindowsFeature WebNetExt45 {
Ensure = "Present"
Name = "Web-Net-Ext45"
IncludeAllSubFeature = $true
}
Service WebManagementService {
Name = "WMSVC"
StartupType = "Automatic"
State = "Running"
DependsOn = "[Registry]EnableIISManagerAuthentication"
}
Registry EnableIISManagerAuthentication {
Key = "HKLM:\SOFTWARE\Microsoft\WebManagement\Server"
ValueName = "RequiresWindowsCredentials"
ValueData = 0
ValueType = "Dword"
}
cNtfsPermissionEntry 'FilePermissionDirectory' {
Ensure = 'Present'
Principal = 'builtin\IIS_IUSRS'
Path = 'C:\Windows\System32\inetsrv\config'
ItemType = 'Directory'
AccessControlInformation = @(
cNtfsAccessControlInformation {
AccessControlType = 'Allow'
FileSystemRights = 'Read'
Inheritance = 'ThisFolderOnly'
#NoPropagateInherit = $true
}
)
}
cNtfsPermissionEntry 'FilePermissionGetClean' {
Ensure = 'Present'
Principal = 'builtin\IIS_IUSRS'
Path = 'C:\inetpub\wwwroot\getclean\'
ItemType = 'Directory'
AccessControlInformation = @(
cNtfsAccessControlInformation {
AccessControlType = 'Allow'
FileSystemRights = 'Modify'
}
)
}
cNtfsPermissionEntry 'FilePermissionFiles' {
Ensure = 'Present'
Principal = 'builtin\IIS_IUSRS'
Path = 'C:\Windows\System32\inetsrv\config\administration.config'
ItemType = 'File'
AccessControlInformation = @(
cNtfsAccessControlInformation {
AccessControlType = 'Allow'
FileSystemRights = 'Read'
Inheritance = 'None'
#NoPropagateInherit = $true
}
)
}
cNtfsPermissionEntry 'FilePermissionFiles1' {
Ensure = 'Present'
Principal = 'builtin\IIS_IUSRS'
Path = 'C:\Windows\System32\inetsrv\config\redirection.config'
ItemType = 'File'
AccessControlInformation = @(
cNtfsAccessControlInformation {
AccessControlType = 'Allow'
FileSystemRights = 'Read'
Inheritance = 'None'
#NoPropagateInherit = $true
}
)
}
xWebsite RemoveDefaultWebsite {
Name ="Default Web Site"
Ensure = 'Absent'
}
File GetCleanFolder {
Type= 'Directory'
DestinationPath = "C:\inetpub\wwwroot\getclean"
Ensure = 'Present'
}
xWebSite GetClean {
Name="GetClean"
State ='Started'
Ensure = "Present"
PhysicalPath = "C:\inetpub\wwwroot\GetClean"
BindingInfo = @(
MSFT_xWebBindingInformation {
Protocol = 'HTTP'
Port = '80'
IPAddress = '*'
};
MSFT_xWebBindingInformation {
Protocol = 'HTTPS'
Port = '443'
CertificateThumbprint = $sslThumbprint
CertificateStoreName = 'My'
IPAddress = '*'
})
}
}
}
$iisusers = @{"username" = "password"}
IIS sslThumbprint (Get-ChildItem Cert:\LocalMachine\My\)[0].Thumbprint Outputpath (Join-Path $PSScriptRoot "BasicIIS")
Start-DscConfiguration Wait Verbose Path (Join-Path $PSScriptRoot "BasicIIS") Force
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Management") | Out-Null
foreach ($user in $IISusers.Keys){
[Microsoft.Web.Management.Server.ManagementAuthentication]::CreateUser($user, $IISusers[$user])
}
Set-WebConfigurationProperty pspath 'MACHINE/WEBROOT/APPHOST' location 'GetClean' filter "system.webServer/webdav/authoring" name "enabled" value "True"
Add-WebConfigurationProperty pspath 'MACHINE/WEBROOT/APPHOST' filter "system.webServer/modules" name "." value @{name='IISManagerAuthentication';type='Microsoft.Web.Management.Server.WebManagementBasicAuthenticationModule, Microsoft.Web.Management, Version=7.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'}
Set-WebConfigurationProperty pspath 'MACHINE/WEBROOT/APPHOST' filter "system.webServer/modules" name "runManagedModulesForWebDavRequests" value "True"
foreach ($user in $IISusers.Keys){
Add-WebConfigurationProperty pspath 'MACHINE/WEBROOT/APPHOST' location 'GetClean' filter "system.webServer/webdav/authoringRules" name "." value @{users="$user";path='*';access='Read,Write'}
}

view raw
startup.ps1
hosted with ❤ by GitHub

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s