- set_fact :
become_test_username : ansible_become_test
become_test_admin_username : ansible_become_admin
gen_pw : password123! + {{ lookup('password', '/dev/null chars=ascii_letters,digits length=8') }}
- name : create unprivileged user
win_user :
name : "{{ become_test_username }}"
password : "{{ gen_pw }}"
update_password : always
groups : Users
register : user_limited_result
- name : create a privileged user
win_user :
name : "{{ become_test_admin_username }}"
password : "{{ gen_pw }}"
update_password : always
groups : Administrators
register : user_admin_result
- name : add requisite logon rights for test user
win_user_right :
name : '{{item}}'
users : '{{become_test_username}}'
action : add
with_items :
- SeNetworkLogonRight
- SeInteractiveLogonRight
- SeBatchLogonRight
- name : execute tests and ensure that test user is deleted regardless of success/failure
block :
- name : ensure current user is not the become user
win_whoami :
register : whoami_out
failed_when : whoami_out.account.sid == user_limited_result.sid or whoami_out.account.sid == user_admin_result.sid
- name : get become user profile dir so we can clean it up later
vars : &become_vars
ansible_become_user : "{{ become_test_username }}"
ansible_become_password : "{{ gen_pw }}"
ansible_become_method : runas
ansible_become : yes
win_shell : $env:USERPROFILE
register : profile_dir_out
- name : ensure profile dir contains test username (eg, if become fails silently, prevent deletion of real user profile)
assert :
that :
- become_test_username in profile_dir_out.stdout_lines[0]
- name : get become admin user profile dir so we can clean it up later
vars : &admin_become_vars
ansible_become_user : "{{ become_test_admin_username }}"
ansible_become_password : "{{ gen_pw }}"
ansible_become_method : runas
ansible_become : yes
win_shell : $env:USERPROFILE
register : admin_profile_dir_out
- name : ensure profile dir contains admin test username
assert :
that :
- become_test_admin_username in admin_profile_dir_out.stdout_lines[0]
- name : test become runas via task vars (underprivileged user)
vars : *become_vars
win_whoami :
register : whoami_out
- name : verify output
assert :
that :
- whoami_out.account.sid == user_limited_result.sid
- whoami_out.account.account_name == become_test_username
- whoami_out.label.account_name == 'Medium Mandatory Level'
- whoami_out.label.sid == 'S-1-16-8192'
- whoami_out.logon_type == 'Interactive'
- name : test become runas via task vars (privileged user)
vars : *admin_become_vars
win_whoami :
register : whoami_out
- name : verify output
assert :
that :
- whoami_out.account.sid == user_admin_result.sid
- whoami_out.account.account_name == become_test_admin_username
- whoami_out.label.account_name == 'High Mandatory Level'
- whoami_out.label.sid == 'S-1-16-12288'
- whoami_out.logon_type == 'Interactive'
- name : test become runas via task keywords
vars :
ansible_become_password : "{{ gen_pw }}"
become : yes
become_method : runas
become_user : "{{ become_test_username }}"
win_shell : whoami
register : whoami_out
- name : verify output
assert :
that :
- whoami_out.stdout_lines[0].endswith(become_test_username)
- name : test become via block vars
vars : *become_vars
block :
- name : ask who the current user is
win_whoami :
register : whoami_out
- name : verify output
assert :
that :
- whoami_out.account.sid == user_limited_result.sid
- whoami_out.account.account_name == become_test_username
- whoami_out.label.account_name == 'Medium Mandatory Level'
- whoami_out.label.sid == 'S-1-16-8192'
- whoami_out.logon_type == 'Interactive'
- name : test with module that will return non-zero exit code (https://github.com/ansible/ansible/issues/30468)
vars : *become_vars
setup :
- name : test become with invalid password
win_whoami :
vars :
ansible_become_pass : '{{ gen_pw }}abc'
become : yes
become_method : runas
become_user : '{{ become_test_username }}'
register : become_invalid_pass
failed_when :
- '"Failed to become user " + become_test_username not in become_invalid_pass.msg'
- '"LogonUser failed" not in become_invalid_pass.msg'
- '"Win32ErrorCode 1326)" not in become_invalid_pass.msg'
- name : test become with SYSTEM account
win_whoami :
become : yes
become_method : runas
become_user : SYSTEM
register : whoami_out
- name : verify output
assert :
that :
- whoami_out.account.sid == "S-1-5-18"
- whoami_out.account.account_name == "SYSTEM"
- whoami_out.account.domain_name == "NT AUTHORITY"
- whoami_out.label.account_name == 'System Mandatory Level'
- whoami_out.label.sid == 'S-1-16-16384'
- whoami_out.logon_type == 'System'
- name : test become with NetworkService account
win_whoami :
become : yes
become_method : runas
become_user : NetworkService
register : whoami_out
- name : verify output
assert :
that :
- whoami_out.account.sid == "S-1-5-20"
- whoami_out.account.account_name == "NETWORK SERVICE"
- whoami_out.account.domain_name == "NT AUTHORITY"
- whoami_out.label.account_name == 'System Mandatory Level'
- whoami_out.label.sid == 'S-1-16-16384'
- whoami_out.logon_type == 'Service'
- name : test become with LocalService account
win_whoami :
become : yes
become_method : runas
become_user : LocalService
register : whoami_out
- name : verify output
assert :
that :
- whoami_out.account.sid == "S-1-5-19"
- whoami_out.account.account_name == "LOCAL SERVICE"
- whoami_out.account.domain_name == "NT AUTHORITY"
- whoami_out.label.account_name == 'System Mandatory Level'
- whoami_out.label.sid == 'S-1-16-16384'
- whoami_out.logon_type == 'Service'
- name : test become + async
vars : *become_vars
win_command : whoami
async : 10
register : whoami_out
- name : verify become + async worked
assert :
that :
- whoami_out is successful
- name : test failure with string become invalid key
vars : *become_vars
win_whoami :
become_flags : logon_type=batch invalid_flags=a
become_method : runas
register : failed_flags_invalid_key
failed_when : "failed_flags_invalid_key.msg != \"internal error: failed to parse become_flags 'logon_type=batch invalid_flags=a': become_flags key 'invalid_flags' is not a valid runas flag, must be 'logon_type' or 'logon_flags'\""
- name : test failure with invalid logon_type
vars : *become_vars
win_whoami :
become_flags : logon_type=invalid
register : failed_flags_invalid_type
failed_when : "failed_flags_invalid_type.msg != \"internal error: failed to parse become_flags 'logon_type=invalid': become_flags logon_type value 'invalid' is not valid, valid values are: interactive, network, batch, service, unlock, network_cleartext, new_credentials\""
- name : test failure with invalid logon_flag
vars : *become_vars
win_whoami :
become_flags : logon_flags=with_profile,invalid
register : failed_flags_invalid_flag
failed_when : "failed_flags_invalid_flag.msg != \"internal error: failed to parse become_flags 'logon_flags=with_profile,invalid': become_flags logon_flags value 'invalid' is not valid, valid values are: with_profile, netcredentials_only\""
# Server 2008 doesn't work with network and network_cleartext, there isn't really a reason why you would want this anyway
- name : check if we are running on a dinosaur, neanderthal or an OS of the modern age
win_shell : |
$version = [System.Environment]::OSVersion.Version
if ($version -lt [Version]"6.1") {
"dinosaur"
} elseif ($version -lt [Version]"6.2") {
"neanderthal"
} else {
"False"
}
register : os_version
- name : become different types
vars : *become_vars
win_whoami :
become_flags : logon_type={{item.type}}
register : become_logon_type
when : not ((item.type == 'network' or item.type == 'network_cleartext') and os_version.stdout_lines[0] == "dinosaur")
failed_when : become_logon_type.logon_type != item.actual and become_logon_type.sid != user_limited_result.sid
with_items :
- type : interactive
actual : Interactive
- type : batch
actual : Batch
- type : network
actual : Network
- type : network_cleartext
actual : NetworkCleartext
- name : become netcredentials with network user
vars :
ansible_become_user : fakeuser
ansible_become_password : fakepassword
ansible_become_method : runas
ansible_become : True
ansible_become_flags : logon_type=new_credentials logon_flags=netcredentials_only
win_whoami :
register : become_netcredentials
- name : assert become netcredentials with network user
assert :
that :
# new_credentials still come up as the ansible_user so we can't test that
- become_netcredentials.label.account_name == 'High Mandatory Level'
- become_netcredentials.label.sid == 'S-1-16-12288'
- name : become logon_flags bitwise tests when loading the profile
# Error code of 2 means no file found == no profile loaded
win_shell : |
Add-Type -Name "Native" -Namespace "Ansible" -MemberDefinition '[DllImport("Userenv.dll", SetLastError=true)]public static extern bool GetProfileType(out UInt32 pdwFlags);'
$profile_type = $null
$res = [Ansible.Native]::GetProfileType([ref]$profile_type)
if (-not $res) {
$last_err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
if ($last_err -eq 2) {
return $false
} else {
throw [System.ComponentModel.Win32Exception]$last_err
}
} else {
return $true
}
vars : *admin_become_vars
become_flags : logon_flags={{item.flags}}
register : become_logon_flags
failed_when : become_logon_flags.stdout_lines[0]|bool != item.actual
when : os_version.stdout_lines[0] not in ["dinosaur", "neanderthal"] # usual suspect 2008 doesn't support the no profile flags
with_items :
- flags :
actual : False
- flags : netcredentials_only
actual : False
- flags : with_profile,netcredentials_only
actual : True
- name : echo some non ascii characters
win_command : cmd.exe /c echo über den Fußgängerübergang gehen
vars : *become_vars
register : nonascii_output
- name : assert echo some non ascii characters
assert :
that :
- nonascii_output is changed
- nonascii_output.rc == 0
- nonascii_output.stdout_lines|count == 1
- nonascii_output.stdout_lines[0] == 'über den Fußgängerübergang gehen'
- nonascii_output.stderr == ''
# FUTURE: test raw + script become behavior once they're running under the exec wrapper again
# FUTURE: add standalone playbook tests to include password prompting and play become keywords
always :
- name : remove explicit logon rights for test user
win_user_right :
name : '{{item}}'
users : '{{become_test_username}}'
action : remove
with_items :
- SeNetworkLogonRight
- SeInteractiveLogonRight
- SeBatchLogonRight
- name : ensure underprivileged test user is deleted
win_user :
name : "{{ become_test_username }}"
state : absent
- name : ensure privileged test user is deleted
win_user :
name : "{{ become_test_admin_username }}"
state : absent
- name : ensure underprivileged test user profile is deleted
# NB: have to work around powershell limitation of long filenames until win_file fixes it
win_shell : rmdir /S /Q {{ profile_dir_out.stdout_lines[0] }}
args :
executable : cmd.exe
when : become_test_username in profile_dir_out.stdout_lines[0]
- name : ensure privileged test user profile is deleted
# NB: have to work around powershell limitation of long filenames until win_file fixes it
win_shell : rmdir /S /Q {{ admin_profile_dir_out.stdout_lines[0] }}
args :
executable : cmd.exe
when : become_test_admin_username in admin_profile_dir_out.stdout_lines[0]