From a2e938efc38fe8cd21e4f796f3f1744bec2920a7 Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Fri, 6 Mar 2020 07:14:49 +1000 Subject: [PATCH 01/10] Initial commit --- plugins/modules/win_iis_webbinding.ps1 | 377 ++++++++++++++ plugins/modules/win_iis_webbinding.py | 152 ++++++ plugins/modules/win_iis_website.ps1 | 180 +++++++ plugins/modules/win_iis_website.py | 119 +++++ .../targets/win_iis_webbinding/aliases | 1 + .../win_iis_webbinding/defaults/main.yml | 30 ++ .../library/test_get_webbindings.ps1 | 113 +++++ .../win_iis_webbinding/tasks/failures.yml | 70 +++ .../targets/win_iis_webbinding/tasks/http.yml | 317 ++++++++++++ .../win_iis_webbinding/tasks/https-ge6.2.yml | 459 ++++++++++++++++++ .../win_iis_webbinding/tasks/https-lt6.2.yml | 423 ++++++++++++++++ .../targets/win_iis_webbinding/tasks/main.yml | 62 +++ .../win_iis_webbinding/tasks/setup.yml | 93 ++++ 13 files changed, 2396 insertions(+) create mode 100644 plugins/modules/win_iis_webbinding.ps1 create mode 100644 plugins/modules/win_iis_webbinding.py create mode 100644 plugins/modules/win_iis_website.ps1 create mode 100644 plugins/modules/win_iis_website.py create mode 100644 tests/integration/targets/win_iis_webbinding/aliases create mode 100644 tests/integration/targets/win_iis_webbinding/defaults/main.yml create mode 100644 tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 create mode 100644 tests/integration/targets/win_iis_webbinding/tasks/failures.yml create mode 100644 tests/integration/targets/win_iis_webbinding/tasks/http.yml create mode 100644 tests/integration/targets/win_iis_webbinding/tasks/https-ge6.2.yml create mode 100644 tests/integration/targets/win_iis_webbinding/tasks/https-lt6.2.yml create mode 100644 tests/integration/targets/win_iis_webbinding/tasks/main.yml create mode 100644 tests/integration/targets/win_iis_webbinding/tasks/setup.yml diff --git a/plugins/modules/win_iis_webbinding.ps1 b/plugins/modules/win_iis_webbinding.ps1 new file mode 100644 index 0000000..ffbd186 --- /dev/null +++ b/plugins/modules/win_iis_webbinding.ps1 @@ -0,0 +1,377 @@ +#!powershell + +# Copyright: (c) 2017, Noah Sparks +# Copyright: (c) 2015, Henrik Wallström +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#Requires -Module Ansible.ModuleUtils.Legacy + +$params = Parse-Args -arguments $args -supports_check_mode $true +$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false + +$name = Get-AnsibleParam $params -name "name" -type str -failifempty $true -aliases 'website' +$state = Get-AnsibleParam $params "state" -default "present" -validateSet "present","absent" +$host_header = Get-AnsibleParam $params -name "host_header" -type str +$protocol = Get-AnsibleParam $params -name "protocol" -type str -default 'http' +$port = Get-AnsibleParam $params -name "port" -default '80' +$ip = Get-AnsibleParam $params -name "ip" -default '*' +$certificateHash = Get-AnsibleParam $params -name "certificate_hash" -type str -default ([string]::Empty) +$certificateStoreName = Get-AnsibleParam $params -name "certificate_store_name" -type str -default ([string]::Empty) +$sslFlags = Get-AnsibleParam $params -name "ssl_flags" -default '0' -ValidateSet '0','1','2','3' + +$result = @{ + changed = $false +} + +################# +### Functions ### +################# +function Create-BindingInfo { + $ht = @{ + 'bindingInformation' = $args[0].bindingInformation + 'ip' = $args[0].bindingInformation.split(':')[0] + 'port' = [int]$args[0].bindingInformation.split(':')[1] + 'hostheader' = $args[0].bindingInformation.split(':')[2] + #'isDsMapperEnabled' = $args[0].isDsMapperEnabled + 'protocol' = $args[0].protocol + 'certificateStoreName' = $args[0].certificateStoreName + 'certificateHash' = $args[0].certificateHash + } + + #handle sslflag support + If ([version][System.Environment]::OSVersion.Version -lt [version]'6.2') + { + $ht.sslFlags = 'not supported' + } + Else + { + $ht.sslFlags = [int]$args[0].sslFlags + } + + Return $ht +} + +# Used instead of get-webbinding to ensure we always return a single binding +# We can't filter properly with get-webbinding...ex get-webbinding ip * returns all bindings +# pass it $binding_parameters hashtable +function Get-SingleWebBinding { + + Try { + $site_bindings = get-webbinding -name $args[0].name + } + Catch { + # 2k8r2 throws this error when you run get-webbinding with no bindings in iis + If (-not $_.Exception.Message.CompareTo('Cannot process argument because the value of argument "obj" is null. Change the value of argument "obj" to a non-null value')) + { + Throw $_.Exception.Message + } + Else { return } + } + + Foreach ($binding in $site_bindings) + { + $splits = $binding.bindingInformation -split ':' + + if ( + $args[0].protocol -eq $binding.protocol -and + $args[0].ipaddress -eq $splits[0] -and + $args[0].port -eq $splits[1] -and + $args[0].hostheader -eq $splits[2] + ) + { + Return $binding + } + } +} + + +############################# +### Pre-Action Validation ### +############################# +$os_version = [version][System.Environment]::OSVersion.Version + +# Ensure WebAdministration module is loaded +If ($os_version -lt [version]'6.1') +{ + Try { + Add-PSSnapin WebAdministration + } + Catch { + Fail-Json -obj $result -message "The WebAdministration snap-in is not present. Please make sure it is installed." + } +} +Else +{ + Try { + Import-Module WebAdministration + } + Catch { + Fail-Json -obj $result -message "Failed to load WebAdministration module. Is IIS installed? $($_.Exception.Message)" + } +} + +# ensure website targetted exists. -Name filter doesn't work on 2k8r2 so do where-object instead +$website_check = get-website | Where-Object {$_.name -eq $name} +If (-not $website_check) +{ + Fail-Json -obj $result -message "Unable to retrieve website with name $Name. Make sure the website name is valid and exists." +} + +# if OS older than 2012 (6.2) and ssl flags are set, fail. Otherwise toggle sni_support +If ($os_version -lt [version]'6.2') +{ + If ($sslFlags -ne 0) + { + Fail-Json -obj $result -message "SNI and Certificate Store support is not available for systems older than 2012 (6.2)" + } + $sni_support = $false #will cause the sslflags check later to skip +} +Else +{ + $sni_support = $true +} + +# make sure ssl flags only specified with https protocol +If ($protocol -ne 'https' -and $sslFlags -gt 0) +{ + Fail-Json -obj $result -message "SSLFlags can only be set for HTTPS protocol" +} + +# validate certificate details if provided +# we don't do anything with cert on state: absent, so only validate present +If ($certificateHash -and $state -eq 'present') +{ + If ($protocol -ne 'https') + { + Fail-Json -obj $result -message "You can only provide a certificate thumbprint when protocol is set to https" + } + + #apply default for cert store name + If (-Not $certificateStoreName) + { + $certificateStoreName = 'my' + } + + #validate cert path + $cert_path = "cert:\LocalMachine\$certificateStoreName\$certificateHash" + If (-Not (Test-Path $cert_path) ) + { + Fail-Json -obj $result -message "Unable to locate certificate at $cert_path" + } +} + +# make sure binding info is valid for central cert store if sslflags -gt 1 +If ($sslFlags -gt 1 -and ($certificateHash -ne [string]::Empty -or $certificateStoreName -ne [string]::Empty)) +{ + Fail-Json -obj $result -message "You set sslFlags to $sslFlags. This indicates you wish to use the Central Certificate Store feature. + This cannot be used in combination with certficiate_hash and certificate_store_name. When using the Central Certificate Store feature, + the certificate is automatically retrieved from the store rather than manually assigned to the binding." +} + +# disallow host_header: '*' +If ($host_header -eq '*') +{ + Fail-Json -obj $result -message "To make or remove a catch-all binding, please omit the host_header parameter entirely rather than specify host_header *" +} + +########################## +### start action items ### +########################## + +# create binding search splat +$binding_parameters = @{ + Name = $name + Protocol = $protocol + Port = $port + IPAddress = $ip +} + +# insert host header to search if specified, otherwise it will return * (all bindings matching protocol/ip) +If ($host_header) +{ + $binding_parameters.HostHeader = $host_header +} +Else +{ + $binding_parameters.HostHeader = [string]::Empty +} + +# Get bindings matching parameters +Try { + $current_bindings = Get-SingleWebBinding $binding_parameters +} +Catch { + Fail-Json -obj $result -message "Failed to retrieve bindings with Get-SingleWebBinding - $($_.Exception.Message)" +} + +################################################ +### Remove binding or exit if already absent ### +################################################ +If ($current_bindings -and $state -eq 'absent') +{ + Try { + #there is a bug in this method that will result in all bindings being removed if the IP in $current_bindings is a * + #$current_bindings | Remove-WebBinding -verbose -WhatIf:$check_mode + + #another method that did not work. It kept failing to match on element and removed everything. + #$element = @{protocol="$protocol";bindingInformation="$ip`:$port`:$host_header"} + #Remove-WebconfigurationProperty -filter $current_bindings.ItemXPath -Name Bindings.collection -AtElement $element -WhatIf #:$check_mode + + #this method works + [array]$bindings = Get-WebconfigurationProperty -filter $current_bindings.ItemXPath -Name Bindings.collection + + $index = Foreach ($item in $bindings) { + If ( $protocol -eq $item.protocol -and $current_bindings.bindingInformation -eq $item.bindingInformation ) { + $bindings.indexof($item) + break + } + } + + Remove-WebconfigurationProperty -filter $current_bindings.ItemXPath -Name Bindings.collection -AtIndex $index -WhatIf:$check_mode + $result.changed = $true + } + + Catch { + Fail-Json -obj $result -message "Failed to remove the binding from IIS - $($_.Exception.Message)" + } + + # removing bindings from iis may not also remove them from iis:\sslbindings + + $result.operation_type = 'removed' + $result.binding_info = $current_bindings | ForEach-Object {Create-BindingInfo $_} + Exit-Json -obj $result +} +ElseIf (-Not $current_bindings -and $state -eq 'absent') +{ + # exit changed: false since it's already gone + Exit-Json -obj $result +} + + +################################ +### Modify existing bindings ### +################################ +<# +since we have already have the parameters available to get-webbinding, +we just need to check here for the ones that are not available which are the +ssl settings (hash, store, sslflags). If they aren't set we update here, or +exit with changed: false +#> +ElseIf ($current_bindings) +{ + #ran into a strange edge case in testing where I was able to retrieve bindings but not expand all the properties + #when adding a self-signed wildcard cert to a binding. it seemed to permanently break the binding. only removing it + #would cause the error to stop. + Try { + $null = $current_bindings | Select-Object * + } + Catch { + Fail-Json -obj $result -message "Found a matching binding, but failed to expand it's properties (get-binding | FL *). In testing, this was caused by using a self-signed wildcard certificate. $($_.Exception.Message)" + } + + # check if there is a match on the ssl parameters + If ( ($current_bindings.sslFlags -ne $sslFlags -and $sni_support) -or + $current_bindings.certificateHash -ne $certificateHash -or + $current_bindings.certificateStoreName -ne $certificateStoreName) + { + # match/update SNI + If ($current_bindings.sslFlags -ne $sslFlags -and $sni_support) + { + Try { + Set-WebBinding -Name $name -IPAddress $ip -Port $port -HostHeader $host_header -PropertyName sslFlags -value $sslFlags -whatif:$check_mode + $result.changed = $true + } + Catch { + Fail-Json -obj $result -message "Failed to update sslFlags on binding - $($_.Exception.Message)" + } + + # Refresh the binding object since it has been changed + Try { + $current_bindings = Get-SingleWebBinding $binding_parameters + } + Catch { + Fail-Json -obj $result -message "Failed to refresh bindings after setting sslFlags - $($_.Exception.Message)" + } + } + # match/update certificate + If ($current_bindings.certificateHash -ne $certificateHash -or $current_bindings.certificateStoreName -ne $certificateStoreName) + { + If (-Not $check_mode) + { + Try { + $current_bindings.AddSslCertificate($certificateHash,$certificateStoreName) + } + Catch { + Fail-Json -obj $result -message "Failed to set new SSL certificate - $($_.Exception.Message)" + } + } + } + $result.changed = $true + $result.operation_type = 'updated' + $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State + $result.binding_info = Create-BindingInfo (Get-SingleWebBinding $binding_parameters) + Exit-Json -obj $result #exit changed true + } + Else + { + $result.operation_type = 'matched' + $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State + $result.binding_info = Create-BindingInfo (Get-SingleWebBinding $binding_parameters) + Exit-Json -obj $result #exit changed false + } +} + +######################## +### Add new bindings ### +######################## +ElseIf (-not $current_bindings -and $state -eq 'present') +{ + # add binding. this creates the binding, but does not apply a certificate to it. + Try + { + If (-not $check_mode) + { + If ($sni_support) + { + New-WebBinding @binding_parameters -SslFlags $sslFlags -Force + } + Else + { + New-WebBinding @binding_parameters -Force + } + } + $result.changed = $true + } + Catch + { + $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State + Fail-Json -obj $result -message "Failed at creating new binding (note: creating binding and adding ssl are separate steps) - $($_.Exception.Message)" + } + + # add certificate to binding + If ($certificateHash -and -not $check_mode) + { + Try { + #$new_binding = get-webbinding -Name $name -IPAddress $ip -port $port -Protocol $protocol -hostheader $host_header + $new_binding = Get-SingleWebBinding $binding_parameters + $new_binding.addsslcertificate($certificateHash,$certificateStoreName) + } + Catch { + $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State + Fail-Json -obj $result -message "Failed to set new SSL certificate - $($_.Exception.Message)" + } + } + + $result.changed = $true + $result.operation_type = 'added' + $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State + + # incase there are no bindings we do a check before calling Create-BindingInfo + $web_binding = Get-SingleWebBinding $binding_parameters + if ($web_binding) { + $result.binding_info = Create-BindingInfo $web_binding + } else { + $result.binding_info = $null + } + Exit-Json $result +} diff --git a/plugins/modules/win_iis_webbinding.py b/plugins/modules/win_iis_webbinding.py new file mode 100644 index 0000000..5a86590 --- /dev/null +++ b/plugins/modules/win_iis_webbinding.py @@ -0,0 +1,152 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2017, Noah Sparks +# Copyright: (c) 2017, Henrik Wallström +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = r''' +--- +module: win_iis_webbinding +short_description: Configures a IIS Web site binding +description: + - Creates, removes and configures a binding to an existing IIS Web site. +options: + name: + description: + - Names of web site. + type: str + required: yes + aliases: [ website ] + state: + description: + - State of the binding. + type: str + choices: [ absent, present ] + default: present + port: + description: + - The port to bind to / use for the new site. + type: str + default: 80 + ip: + description: + - The IP address to bind to / use for the new site. + type: str + default: '*' + host_header: + description: + - The host header to bind to / use for the new site. + - If you are creating/removing a catch-all binding, omit this parameter rather than defining it as '*'. + type: str + protocol: + description: + - The protocol to be used for the Web binding (usually HTTP, HTTPS, or FTP). + type: str + default: http + certificate_hash: + description: + - Certificate hash (thumbprint) for the SSL binding. The certificate hash is the unique identifier for the certificate. + type: str + certificate_store_name: + description: + - Name of the certificate store where the certificate for the binding is located. + type: str + default: my + ssl_flags: + description: + - This parameter is only valid on Server 2012 and newer. + - Primarily used for enabling and disabling server name indication (SNI). + - Set to C(0) to disable SNI. + - Set to C(1) to enable SNI. + type: str +seealso: +- module: win_iis_virtualdirectory +- module: win_iis_webapplication +- module: win_iis_webapppool +- module: win_iis_website +author: + - Noah Sparks (@nwsparks) + - Henrik Wallström (@henrikwallstrom) +''' + +EXAMPLES = r''' +- name: Add a HTTP binding on port 9090 + win_iis_webbinding: + name: Default Web Site + port: 9090 + state: present + +- name: Remove the HTTP binding on port 9090 + win_iis_webbinding: + name: Default Web Site + port: 9090 + state: absent + +- name: Remove the default http binding + win_iis_webbinding: + name: Default Web Site + port: 80 + ip: '*' + state: absent + +- name: Add a HTTPS binding + win_iis_webbinding: + name: Default Web Site + protocol: https + port: 443 + ip: 127.0.0.1 + certificate_hash: B0D0FA8408FC67B230338FCA584D03792DA73F4C + state: present + +- name: Add a HTTPS binding with host header and SNI enabled + win_iis_webbinding: + name: Default Web Site + protocol: https + port: 443 + host_header: test.com + ssl_flags: 1 + certificate_hash: D1A3AF8988FD32D1A3AF8988FD323792DA73F4C + state: present +''' + +RETURN = r''' +website_state: + description: + - The state of the website being targetted + - Can be helpful in case you accidentally cause a binding collision + which can result in the targetted site being stopped + returned: always + type: str + sample: "Started" + version_added: "2.5" +operation_type: + description: + - The type of operation performed + - Can be removed, updated, matched, or added + returned: on success + type: str + sample: "removed" + version_added: "2.5" +binding_info: + description: + - Information on the binding being manipulated + returned: on success + type: dict + sample: |- + "binding_info": { + "bindingInformation": "127.0.0.1:443:", + "certificateHash": "FF3910CE089397F1B5A77EB7BAFDD8F44CDE77DD", + "certificateStoreName": "MY", + "hostheader": "", + "ip": "127.0.0.1", + "port": 443, + "protocol": "https", + "sslFlags": "not supported" + } + version_added: "2.5" +''' diff --git a/plugins/modules/win_iis_website.ps1 b/plugins/modules/win_iis_website.ps1 new file mode 100644 index 0000000..e7b6cab --- /dev/null +++ b/plugins/modules/win_iis_website.ps1 @@ -0,0 +1,180 @@ +#!powershell + +# Copyright: (c) 2015, Henrik Wallström +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#Requires -Module Ansible.ModuleUtils.Legacy + +$ErrorActionPreference = "Stop" + +$params = Parse-Args $args +$name = Get-AnsibleParam -obj $params -name "name" -type "str" -failifempty $true +$application_pool = Get-AnsibleParam -obj $params -name "application_pool" -type "str" +$physical_path = Get-AnsibleParam -obj $params -name "physical_path" -type "str" +$site_id = Get-AnsibleParam -obj $params -name "site_id" -type "str" +$state = Get-AnsibleParam -obj $params -name "state" -type "str" -validateset "absent","restarted","started","stopped" + +# Binding Parameters +$bind_port = Get-AnsibleParam -obj $params -name "port" -type "int" +$bind_ip = Get-AnsibleParam -obj $params -name "ip" -type "str" +$bind_hostname = Get-AnsibleParam -obj $params -name "hostname" -type "str" + +# Custom site Parameters from string where properties +# are separated by a pipe and property name/values by colon. +# Ex. "foo:1|bar:2" +$parameters = Get-AnsibleParam -obj $params -name "parameters" -type "str" +if($null -ne $parameters) { + $parameters = @($parameters -split '\|' | ForEach-Object { + return ,($_ -split "\:", 2); + }) +} + + +# Ensure WebAdministration module is loaded +if ($null -eq (Get-Module "WebAdministration" -ErrorAction SilentlyContinue)) { + Import-Module WebAdministration +} + +# Result +$result = @{ + site = @{} + changed = $false +} + +# Site info +$site = Get-Website | Where-Object { $_.Name -eq $name } + +Try { + # Add site + If(($state -ne 'absent') -and (-not $site)) { + If (-not $physical_path) { + Fail-Json -obj $result -message "missing required arguments: physical_path" + } + ElseIf (-not (Test-Path $physical_path)) { + Fail-Json -obj $result -message "specified folder must already exist: physical_path" + } + + $site_parameters = @{ + Name = $name + PhysicalPath = $physical_path + } + + If ($application_pool) { + $site_parameters.ApplicationPool = $application_pool + } + + If ($site_id) { + $site_parameters.ID = $site_id + } + + If ($bind_port) { + $site_parameters.Port = $bind_port + } + + If ($bind_ip) { + $site_parameters.IPAddress = $bind_ip + } + + If ($bind_hostname) { + $site_parameters.HostHeader = $bind_hostname + } + + # Fix for error "New-Item : Index was outside the bounds of the array." + # This is a bug in the New-WebSite commandlet. Apparently there must be at least one site configured in IIS otherwise New-WebSite crashes. + # For more details, see http://stackoverflow.com/questions/3573889/ps-c-new-website-blah-throws-index-was-outside-the-bounds-of-the-array + $sites_list = get-childitem -Path IIS:\sites + if ($null -eq $sites_list) { + if ($site_id) { + $site_parameters.ID = $site_id + } else { + $site_parameters.ID = 1 + } + } + + $site = New-Website @site_parameters -Force + $result.changed = $true + } + + # Remove site + If ($state -eq 'absent' -and $site) { + $site = Remove-Website -Name $name + $result.changed = $true + } + + $site = Get-Website | Where-Object { $_.Name -eq $name } + If($site) { + # Change Physical Path if needed + if($physical_path) { + If (-not (Test-Path $physical_path)) { + Fail-Json -obj $result -message "specified folder must already exist: physical_path" + } + + $folder = Get-Item $physical_path + If($folder.FullName -ne $site.PhysicalPath) { + Set-ItemProperty "IIS:\Sites\$($site.Name)" -name physicalPath -value $folder.FullName + $result.changed = $true + } + } + + # Change Application Pool if needed + if($application_pool) { + If($application_pool -ne $site.applicationPool) { + Set-ItemProperty "IIS:\Sites\$($site.Name)" -name applicationPool -value $application_pool + $result.changed = $true + } + } + + # Set properties + if($parameters) { + $parameters | ForEach-Object { + $property_value = Get-ItemProperty "IIS:\Sites\$($site.Name)" $_[0] + + switch ($property_value.GetType().Name) + { + "ConfigurationAttribute" { $parameter_value = $property_value.value } + "String" { $parameter_value = $property_value } + } + + if((-not $parameter_value) -or ($parameter_value) -ne $_[1]) { + Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" $_[0] $_[1] + $result.changed = $true + } + } + } + + # Set run state + if ((($state -eq 'stopped') -or ($state -eq 'restarted')) -and ($site.State -eq 'Started')) + { + Stop-Website -Name $name -ErrorAction Stop + $result.changed = $true + } + if ((($state -eq 'started') -and ($site.State -eq 'Stopped')) -or ($state -eq 'restarted')) + { + Start-Website -Name $name -ErrorAction Stop + $result.changed = $true + } + } +} +Catch +{ + Fail-Json -obj $result -message $_.Exception.Message +} + +if ($state -ne 'absent') +{ + $site = Get-Website | Where-Object { $_.Name -eq $name } +} + +if ($site) +{ + $result.site = @{ + Name = $site.Name + ID = $site.ID + State = $site.State + PhysicalPath = $site.PhysicalPath + ApplicationPool = $site.applicationPool + Bindings = @($site.Bindings.Collection | ForEach-Object { $_.BindingInformation }) + } +} + +Exit-Json -obj $result diff --git a/plugins/modules/win_iis_website.py b/plugins/modules/win_iis_website.py new file mode 100644 index 0000000..aa2597c --- /dev/null +++ b/plugins/modules/win_iis_website.py @@ -0,0 +1,119 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2015, Henrik Wallström +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = r''' +--- +module: win_iis_website +short_description: Configures a IIS Web site +description: + - Creates, Removes and configures a IIS Web site. +options: + name: + description: + - Names of web site. + type: str + required: yes + site_id: + description: + - Explicitly set the IIS numeric ID for a site. + - Note that this value cannot be changed after the website has been created. + type: str + state: + description: + - State of the web site + type: str + choices: [ absent, started, stopped, restarted ] + physical_path: + description: + - The physical path on the remote host to use for the new site. + - The specified folder must already exist. + type: str + application_pool: + description: + - The application pool in which the new site executes. + type: str + port: + description: + - The port to bind to / use for the new site. + type: int + ip: + description: + - The IP address to bind to / use for the new site. + type: str + hostname: + description: + - The host header to bind to / use for the new site. + type: str + ssl: + description: + - Enables HTTPS binding on the site.. + type: str + parameters: + description: + - Custom site Parameters from string where properties are separated by a pipe and property name/values by colon Ex. "foo:1|bar:2" + type: str +seealso: +- module: win_iis_virtualdirectory +- module: win_iis_webapplication +- module: win_iis_webapppool +- module: win_iis_webbinding +author: +- Henrik Wallström (@henrikwallstrom) +''' + +EXAMPLES = r''' + +# Start a website + +- name: Acme IIS site + win_iis_website: + name: Acme + state: started + port: 80 + ip: 127.0.0.1 + hostname: acme.local + application_pool: acme + physical_path: C:\sites\acme + parameters: logfile.directory:C:\sites\logs + register: website + +# Remove Default Web Site and the standard port 80 binding +- name: Remove Default Web Site + win_iis_website: + name: "Default Web Site" + state: absent + +# Some commandline examples: + +# This return information about an existing host +# $ ansible -i vagrant-inventory -m win_iis_website -a "name='Default Web Site'" window +# host | success >> { +# "changed": false, +# "site": { +# "ApplicationPool": "DefaultAppPool", +# "Bindings": [ +# "*:80:" +# ], +# "ID": 1, +# "Name": "Default Web Site", +# "PhysicalPath": "%SystemDrive%\\inetpub\\wwwroot", +# "State": "Stopped" +# } +# } + +# This stops an existing site. +# $ ansible -i hosts -m win_iis_website -a "name='Default Web Site' state=stopped" host + +# This creates a new site. +# $ ansible -i hosts -m win_iis_website -a "name=acme physical_path=C:\\sites\\acme" host + +# Change logfile. +# $ ansible -i hosts -m win_iis_website -a "name=acme physical_path=C:\\sites\\acme" host +''' diff --git a/tests/integration/targets/win_iis_webbinding/aliases b/tests/integration/targets/win_iis_webbinding/aliases new file mode 100644 index 0000000..4f4664b --- /dev/null +++ b/tests/integration/targets/win_iis_webbinding/aliases @@ -0,0 +1 @@ +shippable/windows/group5 diff --git a/tests/integration/targets/win_iis_webbinding/defaults/main.yml b/tests/integration/targets/win_iis_webbinding/defaults/main.yml new file mode 100644 index 0000000..13f0bc3 --- /dev/null +++ b/tests/integration/targets/win_iis_webbinding/defaults/main.yml @@ -0,0 +1,30 @@ +test_iis_site_name: default web site + +http_vars: + protocol: http + port: 80 + ip: '*' + +http_header_vars: + protocol: http + port: 80 + ip: '*' + header: test.com + +https_vars: + protocol: https + port: 443 + ip: '*' + +https_header_vars: + protocol: https + port: 443 + ip: '*' + header: test.com + ssl_flags: 1 + +https_wc_vars: + protocol: https + port: 443 + ip: '127.0.0.1' + header: wc.test.com diff --git a/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 b/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 new file mode 100644 index 0000000..84ef10b --- /dev/null +++ b/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 @@ -0,0 +1,113 @@ +#!powershell + +# Copyright: (c) 2017, Noah Sparks +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#Requires -Module Ansible.ModuleUtils.Legacy + +$params = Parse-Args -arguments $args -supports_check_mode $true + +$name = Get-AnsibleParam $params -name "name" -type str -failifempty $true -aliases 'website' +$host_header = Get-AnsibleParam $params -name "host_header" -type str +$protocol = Get-AnsibleParam $params -name "protocol" -type str -default 'http' +$port = Get-AnsibleParam $params -name "port" -type int -default '80' +$ip = Get-AnsibleParam $params -name "ip" -default '*' + +$result = @{ + changed = $false +} +function Create-BindingInfo { + $ht = @{ + 'bindingInformation' = $args[0].bindingInformation + 'ip' = $args[0].bindingInformation.split(':')[0] + 'port' = [int]$args[0].bindingInformation.split(':')[1] + 'hostheader' = $args[0].bindingInformation.split(':')[2] + 'isDsMapperEnabled' = $args[0].isDsMapperEnabled + 'protocol' = $args[0].protocol + 'certificateStoreName' = $args[0].certificateStoreName + 'certificateHash' = $args[0].certificateHash + } + + #handle sslflag support + If ([version][System.Environment]::OSVersion.Version -lt [version]'6.2') + { + $ht.sslFlags = 'not supported' + } + Else + { + $ht.sslFlags = [int]$args[0].sslFlags + } + + Return $ht +} + +# Used instead of get-webbinding to ensure we always return a single binding +# pass it $binding_parameters hashtable +function Get-SingleWebBinding { + + Try { + $site_bindings = get-webbinding -name $args[0].name + } + Catch { + # 2k8r2 throws this error when you run get-webbinding with no bindings in iis + If (-not $_.Exception.Message.CompareTo('Cannot process argument because the value of argument "obj" is null. Change the value of argument "obj" to a non-null value')) + { + Throw $_.Exception.Message + } + Else { return } + } + + Foreach ($binding in $site_bindings) + { + $splits = $binding.bindingInformation -split ':' + + if ( + $args[0].protocol -eq $binding.protocol -and + $args[0].ipaddress -eq $splits[0] -and + $args[0].port -eq $splits[1] -and + $args[0].hostheader -eq $splits[2] + ) + { + Return $binding + } + } +} + +# create binding search splat +$binding_parameters = @{ + Name = $name + Protocol = $protocol + Port = $port + IPAddress = $ip +} + +# insert host header to search if specified, otherwise it will return * (all bindings matching protocol/ip) +If ($host_header) +{ + $binding_parameters.HostHeader = $host_header +} +Else +{ + $binding_parameters.HostHeader = [string]::Empty +} + +# Get bindings matching parameters +Try { + $current_bindings = Get-SingleWebBinding $binding_parameters +} +Catch { + Fail-Json -obj $result -message "Failed to retrieve bindings with Get-SingleWebBinding - $($_.Exception.Message)" +} + +If ($current_bindings) +{ + Try { + $binding_info = Create-BindingInfo $current_bindings + } + Catch { + Fail-Json -obj $result -message "Failed to create binding info - $($_.Exception.Message)" + } + + $result.binding = $binding_info +} +exit-json -obj $result \ No newline at end of file diff --git a/tests/integration/targets/win_iis_webbinding/tasks/failures.yml b/tests/integration/targets/win_iis_webbinding/tasks/failures.yml new file mode 100644 index 0000000..92736fe --- /dev/null +++ b/tests/integration/targets/win_iis_webbinding/tasks/failures.yml @@ -0,0 +1,70 @@ +- name: failure check define * for host header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + host_header: '*' + protocol: http + ip: '*' + register: failure + failed_when: failure.msg != "To make or remove a catch-all binding, please omit the host_header parameter entirely rather than specify host_header *" + +- debug: + var: failure + verbosity: 1 + +- block: + - name: get all websites from server + raw: powershell.exe "(get-website).name" + register: existing_sites + + - name: ensure all sites are removed for clean testing + win_iis_website: + name: "{{ item }}" + state: absent + with_items: + - "{{ existing_sites.stdout_lines }}" + + - name: add testremove site + win_iis_website: + name: testremove + state: started + physical_path: c:\inetpub\wwwroot + + - name: add bindings to testremove + win_iis_webbinding: + name: testremove + ip: "{{ item.ip }}" + port: "{{ item.port }}" + with_items: + - {ip: 127.0.0.1, port: 80} + - {ip: '*', port: 80} + + - name: remove ip * binding from testremove + win_iis_webbinding: + name: testremove + state: absent + port: 80 + ip: '*' + + - name: get the remaining binding from testremove + test_get_webbindings: + name: testremove + port: 80 + ip: 127.0.0.1 + register: test_result + + - debug: + var: test_result + verbosity: 1 + + - name: assert that remove *:80 doesn't also remove 127.0.0.1:80 + assert: + that: + - test_result.binding.ip == '127.0.0.1' + - test_result.binding.port == 80 + + always: + - name: remove websites + win_iis_website: + name: testremove + state: absent diff --git a/tests/integration/targets/win_iis_webbinding/tasks/http.yml b/tests/integration/targets/win_iis_webbinding/tasks/http.yml new file mode 100644 index 0000000..34c4cc2 --- /dev/null +++ b/tests/integration/targets/win_iis_webbinding/tasks/http.yml @@ -0,0 +1,317 @@ +#cm add +#changed true, check nothing present +- name: CM add http binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + protocol: "{{ http_vars.protocol }}" + ip: "{{ http_vars.ip }}" + port: "{{ http_vars.port }}" + register: http_no_header + check_mode: yes + +- name: CM get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ http_vars.protocol }}" + ip: "{{ http_vars.ip }}" + port: "{{ http_vars.port }}" + register: get_http_no_header + changed_when: false + +- name: CM add http binding with header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + host_header: "{{ http_header_vars.header }}" + protocol: "{{ http_header_vars.protocol }}" + ip: "{{ http_header_vars.ip }}" + port: "{{ http_header_vars.port }}" + register: http_header + check_mode: yes + +- name: CM get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + host_header: "{{ http_header_vars.header }}" + protocol: "{{ http_header_vars.protocol }}" + ip: "{{ http_header_vars.ip }}" + port: "{{ http_header_vars.port }}" + register: get_http_header + changed_when: false + +- name: CM assert changed, but not added + assert: + that: + - http_no_header is changed + - http_no_header.binding_info is none + - get_http_no_header.binding is not defined + - http_header is changed + - http_header.binding_info is none + - get_http_header.binding is not defined + +#add +#changed true, new bindings present +- name: add http binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + protocol: "{{ http_vars.protocol }}" + ip: "{{ http_vars.ip }}" + port: "{{ http_vars.port }}" + register: http_no_header + +- name: get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ http_vars.protocol }}" + ip: "{{ http_vars.ip }}" + port: "{{ http_vars.port }}" + register: get_http_no_header + changed_when: false + +- name: add http binding with header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + host_header: "{{ http_header_vars.header }}" + protocol: "{{ http_header_vars.protocol }}" + ip: "{{ http_header_vars.ip }}" + port: "{{ http_header_vars.port }}" + register: http_header + +- name: get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + host_header: "{{ http_header_vars.header }}" + protocol: "{{ http_header_vars.protocol }}" + ip: "{{ http_header_vars.ip }}" + port: "{{ http_header_vars.port }}" + register: get_http_header + changed_when: false + +- name: assert changed and added + assert: + that: + - http_no_header is changed + - http_no_header.binding_info is defined + - http_no_header.operation_type == 'added' + - http_no_header.binding_info.ip == "{{ http_vars.ip }}" + - http_no_header.binding_info.port == {{ http_vars.port }} + - http_no_header.binding_info.protocol == "{{ http_vars.protocol }}" + - http_header is changed + - http_header.binding_info is defined + - http_header.operation_type == 'added' + - http_header.binding_info.ip == "{{ http_header_vars.ip }}" + - http_header.binding_info.port == {{ http_header_vars.port }} + - http_header.binding_info.protocol == "{{ http_header_vars.protocol }}" + - http_header.binding_info.hostheader == "{{ http_header_vars.header }}" + +#add idem +#changed false +- name: idem add http binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + protocol: "{{ http_vars.protocol }}" + ip: "{{ http_vars.ip }}" + port: "{{ http_vars.port }}" + register: http_no_header + +- name: idem add http binding with header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + host_header: "{{ http_header_vars.header }}" + protocol: "{{ http_header_vars.protocol }}" + ip: "{{ http_header_vars.ip }}" + port: "{{ http_header_vars.port }}" + register: http_header + +- name: idem assert not changed + assert: + that: + - http_no_header is not changed + - http_header is not changed + +#modify +#can't test modify for http, it will add a new binding instead since +#there's no way to match existing bindings against the new parameters + +#cm remove +#changed true, bindings still present +- name: cm remove http binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + protocol: "{{ http_vars.protocol }}" + ip: "{{ http_vars.ip }}" + port: "{{ http_vars.port }}" + register: http_no_header + check_mode: yes + +- name: get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ http_vars.protocol }}" + ip: "{{ http_vars.ip }}" + port: "{{ http_vars.port }}" + register: get_http_no_header + changed_when: false + +- name: cm remove http binding with header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + host_header: "{{ http_header_vars.header }}" + protocol: "{{ http_header_vars.protocol }}" + ip: "{{ http_header_vars.ip }}" + port: "{{ http_header_vars.port }}" + register: http_header + check_mode: yes + +- name: get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + host_header: "{{ http_header_vars.header }}" + protocol: "{{ http_header_vars.protocol }}" + ip: "{{ http_header_vars.ip }}" + port: "{{ http_header_vars.port }}" + register: get_http_header + changed_when: false + +- name: cm remove assert changed, but still present + assert: + that: + - http_no_header is changed + - http_no_header.binding_info is defined + - http_no_header.operation_type == 'removed' + - http_no_header.binding_info.ip == "{{ http_vars.ip }}" + - http_no_header.binding_info.port == {{ http_vars.port }} + - http_no_header.binding_info.protocol == "{{ http_vars.protocol }}" + - get_http_no_header.binding is defined + - get_http_no_header.binding.ip == "{{ http_vars.ip }}" + - get_http_no_header.binding.port == {{ http_vars.port }} + - get_http_no_header.binding.protocol == "{{ http_vars.protocol }}" + - http_header is changed + - http_header.binding_info is defined + - http_header.operation_type == 'removed' + - http_header.binding_info.ip == "{{ http_header_vars.ip }}" + - http_header.binding_info.port == {{ http_header_vars.port }} + - http_header.binding_info.protocol == "{{ http_header_vars.protocol }}" + - http_header.binding_info.hostheader == "{{ http_header_vars.header }}" + - get_http_header.binding is defined + - get_http_header.binding.ip == "{{ http_header_vars.ip }}" + - get_http_header.binding.port == {{ http_header_vars.port }} + - get_http_header.binding.protocol == "{{ http_header_vars.protocol }}" + - get_http_header.binding.hostheader == "{{ http_header_vars.header }}" + + +#remove +#changed true, bindings gone +- name: remove http binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + protocol: "{{ http_vars.protocol }}" + ip: "{{ http_vars.ip }}" + port: "{{ http_vars.port }}" + register: http_no_header + +- name: get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ http_vars.protocol }}" + ip: "{{ http_vars.ip }}" + port: "{{ http_vars.port }}" + register: get_http_no_header + changed_when: false + +- name: remove http binding with header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + host_header: "{{ http_header_vars.header }}" + protocol: "{{ http_header_vars.protocol }}" + ip: "{{ http_header_vars.ip }}" + port: "{{ http_header_vars.port }}" + register: http_header + +- name: get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + host_header: "{{ http_header_vars.header }}" + protocol: "{{ http_header_vars.protocol }}" + ip: "{{ http_header_vars.ip }}" + port: "{{ http_header_vars.port }}" + register: get_http_header + changed_when: false + +- name: remove assert changed and gone + assert: + that: + - http_no_header is changed + - http_no_header.operation_type == 'removed' + - http_no_header.binding_info is defined + - http_no_header.binding_info.ip == "{{ http_vars.ip }}" + - http_no_header.binding_info.port == {{ http_vars.port }} + - http_no_header.binding_info.protocol == "{{ http_vars.protocol }}" + - get_http_no_header.binding is not defined + - http_header is changed + - http_header.binding_info is defined + - http_header.operation_type == 'removed' + - http_header.binding_info.ip == "{{ http_header_vars.ip }}" + - http_header.binding_info.port == {{ http_header_vars.port }} + - http_header.binding_info.protocol == "{{ http_header_vars.protocol }}" + - http_header.binding_info.hostheader == "{{ http_header_vars.header }}" + - get_http_header.binding is not defined + +#remove idem +#change false, bindings gone +- name: idem remove http binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + protocol: "{{ http_vars.protocol }}" + ip: "{{ http_vars.ip }}" + port: "{{ http_vars.port }}" + register: http_no_header + +- name: get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ http_vars.protocol }}" + ip: "{{ http_vars.ip }}" + port: "{{ http_vars.port }}" + register: get_http_no_header + changed_when: false + +- name: idem remove http binding with header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + host_header: "{{ http_header_vars.header }}" + protocol: "{{ http_header_vars.protocol }}" + ip: "{{ http_header_vars.ip }}" + port: "{{ http_header_vars.port }}" + register: http_header + +- name: get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + host_header: "{{ http_header_vars.header }}" + protocol: "{{ http_header_vars.protocol }}" + ip: "{{ http_header_vars.ip }}" + port: "{{ http_header_vars.port }}" + register: get_http_header + changed_when: false + +- name: idem remove assert changed and gone + assert: + that: + - http_no_header is not changed + - http_no_header.binding_info is not defined + - get_http_no_header.binding is not defined + - http_header is not changed + - http_header.binding_info is not defined + - get_http_header.binding is not defined diff --git a/tests/integration/targets/win_iis_webbinding/tasks/https-ge6.2.yml b/tests/integration/targets/win_iis_webbinding/tasks/https-ge6.2.yml new file mode 100644 index 0000000..f883c67 --- /dev/null +++ b/tests/integration/targets/win_iis_webbinding/tasks/https-ge6.2.yml @@ -0,0 +1,459 @@ +############## +### CM Add ### +############## +#changed true, check nothing present +- name: CM add https binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" + register: https_no_header + check_mode: yes + +- name: CM get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: get_https_no_header + changed_when: false + +- name: CM add https binding with header and SNI + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + ssl_flags: 1 + certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" + register: https_header + check_mode: yes + +- name: CM get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + register: get_https_header + changed_when: false + +- name: CM assert changed, but not added + assert: + that: + - https_no_header is changed + - https_no_header.operation_type == 'added' + - https_no_header.binding_info is none + - get_https_no_header.binding is not defined + - https_header is changed + - https_header.operation_type == 'added' + - https_header.binding_info is none + - get_https_header.binding is not defined + +########### +### Add ### +########### +#changed true, new bindings present +- name: add https binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" + register: https_no_header + +- name: get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: get_https_no_header + changed_when: false + +- name: add https binding with header SNI + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + ssl_flags: 1 + certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" + register: https_header + +- name: get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + register: get_https_header + changed_when: false + +- name: assert changed and added + assert: + that: + - https_no_header is changed + - https_no_header.operation_type == 'added' + - https_no_header.binding_info is defined + - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" + - https_no_header.binding_info.ip == "{{ https_vars.ip }}" + - https_no_header.binding_info.port == {{ https_vars.port }} + - https_no_header.binding_info.hostheader == '' + - https_no_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" + - https_header is changed + - https_header.operation_type == 'added' + - https_header.binding_info is defined + - https_header.binding_info.hostheader == "{{ https_header_vars.header }}" + - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}" + - https_header.binding_info.ip == "{{ https_header_vars.ip }}" + - https_header.binding_info.port == {{ https_header_vars.port }} + - https_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" + - https_header.binding_info.sslFlags == 1 + +################ +### Idem Add ### +################ +#changed false +- name: idem add https binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + protocol: https + ip: '*' + port: 443 + certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" + register: https_no_header + +- name: idem add https binding with header and SNI + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + host_header: test.com + protocol: https + ip: '*' + port: 443 + ssl_flags: 1 + certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" + register: https_header + +- name: idem assert not changed + assert: + that: + - https_no_header is not changed + - https_header is not changed + +################# +### CM Modify ### +################# +# changed true, verify no changes occurred + +#modify sni +- name: CM modify https binding with header, change cert + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + ssl_flags: 1 + certificate_hash: "{{ thumbprint2.stdout_lines[0] }}" + register: https_header + check_mode: yes + +- name: get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + register: get_https_header + changed_when: false + +- name: CM assert changed but old cert + assert: + that: + - https_header is changed + - https_header.operation_type == 'updated' + - https_header.binding_info is defined + - https_header.binding_info.ip == "{{ https_header_vars.ip }}" + - https_header.binding_info.port == {{ https_header_vars.port }} + - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}" + - https_header.binding_info.hostheader == "{{ https_header_vars.header }}" + - https_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" + - https_header.binding_info.sslFlags == 1 + - get_https_header.binding is defined + - get_https_header.binding.ip == "{{ https_header_vars.ip }}" + - get_https_header.binding.port == {{ https_header_vars.port }} + - get_https_header.binding.protocol == "{{ https_header_vars.protocol }}" + - get_https_header.binding.hostheader == "{{ https_header_vars.header }}" + - get_https_header.binding.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" + - get_https_header.binding.sslFlags == 1 + +############## +### Modify ### +############## +# modify ssl flags +- name: modify https binding with header, change cert + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + ssl_flags: 1 + certificate_hash: "{{ thumbprint2.stdout_lines[0] }}" + register: https_header + +- name: get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + register: get_https_header + changed_when: false + +- name: modify assert changed and new cert + assert: + that: + - https_header is changed + - https_header.operation_type == 'updated' + - https_header.binding_info is defined + - https_header.binding_info.ip == "{{ https_header_vars.ip }}" + - https_header.binding_info.port == {{ https_header_vars.port }} + - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}" + - https_header.binding_info.hostheader == "{{ https_header_vars.header }}" + - https_header.binding_info.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" + - https_header.binding_info.sslFlags == 1 + - get_https_header.binding is defined + - get_https_header.binding.ip == "{{ https_header_vars.ip }}" + - get_https_header.binding.port == {{ https_header_vars.port }} + - get_https_header.binding.protocol == "{{ https_header_vars.protocol }}" + - get_https_header.binding.hostheader == "{{ https_header_vars.header }}" + - get_https_header.binding.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" + - get_https_header.binding.sslFlags == 1 + +################### +### Idem Modify ### +################### +#changed false + +#idem modify ssl flags +- name: idem modify https binding with header, enable SNI and change cert + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + ssl_flags: 1 + certificate_hash: "{{ thumbprint2.stdout_lines[0] }}" + register: https_header + +- name: idem assert not changed + assert: + that: + - https_header is not changed + +################# +### CM Remove ### +################# +#changed true, bindings still present +- name: cm remove https binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: https_no_header + check_mode: yes + +- name: get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: get_https_no_header + changed_when: false + +- name: cm remove https binding with header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + register: https_header + check_mode: yes + +- name: get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + register: get_https_header + changed_when: false + +- name: cm remove assert changed, but still present + assert: + that: + - https_no_header is changed + - https_no_header.operation_type == 'removed' + - https_no_header.binding_info is defined + - https_no_header.binding_info.ip == "{{ https_vars.ip }}" + - https_no_header.binding_info.port == {{ https_vars.port }} + - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" + - get_https_no_header.binding is defined + - get_https_no_header.binding.ip == "{{ https_vars.ip }}" + - get_https_no_header.binding.port == {{ https_vars.port }} + - get_https_no_header.binding.protocol == "{{ https_vars.protocol }}" + - get_https_no_header.binding.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" + - https_header is changed + - https_header.binding_info is defined + - https_header.operation_type == 'removed' + - https_header.binding_info.ip == "{{ https_header_vars.ip }}" + - https_header.binding_info.port == {{ https_header_vars.port }} + - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}" + - https_header.binding_info.hostheader == "{{ https_header_vars.header }}" + - get_https_header.binding is defined + - get_https_header.binding.ip == "{{ https_header_vars.ip }}" + - get_https_header.binding.port == {{ https_header_vars.port }} + - get_https_header.binding.protocol == "{{ https_header_vars.protocol }}" + - get_https_header.binding.hostheader == "{{ https_header_vars.header }}" + - get_https_header.binding.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" + +############## +### remove ### +############## +#changed true, bindings gone +- name: remove https binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: https_no_header + +- name: get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: get_https_no_header + changed_when: false + +- name: remove https binding with header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + register: https_header + +- name: get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + register: get_https_header + changed_when: false + +- name: remove assert changed and gone + assert: + that: + - https_no_header is changed + - https_no_header.binding_info is defined + - https_no_header.operation_type == 'removed' + - https_no_header.binding_info.ip == "{{ https_vars.ip }}" + - https_no_header.binding_info.port == {{ https_vars.port }} + - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" + - get_https_no_header.binding is not defined + - https_header is changed + - https_header.binding_info is defined + - https_header.operation_type == 'removed' + - https_header.binding_info.ip == "{{ https_header_vars.ip }}" + - https_header.binding_info.port == {{ https_header_vars.port }} + - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}" + - https_header.binding_info.hostheader == "{{ https_header_vars.header }}" + - get_https_header.binding is not defined + +################### +### remove idem ### +################### +#change false, bindings gone +- name: idem remove https binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: https_no_header + +- name: get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: get_https_no_header + changed_when: false + +- name: idem remove https binding with header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + register: https_header + +- name: get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + host_header: "{{ https_header_vars.header }}" + protocol: "{{ https_header_vars.protocol }}" + ip: "{{ https_header_vars.ip }}" + port: "{{ https_header_vars.port }}" + register: get_https_header + changed_when: false + +- name: idem remove assert changed and gone + assert: + that: + - https_no_header is not changed + - https_no_header.binding_info is not defined + - get_https_no_header.binding is not defined + - https_header is not changed + - https_header.binding_info is not defined + - get_https_header.binding is not defined diff --git a/tests/integration/targets/win_iis_webbinding/tasks/https-lt6.2.yml b/tests/integration/targets/win_iis_webbinding/tasks/https-lt6.2.yml new file mode 100644 index 0000000..1950641 --- /dev/null +++ b/tests/integration/targets/win_iis_webbinding/tasks/https-lt6.2.yml @@ -0,0 +1,423 @@ +############## +### CM Add ### +############## +#changed true, check nothing present +- name: CM add https binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" + register: https_no_header + check_mode: yes + +- name: CM get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: get_https_no_header + changed_when: false + +- name: CM assert changed, but not added + assert: + that: + - https_no_header is changed + - https_no_header.operation_type == 'added' + - https_no_header.binding_info is none + - get_https_no_header.binding is not defined + +########### +### Add ### +########### +#changed true, new bindings present +- name: add https binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" + register: https_no_header + +- name: assert changed and added + assert: + that: + - https_no_header is changed + - https_no_header.binding_info is defined + - https_no_header.operation_type == 'added' + - https_no_header.binding_info.ip == "{{ https_vars.ip }}" + - https_no_header.binding_info.port == {{ https_vars.port }} + - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" + - https_no_header.binding_info.hostheader == '' + - https_no_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" + +################ +### Idem Add ### +################ +#changed false +- name: idem add https binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" + register: https_no_header + +- name: idem assert not changed + assert: + that: + - https_no_header is not changed + +################# +### CM Modify ### +################# +# changed true, verify no changes occurred + +#modify sni +- name: CM modify https binding change cert + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + certificate_hash: "{{ thumbprint2.stdout_lines[0] }}" + register: https_no_header + check_mode: yes + +- name: get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: get_https_no_header + changed_when: false + +- name: CM assert changed but old cert + assert: + that: + - https_no_header is changed + - https_no_header.operation_type == 'updated' + - https_no_header.binding_info is defined + - https_no_header.binding_info.ip == "{{ https_vars.ip }}" + - https_no_header.binding_info.port == {{ https_vars.port }} + - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" + - https_no_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" + - get_https_no_header.binding is defined + - get_https_no_header.binding.ip == "{{ https_vars.ip }}" + - get_https_no_header.binding.port == {{ https_vars.port }} + - get_https_no_header.binding.protocol == "{{ https_vars.protocol }}" + - get_https_no_header.binding.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" + +############## +### Modify ### +############## +# modify ssl flags +- name: modify https binding, change cert + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + certificate_hash: "{{ thumbprint2.stdout_lines[0] }}" + register: https_no_header + +- name: get binding info header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: get_https_no_header + changed_when: false + +- name: modify assert changed and new cert + assert: + that: + - https_no_header is changed + - https_no_header.operation_type == 'updated' + - https_no_header.binding_info is defined + - https_no_header.binding_info.ip == "{{ https_vars.ip }}" + - https_no_header.binding_info.port == {{ https_vars.port }} + - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" + - https_no_header.binding_info.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" + - get_https_no_header.binding is defined + - get_https_no_header.binding.ip == "{{ https_vars.ip }}" + - get_https_no_header.binding.port == {{ https_vars.port }} + - get_https_no_header.binding.protocol == "{{ https_vars.protocol }}" + - get_https_no_header.binding.hostheader == '' + - get_https_no_header.binding.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" + +################### +### Idem Modify ### +################### +#changed false + +#idem modify ssl flags +- name: idem modify https binding and change cert + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: present + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + certificate_hash: "{{ thumbprint2.stdout_lines[0] }}" + register: https_header + +- name: idem assert not changed + assert: + that: + - https_header is not changed + +################# +### CM Remove ### +################# +#changed true, bindings still present +- name: cm remove https binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: https_no_header + check_mode: yes + +- name: get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: get_https_no_header + changed_when: false + +- name: cm remove assert changed, but still present + assert: + that: + - https_no_header is changed + - https_no_header.operation_type == 'removed' + - https_no_header.binding_info is defined + - https_no_header.binding_info.ip == "{{ https_vars.ip }}" + - https_no_header.binding_info.port == {{ https_vars.port }} + - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" + - https_no_header.binding_info.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" + - get_https_no_header.binding is defined + - get_https_no_header.binding.ip == "{{ https_vars.ip }}" + - get_https_no_header.binding.port == {{ https_vars.port }} + - get_https_no_header.binding.protocol == "{{ https_vars.protocol }}" + - get_https_no_header.binding.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" + +############## +### remove ### +############## +#changed true, bindings gone +- name: remove https binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: https_no_header + +- name: get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: get_https_no_header + changed_when: false + +- name: remove assert changed and gone + assert: + that: + - https_no_header is changed + - https_no_header.operation_type == 'removed' + - https_no_header.binding_info is defined + - https_no_header.binding_info.ip == "{{ https_vars.ip }}" + - https_no_header.binding_info.port == {{ https_vars.port }} + - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" + - get_https_no_header.binding is not defined + +################### +### remove idem ### +################### +#change false, bindings gone +- name: idem remove https binding no header + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: https_no_header + +- name: get binding info no header + test_get_webbindings: + name: "{{ test_iis_site_name }}" + protocol: "{{ https_vars.protocol }}" + ip: "{{ https_vars.ip }}" + port: "{{ https_vars.port }}" + register: get_https_no_header + changed_when: false + +- name: idem remove assert changed and gone + assert: + that: + - https_no_header is not changed + - https_no_header.binding_info is not defined + - get_https_no_header.binding is not defined + + +################## +### WC Testing ### +################## + +# Unfortunately this does not work due to some strange errors +# that are caused when using a self signed wildcard cert. +# I'm leaving this here in case someone finds a solution in the +# future. + +# - name: add https binding wildcard with header +# win_iis_webbinding: +# name: "{{ test_iis_site_name }}" +# state: present +# host_header: "{{ https_wc_vars.header }}" +# protocol: "{{ https_wc_vars.protocol }}" +# ip: "{{ https_wc_vars.ip }}" +# port: "{{ https_wc_vars.port }}" +# certificate_hash: "{{ thumbprint_wc.stdout_lines[0] }}" +# register: https_header + +# - name: assert changed and added +# assert: +# that: +# - https_header is changed +# - https_header.added is defined +# - https_header.added.ip == "{{ https_wc_vars.ip }}" +# - https_header.added.port == {{ https_wc_vars.port }} +# - https_header.added.protocol == "{{ https_wc_vars.protocol }}" +# - https_header.added.hostheader == "{{ https_wc_vars.header }}" +# - https_header.added.certificateHash == "{{ thumbprint_wc.stdout_lines[0] }}" + + +# - name: idem add https binding wildcard with header +# win_iis_webbinding: +# name: "{{ test_iis_site_name }}" +# state: present +# host_header: "{{ https_wc_vars.header }}" +# protocol: "{{ https_wc_vars.protocol }}" +# ip: "{{ https_wc_vars.ip }}" +# port: "{{ https_wc_vars.port }}" +# certificate_hash: "{{ thumbprint_wc.stdout_lines[0] }}" +# register: https_header + + +# - name: cm remove wildcard https binding +# win_iis_webbinding: +# name: "{{ test_iis_site_name }}" +# state: absent +# host_header: "{{ https_wc_vars.header }}" +# protocol: "{{ https_wc_vars.protocol }}" +# ip: "{{ https_wc_vars.ip }}" +# port: "{{ https_wc_vars.port }}" +# register: https_header +# check_mode: yes + +# - name: get binding info header +# test_get_webbindings: +# name: "{{ test_iis_site_name }}" +# host_header: "{{ https_wc_vars.header }}" +# protocol: "{{ https_wc_vars.protocol }}" +# ip: "{{ https_wc_vars.ip }}" +# port: "{{ https_wc_vars.port }}" +# register: get_https_header +# changed_when: false + +# - name: cm remove assert changed, but still present +# assert: +# that: +# - https_header is changed +# - https_header.removed is defined +# - https_header.removed.ip == "{{ https_wc_vars.ip }}" +# - https_header.removed.port == {{ https_wc_vars.port }} +# - https_header.removed.protocol == "{{ https_wc_vars.protocol }}" +# - https_header.removed.hostheader == "{{ https_wc_vars.header }}" +# - https_header.removed.certificateHash == "{{ thumbprint_wc.stdout_lines[0] }}" +# - get_https_header.binding is defined +# - get_https_header.removed.ip == "{{ https_wc_vars.ip }}" +# - get_https_header.removed.port == {{ https_wc_vars.port }} +# - get_https_header.removed.protocol == "{{ https_wc_vars.protocol }}" +# - get_https_header.removed.hostheader == "{{ https_wc_vars.header }}" +# - get_https_header.removed.certificateHash == "{{ thumbprint_wc.stdout_lines[0] }}" + +# - name: remove wildcard https binding +# win_iis_webbinding: +# name: "{{ test_iis_site_name }}" +# state: absent +# host_header: "{{ https_wc_vars.header }}" +# protocol: "{{ https_wc_vars.protocol }}" +# ip: "{{ https_wc_vars.ip }}" +# port: "{{ https_wc_vars.port }}" +# register: https_header + +# - name: get binding info header +# test_get_webbindings: +# name: "{{ test_iis_site_name }}" +# host_header: "{{ https_wc_vars.header }}" +# protocol: "{{ https_wc_vars.protocol }}" +# ip: "{{ https_wc_vars.ip }}" +# port: "{{ https_wc_vars.port }}" +# register: get_https_header +# changed_when: false + + +# - name: remove assert changed and gone +# assert: +# that: +# - https_header is changed +# - https_header.removed is defined +# - https_header.removed.ip == "{{ https_wc_vars.ip }}" +# - https_header.removed.port == {{ https_wc_vars.port }} +# - https_header.removed.protocol == "{{ https_wc_vars.protocol }}" +# - https_header.removed.hostheader == "{{ https_wc_vars.header }}" +# - https_header.removed.certificateHash == "{{ thumbprint_wc.stdout_lines[0] }}" +# - get_https_header.binding is not defined + +# - name: idem remove wildcard https binding +# win_iis_webbinding: +# name: "{{ test_iis_site_name }}" +# state: absent +# host_header: "{{ https_wc_vars.header }}" +# protocol: "{{ https_wc_vars.protocol }}" +# ip: "{{ https_wc_vars.ip }}" +# port: "{{ https_wc_vars.port }}" +# register: https_header + +# - name: get binding info header +# test_get_webbindings: +# name: "{{ test_iis_site_name }}" +# host_header: "{{ https_wc_vars.header }}" +# protocol: "{{ https_wc_vars.protocol }}" +# ip: "{{ https_wc_vars.ip }}" +# port: "{{ https_wc_vars.port }}" +# register: get_https_header +# changed_when: false + +# - name: idem remove assert changed and gone +# assert: +# that: +# - https_header is not changed +# - https_header.removed is not defined +# - get_https_header.binding is not defined diff --git a/tests/integration/targets/win_iis_webbinding/tasks/main.yml b/tests/integration/targets/win_iis_webbinding/tasks/main.yml new file mode 100644 index 0000000..ee12ff7 --- /dev/null +++ b/tests/integration/targets/win_iis_webbinding/tasks/main.yml @@ -0,0 +1,62 @@ +--- +# Cannot use win_feature to install IIS on Server 2008. +# Run a brief check and skip hosts that don't support +# that operation +#seems "raw" is the only module that works on 2008 non-r2. win_command and win_shell both failed +- name: register os version (seems integration tests don't gather this fact) + raw: powershell.exe "gwmi Win32_OperatingSystem | select -expand version" + register: os_version + changed_when: False + +- block: + - include_tasks: setup.yml + - include_tasks: http.yml + - include_tasks: https-lt6.2.yml + when: os_version.stdout_lines[0] is version('6.2','lt') + - include_tasks: https-ge6.2.yml + when: os_version.stdout_lines[0] is version('6.2','ge') + - include_tasks: failures.yml + + always: + - name: get all websites from server + raw: powershell.exe "(get-website).name" + register: existing_sites + + - name: ensure all sites are removed for clean testing + win_iis_website: + name: "{{ item }}" + state: absent + with_items: + - "{{ existing_sites.stdout_lines }}" + + - name: cleanup certreq files + ansible.windows.win_file: + path: "{{ item }}" + state: absent + with_items: + - c:\windows\temp\certreq1.txt + - c:\windows\temp\certreq2.txt + - c:\windows\temp\certreqwc.txt + - c:\windows\temp\certreqresp1.txt + - c:\windows\temp\certreqresp2.txt + - c:\windows\temp\certreqrespwc.txt + + - name: remove certs + raw: 'remove-item cert:\localmachine\my\{{ item }} -force -ea silentlycontinue' + with_items: + - "{{ thumbprint1.stdout_lines[0] }}" + - "{{ thumbprint2.stdout_lines[0] }}" + - "{{ thumbprint_wc.stdout_lines[0] }}" + + - name: remove IIS features after test + ansible.windows.win_feature: + name: Web-Server + state: absent + includ_sub_features: True + include_management_tools: True + register: feature_uninstall + + - name: reboot after feature install + ansible.windows.win_reboot: + when: feature_uninstall.reboot_required + when: os_version.stdout_lines[0] is version('6.1','gt') diff --git a/tests/integration/targets/win_iis_webbinding/tasks/setup.yml b/tests/integration/targets/win_iis_webbinding/tasks/setup.yml new file mode 100644 index 0000000..234cc40 --- /dev/null +++ b/tests/integration/targets/win_iis_webbinding/tasks/setup.yml @@ -0,0 +1,93 @@ +- name: reboot before feature install to ensure server is in clean state + ansible.windows.win_reboot: + +- name: ensure IIS features are installed + ansible.windows.win_feature: + name: Web-Server + state: present + includ_sub_features: True + include_management_tools: True + register: feature_install + +- name: reboot after feature install + ansible.windows.win_reboot: + when: feature_install.reboot_required + +- name: get all websites from server + raw: powershell.exe "(get-website).name" + register: existing_sites + +- name: ensure all sites are removed for clean testing + win_iis_website: + name: "{{ item }}" + state: absent + with_items: + - "{{ existing_sites.stdout_lines }}" + +- name: add testing site {{ test_iis_site_name }} + win_iis_website: + name: "{{ test_iis_site_name }}" + physical_path: c:\inetpub\wwwroot + +- name: ensure all bindings are removed prior to starting testing + win_iis_webbinding: + name: "{{ test_iis_site_name }}" + state: absent + protocol: "{{ item.protocol }}" + port: "{{ item.port }}" + with_items: + - {protocol: http, port: 80} + - {protocol: https, port: 443} + +- name: copy certreq file + ansible.windows.win_copy: + content: |- + [NewRequest] + Subject = "CN={{ item.name }}" + KeyLength = 2048 + KeyAlgorithm = RSA + MachineKeySet = true + RequestType = Cert + dest: "{{ item.dest }}" + with_items: + - {name: test.com, dest: 'c:\windows\temp\certreq1.txt'} + - {name: test1.com, dest: 'c:\windows\temp\certreq2.txt'} + - {name: '*.test.com', dest: 'c:\windows\temp\certreqwc.txt'} + +- name: make sure response files are absent + ansible.windows.win_file: + path: "{{ item }}" + state: absent + with_items: + - 'c:\windows\temp\certreqresp1.txt' + - 'c:\windows\temp\certreqresp2.txt' + - 'c:\windows\temp\certreqrespwc.txt' + +- name: create self signed cert from certreq + ansible.windows.win_command: certreq -new -machine {{ item.req }} {{ item.resp }} + with_items: + - {req: 'c:\windows\temp\certreq1.txt', resp: 'c:\windows\temp\certreqresp1.txt'} + - {req: 'c:\windows\temp\certreq2.txt', resp: 'c:\windows\temp\certreqresp2.txt'} + - {req: 'c:\windows\temp\certreqwc.txt', resp: 'c:\windows\temp\certreqrespwc.txt'} + +- name: register certificate thumbprint1 + raw: '(gci Cert:\LocalMachine\my | ? {$_.subject -eq "CN=test.com"})[0].Thumbprint' + register: thumbprint1 + +- name: register certificate thumbprint2 + raw: '(gci Cert:\LocalMachine\my | ? {$_.subject -eq "CN=test1.com"})[0].Thumbprint' + register: thumbprint2 + +- name: register certificate thumbprint_wc + raw: '(gci Cert:\LocalMachine\my | ? {$_.subject -eq "CN=*.test.com"})[0].Thumbprint' + register: thumbprint_wc + +- debug: + var: thumbprint1.stdout + verbosity: 1 +- debug: + var: thumbprint2.stdout + verbosity: 1 +- debug: + var: thumbprint_wc.stdout + verbosity: 1 From 676de8cdddaf3a4483f4ab707c1abee758a2c5e3 Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Wed, 10 Jun 2020 12:08:35 +1000 Subject: [PATCH 02/10] Fix up docs after migration (#95) * Fix up docs after migration * Fix up sanity errors --- plugins/modules/win_iis_webbinding.py | 25 +++++++++---------------- plugins/modules/win_iis_website.py | 24 ++++++++++-------------- 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/plugins/modules/win_iis_webbinding.py b/plugins/modules/win_iis_webbinding.py index 5a86590..860226a 100644 --- a/plugins/modules/win_iis_webbinding.py +++ b/plugins/modules/win_iis_webbinding.py @@ -5,10 +5,6 @@ # Copyright: (c) 2017, Henrik Wallström # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - DOCUMENTATION = r''' --- module: win_iis_webbinding @@ -65,10 +61,10 @@ - Set to C(1) to enable SNI. type: str seealso: -- module: win_iis_virtualdirectory -- module: win_iis_webapplication -- module: win_iis_webapppool -- module: win_iis_website +- module: community.windows.win_iis_virtualdirectory +- module: community.windows.win_iis_webapplication +- module: community.windows.win_iis_webapppool +- module: community.windows.win_iis_website author: - Noah Sparks (@nwsparks) - Henrik Wallström (@henrikwallstrom) @@ -76,26 +72,26 @@ EXAMPLES = r''' - name: Add a HTTP binding on port 9090 - win_iis_webbinding: + community.windows.win_iis_webbinding: name: Default Web Site port: 9090 state: present - name: Remove the HTTP binding on port 9090 - win_iis_webbinding: + community.windows.win_iis_webbinding: name: Default Web Site port: 9090 state: absent - name: Remove the default http binding - win_iis_webbinding: + community.windows.win_iis_webbinding: name: Default Web Site port: 80 ip: '*' state: absent - name: Add a HTTPS binding - win_iis_webbinding: + community.windows.win_iis_webbinding: name: Default Web Site protocol: https port: 443 @@ -104,7 +100,7 @@ state: present - name: Add a HTTPS binding with host header and SNI enabled - win_iis_webbinding: + community.windows.win_iis_webbinding: name: Default Web Site protocol: https port: 443 @@ -123,7 +119,6 @@ returned: always type: str sample: "Started" - version_added: "2.5" operation_type: description: - The type of operation performed @@ -131,7 +126,6 @@ returned: on success type: str sample: "removed" - version_added: "2.5" binding_info: description: - Information on the binding being manipulated @@ -148,5 +142,4 @@ "protocol": "https", "sslFlags": "not supported" } - version_added: "2.5" ''' diff --git a/plugins/modules/win_iis_website.py b/plugins/modules/win_iis_website.py index aa2597c..34b1ac1 100644 --- a/plugins/modules/win_iis_website.py +++ b/plugins/modules/win_iis_website.py @@ -4,10 +4,6 @@ # Copyright: (c) 2015, Henrik Wallström # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - DOCUMENTATION = r''' --- module: win_iis_website @@ -60,10 +56,10 @@ - Custom site Parameters from string where properties are separated by a pipe and property name/values by colon Ex. "foo:1|bar:2" type: str seealso: -- module: win_iis_virtualdirectory -- module: win_iis_webapplication -- module: win_iis_webapppool -- module: win_iis_webbinding +- module: community.windows.win_iis_virtualdirectory +- module: community.windows.win_iis_webapplication +- module: community.windows.win_iis_webapppool +- module: community.windows.win_iis_webbinding author: - Henrik Wallström (@henrikwallstrom) ''' @@ -73,7 +69,7 @@ # Start a website - name: Acme IIS site - win_iis_website: + community.windows.win_iis_website: name: Acme state: started port: 80 @@ -86,14 +82,14 @@ # Remove Default Web Site and the standard port 80 binding - name: Remove Default Web Site - win_iis_website: + community.windows.win_iis_website: name: "Default Web Site" state: absent # Some commandline examples: # This return information about an existing host -# $ ansible -i vagrant-inventory -m win_iis_website -a "name='Default Web Site'" window +# $ ansible -i vagrant-inventory -m community.windows.win_iis_website -a "name='Default Web Site'" window # host | success >> { # "changed": false, # "site": { @@ -109,11 +105,11 @@ # } # This stops an existing site. -# $ ansible -i hosts -m win_iis_website -a "name='Default Web Site' state=stopped" host +# $ ansible -i hosts -m community.windows.win_iis_website -a "name='Default Web Site' state=stopped" host # This creates a new site. -# $ ansible -i hosts -m win_iis_website -a "name=acme physical_path=C:\\sites\\acme" host +# $ ansible -i hosts -m community.windows.win_iis_website -a "name=acme physical_path=C:\\sites\\acme" host # Change logfile. -# $ ansible -i hosts -m win_iis_website -a "name=acme physical_path=C:\\sites\\acme" host +# $ ansible -i hosts -m community.windows.win_iis_website -a "name=acme physical_path=C:\\sites\\acme" host ''' From f620cce04234fe08165be8a18d009bfe35db482c Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Thu, 11 Jun 2020 05:06:08 +1000 Subject: [PATCH 03/10] fix up sanity ignores (#97) * fix up sanity ignores * Bump ansible-windows dep * Fix bad change for win_region --- plugins/modules/win_iis_webbinding.ps1 | 14 +++++++------- plugins/modules/win_iis_website.ps1 | 14 +++++++------- .../library/test_get_webbindings.ps1 | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/plugins/modules/win_iis_webbinding.ps1 b/plugins/modules/win_iis_webbinding.ps1 index ffbd186..a9d90e6 100644 --- a/plugins/modules/win_iis_webbinding.ps1 +++ b/plugins/modules/win_iis_webbinding.ps1 @@ -26,7 +26,7 @@ $result = @{ ################# ### Functions ### ################# -function Create-BindingInfo { +function New-BindingInfo { $ht = @{ 'bindingInformation' = $args[0].bindingInformation 'ip' = $args[0].bindingInformation.split(':')[0] @@ -154,7 +154,7 @@ If ($certificateHash -and $state -eq 'present') #validate cert path $cert_path = "cert:\LocalMachine\$certificateStoreName\$certificateHash" - If (-Not (Test-Path $cert_path) ) + If (-Not (Test-Path -LiteralPath $cert_path) ) { Fail-Json -obj $result -message "Unable to locate certificate at $cert_path" } @@ -238,7 +238,7 @@ If ($current_bindings -and $state -eq 'absent') # removing bindings from iis may not also remove them from iis:\sslbindings $result.operation_type = 'removed' - $result.binding_info = $current_bindings | ForEach-Object {Create-BindingInfo $_} + $result.binding_info = $current_bindings | ForEach-Object {New-BindingInfo $_} Exit-Json -obj $result } ElseIf (-Not $current_bindings -and $state -eq 'absent') @@ -309,14 +309,14 @@ ElseIf ($current_bindings) $result.changed = $true $result.operation_type = 'updated' $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State - $result.binding_info = Create-BindingInfo (Get-SingleWebBinding $binding_parameters) + $result.binding_info = New-BindingInfo (Get-SingleWebBinding $binding_parameters) Exit-Json -obj $result #exit changed true } Else { $result.operation_type = 'matched' $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State - $result.binding_info = Create-BindingInfo (Get-SingleWebBinding $binding_parameters) + $result.binding_info = New-BindingInfo (Get-SingleWebBinding $binding_parameters) Exit-Json -obj $result #exit changed false } } @@ -366,10 +366,10 @@ ElseIf (-not $current_bindings -and $state -eq 'present') $result.operation_type = 'added' $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State - # incase there are no bindings we do a check before calling Create-BindingInfo + # incase there are no bindings we do a check before calling New-BindingInfo $web_binding = Get-SingleWebBinding $binding_parameters if ($web_binding) { - $result.binding_info = Create-BindingInfo $web_binding + $result.binding_info = New-BindingInfo $web_binding } else { $result.binding_info = $null } diff --git a/plugins/modules/win_iis_website.ps1 b/plugins/modules/win_iis_website.ps1 index e7b6cab..0b23c77 100644 --- a/plugins/modules/win_iis_website.ps1 +++ b/plugins/modules/win_iis_website.ps1 @@ -50,7 +50,7 @@ Try { If (-not $physical_path) { Fail-Json -obj $result -message "missing required arguments: physical_path" } - ElseIf (-not (Test-Path $physical_path)) { + ElseIf (-not (Test-Path -LiteralPath $physical_path)) { Fail-Json -obj $result -message "specified folder must already exist: physical_path" } @@ -82,7 +82,7 @@ Try { # Fix for error "New-Item : Index was outside the bounds of the array." # This is a bug in the New-WebSite commandlet. Apparently there must be at least one site configured in IIS otherwise New-WebSite crashes. # For more details, see http://stackoverflow.com/questions/3573889/ps-c-new-website-blah-throws-index-was-outside-the-bounds-of-the-array - $sites_list = get-childitem -Path IIS:\sites + $sites_list = Get-ChildItem -LiteralPath IIS:\sites if ($null -eq $sites_list) { if ($site_id) { $site_parameters.ID = $site_id @@ -105,13 +105,13 @@ Try { If($site) { # Change Physical Path if needed if($physical_path) { - If (-not (Test-Path $physical_path)) { + If (-not (Test-Path -LiteralPath $physical_path)) { Fail-Json -obj $result -message "specified folder must already exist: physical_path" } - $folder = Get-Item $physical_path + $folder = Get-Item -LiteralPath $physical_path If($folder.FullName -ne $site.PhysicalPath) { - Set-ItemProperty "IIS:\Sites\$($site.Name)" -name physicalPath -value $folder.FullName + Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" -name physicalPath -value $folder.FullName $result.changed = $true } } @@ -119,7 +119,7 @@ Try { # Change Application Pool if needed if($application_pool) { If($application_pool -ne $site.applicationPool) { - Set-ItemProperty "IIS:\Sites\$($site.Name)" -name applicationPool -value $application_pool + Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" -name applicationPool -value $application_pool $result.changed = $true } } @@ -127,7 +127,7 @@ Try { # Set properties if($parameters) { $parameters | ForEach-Object { - $property_value = Get-ItemProperty "IIS:\Sites\$($site.Name)" $_[0] + $property_value = Get-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" $_[0] switch ($property_value.GetType().Name) { diff --git a/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 b/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 index 84ef10b..065f670 100644 --- a/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 +++ b/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 @@ -16,7 +16,7 @@ $ip = Get-AnsibleParam $params -name "ip" -default '*' $result = @{ changed = $false } -function Create-BindingInfo { +function New-BindingInfo { $ht = @{ 'bindingInformation' = $args[0].bindingInformation 'ip' = $args[0].bindingInformation.split(':')[0] @@ -102,7 +102,7 @@ Catch { If ($current_bindings) { Try { - $binding_info = Create-BindingInfo $current_bindings + $binding_info = New-BindingInfo $current_bindings } Catch { Fail-Json -obj $result -message "Failed to create binding info - $($_.Exception.Message)" From 1890b8fe95b20dcd5cfa05dad68ce8b15c36bbb5 Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Sat, 20 Jun 2020 09:40:00 +1000 Subject: [PATCH 04/10] Add Extra Information for IIS parameters. (#9) * Add Extra Information for IIS parameters. hen configuring a website with custom site parameters, for people who are not familiar with PowerShell or IIS, it would be great to add in the documentation some examples to show them how to use these parameters. * Slight tweaks to the docs Co-authored-by: Emir Madrueno Peregrina <41549325+jorgeemir29@users.noreply.github.com> --- plugins/modules/win_iis_website.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/plugins/modules/win_iis_website.py b/plugins/modules/win_iis_website.py index 34b1ac1..130a42b 100644 --- a/plugins/modules/win_iis_website.py +++ b/plugins/modules/win_iis_website.py @@ -54,6 +54,12 @@ parameters: description: - Custom site Parameters from string where properties are separated by a pipe and property name/values by colon Ex. "foo:1|bar:2" + - Some custom parameters that you can use are listed below, this isn't a definitive list but some common parameters. + - C(logfile.directory) - Physical path to store Logs, e.g. C(D:\IIS-LOGs\). + - C(logfile.period) - Log file rollover scheduled accepting these values, how frequently the log file should be rolled-over, + e.g. C(Hourly, Daily, Weekly, Monthly). + - C(logfile.LogFormat) - Log file format, by default IIS uses C(W3C). + - C(logfile.truncateSize) - The size at which the log file contents will be trunsted, expressed in bytes. type: str seealso: - module: community.windows.win_iis_virtualdirectory @@ -86,6 +92,19 @@ name: "Default Web Site" state: absent +# Create a WebSite with custom Logging configuration (Logs Location, Format and Rolling Over). + +- name: Creating WebSite with Custom Log location, Format 3WC and rolling over every hour. + community.windows.win_iis_website: + name: MyCustom_Web_Shop_Site + state: started + port: 80 + ip: '*' + hostname: '*' + physical_path: D:\wwwroot\websites\my-shop-site + parameters: logfile.directory:D:\IIS-LOGS\websites\my-shop-site|logfile.period:Hourly|logFile.logFormat:W3C + application_pool: my-shop-site + # Some commandline examples: # This return information about an existing host From b1219d529bb45ea8ca906e1218131f88dd0173ee Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Fri, 14 Aug 2020 09:39:14 +1000 Subject: [PATCH 05/10] Rebalance the test targets (#128) * Rebalance the test targets * Make sure IIS test removes the service so our httptester works --- tests/integration/targets/win_iis_webbinding/aliases | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/targets/win_iis_webbinding/aliases b/tests/integration/targets/win_iis_webbinding/aliases index 4f4664b..423ce39 100644 --- a/tests/integration/targets/win_iis_webbinding/aliases +++ b/tests/integration/targets/win_iis_webbinding/aliases @@ -1 +1 @@ -shippable/windows/group5 +shippable/windows/group2 From 135cb97e22cd40356a62686c581b3542dff43160 Mon Sep 17 00:00:00 2001 From: egvimo Date: Sat, 8 May 2021 04:56:50 +0200 Subject: [PATCH 06/10] Remove obsolte ssl parameter (#234) Co-authored-by: Egor Moor --- plugins/modules/win_iis_website.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/modules/win_iis_website.py b/plugins/modules/win_iis_website.py index 130a42b..c1fe192 100644 --- a/plugins/modules/win_iis_website.py +++ b/plugins/modules/win_iis_website.py @@ -47,10 +47,6 @@ description: - The host header to bind to / use for the new site. type: str - ssl: - description: - - Enables HTTPS binding on the site.. - type: str parameters: description: - Custom site Parameters from string where properties are separated by a pipe and property name/values by colon Ex. "foo:1|bar:2" From 790753da80ee1864e175ee2ea74fec8f00d0c294 Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Thu, 11 Nov 2021 18:21:45 +1000 Subject: [PATCH 07/10] Fix devel sanity checks - ci_complete (#331) --- plugins/modules/win_iis_webbinding.ps1 | 147 +++++------- plugins/modules/win_iis_website.ps1 | 221 +++++++++--------- .../library/test_get_webbindings.ps1 | 27 +-- 3 files changed, 177 insertions(+), 218 deletions(-) diff --git a/plugins/modules/win_iis_webbinding.ps1 b/plugins/modules/win_iis_webbinding.ps1 index a9d90e6..b6073f4 100644 --- a/plugins/modules/win_iis_webbinding.ps1 +++ b/plugins/modules/win_iis_webbinding.ps1 @@ -10,17 +10,17 @@ $params = Parse-Args -arguments $args -supports_check_mode $true $check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false $name = Get-AnsibleParam $params -name "name" -type str -failifempty $true -aliases 'website' -$state = Get-AnsibleParam $params "state" -default "present" -validateSet "present","absent" +$state = Get-AnsibleParam $params "state" -default "present" -validateSet "present", "absent" $host_header = Get-AnsibleParam $params -name "host_header" -type str $protocol = Get-AnsibleParam $params -name "protocol" -type str -default 'http' $port = Get-AnsibleParam $params -name "port" -default '80' $ip = Get-AnsibleParam $params -name "ip" -default '*' $certificateHash = Get-AnsibleParam $params -name "certificate_hash" -type str -default ([string]::Empty) $certificateStoreName = Get-AnsibleParam $params -name "certificate_store_name" -type str -default ([string]::Empty) -$sslFlags = Get-AnsibleParam $params -name "ssl_flags" -default '0' -ValidateSet '0','1','2','3' +$sslFlags = Get-AnsibleParam $params -name "ssl_flags" -default '0' -ValidateSet '0', '1', '2', '3' $result = @{ - changed = $false + changed = $false } ################# @@ -39,12 +39,10 @@ function New-BindingInfo { } #handle sslflag support - If ([version][System.Environment]::OSVersion.Version -lt [version]'6.2') - { + If ([version][System.Environment]::OSVersion.Version -lt [version]'6.2') { $ht.sslFlags = 'not supported' } - Else - { + Else { $ht.sslFlags = [int]$args[0].sslFlags } @@ -61,15 +59,14 @@ function Get-SingleWebBinding { } Catch { # 2k8r2 throws this error when you run get-webbinding with no bindings in iis - If (-not $_.Exception.Message.CompareTo('Cannot process argument because the value of argument "obj" is null. Change the value of argument "obj" to a non-null value')) - { + $msg = 'Cannot process argument because the value of argument "obj" is null. Change the value of argument "obj" to a non-null value' + If (-not $_.Exception.Message.CompareTo($msg)) { Throw $_.Exception.Message } Else { return } } - Foreach ($binding in $site_bindings) - { + Foreach ($binding in $site_bindings) { $splits = $binding.bindingInformation -split ':' if ( @@ -77,8 +74,7 @@ function Get-SingleWebBinding { $args[0].ipaddress -eq $splits[0] -and $args[0].port -eq $splits[1] -and $args[0].hostheader -eq $splits[2] - ) - { + ) { Return $binding } } @@ -91,8 +87,7 @@ function Get-SingleWebBinding { $os_version = [version][System.Environment]::OSVersion.Version # Ensure WebAdministration module is loaded -If ($os_version -lt [version]'6.1') -{ +If ($os_version -lt [version]'6.1') { Try { Add-PSSnapin WebAdministration } @@ -100,8 +95,7 @@ If ($os_version -lt [version]'6.1') Fail-Json -obj $result -message "The WebAdministration snap-in is not present. Please make sure it is installed." } } -Else -{ +Else { Try { Import-Module WebAdministration } @@ -111,66 +105,55 @@ Else } # ensure website targetted exists. -Name filter doesn't work on 2k8r2 so do where-object instead -$website_check = get-website | Where-Object {$_.name -eq $name} -If (-not $website_check) -{ +$website_check = get-website | Where-Object { $_.name -eq $name } +If (-not $website_check) { Fail-Json -obj $result -message "Unable to retrieve website with name $Name. Make sure the website name is valid and exists." } # if OS older than 2012 (6.2) and ssl flags are set, fail. Otherwise toggle sni_support -If ($os_version -lt [version]'6.2') -{ - If ($sslFlags -ne 0) - { +If ($os_version -lt [version]'6.2') { + If ($sslFlags -ne 0) { Fail-Json -obj $result -message "SNI and Certificate Store support is not available for systems older than 2012 (6.2)" } $sni_support = $false #will cause the sslflags check later to skip } -Else -{ +Else { $sni_support = $true } # make sure ssl flags only specified with https protocol -If ($protocol -ne 'https' -and $sslFlags -gt 0) -{ +If ($protocol -ne 'https' -and $sslFlags -gt 0) { Fail-Json -obj $result -message "SSLFlags can only be set for HTTPS protocol" } # validate certificate details if provided # we don't do anything with cert on state: absent, so only validate present -If ($certificateHash -and $state -eq 'present') -{ - If ($protocol -ne 'https') - { +If ($certificateHash -and $state -eq 'present') { + If ($protocol -ne 'https') { Fail-Json -obj $result -message "You can only provide a certificate thumbprint when protocol is set to https" } #apply default for cert store name - If (-Not $certificateStoreName) - { + If (-Not $certificateStoreName) { $certificateStoreName = 'my' } #validate cert path $cert_path = "cert:\LocalMachine\$certificateStoreName\$certificateHash" - If (-Not (Test-Path -LiteralPath $cert_path) ) - { + If (-Not (Test-Path -LiteralPath $cert_path) ) { Fail-Json -obj $result -message "Unable to locate certificate at $cert_path" } } # make sure binding info is valid for central cert store if sslflags -gt 1 -If ($sslFlags -gt 1 -and ($certificateHash -ne [string]::Empty -or $certificateStoreName -ne [string]::Empty)) -{ +If ($sslFlags -gt 1 -and ($certificateHash -ne [string]::Empty -or $certificateStoreName -ne [string]::Empty)) { Fail-Json -obj $result -message "You set sslFlags to $sslFlags. This indicates you wish to use the Central Certificate Store feature. This cannot be used in combination with certficiate_hash and certificate_store_name. When using the Central Certificate Store feature, the certificate is automatically retrieved from the store rather than manually assigned to the binding." } # disallow host_header: '*' -If ($host_header -eq '*') -{ +If ($host_header -eq '*') { Fail-Json -obj $result -message "To make or remove a catch-all binding, please omit the host_header parameter entirely rather than specify host_header *" } @@ -180,19 +163,17 @@ If ($host_header -eq '*') # create binding search splat $binding_parameters = @{ - Name = $name - Protocol = $protocol - Port = $port - IPAddress = $ip + Name = $name + Protocol = $protocol + Port = $port + IPAddress = $ip } # insert host header to search if specified, otherwise it will return * (all bindings matching protocol/ip) -If ($host_header) -{ +If ($host_header) { $binding_parameters.HostHeader = $host_header } -Else -{ +Else { $binding_parameters.HostHeader = [string]::Empty } @@ -207,8 +188,7 @@ Catch { ################################################ ### Remove binding or exit if already absent ### ################################################ -If ($current_bindings -and $state -eq 'absent') -{ +If ($current_bindings -and $state -eq 'absent') { Try { #there is a bug in this method that will result in all bindings being removed if the IP in $current_bindings is a * #$current_bindings | Remove-WebBinding -verbose -WhatIf:$check_mode @@ -238,11 +218,10 @@ If ($current_bindings -and $state -eq 'absent') # removing bindings from iis may not also remove them from iis:\sslbindings $result.operation_type = 'removed' - $result.binding_info = $current_bindings | ForEach-Object {New-BindingInfo $_} + $result.binding_info = $current_bindings | ForEach-Object { New-BindingInfo $_ } Exit-Json -obj $result } -ElseIf (-Not $current_bindings -and $state -eq 'absent') -{ +ElseIf (-Not $current_bindings -and $state -eq 'absent') { # exit changed: false since it's already gone Exit-Json -obj $result } @@ -257,8 +236,7 @@ we just need to check here for the ones that are not available which are the ssl settings (hash, store, sslflags). If they aren't set we update here, or exit with changed: false #> -ElseIf ($current_bindings) -{ +ElseIf ($current_bindings) { #ran into a strange edge case in testing where I was able to retrieve bindings but not expand all the properties #when adding a self-signed wildcard cert to a binding. it seemed to permanently break the binding. only removing it #would cause the error to stop. @@ -266,17 +244,19 @@ ElseIf ($current_bindings) $null = $current_bindings | Select-Object * } Catch { - Fail-Json -obj $result -message "Found a matching binding, but failed to expand it's properties (get-binding | FL *). In testing, this was caused by using a self-signed wildcard certificate. $($_.Exception.Message)" + $msg = -join @( + "Found a matching binding, but failed to expand it's properties (get-binding | FL *). " + "In testing, this was caused by using a self-signed wildcard certificate. $($_.Exception.Message)" + ) + Fail-Json -obj $result -message $msg } # check if there is a match on the ssl parameters If ( ($current_bindings.sslFlags -ne $sslFlags -and $sni_support) -or $current_bindings.certificateHash -ne $certificateHash -or - $current_bindings.certificateStoreName -ne $certificateStoreName) - { + $current_bindings.certificateStoreName -ne $certificateStoreName) { # match/update SNI - If ($current_bindings.sslFlags -ne $sslFlags -and $sni_support) - { + If ($current_bindings.sslFlags -ne $sslFlags -and $sni_support) { Try { Set-WebBinding -Name $name -IPAddress $ip -Port $port -HostHeader $host_header -PropertyName sslFlags -value $sslFlags -whatif:$check_mode $result.changed = $true @@ -294,12 +274,10 @@ ElseIf ($current_bindings) } } # match/update certificate - If ($current_bindings.certificateHash -ne $certificateHash -or $current_bindings.certificateStoreName -ne $certificateStoreName) - { - If (-Not $check_mode) - { + If ($current_bindings.certificateHash -ne $certificateHash -or $current_bindings.certificateStoreName -ne $certificateStoreName) { + If (-Not $check_mode) { Try { - $current_bindings.AddSslCertificate($certificateHash,$certificateStoreName) + $current_bindings.AddSslCertificate($certificateHash, $certificateStoreName) } Catch { Fail-Json -obj $result -message "Failed to set new SSL certificate - $($_.Exception.Message)" @@ -308,14 +286,13 @@ ElseIf ($current_bindings) } $result.changed = $true $result.operation_type = 'updated' - $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State + $result.website_state = (Get-Website | Where-Object { $_.Name -eq $Name }).State $result.binding_info = New-BindingInfo (Get-SingleWebBinding $binding_parameters) Exit-Json -obj $result #exit changed true } - Else - { + Else { $result.operation_type = 'matched' - $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State + $result.website_state = (Get-Website | Where-Object { $_.Name -eq $Name }).State $result.binding_info = New-BindingInfo (Get-SingleWebBinding $binding_parameters) Exit-Json -obj $result #exit changed false } @@ -324,53 +301,47 @@ ElseIf ($current_bindings) ######################## ### Add new bindings ### ######################## -ElseIf (-not $current_bindings -and $state -eq 'present') -{ +ElseIf (-not $current_bindings -and $state -eq 'present') { # add binding. this creates the binding, but does not apply a certificate to it. - Try - { - If (-not $check_mode) - { - If ($sni_support) - { + Try { + If (-not $check_mode) { + If ($sni_support) { New-WebBinding @binding_parameters -SslFlags $sslFlags -Force } - Else - { + Else { New-WebBinding @binding_parameters -Force } } $result.changed = $true } - Catch - { - $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State + Catch { + $result.website_state = (Get-Website | Where-Object { $_.Name -eq $Name }).State Fail-Json -obj $result -message "Failed at creating new binding (note: creating binding and adding ssl are separate steps) - $($_.Exception.Message)" } # add certificate to binding - If ($certificateHash -and -not $check_mode) - { + If ($certificateHash -and -not $check_mode) { Try { #$new_binding = get-webbinding -Name $name -IPAddress $ip -port $port -Protocol $protocol -hostheader $host_header $new_binding = Get-SingleWebBinding $binding_parameters - $new_binding.addsslcertificate($certificateHash,$certificateStoreName) + $new_binding.addsslcertificate($certificateHash, $certificateStoreName) } Catch { - $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State + $result.website_state = (Get-Website | Where-Object { $_.Name -eq $Name }).State Fail-Json -obj $result -message "Failed to set new SSL certificate - $($_.Exception.Message)" } } $result.changed = $true $result.operation_type = 'added' - $result.website_state = (Get-Website | Where-Object {$_.Name -eq $Name}).State + $result.website_state = (Get-Website | Where-Object { $_.Name -eq $Name }).State # incase there are no bindings we do a check before calling New-BindingInfo $web_binding = Get-SingleWebBinding $binding_parameters if ($web_binding) { $result.binding_info = New-BindingInfo $web_binding - } else { + } + else { $result.binding_info = $null } Exit-Json $result diff --git a/plugins/modules/win_iis_website.ps1 b/plugins/modules/win_iis_website.ps1 index 0b23c77..e625821 100644 --- a/plugins/modules/win_iis_website.ps1 +++ b/plugins/modules/win_iis_website.ps1 @@ -12,7 +12,7 @@ $name = Get-AnsibleParam -obj $params -name "name" -type "str" -failifempty $tru $application_pool = Get-AnsibleParam -obj $params -name "application_pool" -type "str" $physical_path = Get-AnsibleParam -obj $params -name "physical_path" -type "str" $site_id = Get-AnsibleParam -obj $params -name "site_id" -type "str" -$state = Get-AnsibleParam -obj $params -name "state" -type "str" -validateset "absent","restarted","started","stopped" +$state = Get-AnsibleParam -obj $params -name "state" -type "str" -validateset "absent", "restarted", "started", "stopped" # Binding Parameters $bind_port = Get-AnsibleParam -obj $params -name "port" -type "int" @@ -23,158 +23,153 @@ $bind_hostname = Get-AnsibleParam -obj $params -name "hostname" -type "str" # are separated by a pipe and property name/values by colon. # Ex. "foo:1|bar:2" $parameters = Get-AnsibleParam -obj $params -name "parameters" -type "str" -if($null -ne $parameters) { - $parameters = @($parameters -split '\|' | ForEach-Object { - return ,($_ -split "\:", 2); - }) +if ($null -ne $parameters) { + $parameters = @($parameters -split '\|' | ForEach-Object { + return , ($_ -split "\:", 2); + }) } # Ensure WebAdministration module is loaded if ($null -eq (Get-Module "WebAdministration" -ErrorAction SilentlyContinue)) { - Import-Module WebAdministration + Import-Module WebAdministration } # Result $result = @{ - site = @{} - changed = $false + site = @{} + changed = $false } # Site info $site = Get-Website | Where-Object { $_.Name -eq $name } Try { - # Add site - If(($state -ne 'absent') -and (-not $site)) { - If (-not $physical_path) { - Fail-Json -obj $result -message "missing required arguments: physical_path" - } - ElseIf (-not (Test-Path -LiteralPath $physical_path)) { - Fail-Json -obj $result -message "specified folder must already exist: physical_path" - } + # Add site + If (($state -ne 'absent') -and (-not $site)) { + If (-not $physical_path) { + Fail-Json -obj $result -message "missing required arguments: physical_path" + } + ElseIf (-not (Test-Path -LiteralPath $physical_path)) { + Fail-Json -obj $result -message "specified folder must already exist: physical_path" + } - $site_parameters = @{ - Name = $name - PhysicalPath = $physical_path - } + $site_parameters = @{ + Name = $name + PhysicalPath = $physical_path + } - If ($application_pool) { - $site_parameters.ApplicationPool = $application_pool - } + If ($application_pool) { + $site_parameters.ApplicationPool = $application_pool + } - If ($site_id) { - $site_parameters.ID = $site_id - } + If ($site_id) { + $site_parameters.ID = $site_id + } - If ($bind_port) { - $site_parameters.Port = $bind_port - } + If ($bind_port) { + $site_parameters.Port = $bind_port + } - If ($bind_ip) { - $site_parameters.IPAddress = $bind_ip - } + If ($bind_ip) { + $site_parameters.IPAddress = $bind_ip + } - If ($bind_hostname) { - $site_parameters.HostHeader = $bind_hostname - } + If ($bind_hostname) { + $site_parameters.HostHeader = $bind_hostname + } - # Fix for error "New-Item : Index was outside the bounds of the array." - # This is a bug in the New-WebSite commandlet. Apparently there must be at least one site configured in IIS otherwise New-WebSite crashes. - # For more details, see http://stackoverflow.com/questions/3573889/ps-c-new-website-blah-throws-index-was-outside-the-bounds-of-the-array - $sites_list = Get-ChildItem -LiteralPath IIS:\sites - if ($null -eq $sites_list) { - if ($site_id) { - $site_parameters.ID = $site_id - } else { - $site_parameters.ID = 1 - } - } + # Fix for error "New-Item : Index was outside the bounds of the array." + # This is a bug in the New-WebSite commandlet. Apparently there must be at least one site configured in IIS otherwise New-WebSite crashes. + # For more details, see http://stackoverflow.com/questions/3573889/ps-c-new-website-blah-throws-index-was-outside-the-bounds-of-the-array + $sites_list = Get-ChildItem -LiteralPath IIS:\sites + if ($null -eq $sites_list) { + if ($site_id) { + $site_parameters.ID = $site_id + } + else { + $site_parameters.ID = 1 + } + } - $site = New-Website @site_parameters -Force - $result.changed = $true - } - - # Remove site - If ($state -eq 'absent' -and $site) { - $site = Remove-Website -Name $name - $result.changed = $true - } - - $site = Get-Website | Where-Object { $_.Name -eq $name } - If($site) { - # Change Physical Path if needed - if($physical_path) { - If (-not (Test-Path -LiteralPath $physical_path)) { - Fail-Json -obj $result -message "specified folder must already exist: physical_path" - } - - $folder = Get-Item -LiteralPath $physical_path - If($folder.FullName -ne $site.PhysicalPath) { - Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" -name physicalPath -value $folder.FullName + $site = New-Website @site_parameters -Force $result.changed = $true - } } - # Change Application Pool if needed - if($application_pool) { - If($application_pool -ne $site.applicationPool) { - Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" -name applicationPool -value $application_pool + # Remove site + If ($state -eq 'absent' -and $site) { + $site = Remove-Website -Name $name $result.changed = $true - } } - # Set properties - if($parameters) { - $parameters | ForEach-Object { - $property_value = Get-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" $_[0] + $site = Get-Website | Where-Object { $_.Name -eq $name } + If ($site) { + # Change Physical Path if needed + if ($physical_path) { + If (-not (Test-Path -LiteralPath $physical_path)) { + Fail-Json -obj $result -message "specified folder must already exist: physical_path" + } + + $folder = Get-Item -LiteralPath $physical_path + If ($folder.FullName -ne $site.PhysicalPath) { + Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" -name physicalPath -value $folder.FullName + $result.changed = $true + } + } - switch ($property_value.GetType().Name) - { - "ConfigurationAttribute" { $parameter_value = $property_value.value } - "String" { $parameter_value = $property_value } + # Change Application Pool if needed + if ($application_pool) { + If ($application_pool -ne $site.applicationPool) { + Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" -name applicationPool -value $application_pool + $result.changed = $true + } } - if((-not $parameter_value) -or ($parameter_value) -ne $_[1]) { - Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" $_[0] $_[1] - $result.changed = $true + # Set properties + if ($parameters) { + $parameters | ForEach-Object { + $property_value = Get-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" $_[0] + + switch ($property_value.GetType().Name) { + "ConfigurationAttribute" { $parameter_value = $property_value.value } + "String" { $parameter_value = $property_value } + } + + if ((-not $parameter_value) -or ($parameter_value) -ne $_[1]) { + Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" $_[0] $_[1] + $result.changed = $true + } + } } - } - } - # Set run state - if ((($state -eq 'stopped') -or ($state -eq 'restarted')) -and ($site.State -eq 'Started')) - { - Stop-Website -Name $name -ErrorAction Stop - $result.changed = $true - } - if ((($state -eq 'started') -and ($site.State -eq 'Stopped')) -or ($state -eq 'restarted')) - { - Start-Website -Name $name -ErrorAction Stop - $result.changed = $true + # Set run state + if ((($state -eq 'stopped') -or ($state -eq 'restarted')) -and ($site.State -eq 'Started')) { + Stop-Website -Name $name -ErrorAction Stop + $result.changed = $true + } + if ((($state -eq 'started') -and ($site.State -eq 'Stopped')) -or ($state -eq 'restarted')) { + Start-Website -Name $name -ErrorAction Stop + $result.changed = $true + } } - } } -Catch -{ - Fail-Json -obj $result -message $_.Exception.Message +Catch { + Fail-Json -obj $result -message $_.Exception.Message } -if ($state -ne 'absent') -{ - $site = Get-Website | Where-Object { $_.Name -eq $name } +if ($state -ne 'absent') { + $site = Get-Website | Where-Object { $_.Name -eq $name } } -if ($site) -{ - $result.site = @{ - Name = $site.Name - ID = $site.ID - State = $site.State - PhysicalPath = $site.PhysicalPath - ApplicationPool = $site.applicationPool - Bindings = @($site.Bindings.Collection | ForEach-Object { $_.BindingInformation }) - } +if ($site) { + $result.site = @{ + Name = $site.Name + ID = $site.ID + State = $site.State + PhysicalPath = $site.PhysicalPath + ApplicationPool = $site.applicationPool + Bindings = @($site.Bindings.Collection | ForEach-Object { $_.BindingInformation }) + } } Exit-Json -obj $result diff --git a/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 b/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 index 065f670..f1d49f4 100644 --- a/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 +++ b/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 @@ -14,7 +14,7 @@ $port = Get-AnsibleParam $params -name "port" -type int -default '80' $ip = Get-AnsibleParam $params -name "ip" -default '*' $result = @{ - changed = $false + changed = $false } function New-BindingInfo { $ht = @{ @@ -29,12 +29,10 @@ function New-BindingInfo { } #handle sslflag support - If ([version][System.Environment]::OSVersion.Version -lt [version]'6.2') - { + If ([version][System.Environment]::OSVersion.Version -lt [version]'6.2') { $ht.sslFlags = 'not supported' } - Else - { + Else { $ht.sslFlags = [int]$args[0].sslFlags } @@ -50,15 +48,14 @@ function Get-SingleWebBinding { } Catch { # 2k8r2 throws this error when you run get-webbinding with no bindings in iis - If (-not $_.Exception.Message.CompareTo('Cannot process argument because the value of argument "obj" is null. Change the value of argument "obj" to a non-null value')) - { + $msg = 'Cannot process argument because the value of argument "obj" is null. Change the value of argument "obj" to a non-null value' + If (-not $_.Exception.Message.CompareTo($msg)) { Throw $_.Exception.Message } Else { return } } - Foreach ($binding in $site_bindings) - { + Foreach ($binding in $site_bindings) { $splits = $binding.bindingInformation -split ':' if ( @@ -66,8 +63,7 @@ function Get-SingleWebBinding { $args[0].ipaddress -eq $splits[0] -and $args[0].port -eq $splits[1] -and $args[0].hostheader -eq $splits[2] - ) - { + ) { Return $binding } } @@ -82,12 +78,10 @@ $binding_parameters = @{ } # insert host header to search if specified, otherwise it will return * (all bindings matching protocol/ip) -If ($host_header) -{ +If ($host_header) { $binding_parameters.HostHeader = $host_header } -Else -{ +Else { $binding_parameters.HostHeader = [string]::Empty } @@ -99,8 +93,7 @@ Catch { Fail-Json -obj $result -message "Failed to retrieve bindings with Get-SingleWebBinding - $($_.Exception.Message)" } -If ($current_bindings) -{ +If ($current_bindings) { Try { $binding_info = New-BindingInfo $current_bindings } From 3d332ad7bd9fabe40486f166071453749ca5e5ca Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Mon, 21 Mar 2022 11:11:32 +1000 Subject: [PATCH 08/10] Fix new sanity issues (#368) --- plugins/modules/win_iis_webbinding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/win_iis_webbinding.py b/plugins/modules/win_iis_webbinding.py index 860226a..cf3d42b 100644 --- a/plugins/modules/win_iis_webbinding.py +++ b/plugins/modules/win_iis_webbinding.py @@ -27,7 +27,7 @@ port: description: - The port to bind to / use for the new site. - type: str + type: int default: 80 ip: description: From 2717358a385d7e22df78d8b040c35365256d43cd Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Wed, 2 Nov 2022 11:03:53 +1000 Subject: [PATCH 09/10] Bulk semicolon fix for pslint rule (#455) --- plugins/modules/win_iis_website.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/win_iis_website.ps1 b/plugins/modules/win_iis_website.ps1 index e625821..571fb3d 100644 --- a/plugins/modules/win_iis_website.ps1 +++ b/plugins/modules/win_iis_website.ps1 @@ -25,7 +25,7 @@ $bind_hostname = Get-AnsibleParam -obj $params -name "hostname" -type "str" $parameters = Get-AnsibleParam -obj $params -name "parameters" -type "str" if ($null -ne $parameters) { $parameters = @($parameters -split '\|' | ForEach-Object { - return , ($_ -split "\:", 2); + return , ($_ -split "\:", 2) }) } From 7a0c42abcae1963c0e29dbeaef9ad6041006ebb4 Mon Sep 17 00:00:00 2001 From: Shahar Golshani Date: Wed, 1 Jan 2025 01:59:41 +0200 Subject: [PATCH 10/10] Migrate win_iis_website and win_iis_webbinding --- plugins/modules/website.ps1 | 265 +++++++++- plugins/modules/website.yml | 241 ++++++++- plugins/modules/website_info.ps1 | 77 +++ plugins/modules/website_info.yml | 121 +++++ plugins/modules/win_iis_webbinding.ps1 | 348 ------------- plugins/modules/win_iis_webbinding.py | 145 ------ plugins/modules/win_iis_website.ps1 | 175 ------- plugins/modules/win_iis_website.py | 130 ----- tests/integration/targets/website/aliases | 2 +- .../targets/website/defaults/main.yml | 11 + .../integration/targets/website/meta/main.yml | 3 + .../targets/website/tasks/bindings.yml | 251 ++++++++++ .../targets/website/tasks/main.yml | 106 +++- .../targets/website/tasks/tests.yml | 187 +++++++ .../integration/targets/website_info/aliases | 2 + .../targets/website_info/defaults/main.yml | 17 + .../targets/website_info/meta/main.yml | 3 + .../targets/website_info/tasks/main.yml | 98 ++++ .../targets/website_info/tasks/tests.yml | 81 ++++ .../targets/win_iis_webbinding/aliases | 1 - .../win_iis_webbinding/defaults/main.yml | 30 -- .../library/test_get_webbindings.ps1 | 106 ---- .../win_iis_webbinding/tasks/failures.yml | 70 --- .../targets/win_iis_webbinding/tasks/http.yml | 317 ------------ .../win_iis_webbinding/tasks/https-ge6.2.yml | 459 ------------------ .../win_iis_webbinding/tasks/https-lt6.2.yml | 423 ---------------- .../targets/win_iis_webbinding/tasks/main.yml | 62 --- .../win_iis_webbinding/tasks/setup.yml | 93 ---- 28 files changed, 1432 insertions(+), 2392 deletions(-) create mode 100644 plugins/modules/website_info.ps1 create mode 100644 plugins/modules/website_info.yml delete mode 100644 plugins/modules/win_iis_webbinding.ps1 delete mode 100644 plugins/modules/win_iis_webbinding.py delete mode 100644 plugins/modules/win_iis_website.ps1 delete mode 100644 plugins/modules/win_iis_website.py create mode 100644 tests/integration/targets/website/defaults/main.yml create mode 100644 tests/integration/targets/website/meta/main.yml create mode 100644 tests/integration/targets/website/tasks/bindings.yml create mode 100644 tests/integration/targets/website/tasks/tests.yml create mode 100644 tests/integration/targets/website_info/aliases create mode 100644 tests/integration/targets/website_info/defaults/main.yml create mode 100644 tests/integration/targets/website_info/meta/main.yml create mode 100644 tests/integration/targets/website_info/tasks/main.yml create mode 100644 tests/integration/targets/website_info/tasks/tests.yml delete mode 100644 tests/integration/targets/win_iis_webbinding/aliases delete mode 100644 tests/integration/targets/win_iis_webbinding/defaults/main.yml delete mode 100644 tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 delete mode 100644 tests/integration/targets/win_iis_webbinding/tasks/failures.yml delete mode 100644 tests/integration/targets/win_iis_webbinding/tasks/http.yml delete mode 100644 tests/integration/targets/win_iis_webbinding/tasks/https-ge6.2.yml delete mode 100644 tests/integration/targets/win_iis_webbinding/tasks/https-lt6.2.yml delete mode 100644 tests/integration/targets/win_iis_webbinding/tasks/main.yml delete mode 100644 tests/integration/targets/win_iis_webbinding/tasks/setup.yml diff --git a/plugins/modules/website.ps1 b/plugins/modules/website.ps1 index 957cf5c..f2ec174 100644 --- a/plugins/modules/website.ps1 +++ b/plugins/modules/website.ps1 @@ -1,27 +1,280 @@ #!powershell -# Copyright: (c) 2024, Ansible Project +# Copyright: (c) 2025, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) #AnsibleRequires -CSharpUtil Ansible.Basic +# Define Bindings Options +$binding_options = @{ + type = 'list' + elements = 'dict' + options = @{ + ip = @{ type = 'str' } + port = @{ type = 'int' } + hostname = @{ type = 'str' } + protocol = @{ type = 'str' ; default = 'http' ; choices = @('http', 'https') } + ssl_flags = @{ type = 'str' ; default = '0' ; choices = @('0', '1', '2', '3') } + certificate_hash = @{ type = 'str' ; default = ([string]::Empty) } + certificate_store_name = @{ type = 'str' ; default = ([string]::Empty) } + } +} + $spec = @{ options = @{ name = @{ required = $true - type = 'str' + type = "str" + } + state = @{ + type = "str" + default = "started" + choices = @("absent", "restarted", "started", "stopped") + } + site_id = @{ + type = "str" + } + application_pool = @{ + type = "str" + } + physical_path = @{ + type = "str" + } + parameters = @{ + type = "str" + } + bindings = @{ + default = @{} + type = 'dict' + options = @{ + add = $binding_options + set = $binding_options + remove = @{ + type = 'list' + elements = 'dict' + options = @{ + ip = @{ type = 'str' } + port = @{ type = 'int' } + hostname = @{ type = 'str' } + } + } + } } } supports_check_mode = $true } - $module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) $name = $module.Params.name +$state = $module.Params.state +$site_id = $module.Params.site_id +$application_pool = $module.Params.application_pool +$physical_path = $module.Params.physical_path +$bindings = $module.Params.bindings + +# Custom site Parameters from string where properties are separated by a pipe and property name/values by colon. +# Ex. "foo:1|bar:2" +$parameters = $module.Params.parameters +if ($null -ne $parameters) { + $parameters = @($parameters -split '\|' | ForEach-Object { + return , ($_ -split "\:", 2) + }) +} + +$check_mode = $module.CheckMode +$module.Result.changed = $false + +if ($check_mode) { + Write-Output "in check mode" +} + +# Ensure WebAdministration module is loaded +if ($null -eq (Get-Module "WebAdministration" -ErrorAction SilentlyContinue)) { + Import-Module WebAdministration +} + +# Site info +$site = Get-Website | Where-Object { $_.Name -eq $name } + +Try { + # Add site + If (($state -ne 'absent') -and (-not $site)) { + If (-not $physical_path) { + $module.FailJson("missing required arguments: physical_path $($_.Exception.Message)") + } + ElseIf (-not (Test-Path -LiteralPath $physical_path)) { + $module.FailJson("specified folder must already exist: physical_path $($_.Exception.Message)") + } -$module.Diff.before = $null -$module.Diff.after = @{ - name = $name + $site_parameters = @{ + Name = $name + PhysicalPath = $physical_path + } + + If ($application_pool) { + $site_parameters.ApplicationPool = $application_pool + } + + If ($site_id) { + $site_parameters.ID = $site_id + } + # Fix for error "New-Item : Index was outside the bounds of the array." + # This is a bug in the New-WebSite commandlet. Apparently there must be at least one site configured in IIS otherwise New-WebSite crashes. + # For more details, see http://stackoverflow.com/questions/3573889/ps-c-new-website-blah-throws-index-was-outside-the-bounds-of-the-array + $sites_list = Get-ChildItem -LiteralPath IIS:\sites + if ($null -eq $sites_list) { + if ($site_id) { + $site_parameters.ID = $site_id + } + else { + $site_parameters.ID = 1 + } + } + if ( -not $check_mode) { + $site = New-Website @site_parameters -Force + } + # Verify that initial site has no binding + Get-WebBinding -Name $site.Name | Remove-WebBinding -WhatIf:$check_mode + $module.Result.changed = $true + } + # Remove site + If ($state -eq 'absent' -and $site) { + $site = Remove-Website -Name $name -WhatIf:$check_mode + $module.Result.changed = $true + } + $site = Get-Website | Where-Object { $_.Name -eq $name } + If ($site) { + # Change Physical Path if needed + if ($physical_path) { + If (-not (Test-Path -LiteralPath $physical_path)) { + $module.FailJson("specified folder must already exist: physical_path $($_.Exception.Message)") + } + + $folder = Get-Item -LiteralPath $physical_path + If ($folder.FullName -ne $site.PhysicalPath) { + Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" -name physicalPath -value $folder.FullName -WhatIf:$check_mode + $module.Result.changed = $true + } + } + # Change Application Pool if needed + if ($application_pool) { + If ($application_pool -ne $site.applicationPool) { + Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" -name applicationPool -value $application_pool -WhatIf:$check_mode + $module.Result.changed = $true + } + } + # Add Remove or Set bindings if needed + if ($bindings) { + $site_bindings = (Get-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)").Bindings.Collection + $user_bindings = if ($Module.Params.bindings.add) { $Module.Params.bindings.add } + elseif ($Module.Params.bindings.remove) { $Module.Params.bindings.remove } + elseif ($Module.Params.bindings.set) { $Module.Params.bindings.set } + # Validate User Bindings Information + $user_bindings | ForEach-Object { + # Make sure ssl flags only specified with https protocol + If ($_.protocol -ne 'https' -and $_.ssl_flags -gt 0) { + $module.FailJson("SSLFlags can only be set for https protocol") + } + # Validate certificate details if provided + If ($_.certificate_hash -and $_.operation -ne 'remove') { + If ($_.protocol -ne 'https') { + $module.FailJson("You can only provide a certificate thumbprint when protocol is set to https") + } + # Apply default for cert store name + If (-Not $_.certificate_store_name) { + $_.certificate_store_name = 'my' + } + # Validate cert path + $cert_path = "cert:\LocalMachine\$($_.certificate_store_name)\$($_.certificate_hash)" + If (-Not (Test-Path -LiteralPath $cert_path) ) { + $module.FailJson("Unable to locate certificate at $cert_path") + } + } + # Make sure binding info is valid for central cert store if sslflags -gt 1 + If ($_.ssl_flags -gt 1 -and ($_.certificate_hash -ne [string]::Empty -or $_.certificate_store_name -ne [string]::Empty)) { + $module.FailJson("You set sslFlags to $($_.ssl_flags). This indicates you wish to use the Central Certificate Store feature. + This cannot be used in combination with certficiate_hash and certificate_store_name. When using the Central Certificate Store feature, + the certificate is automatically retrieved from the store rather than manually assigned to the binding.") + } + } + if ($null -ne $bindings.add) { + $add_binding = $user_bindings | Where-Object { -not ($site_bindings.bindingInformation -contains "$($_.ip):$($_.port):$($_.hostname)") } + if ($add_binding) { + $add_binding | ForEach-Object { + if (-not $check_mode) { + New-WebBinding -Name $site.Name -IPAddress $_.ip -Port $_.port -HostHeader $_.hostname -Protocol $_.protocol -SslFlags $_.ssl_flags + If ($_.certificate_hash) { + $new_binding = Get-WebBinding -Name $site.Name -IPAddress $_.ip -Port $_.port -HostHeader $_.hostname + $new_binding.AddSslCertificate($_.certificate_hash, $_.certificate_store_name) + } + } + $module.Result.changed = $true + } + } + } + if ($null -ne $bindings.remove) { + $remove_binding = $user_bindings | Where-Object { ($site_bindings.bindingInformation -contains "$($_.ip):$($_.port):$($_.hostname)") } + if ($remove_binding) { + $remove_binding | ForEach-Object { + Get-WebBinding -Name $site.Name -IPAddress $_.ip -Port $_.port -HostHeader $_.hostname | Remove-WebBinding -WhatIf:$check_mode + $module.Result.changed = $true + } + } + } + if ($null -ne $bindings.set) { + $set_binding = $user_bindings | ForEach-Object { "$($_.ip):$($_.port):$($_.hostname)" } + $diff = Compare-Object -ReferenceObject @($set_binding | Select-Object) -DifferenceObject @($site_bindings.bindingInformation | Select-Object) + if ($diff.Count -ne 0) { + # Remove All Bindings + Get-WebBinding -Name $site.Name | Remove-WebBinding -WhatIf:$check_mode + # Set Bindings + $user_bindings | ForEach-Object { + if (-not $check_mode) { + New-WebBinding -Name $site.Name -IPAddress $_.ip -Port $_.port -HostHeader $_.hostname -Protocol $_.protocol -SslFlags $_.ssl_flags + If ($_.certificate_hash) { + $new_binding = Get-WebBinding -Name $site.Name -IPAddress $_.ip -Port $_.port -HostHeader $_.hostname + $new_binding.AddSslCertificate($_.certificate_hash, $_.certificate_store_name) + } + } + } + $module.Result.changed = $true + } + } + } + # Set properties + if ($parameters) { + $parameters | ForEach-Object { + $property_value = Get-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" $_[0] + + switch ($property_value.GetType().Name) { + "ConfigurationAttribute" { $parameter_value = $property_value.value } + "String" { $parameter_value = $property_value } + } + + if ((-not $parameter_value) -or ($parameter_value) -ne $_[1]) { + Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" $_[0] $_[1] -WhatIf:$check_mode + $module.Result.changed = $true + } + } + } + + # Set run state + if ((($state -eq 'stopped') -or ($state -eq 'restarted')) -and ($site.State -eq 'Started')) { + if (-not $check_mode) { + Stop-Website -Name $name -ErrorAction Stop + } + $module.Result.changed = $true + } + if ((($state -eq 'started') -and ($site.State -eq 'Stopped')) -or ($state -eq 'restarted')) { + if (-not $check_mode) { + Start-Website -Name $name -ErrorAction Stop + } + $module.Result.changed = $true + } + } +} +Catch { + $module.FailJson("$($module.Result) - $($_.Exception.Message)") } $module.ExitJson() diff --git a/plugins/modules/website.yml b/plugins/modules/website.yml index 3cbf287..50fc707 100644 --- a/plugins/modules/website.yml +++ b/plugins/modules/website.yml @@ -1,46 +1,241 @@ --- -# Copyright: (c) 2024, Ansible Project +# Copyright: (c) 2025, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) DOCUMENTATION: module: website short_description: Configures an IIS website description: - - Creates, removes, and configures an IIS Website. + - Creates, removes, and configures an IIS website. + requirements: + - C(IISAdministration) PowerShell module options: name: description: - The name of the website to manage. - - Other change for testing. required: true type: str + site_id: + description: + - Explicitly set the IIS website numeric ID. + - Note that this value cannot be changed after the website has been created. + - The site ID must be available and not used by any other website on the server. + required: false + type: str + state: + description: + - State of the website + - In order to start the website at least one binding should be configured + type: str + default: started + choices: [absent, started, stopped, restarted] + physical_path: + description: + - Specifies the physical folder path on the remote host to use for the website. + - When create a new website physical_path is required. + - The specified folder must already exist. + type: str + application_pool: + description: + - Specifies the application pool in which the website runs. + - The application pool must already exist - otherwise the website will not start. + type: str + bindings: + description: + - Specifies the website bindings to add, remove or set. + - The combination of C(ip:port:hostname) is the binding unique identifier + - The binding C(ip:port) must be avialble and not used by any other website on the server. + - To clear all website bindings, use I(set) with an empty list. + type: dict + default: {} + suboptions: + add: + description: + - Specifies a list of bindings to add to the website. + type: list + elements: dict + suboptions: + hostname: + description: The website binding hostname (DNS) + type: str + ip: + description: The website binding listen IP + type: str + port: + description: The website binding listen port + type: int + protocol: + description: + - The website used protocol (http, https) + type: str + default: http + choices: ["http", "https"] + ssl_flags: + description: + - Indicates what type of certificate and certificate storage the website supports + - Make sure C(ssl_flags) greater than zero (1,2,3) only specified with https protocol + - C(ssl_flags) greater than one (2,3) indicates you wish to use the Central Certificate Store feature. + - '0: Regular certificate in Windows certificate storage.' + - '1: SNI certificate.' + - '2: Central certificate store.' + - '3: SNI certificate in central certificate store.' + type: str + default: "0" + choices: ["0", "1", "2", "3"] + certificate_hash: + description: + - Certificate hash (thumbprint) for the SSL binding. The certificate hash is the unique identifier for the certificate. + - You can only provide a certificate thumbprint when protocol is set to https + - This can be used only in combination with C(ssl_flags) 0 or 1. + - When using the Central Certificate Store feature, the certificate is automatically retrieved from the store rather than manually assigned to + the binding. + type: str + default: '' + certificate_store_name: + description: + - Name of the certificate store where the certificate for the binding is located. + - This can be used only in combination with C(ssl_flags) 0 or 1 + - If not set store name 'my' will be used. + type: str + default: '' + remove: + description: + - Specifies a list of bindings to remove from the website. + - The combination of C(ip:port:hostname) is the binding unique identifier + type: list + elements: dict + suboptions: + hostname: + description: The website binding hostname (DNS) + type: str + ip: + description: The website binding listen IP + type: str + port: + description: The website binding listen port + type: int + set: + description: + - Specifies a exact list of bindings to set to the website. + - This will clear out any existing bindings if not in the specified + list. + - Set to an empty list to clear all the website bindings. + type: list + elements: dict + suboptions: + hostname: + description: The website binding hostname (DNS) + type: str + ip: + description: The website binding listen IP + type: str + port: + description: The website binding listen port + type: int + protocol: + description: + - The website used protocol (http, https) + type: str + default: http + choices: ["http", "https"] + ssl_flags: + description: + - Indicates what type of certificate and certificate storage the website supports + - Make sure C(ssl_flags) greater than zero (1,2,3) only specified with https protocol + - C(ssl_flags) greater than one (2,3) indicates you wish to use the Central Certificate Store feature. + - '0: Regular certificate in Windows certificate storage.' + - '1: SNI certificate.' + - '2: Central certificate store.' + - '3: SNI certificate in central certificate store.' + type: str + default: "0" + choices: ["0", "1", "2", "3"] + certificate_hash: + description: + - Certificate hash (thumbprint) for the SSL binding. The certificate hash is the unique identifier for the certificate. + - You can only provide a certificate thumbprint when protocol is set to https + - This can be used only in combination with C(ssl_flags) 0 or 1. + - When using the Central Certificate Store feature, the certificate is automatically retrieved from the store rather than manually assigned to + the binding. + type: str + default: '' + certificate_store_name: + description: + - Name of the certificate store where the certificate for the binding is located. + - This can be used only in combination with C(ssl_flags) 0 or 1 + - If not set store name 'my' will be used. + type: str + default: '' + parameters: + description: + - Custom site Parameters from string where properties are separated by a pipe and property name/values by colon Ex. "foo:1|bar:2" + - Some custom parameters that you can use are listed below, this isn't a definitive list but some common parameters. + - C(logfile.directory) - Physical path to store Logs, e.g. C(D:\IIS-LOGs\). + - C(logfile.period) - Log file rollover scheduled accepting these values, how frequently the log file should be rolled-over, + e.g. C(Hourly, Daily, Weekly, Monthly). + - C(logfile.LogFormat) - Log file format, by default IIS uses C(W3C). + - C(logfile.truncateSize) - The size at which the log file contents will be trunsted, expressed in bytes. + type: str notes: - - See - R(win_iis_website migration,ansible_collections.microsoft.iis.docsite.guide_migration.migrated_modules.win_iis_website) - for help on migrating from M(community.windows.win_iis_website) to - this module. + - This module consolidates M(community.windows.win_iis_website) and M(community.windows.win_iis_webbinding) - This module must be run on a Windows target host with the C(IISAdministration) module installed. - extends_documentation_fragment: - - ansible.builtin.action_common_attributes - attributes: - check_mode: - support: full - diff_mode: - support: full - platform: - platforms: - - windows seealso: - - ref: Migration guide - description: This module replaces C(community.windows.win_iis_website). See the migration guide for details. - - module: community.windows.win_iis_website + - module: microsoft.iis.website_info + - module: microsoft.iis.web_app_pool author: - - Insert Author (@author) + - Shahar Golshani (@sgolshan) EXAMPLES: | - - name: Example 1 + - name: Create a new website in 'Started' state + microsoft.iis.website: + name: WebSite + physical_path: C:\inetpub\wwwroot + state: started + + - name: Stop a website + microsoft.iis.website: + name: WebSite + state: stopped + + - name: Restart a website (non-idempotent) + microsoft.iis.website: + name: WebSite + state: restarted + + - name: Change a website application pool + microsoft.iis.website: + name: WebSite + application_pool: NewAppPool + + - name: Change a website physical path + microsoft.iis.website: + name: WebSite + physical_path: C:\wwwroot\websites\my-website + + - name: Change the website parameters + microsoft.iis.website: + name: WebSite + parameters: logfile.directory:"C:\IIS-LOGs"|logfile.period:Hourly|logFile.logFormat:W3C + + - name: Creates a website with two bindings, set all values and starts it microsoft.iis.website: - name: foo + name: WebSite + site_id: 2 + state: started + physical_path: C:\wwwroot\websites\my-website + application_pool: DefaultAppPool + bindings: + set: + - ip: 127.0.0.1 + port: 8081 + hostname: my-website.com + - ip: 127.0.0.2 + port: 8082 + hostname: my-website.net + protocol: https + ssl_flags: 1 + certificate_hash: 5409124040FA1C8FA74939BDA2EF8FD5975BD25B + certificate_store_name: my RETURN: {} diff --git a/plugins/modules/website_info.ps1 b/plugins/modules/website_info.ps1 new file mode 100644 index 0000000..a9c9d01 --- /dev/null +++ b/plugins/modules/website_info.ps1 @@ -0,0 +1,77 @@ +#!powershell + +# Copyright: (c) 2025, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#AnsibleRequires -CSharpUtil Ansible.Basic + +$spec = @{ + options = @{ + name = @{ type = "str" } + } + supports_check_mode = $true +} + +$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) + +$name = $module.Params.name + +$module.Result.exists = $false +$module.Result.site = @() + +# Ensure WebAdministration module is loaded +if ($null -eq (Get-Module -Name "WebAdministration" -ErrorAction SilentlyContinue)) { + Import-Module WebAdministration + $web_admin_dll_path = Join-Path $env:SystemRoot system32\inetsrv\Microsoft.Web.Administration.dll + Add-Type -LiteralPath $web_admin_dll_path +} + +function Get-WebsiteInfo ($name) { + # Get all the current site details + $site = Get-Item -LiteralPath IIS:\Sites\$name + if ($null -ne $site) { + $module.Result.exists = $true + } + $site_bindings = Get-WebBinding -Name $name + $bindings_list = @( + $site_bindings | ForEach-Object { + [PSCustomObject]@{ + ip = $($_.bindingInformation -split ":")[0] + port = $($_.bindingInformation -split ":")[1] + hostname = $($_.bindingInformation -split ":")[2] + protocol = $_.protocol + ssl_flags = $_.sslFlags + } + } + ) + $WebsiteInfoDict = @{ + name = $site.Name + id = $site.ID + state = $site.State + physical_path = $site.PhysicalPath + application_pool = $site.applicationPool + bindings = $bindings_list + } + return $WebsiteInfoDict +} + +try { + # In case a user specified website name return information only for this website + if ($null -ne $name) { + [array]$module.Result.site = Get-WebsiteInfo -name $name + } + # Return information of all the websites available on the system + else { + $WebsiteList = $(Get-Website).Name + [array]$module.Result.site = $WebsiteList | ForEach-Object { Get-WebsiteInfo -name $_ } + } +} +catch { + $msg = -join @( + "Failed to fetch the info of the required Website " + "Exception: $($_.Exception.Message)" + ) + $module.FailJson($msg, $_) +} + +$module.ExitJson() \ No newline at end of file diff --git a/plugins/modules/website_info.yml b/plugins/modules/website_info.yml new file mode 100644 index 0000000..c2d3748 --- /dev/null +++ b/plugins/modules/website_info.yml @@ -0,0 +1,121 @@ +--- +# Copyright: (c) 2025, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +DOCUMENTATION: + module: website_info + short_description: Get information on IIS websites + description: + - Returns information about IIS websites + requirements: + - C(IISAdministration) PowerShell module + options: + name: + description: + - Name of the website. + - When not specified, information of all existing websites will be fetched + type: str + required: false + notes: + - This module must be run on a Windows target host with the + C(IISAdministration) module installed. + seealso: + - module: microsoft.iis.website + author: + - Shahar Golshani (@sgolshan) + +EXAMPLES: | + - name: Return information about an existing website + microsoft.iis.website_info: + name: 'Default Web Site' + register: stored_info + + - name: Returns information about all websites that exist on the system + microsoft.iis.website_info: + register: stored_info_all + +RETURN: + exists: + description: + - Whether any website were found. + returned: always + type: bool + sample: true + site: + description: + - Contains list of dictionaries. + - Every dictionary in the list contains name and information of a website. + returned: success + type: list + elements: dict + sample: | + [ + { + "application_pool": "DefaultAppPool", + "bindings": [ + { + "hostname": "iis_website.com", + "ip": "127.0.0.1", + "port": "80", + "protocol": "http", + "ssl_flags": 0 + } + ], + "id": 1, + "name": "Default Web Site", + "physical_path": "C:\\inetpub\\wwwroot", + "state": "Started" + } + ] + contains: + name: + description: + - Name of the website. + type: str + sample: Default Web Site + id: + description: + - Specifies the website ID. + type: str + sample: "1" + state: + description: + - Specifies the website state Started/Stopped. + type: str + sample: "Started" + application_pool: + description: + - Specifies the application pool in which the website runs. + type: str + sample: "DefaultAppPool" + physical_path: + description: + - Specifies the physical folder path of the website. + type: str + sample: "C:\\inetpub\\wwwroot" + bindings: + description: + - List of dictionaries that hold the information of all the website bindings. + type: list + elements: dict + contains: + hostname: + description: The website binding hostname (DNS) + type: str + sample: "iis_website.com" + ip: + description: The website binding listen IP + type: str + sample: "127.0.0.1" + port: + description: The website binding listen port + type: str + sample: "80" + protocol: + description: The website used protocol + type: str + sample: "http" + ssl_flags: + description: Indicates what type of certificate and certificate storage the website supports + type: str + sample: "0" diff --git a/plugins/modules/win_iis_webbinding.ps1 b/plugins/modules/win_iis_webbinding.ps1 deleted file mode 100644 index b6073f4..0000000 --- a/plugins/modules/win_iis_webbinding.ps1 +++ /dev/null @@ -1,348 +0,0 @@ -#!powershell - -# Copyright: (c) 2017, Noah Sparks -# Copyright: (c) 2015, Henrik Wallström -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -#Requires -Module Ansible.ModuleUtils.Legacy - -$params = Parse-Args -arguments $args -supports_check_mode $true -$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false - -$name = Get-AnsibleParam $params -name "name" -type str -failifempty $true -aliases 'website' -$state = Get-AnsibleParam $params "state" -default "present" -validateSet "present", "absent" -$host_header = Get-AnsibleParam $params -name "host_header" -type str -$protocol = Get-AnsibleParam $params -name "protocol" -type str -default 'http' -$port = Get-AnsibleParam $params -name "port" -default '80' -$ip = Get-AnsibleParam $params -name "ip" -default '*' -$certificateHash = Get-AnsibleParam $params -name "certificate_hash" -type str -default ([string]::Empty) -$certificateStoreName = Get-AnsibleParam $params -name "certificate_store_name" -type str -default ([string]::Empty) -$sslFlags = Get-AnsibleParam $params -name "ssl_flags" -default '0' -ValidateSet '0', '1', '2', '3' - -$result = @{ - changed = $false -} - -################# -### Functions ### -################# -function New-BindingInfo { - $ht = @{ - 'bindingInformation' = $args[0].bindingInformation - 'ip' = $args[0].bindingInformation.split(':')[0] - 'port' = [int]$args[0].bindingInformation.split(':')[1] - 'hostheader' = $args[0].bindingInformation.split(':')[2] - #'isDsMapperEnabled' = $args[0].isDsMapperEnabled - 'protocol' = $args[0].protocol - 'certificateStoreName' = $args[0].certificateStoreName - 'certificateHash' = $args[0].certificateHash - } - - #handle sslflag support - If ([version][System.Environment]::OSVersion.Version -lt [version]'6.2') { - $ht.sslFlags = 'not supported' - } - Else { - $ht.sslFlags = [int]$args[0].sslFlags - } - - Return $ht -} - -# Used instead of get-webbinding to ensure we always return a single binding -# We can't filter properly with get-webbinding...ex get-webbinding ip * returns all bindings -# pass it $binding_parameters hashtable -function Get-SingleWebBinding { - - Try { - $site_bindings = get-webbinding -name $args[0].name - } - Catch { - # 2k8r2 throws this error when you run get-webbinding with no bindings in iis - $msg = 'Cannot process argument because the value of argument "obj" is null. Change the value of argument "obj" to a non-null value' - If (-not $_.Exception.Message.CompareTo($msg)) { - Throw $_.Exception.Message - } - Else { return } - } - - Foreach ($binding in $site_bindings) { - $splits = $binding.bindingInformation -split ':' - - if ( - $args[0].protocol -eq $binding.protocol -and - $args[0].ipaddress -eq $splits[0] -and - $args[0].port -eq $splits[1] -and - $args[0].hostheader -eq $splits[2] - ) { - Return $binding - } - } -} - - -############################# -### Pre-Action Validation ### -############################# -$os_version = [version][System.Environment]::OSVersion.Version - -# Ensure WebAdministration module is loaded -If ($os_version -lt [version]'6.1') { - Try { - Add-PSSnapin WebAdministration - } - Catch { - Fail-Json -obj $result -message "The WebAdministration snap-in is not present. Please make sure it is installed." - } -} -Else { - Try { - Import-Module WebAdministration - } - Catch { - Fail-Json -obj $result -message "Failed to load WebAdministration module. Is IIS installed? $($_.Exception.Message)" - } -} - -# ensure website targetted exists. -Name filter doesn't work on 2k8r2 so do where-object instead -$website_check = get-website | Where-Object { $_.name -eq $name } -If (-not $website_check) { - Fail-Json -obj $result -message "Unable to retrieve website with name $Name. Make sure the website name is valid and exists." -} - -# if OS older than 2012 (6.2) and ssl flags are set, fail. Otherwise toggle sni_support -If ($os_version -lt [version]'6.2') { - If ($sslFlags -ne 0) { - Fail-Json -obj $result -message "SNI and Certificate Store support is not available for systems older than 2012 (6.2)" - } - $sni_support = $false #will cause the sslflags check later to skip -} -Else { - $sni_support = $true -} - -# make sure ssl flags only specified with https protocol -If ($protocol -ne 'https' -and $sslFlags -gt 0) { - Fail-Json -obj $result -message "SSLFlags can only be set for HTTPS protocol" -} - -# validate certificate details if provided -# we don't do anything with cert on state: absent, so only validate present -If ($certificateHash -and $state -eq 'present') { - If ($protocol -ne 'https') { - Fail-Json -obj $result -message "You can only provide a certificate thumbprint when protocol is set to https" - } - - #apply default for cert store name - If (-Not $certificateStoreName) { - $certificateStoreName = 'my' - } - - #validate cert path - $cert_path = "cert:\LocalMachine\$certificateStoreName\$certificateHash" - If (-Not (Test-Path -LiteralPath $cert_path) ) { - Fail-Json -obj $result -message "Unable to locate certificate at $cert_path" - } -} - -# make sure binding info is valid for central cert store if sslflags -gt 1 -If ($sslFlags -gt 1 -and ($certificateHash -ne [string]::Empty -or $certificateStoreName -ne [string]::Empty)) { - Fail-Json -obj $result -message "You set sslFlags to $sslFlags. This indicates you wish to use the Central Certificate Store feature. - This cannot be used in combination with certficiate_hash and certificate_store_name. When using the Central Certificate Store feature, - the certificate is automatically retrieved from the store rather than manually assigned to the binding." -} - -# disallow host_header: '*' -If ($host_header -eq '*') { - Fail-Json -obj $result -message "To make or remove a catch-all binding, please omit the host_header parameter entirely rather than specify host_header *" -} - -########################## -### start action items ### -########################## - -# create binding search splat -$binding_parameters = @{ - Name = $name - Protocol = $protocol - Port = $port - IPAddress = $ip -} - -# insert host header to search if specified, otherwise it will return * (all bindings matching protocol/ip) -If ($host_header) { - $binding_parameters.HostHeader = $host_header -} -Else { - $binding_parameters.HostHeader = [string]::Empty -} - -# Get bindings matching parameters -Try { - $current_bindings = Get-SingleWebBinding $binding_parameters -} -Catch { - Fail-Json -obj $result -message "Failed to retrieve bindings with Get-SingleWebBinding - $($_.Exception.Message)" -} - -################################################ -### Remove binding or exit if already absent ### -################################################ -If ($current_bindings -and $state -eq 'absent') { - Try { - #there is a bug in this method that will result in all bindings being removed if the IP in $current_bindings is a * - #$current_bindings | Remove-WebBinding -verbose -WhatIf:$check_mode - - #another method that did not work. It kept failing to match on element and removed everything. - #$element = @{protocol="$protocol";bindingInformation="$ip`:$port`:$host_header"} - #Remove-WebconfigurationProperty -filter $current_bindings.ItemXPath -Name Bindings.collection -AtElement $element -WhatIf #:$check_mode - - #this method works - [array]$bindings = Get-WebconfigurationProperty -filter $current_bindings.ItemXPath -Name Bindings.collection - - $index = Foreach ($item in $bindings) { - If ( $protocol -eq $item.protocol -and $current_bindings.bindingInformation -eq $item.bindingInformation ) { - $bindings.indexof($item) - break - } - } - - Remove-WebconfigurationProperty -filter $current_bindings.ItemXPath -Name Bindings.collection -AtIndex $index -WhatIf:$check_mode - $result.changed = $true - } - - Catch { - Fail-Json -obj $result -message "Failed to remove the binding from IIS - $($_.Exception.Message)" - } - - # removing bindings from iis may not also remove them from iis:\sslbindings - - $result.operation_type = 'removed' - $result.binding_info = $current_bindings | ForEach-Object { New-BindingInfo $_ } - Exit-Json -obj $result -} -ElseIf (-Not $current_bindings -and $state -eq 'absent') { - # exit changed: false since it's already gone - Exit-Json -obj $result -} - - -################################ -### Modify existing bindings ### -################################ -<# -since we have already have the parameters available to get-webbinding, -we just need to check here for the ones that are not available which are the -ssl settings (hash, store, sslflags). If they aren't set we update here, or -exit with changed: false -#> -ElseIf ($current_bindings) { - #ran into a strange edge case in testing where I was able to retrieve bindings but not expand all the properties - #when adding a self-signed wildcard cert to a binding. it seemed to permanently break the binding. only removing it - #would cause the error to stop. - Try { - $null = $current_bindings | Select-Object * - } - Catch { - $msg = -join @( - "Found a matching binding, but failed to expand it's properties (get-binding | FL *). " - "In testing, this was caused by using a self-signed wildcard certificate. $($_.Exception.Message)" - ) - Fail-Json -obj $result -message $msg - } - - # check if there is a match on the ssl parameters - If ( ($current_bindings.sslFlags -ne $sslFlags -and $sni_support) -or - $current_bindings.certificateHash -ne $certificateHash -or - $current_bindings.certificateStoreName -ne $certificateStoreName) { - # match/update SNI - If ($current_bindings.sslFlags -ne $sslFlags -and $sni_support) { - Try { - Set-WebBinding -Name $name -IPAddress $ip -Port $port -HostHeader $host_header -PropertyName sslFlags -value $sslFlags -whatif:$check_mode - $result.changed = $true - } - Catch { - Fail-Json -obj $result -message "Failed to update sslFlags on binding - $($_.Exception.Message)" - } - - # Refresh the binding object since it has been changed - Try { - $current_bindings = Get-SingleWebBinding $binding_parameters - } - Catch { - Fail-Json -obj $result -message "Failed to refresh bindings after setting sslFlags - $($_.Exception.Message)" - } - } - # match/update certificate - If ($current_bindings.certificateHash -ne $certificateHash -or $current_bindings.certificateStoreName -ne $certificateStoreName) { - If (-Not $check_mode) { - Try { - $current_bindings.AddSslCertificate($certificateHash, $certificateStoreName) - } - Catch { - Fail-Json -obj $result -message "Failed to set new SSL certificate - $($_.Exception.Message)" - } - } - } - $result.changed = $true - $result.operation_type = 'updated' - $result.website_state = (Get-Website | Where-Object { $_.Name -eq $Name }).State - $result.binding_info = New-BindingInfo (Get-SingleWebBinding $binding_parameters) - Exit-Json -obj $result #exit changed true - } - Else { - $result.operation_type = 'matched' - $result.website_state = (Get-Website | Where-Object { $_.Name -eq $Name }).State - $result.binding_info = New-BindingInfo (Get-SingleWebBinding $binding_parameters) - Exit-Json -obj $result #exit changed false - } -} - -######################## -### Add new bindings ### -######################## -ElseIf (-not $current_bindings -and $state -eq 'present') { - # add binding. this creates the binding, but does not apply a certificate to it. - Try { - If (-not $check_mode) { - If ($sni_support) { - New-WebBinding @binding_parameters -SslFlags $sslFlags -Force - } - Else { - New-WebBinding @binding_parameters -Force - } - } - $result.changed = $true - } - Catch { - $result.website_state = (Get-Website | Where-Object { $_.Name -eq $Name }).State - Fail-Json -obj $result -message "Failed at creating new binding (note: creating binding and adding ssl are separate steps) - $($_.Exception.Message)" - } - - # add certificate to binding - If ($certificateHash -and -not $check_mode) { - Try { - #$new_binding = get-webbinding -Name $name -IPAddress $ip -port $port -Protocol $protocol -hostheader $host_header - $new_binding = Get-SingleWebBinding $binding_parameters - $new_binding.addsslcertificate($certificateHash, $certificateStoreName) - } - Catch { - $result.website_state = (Get-Website | Where-Object { $_.Name -eq $Name }).State - Fail-Json -obj $result -message "Failed to set new SSL certificate - $($_.Exception.Message)" - } - } - - $result.changed = $true - $result.operation_type = 'added' - $result.website_state = (Get-Website | Where-Object { $_.Name -eq $Name }).State - - # incase there are no bindings we do a check before calling New-BindingInfo - $web_binding = Get-SingleWebBinding $binding_parameters - if ($web_binding) { - $result.binding_info = New-BindingInfo $web_binding - } - else { - $result.binding_info = $null - } - Exit-Json $result -} diff --git a/plugins/modules/win_iis_webbinding.py b/plugins/modules/win_iis_webbinding.py deleted file mode 100644 index cf3d42b..0000000 --- a/plugins/modules/win_iis_webbinding.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2017, Noah Sparks -# Copyright: (c) 2017, Henrik Wallström -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -DOCUMENTATION = r''' ---- -module: win_iis_webbinding -short_description: Configures a IIS Web site binding -description: - - Creates, removes and configures a binding to an existing IIS Web site. -options: - name: - description: - - Names of web site. - type: str - required: yes - aliases: [ website ] - state: - description: - - State of the binding. - type: str - choices: [ absent, present ] - default: present - port: - description: - - The port to bind to / use for the new site. - type: int - default: 80 - ip: - description: - - The IP address to bind to / use for the new site. - type: str - default: '*' - host_header: - description: - - The host header to bind to / use for the new site. - - If you are creating/removing a catch-all binding, omit this parameter rather than defining it as '*'. - type: str - protocol: - description: - - The protocol to be used for the Web binding (usually HTTP, HTTPS, or FTP). - type: str - default: http - certificate_hash: - description: - - Certificate hash (thumbprint) for the SSL binding. The certificate hash is the unique identifier for the certificate. - type: str - certificate_store_name: - description: - - Name of the certificate store where the certificate for the binding is located. - type: str - default: my - ssl_flags: - description: - - This parameter is only valid on Server 2012 and newer. - - Primarily used for enabling and disabling server name indication (SNI). - - Set to C(0) to disable SNI. - - Set to C(1) to enable SNI. - type: str -seealso: -- module: community.windows.win_iis_virtualdirectory -- module: community.windows.win_iis_webapplication -- module: community.windows.win_iis_webapppool -- module: community.windows.win_iis_website -author: - - Noah Sparks (@nwsparks) - - Henrik Wallström (@henrikwallstrom) -''' - -EXAMPLES = r''' -- name: Add a HTTP binding on port 9090 - community.windows.win_iis_webbinding: - name: Default Web Site - port: 9090 - state: present - -- name: Remove the HTTP binding on port 9090 - community.windows.win_iis_webbinding: - name: Default Web Site - port: 9090 - state: absent - -- name: Remove the default http binding - community.windows.win_iis_webbinding: - name: Default Web Site - port: 80 - ip: '*' - state: absent - -- name: Add a HTTPS binding - community.windows.win_iis_webbinding: - name: Default Web Site - protocol: https - port: 443 - ip: 127.0.0.1 - certificate_hash: B0D0FA8408FC67B230338FCA584D03792DA73F4C - state: present - -- name: Add a HTTPS binding with host header and SNI enabled - community.windows.win_iis_webbinding: - name: Default Web Site - protocol: https - port: 443 - host_header: test.com - ssl_flags: 1 - certificate_hash: D1A3AF8988FD32D1A3AF8988FD323792DA73F4C - state: present -''' - -RETURN = r''' -website_state: - description: - - The state of the website being targetted - - Can be helpful in case you accidentally cause a binding collision - which can result in the targetted site being stopped - returned: always - type: str - sample: "Started" -operation_type: - description: - - The type of operation performed - - Can be removed, updated, matched, or added - returned: on success - type: str - sample: "removed" -binding_info: - description: - - Information on the binding being manipulated - returned: on success - type: dict - sample: |- - "binding_info": { - "bindingInformation": "127.0.0.1:443:", - "certificateHash": "FF3910CE089397F1B5A77EB7BAFDD8F44CDE77DD", - "certificateStoreName": "MY", - "hostheader": "", - "ip": "127.0.0.1", - "port": 443, - "protocol": "https", - "sslFlags": "not supported" - } -''' diff --git a/plugins/modules/win_iis_website.ps1 b/plugins/modules/win_iis_website.ps1 deleted file mode 100644 index 571fb3d..0000000 --- a/plugins/modules/win_iis_website.ps1 +++ /dev/null @@ -1,175 +0,0 @@ -#!powershell - -# Copyright: (c) 2015, Henrik Wallström -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -#Requires -Module Ansible.ModuleUtils.Legacy - -$ErrorActionPreference = "Stop" - -$params = Parse-Args $args -$name = Get-AnsibleParam -obj $params -name "name" -type "str" -failifempty $true -$application_pool = Get-AnsibleParam -obj $params -name "application_pool" -type "str" -$physical_path = Get-AnsibleParam -obj $params -name "physical_path" -type "str" -$site_id = Get-AnsibleParam -obj $params -name "site_id" -type "str" -$state = Get-AnsibleParam -obj $params -name "state" -type "str" -validateset "absent", "restarted", "started", "stopped" - -# Binding Parameters -$bind_port = Get-AnsibleParam -obj $params -name "port" -type "int" -$bind_ip = Get-AnsibleParam -obj $params -name "ip" -type "str" -$bind_hostname = Get-AnsibleParam -obj $params -name "hostname" -type "str" - -# Custom site Parameters from string where properties -# are separated by a pipe and property name/values by colon. -# Ex. "foo:1|bar:2" -$parameters = Get-AnsibleParam -obj $params -name "parameters" -type "str" -if ($null -ne $parameters) { - $parameters = @($parameters -split '\|' | ForEach-Object { - return , ($_ -split "\:", 2) - }) -} - - -# Ensure WebAdministration module is loaded -if ($null -eq (Get-Module "WebAdministration" -ErrorAction SilentlyContinue)) { - Import-Module WebAdministration -} - -# Result -$result = @{ - site = @{} - changed = $false -} - -# Site info -$site = Get-Website | Where-Object { $_.Name -eq $name } - -Try { - # Add site - If (($state -ne 'absent') -and (-not $site)) { - If (-not $physical_path) { - Fail-Json -obj $result -message "missing required arguments: physical_path" - } - ElseIf (-not (Test-Path -LiteralPath $physical_path)) { - Fail-Json -obj $result -message "specified folder must already exist: physical_path" - } - - $site_parameters = @{ - Name = $name - PhysicalPath = $physical_path - } - - If ($application_pool) { - $site_parameters.ApplicationPool = $application_pool - } - - If ($site_id) { - $site_parameters.ID = $site_id - } - - If ($bind_port) { - $site_parameters.Port = $bind_port - } - - If ($bind_ip) { - $site_parameters.IPAddress = $bind_ip - } - - If ($bind_hostname) { - $site_parameters.HostHeader = $bind_hostname - } - - # Fix for error "New-Item : Index was outside the bounds of the array." - # This is a bug in the New-WebSite commandlet. Apparently there must be at least one site configured in IIS otherwise New-WebSite crashes. - # For more details, see http://stackoverflow.com/questions/3573889/ps-c-new-website-blah-throws-index-was-outside-the-bounds-of-the-array - $sites_list = Get-ChildItem -LiteralPath IIS:\sites - if ($null -eq $sites_list) { - if ($site_id) { - $site_parameters.ID = $site_id - } - else { - $site_parameters.ID = 1 - } - } - - $site = New-Website @site_parameters -Force - $result.changed = $true - } - - # Remove site - If ($state -eq 'absent' -and $site) { - $site = Remove-Website -Name $name - $result.changed = $true - } - - $site = Get-Website | Where-Object { $_.Name -eq $name } - If ($site) { - # Change Physical Path if needed - if ($physical_path) { - If (-not (Test-Path -LiteralPath $physical_path)) { - Fail-Json -obj $result -message "specified folder must already exist: physical_path" - } - - $folder = Get-Item -LiteralPath $physical_path - If ($folder.FullName -ne $site.PhysicalPath) { - Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" -name physicalPath -value $folder.FullName - $result.changed = $true - } - } - - # Change Application Pool if needed - if ($application_pool) { - If ($application_pool -ne $site.applicationPool) { - Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" -name applicationPool -value $application_pool - $result.changed = $true - } - } - - # Set properties - if ($parameters) { - $parameters | ForEach-Object { - $property_value = Get-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" $_[0] - - switch ($property_value.GetType().Name) { - "ConfigurationAttribute" { $parameter_value = $property_value.value } - "String" { $parameter_value = $property_value } - } - - if ((-not $parameter_value) -or ($parameter_value) -ne $_[1]) { - Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" $_[0] $_[1] - $result.changed = $true - } - } - } - - # Set run state - if ((($state -eq 'stopped') -or ($state -eq 'restarted')) -and ($site.State -eq 'Started')) { - Stop-Website -Name $name -ErrorAction Stop - $result.changed = $true - } - if ((($state -eq 'started') -and ($site.State -eq 'Stopped')) -or ($state -eq 'restarted')) { - Start-Website -Name $name -ErrorAction Stop - $result.changed = $true - } - } -} -Catch { - Fail-Json -obj $result -message $_.Exception.Message -} - -if ($state -ne 'absent') { - $site = Get-Website | Where-Object { $_.Name -eq $name } -} - -if ($site) { - $result.site = @{ - Name = $site.Name - ID = $site.ID - State = $site.State - PhysicalPath = $site.PhysicalPath - ApplicationPool = $site.applicationPool - Bindings = @($site.Bindings.Collection | ForEach-Object { $_.BindingInformation }) - } -} - -Exit-Json -obj $result diff --git a/plugins/modules/win_iis_website.py b/plugins/modules/win_iis_website.py deleted file mode 100644 index c1fe192..0000000 --- a/plugins/modules/win_iis_website.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2015, Henrik Wallström -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -DOCUMENTATION = r''' ---- -module: win_iis_website -short_description: Configures a IIS Web site -description: - - Creates, Removes and configures a IIS Web site. -options: - name: - description: - - Names of web site. - type: str - required: yes - site_id: - description: - - Explicitly set the IIS numeric ID for a site. - - Note that this value cannot be changed after the website has been created. - type: str - state: - description: - - State of the web site - type: str - choices: [ absent, started, stopped, restarted ] - physical_path: - description: - - The physical path on the remote host to use for the new site. - - The specified folder must already exist. - type: str - application_pool: - description: - - The application pool in which the new site executes. - type: str - port: - description: - - The port to bind to / use for the new site. - type: int - ip: - description: - - The IP address to bind to / use for the new site. - type: str - hostname: - description: - - The host header to bind to / use for the new site. - type: str - parameters: - description: - - Custom site Parameters from string where properties are separated by a pipe and property name/values by colon Ex. "foo:1|bar:2" - - Some custom parameters that you can use are listed below, this isn't a definitive list but some common parameters. - - C(logfile.directory) - Physical path to store Logs, e.g. C(D:\IIS-LOGs\). - - C(logfile.period) - Log file rollover scheduled accepting these values, how frequently the log file should be rolled-over, - e.g. C(Hourly, Daily, Weekly, Monthly). - - C(logfile.LogFormat) - Log file format, by default IIS uses C(W3C). - - C(logfile.truncateSize) - The size at which the log file contents will be trunsted, expressed in bytes. - type: str -seealso: -- module: community.windows.win_iis_virtualdirectory -- module: community.windows.win_iis_webapplication -- module: community.windows.win_iis_webapppool -- module: community.windows.win_iis_webbinding -author: -- Henrik Wallström (@henrikwallstrom) -''' - -EXAMPLES = r''' - -# Start a website - -- name: Acme IIS site - community.windows.win_iis_website: - name: Acme - state: started - port: 80 - ip: 127.0.0.1 - hostname: acme.local - application_pool: acme - physical_path: C:\sites\acme - parameters: logfile.directory:C:\sites\logs - register: website - -# Remove Default Web Site and the standard port 80 binding -- name: Remove Default Web Site - community.windows.win_iis_website: - name: "Default Web Site" - state: absent - -# Create a WebSite with custom Logging configuration (Logs Location, Format and Rolling Over). - -- name: Creating WebSite with Custom Log location, Format 3WC and rolling over every hour. - community.windows.win_iis_website: - name: MyCustom_Web_Shop_Site - state: started - port: 80 - ip: '*' - hostname: '*' - physical_path: D:\wwwroot\websites\my-shop-site - parameters: logfile.directory:D:\IIS-LOGS\websites\my-shop-site|logfile.period:Hourly|logFile.logFormat:W3C - application_pool: my-shop-site - -# Some commandline examples: - -# This return information about an existing host -# $ ansible -i vagrant-inventory -m community.windows.win_iis_website -a "name='Default Web Site'" window -# host | success >> { -# "changed": false, -# "site": { -# "ApplicationPool": "DefaultAppPool", -# "Bindings": [ -# "*:80:" -# ], -# "ID": 1, -# "Name": "Default Web Site", -# "PhysicalPath": "%SystemDrive%\\inetpub\\wwwroot", -# "State": "Stopped" -# } -# } - -# This stops an existing site. -# $ ansible -i hosts -m community.windows.win_iis_website -a "name='Default Web Site' state=stopped" host - -# This creates a new site. -# $ ansible -i hosts -m community.windows.win_iis_website -a "name=acme physical_path=C:\\sites\\acme" host - -# Change logfile. -# $ ansible -i hosts -m community.windows.win_iis_website -a "name=acme physical_path=C:\\sites\\acme" host -''' diff --git a/tests/integration/targets/website/aliases b/tests/integration/targets/website/aliases index ccd8a25..8edd9c5 100644 --- a/tests/integration/targets/website/aliases +++ b/tests/integration/targets/website/aliases @@ -1,2 +1,2 @@ windows -shippable/windows/group1 +shippable/windows/group1 \ No newline at end of file diff --git a/tests/integration/targets/website/defaults/main.yml b/tests/integration/targets/website/defaults/main.yml new file mode 100644 index 0000000..f8eac31 --- /dev/null +++ b/tests/integration/targets/website/defaults/main.yml @@ -0,0 +1,11 @@ +--- + +test_website_name: TestWebSite +test_apppool: TestWebSitePool +test_site_id: 99 +test_phisical_path: C:\wwwroot\websites\my-test-website +test_alt_phisical_path: C:\wwwroot\websites\my-test-website-alt +test_website_port: 8080 +test_website_ip: 127.0.0.1 +test_website_hostname: 'acme.com' + \ No newline at end of file diff --git a/tests/integration/targets/website/meta/main.yml b/tests/integration/targets/website/meta/main.yml new file mode 100644 index 0000000..e3dd5fb --- /dev/null +++ b/tests/integration/targets/website/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: +- setup_remote_tmp_dir diff --git a/tests/integration/targets/website/tasks/bindings.yml b/tests/integration/targets/website/tasks/bindings.yml new file mode 100644 index 0000000..5d31a30 --- /dev/null +++ b/tests/integration/targets/website/tasks/bindings.yml @@ -0,0 +1,251 @@ +- name: copy certreq file + ansible.windows.win_copy: + content: |- + [NewRequest] + Subject = "CN={{ item.name }}" + KeyLength = 2048 + KeyAlgorithm = RSA + MachineKeySet = true + RequestType = Cert + dest: "{{ item.dest }}" + with_items: + - {name: test.com, dest: 'c:\windows\temp\certreq1.txt'} + +- name: make sure response files are absent + ansible.windows.win_file: + path: "{{ item }}" + state: absent + with_items: + - 'c:\windows\temp\certreqresp1.txt' + +- name: create self signed cert from certreq + ansible.windows.win_command: certreq -new -machine {{ item.req }} {{ item.resp }} + with_items: + - {req: 'c:\windows\temp\certreq1.txt', resp: 'c:\windows\temp\certreqresp1.txt'} + +- name: register certificate thumbprint1 + raw: '(gci Cert:\LocalMachine\my | ? {$_.subject -eq "CN=test.com"})[0].Thumbprint' + register: thumbprint1 + +- debug: + var: thumbprint1.stdout + verbosity: 1 + +- name: add website binding + microsoft.iis.website: + name: "{{ test_website_name }}" + bindings: + add: + - ip: '127.0.1.1' + port: 8091 + hostname: 'microsoft.iis.website.com' + - ip: '127.0.2.1' + port: 8092 + hostname: 'microsoft.iis.website.net' + register: website + +- name: add website binding info + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is changed + - website_info.site[0].bindings[1].ip == "127.0.1.1" + - website_info.site[0].bindings[1].port == "8091" + - website_info.site[0].bindings[1].hostname == "microsoft.iis.website.com" + - website_info.site[0].bindings[2].ip == "127.0.2.1" + - website_info.site[0].bindings[2].port == "8092" + - website_info.site[0].bindings[2].hostname == "microsoft.iis.website.net" + +- name: add website binding (idempotent) + microsoft.iis.website: + name: "{{ test_website_name }}" + bindings: + add: + - ip: '127.0.1.1' + port: 8091 + hostname: 'microsoft.iis.website.com' + - ip: '127.0.2.1' + port: 8092 + hostname: 'microsoft.iis.website.net' + register: website + +- name: add website binding info (idempotent) + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is not changed + - website_info.site[0].bindings[1].ip == "127.0.1.1" + - website_info.site[0].bindings[1].port == "8091" + - website_info.site[0].bindings[1].hostname == "microsoft.iis.website.com" + - website_info.site[0].bindings[2].ip == "127.0.2.1" + - website_info.site[0].bindings[2].port == "8092" + - website_info.site[0].bindings[2].hostname == "microsoft.iis.website.net" + +# Remove all bindings with set: [] empty list +- name: set empty website bindings + microsoft.iis.website: + name: "{{ test_website_name }}" + bindings: + set: [] + register: website + +- name: set empty website bindings info + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is changed + - website_info.site[0].bindings == [] + +- name: set empty website bindings (idempotent) + microsoft.iis.website: + name: "{{ test_website_name }}" + bindings: + set: [] + register: website + +- name: set empty website bindings info (idempotent) + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is not changed + - website_info.site[0].bindings == [] + +- name: set website binding + microsoft.iis.website: + name: "{{ test_website_name }}" + bindings: + set: + - ip: '127.0.3.1' + port: 8093 + hostname: 'microsoft.iis.website.set1' + - ip: '127.0.4.1' + port: 8094 + hostname: 'microsoft.iis.website.set2' + register: website + +- name: set website binding info + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is changed + - website_info.site[0].bindings[0].ip == "127.0.3.1" + - website_info.site[0].bindings[0].port == "8093" + - website_info.site[0].bindings[0].hostname == "microsoft.iis.website.set1" + - website_info.site[0].bindings[1].ip == "127.0.4.1" + - website_info.site[0].bindings[1].port == "8094" + - website_info.site[0].bindings[1].hostname == "microsoft.iis.website.set2" + +- name: set website binding (idempotent) + microsoft.iis.website: + name: "{{ test_website_name }}" + bindings: + set: + - ip: '127.0.3.1' + port: 8093 + hostname: 'microsoft.iis.website.set1' + - ip: '127.0.4.1' + port: 8094 + hostname: 'microsoft.iis.website.set2' + register: website + +- name: set website binding info (idempotent) + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is not changed + - website_info.site[0].bindings[0].ip == "127.0.3.1" + - website_info.site[0].bindings[0].port == "8093" + - website_info.site[0].bindings[0].hostname == "microsoft.iis.website.set1" + - website_info.site[0].bindings[1].ip == "127.0.4.1" + - website_info.site[0].bindings[1].port == "8094" + - website_info.site[0].bindings[1].hostname == "microsoft.iis.website.set2" + +- name: remove website binding + microsoft.iis.website: + name: "{{ test_website_name }}" + bindings: + remove: + - ip: '127.0.3.1' + port: 8093 + hostname: 'microsoft.iis.website.set1' + - ip: '127.0.4.1' + port: 8094 + hostname: 'microsoft.iis.website.set2' + register: website + +- name: remove website binding info + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is changed + - website_info.site[0].bindings == [] + +- name: remove website binding (idempotent) + microsoft.iis.website: + name: "{{ test_website_name }}" + bindings: + remove: + - ip: '127.0.3.1' + port: 8093 + hostname: 'microsoft.iis.website.set1' + - ip: '127.0.4.1' + port: 8094 + hostname: 'microsoft.iis.website.set2' + register: website + +- name: remove website binding info (idempotent) + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is not changed + - website_info.site[0].bindings == [] + +- name: add binding with certificate + microsoft.iis.website: + name: "{{ test_website_name }}" + state: started + bindings: + add: + - ip: "{{ test_website_ip }}" + port: "{{ test_website_port }}" + hostname: "{{ test_website_hostname }}" + protocol: https + ssl_flags: 1 + certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" + certificate_store_name: "my" + register: website + +- name: add binding with certificate info + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is changed + - website_info.site[0].bindings[0].protocol == "https" + - website_info.site[0].bindings[0].ssl_flags == 1 \ No newline at end of file diff --git a/tests/integration/targets/website/tasks/main.yml b/tests/integration/targets/website/tasks/main.yml index 9c16628..7f67de5 100644 --- a/tests/integration/targets/website/tasks/main.yml +++ b/tests/integration/targets/website/tasks/main.yml @@ -1,3 +1,103 @@ -- name: Run test - microsoft.iis.website: - name: foo +--- +- name: run website integration tests + block: + - name: ensure IIS features are installed + ansible.windows.win_feature: + name: Web-Server + state: present + include_management_tools: True + register: feature_install + + - name: reboot after feature install + ansible.windows.win_reboot: + when: feature_install.reboot_required + + - name: get iis configuration checksum + ansible.windows.win_stat: + path: C:\Windows\System32\inetsrv\config\applicationHost.config + checksum_algorithm: sha1 + register: stat_result + + - name: take a copy of the original iis configuration + ansible.windows.win_copy: + src: C:\Windows\System32\inetsrv\config\applicationHost.config + dest: '{{ remote_tmp_dir }}\applicationHost.config' + remote_src: yes + register: copy_result + + - assert: + that: + - "stat_result.stat.checksum == copy_result.checksum" + + - name: create website directory structure + ansible.windows.win_file: + path: "{{ item }}" + state: directory + loop: + - "{{ test_phisical_path }}" + - "{{ test_alt_phisical_path }}" + + - name: create test application pool + microsoft.iis.web_app_pool: + name: "{{ test_apppool }}" + state: present + + # Tests + - include_tasks: tests.yml + - include_tasks: bindings.yml + + always: + # Cleanup + - name: remove website directory structure + ansible.windows.win_file: + path: "{{ item }}" + state: absent + loop: + - "{{ test_phisical_path }}" + - "{{ test_alt_phisical_path }}" + + - name: remove test website + microsoft.iis.website: + name: "{{ test_website_name }}" + state: absent + + - name: remove test application pool + microsoft.iis.web_app_pool: + name: "{{ test_apppool }}" + state: absent + + - name: cleanup certreq files + ansible.windows.win_file: + path: "{{ item }}" + state: absent + with_items: + - c:\windows\temp\certreq1.txt + - c:\windows\temp\certreqresp1.txt + + - name: remove certs + raw: 'remove-item cert:\localmachine\my\{{ item }} -force -ea silentlycontinue' + with_items: + - "{{ thumbprint1.stdout_lines[0] }}" + + - name: restore iis configuration + ansible.windows.win_copy: + src: '{{ remote_tmp_dir }}\applicationHost.config' + dest: C:\Windows\System32\inetsrv\config\applicationHost.config + remote_src: yes + register: copy_result + + - assert: + that: + - "stat_result.stat.checksum == copy_result.checksum" + + - name: remove IIS feature if it was installed + ansible.windows.win_feature: + name: Web-Server + state: absent + include_management_tools: True + when: feature_install is changed + register: feature_uninstall + + - name: reboot after removing IIS features + ansible.windows.win_reboot: + when: feature_uninstall.reboot_required | default(False) diff --git a/tests/integration/targets/website/tasks/tests.yml b/tests/integration/targets/website/tasks/tests.yml new file mode 100644 index 0000000..71edcbf --- /dev/null +++ b/tests/integration/targets/website/tasks/tests.yml @@ -0,0 +1,187 @@ +--- +- name: verify website does not exist + microsoft.iis.website: + name: "{{ test_website_name }}" + state: absent + +- name: create new website + microsoft.iis.website: + name: "{{ test_website_name }}" + site_id: "{{ test_site_id }}" + state: started + physical_path: "{{ test_phisical_path }}" + application_pool: DefaultAppPool + bindings: + set: + - ip: "{{ test_website_ip }}" + port: "{{ test_website_port }}" + hostname: "{{ test_website_hostname }}" + register: website + +- name: get new website info + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is changed + - website_info.site[0].name == test_website_name + - website_info.site[0].id == test_site_id + - website_info.site[0].state == "Started" + +- name: create new website (idempotent) + microsoft.iis.website: + name: "{{ test_website_name }}" + site_id: "{{ test_site_id }}" + state: started + physical_path: "{{ test_phisical_path }}" + application_pool: DefaultAppPool + bindings: + set: + - ip: "{{ test_website_ip }}" + port: "{{ test_website_port }}" + hostname: "{{ test_website_hostname }}" + register: website + +- name: get new website info (idempotent) + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is not changed + - website_info.site[0].name == test_website_name + - website_info.site[0].state == "Started" + +- name: stop website + microsoft.iis.website: + name: "{{ test_website_name }}" + state: stopped + register: website + +- name: get stop website info + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is changed + - website_info.site[0].name == test_website_name + - website_info.site[0].state == "Stopped" + +- name: stop website (idempotent) + microsoft.iis.website: + name: "{{ test_website_name }}" + state: stopped + register: website + +- name: get stop website info (idempotent) + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is not changed + - website_info.site[0].name == test_website_name + - website_info.site[0].state == "Stopped" + +- name: restart website + microsoft.iis.website: + name: "{{ test_website_name }}" + state: restarted + register: website + +- name: get restart website info + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is changed + - website_info.site[0].name == test_website_name + - website_info.site[0].state == "Started" + +- name: update website with custom parameters - Log location, Format 3WC and rolling over every hour + microsoft.iis.website: + name: "{{ test_website_name }}" + parameters: logfile.directory:"{{ test_phisical_path }}"|logfile.period:Hourly|logFile.logFormat:W3C + register: website + +- name: get update website with custom parameters info + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is changed + - website_info.site[0].name == test_website_name + +- name: change website physical path + microsoft.iis.website: + name: "{{ test_website_name }}" + physical_path: "{{ test_alt_phisical_path }}" + register: website + +- name: get change website physical path info + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is changed + - website_info.site[0].physical_path == test_alt_phisical_path + +- name: change website physical path (idempotent) + microsoft.iis.website: + name: "{{ test_website_name }}" + physical_path: "{{ test_alt_phisical_path }}" + register: website + +- name: get change website physical path info (idempotent) + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is not changed + - website_info.site[0].physical_path == test_alt_phisical_path + +- name: change website application pool + microsoft.iis.website: + name: "{{ test_website_name }}" + application_pool: "{{ test_apppool }}" + register: website + +- name: get change website application pool + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is changed + - website_info.site[0].application_pool == test_apppool + +- name: change website application pool (idempotent) + microsoft.iis.website: + name: "{{ test_website_name }}" + application_pool: "{{ test_apppool }}" + register: website + +- name: get change website application pool info (idempotent) + microsoft.iis.website_info: + name: "{{ test_website_name }}" + register: website_info + +- assert: + that: + - website is not changed + - website_info.site[0].application_pool == test_apppool \ No newline at end of file diff --git a/tests/integration/targets/website_info/aliases b/tests/integration/targets/website_info/aliases new file mode 100644 index 0000000..8edd9c5 --- /dev/null +++ b/tests/integration/targets/website_info/aliases @@ -0,0 +1,2 @@ +windows +shippable/windows/group1 \ No newline at end of file diff --git a/tests/integration/targets/website_info/defaults/main.yml b/tests/integration/targets/website_info/defaults/main.yml new file mode 100644 index 0000000..69f3263 --- /dev/null +++ b/tests/integration/targets/website_info/defaults/main.yml @@ -0,0 +1,17 @@ +--- + +test_website_name: InfoWebSite1 +test_apppool: InfoWebSitePool1 +test_site_id: 91 +test_phisical_path: C:\wwwroot\websites\my-test-website +test_website_port: 8021 +test_website_ip: 127.0.0.1 +test_website_hostname: 'acme1.com' + +test_alt_website_name: InfoWebSite2 +test_alt_apppool: InfoWebSitePool2 +test_alt_site_id: 92 +test_alt_phisical_path: C:\wwwroot\websites\my-test-website-alt +test_alt_website_port: 8022 +test_alt_website_ip: 127.0.0.2 +test_alt_website_hostname: 'acme2.com' \ No newline at end of file diff --git a/tests/integration/targets/website_info/meta/main.yml b/tests/integration/targets/website_info/meta/main.yml new file mode 100644 index 0000000..e3dd5fb --- /dev/null +++ b/tests/integration/targets/website_info/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: +- setup_remote_tmp_dir diff --git a/tests/integration/targets/website_info/tasks/main.yml b/tests/integration/targets/website_info/tasks/main.yml new file mode 100644 index 0000000..06185f8 --- /dev/null +++ b/tests/integration/targets/website_info/tasks/main.yml @@ -0,0 +1,98 @@ +--- +- name: run website_info integration tests + block: + - name: ensure IIS features are installed + ansible.windows.win_feature: + name: Web-Server + state: present + include_management_tools: True + register: feature_install + + - name: reboot after feature install + ansible.windows.win_reboot: + when: feature_install.reboot_required + + - name: get iis configuration checksum + ansible.windows.win_stat: + path: C:\Windows\System32\inetsrv\config\applicationHost.config + checksum_algorithm: sha1 + register: stat_result + + - name: take a copy of the original iis configuration + ansible.windows.win_copy: + src: C:\Windows\System32\inetsrv\config\applicationHost.config + dest: '{{ remote_tmp_dir }}\applicationHost.config' + remote_src: yes + register: copy_result + + - assert: + that: + - "stat_result.stat.checksum == copy_result.checksum" + + - name: create website directory structure + ansible.windows.win_file: + path: "{{ item }}" + state: directory + loop: + - "{{ test_phisical_path }}" + - "{{ test_alt_phisical_path }}" + + - name: create test application pool + microsoft.iis.web_app_pool: + name: "{{ item }}" + state: present + loop: + - "{{ test_apppool }}" + - "{{ test_alt_apppool }}" + + # Tests + - include_tasks: tests.yml + + always: + # Cleanup + - name: remove website directory structure + ansible.windows.win_file: + path: "{{ item }}" + state: absent + loop: + - "{{ test_phisical_path }}" + - "{{ test_alt_phisical_path }}" + + - name: remove test website + microsoft.iis.website: + name: "{{ item }}" + state: absent + loop: + - "{{ test_website_name }}" + - "{{ test_alt_website_name }}" + + - name: remove test application pool + microsoft.iis.web_app_pool: + name: "{{ item }}" + state: absent + loop: + - "{{ test_phisical_path }}" + - "{{ test_alt_phisical_path }}" + + - name: restore iis configuration + ansible.windows.win_copy: + src: '{{ remote_tmp_dir }}\applicationHost.config' + dest: C:\Windows\System32\inetsrv\config\applicationHost.config + remote_src: yes + register: copy_result + + - assert: + that: + - "stat_result.stat.checksum == copy_result.checksum" + + - name: remove IIS feature if it was installed + ansible.windows.win_feature: + name: Web-Server + state: absent + include_management_tools: True + when: feature_install is changed + register: feature_uninstall + + - name: reboot after removing IIS features + ansible.windows.win_reboot: + when: feature_uninstall.reboot_required | default(False) diff --git a/tests/integration/targets/website_info/tasks/tests.yml b/tests/integration/targets/website_info/tasks/tests.yml new file mode 100644 index 0000000..1b323f1 --- /dev/null +++ b/tests/integration/targets/website_info/tasks/tests.yml @@ -0,0 +1,81 @@ +--- +- name: get all websites from server + raw: powershell.exe "(get-website).name" + register: existing_sites + +- name: ensure all sites are removed for clean testing + microsoft.iis.website: + name: "{{ item }}" + state: absent + with_items: + - "{{ existing_sites.stdout_lines }}" + +- name: create first website + microsoft.iis.website: + name: "{{ test_website_name }}" + site_id: "{{ test_site_id }}" + state: started + physical_path: "{{ test_phisical_path }}" + application_pool: "{{ test_apppool }}" + bindings: + set: + - ip: "{{ test_website_ip }}" + port: "{{ test_website_port }}" + hostname: "{{ test_website_hostname }}" + protocol: "http" + ssl_flags: 0 + register: website1 + +- name: create second website + microsoft.iis.website: + name: "{{ test_alt_website_name }}" + site_id: "{{ test_alt_site_id }}" + state: started + physical_path: "{{ test_alt_phisical_path }}" + application_pool: "{{ test_alt_apppool }}" + bindings: + set: + - ip: "{{ test_alt_website_ip }}" + port: "{{ test_alt_website_port }}" + hostname: "{{ test_alt_website_hostname }}" + protocol: "http" + ssl_flags: 0 + register: website2 + +- name: Fetch test website info + microsoft.iis.website_info: + name: '{{ test_website_name }}' + register: website_info + +- name: Check that the fetched info is correct + assert: + that: + - website_info.exists + - website_info.site[0].name == test_website_name + - website_info.site[0].id == test_site_id + - website_info.site[0].state == "Started" + - website_info.site[0].application_pool == test_apppool + - website_info.site[0].physical_path == test_phisical_path + - website_info.site[0].bindings[0].ip == test_website_ip + - website_info.site[0].bindings[0].port == test_website_port | string + - website_info.site[0].bindings[0].hostname == test_website_hostname + - website_info.site[0].bindings[0].protocol == "http" + - website_info.site[0].bindings[0].ssl_flags == 0 + +- name: Get info of a none existent website + microsoft.iis.website_info: + name: notReal + register: not_real + failed_when: "'Failed to fetch the info of the required Website Exception:' not in not_real.msg" + +- name: Fetch all websites that exist on the system + microsoft.iis.website_info: + register: all_websites_info + +- name: Verify all websites were fetched + assert: + that: + - all_websites_info.exists + - all_websites_info.site | length == 2 + - all_websites_info.site[0].name == test_website_name + - all_websites_info.site[1].name == test_alt_website_name \ No newline at end of file diff --git a/tests/integration/targets/win_iis_webbinding/aliases b/tests/integration/targets/win_iis_webbinding/aliases deleted file mode 100644 index 423ce39..0000000 --- a/tests/integration/targets/win_iis_webbinding/aliases +++ /dev/null @@ -1 +0,0 @@ -shippable/windows/group2 diff --git a/tests/integration/targets/win_iis_webbinding/defaults/main.yml b/tests/integration/targets/win_iis_webbinding/defaults/main.yml deleted file mode 100644 index 13f0bc3..0000000 --- a/tests/integration/targets/win_iis_webbinding/defaults/main.yml +++ /dev/null @@ -1,30 +0,0 @@ -test_iis_site_name: default web site - -http_vars: - protocol: http - port: 80 - ip: '*' - -http_header_vars: - protocol: http - port: 80 - ip: '*' - header: test.com - -https_vars: - protocol: https - port: 443 - ip: '*' - -https_header_vars: - protocol: https - port: 443 - ip: '*' - header: test.com - ssl_flags: 1 - -https_wc_vars: - protocol: https - port: 443 - ip: '127.0.0.1' - header: wc.test.com diff --git a/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 b/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 deleted file mode 100644 index f1d49f4..0000000 --- a/tests/integration/targets/win_iis_webbinding/library/test_get_webbindings.ps1 +++ /dev/null @@ -1,106 +0,0 @@ -#!powershell - -# Copyright: (c) 2017, Noah Sparks -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -#Requires -Module Ansible.ModuleUtils.Legacy - -$params = Parse-Args -arguments $args -supports_check_mode $true - -$name = Get-AnsibleParam $params -name "name" -type str -failifempty $true -aliases 'website' -$host_header = Get-AnsibleParam $params -name "host_header" -type str -$protocol = Get-AnsibleParam $params -name "protocol" -type str -default 'http' -$port = Get-AnsibleParam $params -name "port" -type int -default '80' -$ip = Get-AnsibleParam $params -name "ip" -default '*' - -$result = @{ - changed = $false -} -function New-BindingInfo { - $ht = @{ - 'bindingInformation' = $args[0].bindingInformation - 'ip' = $args[0].bindingInformation.split(':')[0] - 'port' = [int]$args[0].bindingInformation.split(':')[1] - 'hostheader' = $args[0].bindingInformation.split(':')[2] - 'isDsMapperEnabled' = $args[0].isDsMapperEnabled - 'protocol' = $args[0].protocol - 'certificateStoreName' = $args[0].certificateStoreName - 'certificateHash' = $args[0].certificateHash - } - - #handle sslflag support - If ([version][System.Environment]::OSVersion.Version -lt [version]'6.2') { - $ht.sslFlags = 'not supported' - } - Else { - $ht.sslFlags = [int]$args[0].sslFlags - } - - Return $ht -} - -# Used instead of get-webbinding to ensure we always return a single binding -# pass it $binding_parameters hashtable -function Get-SingleWebBinding { - - Try { - $site_bindings = get-webbinding -name $args[0].name - } - Catch { - # 2k8r2 throws this error when you run get-webbinding with no bindings in iis - $msg = 'Cannot process argument because the value of argument "obj" is null. Change the value of argument "obj" to a non-null value' - If (-not $_.Exception.Message.CompareTo($msg)) { - Throw $_.Exception.Message - } - Else { return } - } - - Foreach ($binding in $site_bindings) { - $splits = $binding.bindingInformation -split ':' - - if ( - $args[0].protocol -eq $binding.protocol -and - $args[0].ipaddress -eq $splits[0] -and - $args[0].port -eq $splits[1] -and - $args[0].hostheader -eq $splits[2] - ) { - Return $binding - } - } -} - -# create binding search splat -$binding_parameters = @{ - Name = $name - Protocol = $protocol - Port = $port - IPAddress = $ip -} - -# insert host header to search if specified, otherwise it will return * (all bindings matching protocol/ip) -If ($host_header) { - $binding_parameters.HostHeader = $host_header -} -Else { - $binding_parameters.HostHeader = [string]::Empty -} - -# Get bindings matching parameters -Try { - $current_bindings = Get-SingleWebBinding $binding_parameters -} -Catch { - Fail-Json -obj $result -message "Failed to retrieve bindings with Get-SingleWebBinding - $($_.Exception.Message)" -} - -If ($current_bindings) { - Try { - $binding_info = New-BindingInfo $current_bindings - } - Catch { - Fail-Json -obj $result -message "Failed to create binding info - $($_.Exception.Message)" - } - - $result.binding = $binding_info -} -exit-json -obj $result \ No newline at end of file diff --git a/tests/integration/targets/win_iis_webbinding/tasks/failures.yml b/tests/integration/targets/win_iis_webbinding/tasks/failures.yml deleted file mode 100644 index 92736fe..0000000 --- a/tests/integration/targets/win_iis_webbinding/tasks/failures.yml +++ /dev/null @@ -1,70 +0,0 @@ -- name: failure check define * for host header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - host_header: '*' - protocol: http - ip: '*' - register: failure - failed_when: failure.msg != "To make or remove a catch-all binding, please omit the host_header parameter entirely rather than specify host_header *" - -- debug: - var: failure - verbosity: 1 - -- block: - - name: get all websites from server - raw: powershell.exe "(get-website).name" - register: existing_sites - - - name: ensure all sites are removed for clean testing - win_iis_website: - name: "{{ item }}" - state: absent - with_items: - - "{{ existing_sites.stdout_lines }}" - - - name: add testremove site - win_iis_website: - name: testremove - state: started - physical_path: c:\inetpub\wwwroot - - - name: add bindings to testremove - win_iis_webbinding: - name: testremove - ip: "{{ item.ip }}" - port: "{{ item.port }}" - with_items: - - {ip: 127.0.0.1, port: 80} - - {ip: '*', port: 80} - - - name: remove ip * binding from testremove - win_iis_webbinding: - name: testremove - state: absent - port: 80 - ip: '*' - - - name: get the remaining binding from testremove - test_get_webbindings: - name: testremove - port: 80 - ip: 127.0.0.1 - register: test_result - - - debug: - var: test_result - verbosity: 1 - - - name: assert that remove *:80 doesn't also remove 127.0.0.1:80 - assert: - that: - - test_result.binding.ip == '127.0.0.1' - - test_result.binding.port == 80 - - always: - - name: remove websites - win_iis_website: - name: testremove - state: absent diff --git a/tests/integration/targets/win_iis_webbinding/tasks/http.yml b/tests/integration/targets/win_iis_webbinding/tasks/http.yml deleted file mode 100644 index 34c4cc2..0000000 --- a/tests/integration/targets/win_iis_webbinding/tasks/http.yml +++ /dev/null @@ -1,317 +0,0 @@ -#cm add -#changed true, check nothing present -- name: CM add http binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - protocol: "{{ http_vars.protocol }}" - ip: "{{ http_vars.ip }}" - port: "{{ http_vars.port }}" - register: http_no_header - check_mode: yes - -- name: CM get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ http_vars.protocol }}" - ip: "{{ http_vars.ip }}" - port: "{{ http_vars.port }}" - register: get_http_no_header - changed_when: false - -- name: CM add http binding with header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - host_header: "{{ http_header_vars.header }}" - protocol: "{{ http_header_vars.protocol }}" - ip: "{{ http_header_vars.ip }}" - port: "{{ http_header_vars.port }}" - register: http_header - check_mode: yes - -- name: CM get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - host_header: "{{ http_header_vars.header }}" - protocol: "{{ http_header_vars.protocol }}" - ip: "{{ http_header_vars.ip }}" - port: "{{ http_header_vars.port }}" - register: get_http_header - changed_when: false - -- name: CM assert changed, but not added - assert: - that: - - http_no_header is changed - - http_no_header.binding_info is none - - get_http_no_header.binding is not defined - - http_header is changed - - http_header.binding_info is none - - get_http_header.binding is not defined - -#add -#changed true, new bindings present -- name: add http binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - protocol: "{{ http_vars.protocol }}" - ip: "{{ http_vars.ip }}" - port: "{{ http_vars.port }}" - register: http_no_header - -- name: get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ http_vars.protocol }}" - ip: "{{ http_vars.ip }}" - port: "{{ http_vars.port }}" - register: get_http_no_header - changed_when: false - -- name: add http binding with header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - host_header: "{{ http_header_vars.header }}" - protocol: "{{ http_header_vars.protocol }}" - ip: "{{ http_header_vars.ip }}" - port: "{{ http_header_vars.port }}" - register: http_header - -- name: get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - host_header: "{{ http_header_vars.header }}" - protocol: "{{ http_header_vars.protocol }}" - ip: "{{ http_header_vars.ip }}" - port: "{{ http_header_vars.port }}" - register: get_http_header - changed_when: false - -- name: assert changed and added - assert: - that: - - http_no_header is changed - - http_no_header.binding_info is defined - - http_no_header.operation_type == 'added' - - http_no_header.binding_info.ip == "{{ http_vars.ip }}" - - http_no_header.binding_info.port == {{ http_vars.port }} - - http_no_header.binding_info.protocol == "{{ http_vars.protocol }}" - - http_header is changed - - http_header.binding_info is defined - - http_header.operation_type == 'added' - - http_header.binding_info.ip == "{{ http_header_vars.ip }}" - - http_header.binding_info.port == {{ http_header_vars.port }} - - http_header.binding_info.protocol == "{{ http_header_vars.protocol }}" - - http_header.binding_info.hostheader == "{{ http_header_vars.header }}" - -#add idem -#changed false -- name: idem add http binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - protocol: "{{ http_vars.protocol }}" - ip: "{{ http_vars.ip }}" - port: "{{ http_vars.port }}" - register: http_no_header - -- name: idem add http binding with header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - host_header: "{{ http_header_vars.header }}" - protocol: "{{ http_header_vars.protocol }}" - ip: "{{ http_header_vars.ip }}" - port: "{{ http_header_vars.port }}" - register: http_header - -- name: idem assert not changed - assert: - that: - - http_no_header is not changed - - http_header is not changed - -#modify -#can't test modify for http, it will add a new binding instead since -#there's no way to match existing bindings against the new parameters - -#cm remove -#changed true, bindings still present -- name: cm remove http binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - protocol: "{{ http_vars.protocol }}" - ip: "{{ http_vars.ip }}" - port: "{{ http_vars.port }}" - register: http_no_header - check_mode: yes - -- name: get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ http_vars.protocol }}" - ip: "{{ http_vars.ip }}" - port: "{{ http_vars.port }}" - register: get_http_no_header - changed_when: false - -- name: cm remove http binding with header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - host_header: "{{ http_header_vars.header }}" - protocol: "{{ http_header_vars.protocol }}" - ip: "{{ http_header_vars.ip }}" - port: "{{ http_header_vars.port }}" - register: http_header - check_mode: yes - -- name: get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - host_header: "{{ http_header_vars.header }}" - protocol: "{{ http_header_vars.protocol }}" - ip: "{{ http_header_vars.ip }}" - port: "{{ http_header_vars.port }}" - register: get_http_header - changed_when: false - -- name: cm remove assert changed, but still present - assert: - that: - - http_no_header is changed - - http_no_header.binding_info is defined - - http_no_header.operation_type == 'removed' - - http_no_header.binding_info.ip == "{{ http_vars.ip }}" - - http_no_header.binding_info.port == {{ http_vars.port }} - - http_no_header.binding_info.protocol == "{{ http_vars.protocol }}" - - get_http_no_header.binding is defined - - get_http_no_header.binding.ip == "{{ http_vars.ip }}" - - get_http_no_header.binding.port == {{ http_vars.port }} - - get_http_no_header.binding.protocol == "{{ http_vars.protocol }}" - - http_header is changed - - http_header.binding_info is defined - - http_header.operation_type == 'removed' - - http_header.binding_info.ip == "{{ http_header_vars.ip }}" - - http_header.binding_info.port == {{ http_header_vars.port }} - - http_header.binding_info.protocol == "{{ http_header_vars.protocol }}" - - http_header.binding_info.hostheader == "{{ http_header_vars.header }}" - - get_http_header.binding is defined - - get_http_header.binding.ip == "{{ http_header_vars.ip }}" - - get_http_header.binding.port == {{ http_header_vars.port }} - - get_http_header.binding.protocol == "{{ http_header_vars.protocol }}" - - get_http_header.binding.hostheader == "{{ http_header_vars.header }}" - - -#remove -#changed true, bindings gone -- name: remove http binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - protocol: "{{ http_vars.protocol }}" - ip: "{{ http_vars.ip }}" - port: "{{ http_vars.port }}" - register: http_no_header - -- name: get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ http_vars.protocol }}" - ip: "{{ http_vars.ip }}" - port: "{{ http_vars.port }}" - register: get_http_no_header - changed_when: false - -- name: remove http binding with header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - host_header: "{{ http_header_vars.header }}" - protocol: "{{ http_header_vars.protocol }}" - ip: "{{ http_header_vars.ip }}" - port: "{{ http_header_vars.port }}" - register: http_header - -- name: get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - host_header: "{{ http_header_vars.header }}" - protocol: "{{ http_header_vars.protocol }}" - ip: "{{ http_header_vars.ip }}" - port: "{{ http_header_vars.port }}" - register: get_http_header - changed_when: false - -- name: remove assert changed and gone - assert: - that: - - http_no_header is changed - - http_no_header.operation_type == 'removed' - - http_no_header.binding_info is defined - - http_no_header.binding_info.ip == "{{ http_vars.ip }}" - - http_no_header.binding_info.port == {{ http_vars.port }} - - http_no_header.binding_info.protocol == "{{ http_vars.protocol }}" - - get_http_no_header.binding is not defined - - http_header is changed - - http_header.binding_info is defined - - http_header.operation_type == 'removed' - - http_header.binding_info.ip == "{{ http_header_vars.ip }}" - - http_header.binding_info.port == {{ http_header_vars.port }} - - http_header.binding_info.protocol == "{{ http_header_vars.protocol }}" - - http_header.binding_info.hostheader == "{{ http_header_vars.header }}" - - get_http_header.binding is not defined - -#remove idem -#change false, bindings gone -- name: idem remove http binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - protocol: "{{ http_vars.protocol }}" - ip: "{{ http_vars.ip }}" - port: "{{ http_vars.port }}" - register: http_no_header - -- name: get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ http_vars.protocol }}" - ip: "{{ http_vars.ip }}" - port: "{{ http_vars.port }}" - register: get_http_no_header - changed_when: false - -- name: idem remove http binding with header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - host_header: "{{ http_header_vars.header }}" - protocol: "{{ http_header_vars.protocol }}" - ip: "{{ http_header_vars.ip }}" - port: "{{ http_header_vars.port }}" - register: http_header - -- name: get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - host_header: "{{ http_header_vars.header }}" - protocol: "{{ http_header_vars.protocol }}" - ip: "{{ http_header_vars.ip }}" - port: "{{ http_header_vars.port }}" - register: get_http_header - changed_when: false - -- name: idem remove assert changed and gone - assert: - that: - - http_no_header is not changed - - http_no_header.binding_info is not defined - - get_http_no_header.binding is not defined - - http_header is not changed - - http_header.binding_info is not defined - - get_http_header.binding is not defined diff --git a/tests/integration/targets/win_iis_webbinding/tasks/https-ge6.2.yml b/tests/integration/targets/win_iis_webbinding/tasks/https-ge6.2.yml deleted file mode 100644 index f883c67..0000000 --- a/tests/integration/targets/win_iis_webbinding/tasks/https-ge6.2.yml +++ /dev/null @@ -1,459 +0,0 @@ -############## -### CM Add ### -############## -#changed true, check nothing present -- name: CM add https binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" - register: https_no_header - check_mode: yes - -- name: CM get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: get_https_no_header - changed_when: false - -- name: CM add https binding with header and SNI - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - ssl_flags: 1 - certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" - register: https_header - check_mode: yes - -- name: CM get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - register: get_https_header - changed_when: false - -- name: CM assert changed, but not added - assert: - that: - - https_no_header is changed - - https_no_header.operation_type == 'added' - - https_no_header.binding_info is none - - get_https_no_header.binding is not defined - - https_header is changed - - https_header.operation_type == 'added' - - https_header.binding_info is none - - get_https_header.binding is not defined - -########### -### Add ### -########### -#changed true, new bindings present -- name: add https binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" - register: https_no_header - -- name: get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: get_https_no_header - changed_when: false - -- name: add https binding with header SNI - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - ssl_flags: 1 - certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" - register: https_header - -- name: get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - register: get_https_header - changed_when: false - -- name: assert changed and added - assert: - that: - - https_no_header is changed - - https_no_header.operation_type == 'added' - - https_no_header.binding_info is defined - - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" - - https_no_header.binding_info.ip == "{{ https_vars.ip }}" - - https_no_header.binding_info.port == {{ https_vars.port }} - - https_no_header.binding_info.hostheader == '' - - https_no_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" - - https_header is changed - - https_header.operation_type == 'added' - - https_header.binding_info is defined - - https_header.binding_info.hostheader == "{{ https_header_vars.header }}" - - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}" - - https_header.binding_info.ip == "{{ https_header_vars.ip }}" - - https_header.binding_info.port == {{ https_header_vars.port }} - - https_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" - - https_header.binding_info.sslFlags == 1 - -################ -### Idem Add ### -################ -#changed false -- name: idem add https binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - protocol: https - ip: '*' - port: 443 - certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" - register: https_no_header - -- name: idem add https binding with header and SNI - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - host_header: test.com - protocol: https - ip: '*' - port: 443 - ssl_flags: 1 - certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" - register: https_header - -- name: idem assert not changed - assert: - that: - - https_no_header is not changed - - https_header is not changed - -################# -### CM Modify ### -################# -# changed true, verify no changes occurred - -#modify sni -- name: CM modify https binding with header, change cert - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - ssl_flags: 1 - certificate_hash: "{{ thumbprint2.stdout_lines[0] }}" - register: https_header - check_mode: yes - -- name: get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - register: get_https_header - changed_when: false - -- name: CM assert changed but old cert - assert: - that: - - https_header is changed - - https_header.operation_type == 'updated' - - https_header.binding_info is defined - - https_header.binding_info.ip == "{{ https_header_vars.ip }}" - - https_header.binding_info.port == {{ https_header_vars.port }} - - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}" - - https_header.binding_info.hostheader == "{{ https_header_vars.header }}" - - https_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" - - https_header.binding_info.sslFlags == 1 - - get_https_header.binding is defined - - get_https_header.binding.ip == "{{ https_header_vars.ip }}" - - get_https_header.binding.port == {{ https_header_vars.port }} - - get_https_header.binding.protocol == "{{ https_header_vars.protocol }}" - - get_https_header.binding.hostheader == "{{ https_header_vars.header }}" - - get_https_header.binding.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" - - get_https_header.binding.sslFlags == 1 - -############## -### Modify ### -############## -# modify ssl flags -- name: modify https binding with header, change cert - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - ssl_flags: 1 - certificate_hash: "{{ thumbprint2.stdout_lines[0] }}" - register: https_header - -- name: get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - register: get_https_header - changed_when: false - -- name: modify assert changed and new cert - assert: - that: - - https_header is changed - - https_header.operation_type == 'updated' - - https_header.binding_info is defined - - https_header.binding_info.ip == "{{ https_header_vars.ip }}" - - https_header.binding_info.port == {{ https_header_vars.port }} - - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}" - - https_header.binding_info.hostheader == "{{ https_header_vars.header }}" - - https_header.binding_info.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" - - https_header.binding_info.sslFlags == 1 - - get_https_header.binding is defined - - get_https_header.binding.ip == "{{ https_header_vars.ip }}" - - get_https_header.binding.port == {{ https_header_vars.port }} - - get_https_header.binding.protocol == "{{ https_header_vars.protocol }}" - - get_https_header.binding.hostheader == "{{ https_header_vars.header }}" - - get_https_header.binding.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" - - get_https_header.binding.sslFlags == 1 - -################### -### Idem Modify ### -################### -#changed false - -#idem modify ssl flags -- name: idem modify https binding with header, enable SNI and change cert - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - ssl_flags: 1 - certificate_hash: "{{ thumbprint2.stdout_lines[0] }}" - register: https_header - -- name: idem assert not changed - assert: - that: - - https_header is not changed - -################# -### CM Remove ### -################# -#changed true, bindings still present -- name: cm remove https binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: https_no_header - check_mode: yes - -- name: get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: get_https_no_header - changed_when: false - -- name: cm remove https binding with header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - register: https_header - check_mode: yes - -- name: get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - register: get_https_header - changed_when: false - -- name: cm remove assert changed, but still present - assert: - that: - - https_no_header is changed - - https_no_header.operation_type == 'removed' - - https_no_header.binding_info is defined - - https_no_header.binding_info.ip == "{{ https_vars.ip }}" - - https_no_header.binding_info.port == {{ https_vars.port }} - - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" - - get_https_no_header.binding is defined - - get_https_no_header.binding.ip == "{{ https_vars.ip }}" - - get_https_no_header.binding.port == {{ https_vars.port }} - - get_https_no_header.binding.protocol == "{{ https_vars.protocol }}" - - get_https_no_header.binding.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" - - https_header is changed - - https_header.binding_info is defined - - https_header.operation_type == 'removed' - - https_header.binding_info.ip == "{{ https_header_vars.ip }}" - - https_header.binding_info.port == {{ https_header_vars.port }} - - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}" - - https_header.binding_info.hostheader == "{{ https_header_vars.header }}" - - get_https_header.binding is defined - - get_https_header.binding.ip == "{{ https_header_vars.ip }}" - - get_https_header.binding.port == {{ https_header_vars.port }} - - get_https_header.binding.protocol == "{{ https_header_vars.protocol }}" - - get_https_header.binding.hostheader == "{{ https_header_vars.header }}" - - get_https_header.binding.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" - -############## -### remove ### -############## -#changed true, bindings gone -- name: remove https binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: https_no_header - -- name: get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: get_https_no_header - changed_when: false - -- name: remove https binding with header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - register: https_header - -- name: get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - register: get_https_header - changed_when: false - -- name: remove assert changed and gone - assert: - that: - - https_no_header is changed - - https_no_header.binding_info is defined - - https_no_header.operation_type == 'removed' - - https_no_header.binding_info.ip == "{{ https_vars.ip }}" - - https_no_header.binding_info.port == {{ https_vars.port }} - - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" - - get_https_no_header.binding is not defined - - https_header is changed - - https_header.binding_info is defined - - https_header.operation_type == 'removed' - - https_header.binding_info.ip == "{{ https_header_vars.ip }}" - - https_header.binding_info.port == {{ https_header_vars.port }} - - https_header.binding_info.protocol == "{{ https_header_vars.protocol }}" - - https_header.binding_info.hostheader == "{{ https_header_vars.header }}" - - get_https_header.binding is not defined - -################### -### remove idem ### -################### -#change false, bindings gone -- name: idem remove https binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: https_no_header - -- name: get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: get_https_no_header - changed_when: false - -- name: idem remove https binding with header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - register: https_header - -- name: get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - host_header: "{{ https_header_vars.header }}" - protocol: "{{ https_header_vars.protocol }}" - ip: "{{ https_header_vars.ip }}" - port: "{{ https_header_vars.port }}" - register: get_https_header - changed_when: false - -- name: idem remove assert changed and gone - assert: - that: - - https_no_header is not changed - - https_no_header.binding_info is not defined - - get_https_no_header.binding is not defined - - https_header is not changed - - https_header.binding_info is not defined - - get_https_header.binding is not defined diff --git a/tests/integration/targets/win_iis_webbinding/tasks/https-lt6.2.yml b/tests/integration/targets/win_iis_webbinding/tasks/https-lt6.2.yml deleted file mode 100644 index 1950641..0000000 --- a/tests/integration/targets/win_iis_webbinding/tasks/https-lt6.2.yml +++ /dev/null @@ -1,423 +0,0 @@ -############## -### CM Add ### -############## -#changed true, check nothing present -- name: CM add https binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" - register: https_no_header - check_mode: yes - -- name: CM get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: get_https_no_header - changed_when: false - -- name: CM assert changed, but not added - assert: - that: - - https_no_header is changed - - https_no_header.operation_type == 'added' - - https_no_header.binding_info is none - - get_https_no_header.binding is not defined - -########### -### Add ### -########### -#changed true, new bindings present -- name: add https binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" - register: https_no_header - -- name: assert changed and added - assert: - that: - - https_no_header is changed - - https_no_header.binding_info is defined - - https_no_header.operation_type == 'added' - - https_no_header.binding_info.ip == "{{ https_vars.ip }}" - - https_no_header.binding_info.port == {{ https_vars.port }} - - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" - - https_no_header.binding_info.hostheader == '' - - https_no_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" - -################ -### Idem Add ### -################ -#changed false -- name: idem add https binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - certificate_hash: "{{ thumbprint1.stdout_lines[0] }}" - register: https_no_header - -- name: idem assert not changed - assert: - that: - - https_no_header is not changed - -################# -### CM Modify ### -################# -# changed true, verify no changes occurred - -#modify sni -- name: CM modify https binding change cert - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - certificate_hash: "{{ thumbprint2.stdout_lines[0] }}" - register: https_no_header - check_mode: yes - -- name: get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: get_https_no_header - changed_when: false - -- name: CM assert changed but old cert - assert: - that: - - https_no_header is changed - - https_no_header.operation_type == 'updated' - - https_no_header.binding_info is defined - - https_no_header.binding_info.ip == "{{ https_vars.ip }}" - - https_no_header.binding_info.port == {{ https_vars.port }} - - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" - - https_no_header.binding_info.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" - - get_https_no_header.binding is defined - - get_https_no_header.binding.ip == "{{ https_vars.ip }}" - - get_https_no_header.binding.port == {{ https_vars.port }} - - get_https_no_header.binding.protocol == "{{ https_vars.protocol }}" - - get_https_no_header.binding.certificateHash == "{{ thumbprint1.stdout_lines[0] }}" - -############## -### Modify ### -############## -# modify ssl flags -- name: modify https binding, change cert - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - certificate_hash: "{{ thumbprint2.stdout_lines[0] }}" - register: https_no_header - -- name: get binding info header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: get_https_no_header - changed_when: false - -- name: modify assert changed and new cert - assert: - that: - - https_no_header is changed - - https_no_header.operation_type == 'updated' - - https_no_header.binding_info is defined - - https_no_header.binding_info.ip == "{{ https_vars.ip }}" - - https_no_header.binding_info.port == {{ https_vars.port }} - - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" - - https_no_header.binding_info.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" - - get_https_no_header.binding is defined - - get_https_no_header.binding.ip == "{{ https_vars.ip }}" - - get_https_no_header.binding.port == {{ https_vars.port }} - - get_https_no_header.binding.protocol == "{{ https_vars.protocol }}" - - get_https_no_header.binding.hostheader == '' - - get_https_no_header.binding.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" - -################### -### Idem Modify ### -################### -#changed false - -#idem modify ssl flags -- name: idem modify https binding and change cert - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: present - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - certificate_hash: "{{ thumbprint2.stdout_lines[0] }}" - register: https_header - -- name: idem assert not changed - assert: - that: - - https_header is not changed - -################# -### CM Remove ### -################# -#changed true, bindings still present -- name: cm remove https binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: https_no_header - check_mode: yes - -- name: get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: get_https_no_header - changed_when: false - -- name: cm remove assert changed, but still present - assert: - that: - - https_no_header is changed - - https_no_header.operation_type == 'removed' - - https_no_header.binding_info is defined - - https_no_header.binding_info.ip == "{{ https_vars.ip }}" - - https_no_header.binding_info.port == {{ https_vars.port }} - - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" - - https_no_header.binding_info.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" - - get_https_no_header.binding is defined - - get_https_no_header.binding.ip == "{{ https_vars.ip }}" - - get_https_no_header.binding.port == {{ https_vars.port }} - - get_https_no_header.binding.protocol == "{{ https_vars.protocol }}" - - get_https_no_header.binding.certificateHash == "{{ thumbprint2.stdout_lines[0] }}" - -############## -### remove ### -############## -#changed true, bindings gone -- name: remove https binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: https_no_header - -- name: get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: get_https_no_header - changed_when: false - -- name: remove assert changed and gone - assert: - that: - - https_no_header is changed - - https_no_header.operation_type == 'removed' - - https_no_header.binding_info is defined - - https_no_header.binding_info.ip == "{{ https_vars.ip }}" - - https_no_header.binding_info.port == {{ https_vars.port }} - - https_no_header.binding_info.protocol == "{{ https_vars.protocol }}" - - get_https_no_header.binding is not defined - -################### -### remove idem ### -################### -#change false, bindings gone -- name: idem remove https binding no header - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: https_no_header - -- name: get binding info no header - test_get_webbindings: - name: "{{ test_iis_site_name }}" - protocol: "{{ https_vars.protocol }}" - ip: "{{ https_vars.ip }}" - port: "{{ https_vars.port }}" - register: get_https_no_header - changed_when: false - -- name: idem remove assert changed and gone - assert: - that: - - https_no_header is not changed - - https_no_header.binding_info is not defined - - get_https_no_header.binding is not defined - - -################## -### WC Testing ### -################## - -# Unfortunately this does not work due to some strange errors -# that are caused when using a self signed wildcard cert. -# I'm leaving this here in case someone finds a solution in the -# future. - -# - name: add https binding wildcard with header -# win_iis_webbinding: -# name: "{{ test_iis_site_name }}" -# state: present -# host_header: "{{ https_wc_vars.header }}" -# protocol: "{{ https_wc_vars.protocol }}" -# ip: "{{ https_wc_vars.ip }}" -# port: "{{ https_wc_vars.port }}" -# certificate_hash: "{{ thumbprint_wc.stdout_lines[0] }}" -# register: https_header - -# - name: assert changed and added -# assert: -# that: -# - https_header is changed -# - https_header.added is defined -# - https_header.added.ip == "{{ https_wc_vars.ip }}" -# - https_header.added.port == {{ https_wc_vars.port }} -# - https_header.added.protocol == "{{ https_wc_vars.protocol }}" -# - https_header.added.hostheader == "{{ https_wc_vars.header }}" -# - https_header.added.certificateHash == "{{ thumbprint_wc.stdout_lines[0] }}" - - -# - name: idem add https binding wildcard with header -# win_iis_webbinding: -# name: "{{ test_iis_site_name }}" -# state: present -# host_header: "{{ https_wc_vars.header }}" -# protocol: "{{ https_wc_vars.protocol }}" -# ip: "{{ https_wc_vars.ip }}" -# port: "{{ https_wc_vars.port }}" -# certificate_hash: "{{ thumbprint_wc.stdout_lines[0] }}" -# register: https_header - - -# - name: cm remove wildcard https binding -# win_iis_webbinding: -# name: "{{ test_iis_site_name }}" -# state: absent -# host_header: "{{ https_wc_vars.header }}" -# protocol: "{{ https_wc_vars.protocol }}" -# ip: "{{ https_wc_vars.ip }}" -# port: "{{ https_wc_vars.port }}" -# register: https_header -# check_mode: yes - -# - name: get binding info header -# test_get_webbindings: -# name: "{{ test_iis_site_name }}" -# host_header: "{{ https_wc_vars.header }}" -# protocol: "{{ https_wc_vars.protocol }}" -# ip: "{{ https_wc_vars.ip }}" -# port: "{{ https_wc_vars.port }}" -# register: get_https_header -# changed_when: false - -# - name: cm remove assert changed, but still present -# assert: -# that: -# - https_header is changed -# - https_header.removed is defined -# - https_header.removed.ip == "{{ https_wc_vars.ip }}" -# - https_header.removed.port == {{ https_wc_vars.port }} -# - https_header.removed.protocol == "{{ https_wc_vars.protocol }}" -# - https_header.removed.hostheader == "{{ https_wc_vars.header }}" -# - https_header.removed.certificateHash == "{{ thumbprint_wc.stdout_lines[0] }}" -# - get_https_header.binding is defined -# - get_https_header.removed.ip == "{{ https_wc_vars.ip }}" -# - get_https_header.removed.port == {{ https_wc_vars.port }} -# - get_https_header.removed.protocol == "{{ https_wc_vars.protocol }}" -# - get_https_header.removed.hostheader == "{{ https_wc_vars.header }}" -# - get_https_header.removed.certificateHash == "{{ thumbprint_wc.stdout_lines[0] }}" - -# - name: remove wildcard https binding -# win_iis_webbinding: -# name: "{{ test_iis_site_name }}" -# state: absent -# host_header: "{{ https_wc_vars.header }}" -# protocol: "{{ https_wc_vars.protocol }}" -# ip: "{{ https_wc_vars.ip }}" -# port: "{{ https_wc_vars.port }}" -# register: https_header - -# - name: get binding info header -# test_get_webbindings: -# name: "{{ test_iis_site_name }}" -# host_header: "{{ https_wc_vars.header }}" -# protocol: "{{ https_wc_vars.protocol }}" -# ip: "{{ https_wc_vars.ip }}" -# port: "{{ https_wc_vars.port }}" -# register: get_https_header -# changed_when: false - - -# - name: remove assert changed and gone -# assert: -# that: -# - https_header is changed -# - https_header.removed is defined -# - https_header.removed.ip == "{{ https_wc_vars.ip }}" -# - https_header.removed.port == {{ https_wc_vars.port }} -# - https_header.removed.protocol == "{{ https_wc_vars.protocol }}" -# - https_header.removed.hostheader == "{{ https_wc_vars.header }}" -# - https_header.removed.certificateHash == "{{ thumbprint_wc.stdout_lines[0] }}" -# - get_https_header.binding is not defined - -# - name: idem remove wildcard https binding -# win_iis_webbinding: -# name: "{{ test_iis_site_name }}" -# state: absent -# host_header: "{{ https_wc_vars.header }}" -# protocol: "{{ https_wc_vars.protocol }}" -# ip: "{{ https_wc_vars.ip }}" -# port: "{{ https_wc_vars.port }}" -# register: https_header - -# - name: get binding info header -# test_get_webbindings: -# name: "{{ test_iis_site_name }}" -# host_header: "{{ https_wc_vars.header }}" -# protocol: "{{ https_wc_vars.protocol }}" -# ip: "{{ https_wc_vars.ip }}" -# port: "{{ https_wc_vars.port }}" -# register: get_https_header -# changed_when: false - -# - name: idem remove assert changed and gone -# assert: -# that: -# - https_header is not changed -# - https_header.removed is not defined -# - get_https_header.binding is not defined diff --git a/tests/integration/targets/win_iis_webbinding/tasks/main.yml b/tests/integration/targets/win_iis_webbinding/tasks/main.yml deleted file mode 100644 index ee12ff7..0000000 --- a/tests/integration/targets/win_iis_webbinding/tasks/main.yml +++ /dev/null @@ -1,62 +0,0 @@ ---- -# Cannot use win_feature to install IIS on Server 2008. -# Run a brief check and skip hosts that don't support -# that operation -#seems "raw" is the only module that works on 2008 non-r2. win_command and win_shell both failed -- name: register os version (seems integration tests don't gather this fact) - raw: powershell.exe "gwmi Win32_OperatingSystem | select -expand version" - register: os_version - changed_when: False - -- block: - - include_tasks: setup.yml - - include_tasks: http.yml - - include_tasks: https-lt6.2.yml - when: os_version.stdout_lines[0] is version('6.2','lt') - - include_tasks: https-ge6.2.yml - when: os_version.stdout_lines[0] is version('6.2','ge') - - include_tasks: failures.yml - - always: - - name: get all websites from server - raw: powershell.exe "(get-website).name" - register: existing_sites - - - name: ensure all sites are removed for clean testing - win_iis_website: - name: "{{ item }}" - state: absent - with_items: - - "{{ existing_sites.stdout_lines }}" - - - name: cleanup certreq files - ansible.windows.win_file: - path: "{{ item }}" - state: absent - with_items: - - c:\windows\temp\certreq1.txt - - c:\windows\temp\certreq2.txt - - c:\windows\temp\certreqwc.txt - - c:\windows\temp\certreqresp1.txt - - c:\windows\temp\certreqresp2.txt - - c:\windows\temp\certreqrespwc.txt - - - name: remove certs - raw: 'remove-item cert:\localmachine\my\{{ item }} -force -ea silentlycontinue' - with_items: - - "{{ thumbprint1.stdout_lines[0] }}" - - "{{ thumbprint2.stdout_lines[0] }}" - - "{{ thumbprint_wc.stdout_lines[0] }}" - - - name: remove IIS features after test - ansible.windows.win_feature: - name: Web-Server - state: absent - includ_sub_features: True - include_management_tools: True - register: feature_uninstall - - - name: reboot after feature install - ansible.windows.win_reboot: - when: feature_uninstall.reboot_required - when: os_version.stdout_lines[0] is version('6.1','gt') diff --git a/tests/integration/targets/win_iis_webbinding/tasks/setup.yml b/tests/integration/targets/win_iis_webbinding/tasks/setup.yml deleted file mode 100644 index 234cc40..0000000 --- a/tests/integration/targets/win_iis_webbinding/tasks/setup.yml +++ /dev/null @@ -1,93 +0,0 @@ -- name: reboot before feature install to ensure server is in clean state - ansible.windows.win_reboot: - -- name: ensure IIS features are installed - ansible.windows.win_feature: - name: Web-Server - state: present - includ_sub_features: True - include_management_tools: True - register: feature_install - -- name: reboot after feature install - ansible.windows.win_reboot: - when: feature_install.reboot_required - -- name: get all websites from server - raw: powershell.exe "(get-website).name" - register: existing_sites - -- name: ensure all sites are removed for clean testing - win_iis_website: - name: "{{ item }}" - state: absent - with_items: - - "{{ existing_sites.stdout_lines }}" - -- name: add testing site {{ test_iis_site_name }} - win_iis_website: - name: "{{ test_iis_site_name }}" - physical_path: c:\inetpub\wwwroot - -- name: ensure all bindings are removed prior to starting testing - win_iis_webbinding: - name: "{{ test_iis_site_name }}" - state: absent - protocol: "{{ item.protocol }}" - port: "{{ item.port }}" - with_items: - - {protocol: http, port: 80} - - {protocol: https, port: 443} - -- name: copy certreq file - ansible.windows.win_copy: - content: |- - [NewRequest] - Subject = "CN={{ item.name }}" - KeyLength = 2048 - KeyAlgorithm = RSA - MachineKeySet = true - RequestType = Cert - dest: "{{ item.dest }}" - with_items: - - {name: test.com, dest: 'c:\windows\temp\certreq1.txt'} - - {name: test1.com, dest: 'c:\windows\temp\certreq2.txt'} - - {name: '*.test.com', dest: 'c:\windows\temp\certreqwc.txt'} - -- name: make sure response files are absent - ansible.windows.win_file: - path: "{{ item }}" - state: absent - with_items: - - 'c:\windows\temp\certreqresp1.txt' - - 'c:\windows\temp\certreqresp2.txt' - - 'c:\windows\temp\certreqrespwc.txt' - -- name: create self signed cert from certreq - ansible.windows.win_command: certreq -new -machine {{ item.req }} {{ item.resp }} - with_items: - - {req: 'c:\windows\temp\certreq1.txt', resp: 'c:\windows\temp\certreqresp1.txt'} - - {req: 'c:\windows\temp\certreq2.txt', resp: 'c:\windows\temp\certreqresp2.txt'} - - {req: 'c:\windows\temp\certreqwc.txt', resp: 'c:\windows\temp\certreqrespwc.txt'} - -- name: register certificate thumbprint1 - raw: '(gci Cert:\LocalMachine\my | ? {$_.subject -eq "CN=test.com"})[0].Thumbprint' - register: thumbprint1 - -- name: register certificate thumbprint2 - raw: '(gci Cert:\LocalMachine\my | ? {$_.subject -eq "CN=test1.com"})[0].Thumbprint' - register: thumbprint2 - -- name: register certificate thumbprint_wc - raw: '(gci Cert:\LocalMachine\my | ? {$_.subject -eq "CN=*.test.com"})[0].Thumbprint' - register: thumbprint_wc - -- debug: - var: thumbprint1.stdout - verbosity: 1 -- debug: - var: thumbprint2.stdout - verbosity: 1 -- debug: - var: thumbprint_wc.stdout - verbosity: 1