winrm 1.7.3 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +10 -10
  3. data/.rspec +3 -3
  4. data/.travis.yml +12 -12
  5. data/Gemfile +9 -9
  6. data/LICENSE +202 -202
  7. data/README.md +213 -194
  8. data/Rakefile +36 -36
  9. data/Vagrantfile +9 -9
  10. data/WinrmAppveyor.psm1 +32 -0
  11. data/appveyor.yml +51 -42
  12. data/bin/rwinrm +97 -97
  13. data/changelog.md +3 -0
  14. data/lib/winrm.rb +42 -42
  15. data/lib/winrm/command_executor.rb +6 -2
  16. data/lib/winrm/command_output_decoder.rb +53 -53
  17. data/lib/winrm/exceptions/exceptions.rb +57 -57
  18. data/lib/winrm/helpers/iso8601_duration.rb +58 -58
  19. data/lib/winrm/helpers/powershell_script.rb +42 -42
  20. data/lib/winrm/http/response_handler.rb +82 -82
  21. data/lib/winrm/http/transport.rb +17 -0
  22. data/lib/winrm/output.rb +43 -43
  23. data/lib/winrm/soap_provider.rb +39 -39
  24. data/lib/winrm/version.rb +1 -1
  25. data/lib/winrm/winrm_service.rb +550 -547
  26. data/preamble +17 -17
  27. data/spec/auth_timeout_spec.rb +16 -16
  28. data/spec/cmd_spec.rb +102 -102
  29. data/spec/command_executor_spec.rb +27 -10
  30. data/spec/command_output_decoder_spec.rb +37 -37
  31. data/spec/config-example.yml +19 -19
  32. data/spec/exception_spec.rb +50 -50
  33. data/spec/issue_184_spec.rb +67 -67
  34. data/spec/issue_59_spec.rb +23 -23
  35. data/spec/matchers.rb +74 -74
  36. data/spec/output_spec.rb +110 -110
  37. data/spec/powershell_spec.rb +97 -97
  38. data/spec/response_handler_spec.rb +59 -59
  39. data/spec/spec_helper.rb +73 -73
  40. data/spec/stubs/responses/get_command_output_response.xml.erb +13 -13
  41. data/spec/stubs/responses/open_shell_v1.xml +19 -19
  42. data/spec/stubs/responses/open_shell_v2.xml +20 -20
  43. data/spec/stubs/responses/soap_fault_v1.xml +36 -36
  44. data/spec/stubs/responses/soap_fault_v2.xml +42 -42
  45. data/spec/stubs/responses/wmi_error_v2.xml +41 -41
  46. data/spec/transport_spec.rb +139 -124
  47. data/spec/winrm_options_spec.rb +76 -76
  48. data/spec/winrm_primitives_spec.rb +51 -51
  49. data/spec/wql_spec.rb +14 -14
  50. data/winrm.gemspec +40 -40
  51. metadata +4 -3
@@ -1,9 +1,9 @@
1
- # encoding: UTF-8
2
- # -*- mode: ruby -*-
3
- # vi: set ft=ruby :
4
-
5
- VAGRANTFILE_API_VERSION = '2'
6
-
7
- Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
8
- config.vm.box = 'mwrock/Windows2012R2'
9
- end
1
+ # encoding: UTF-8
2
+ # -*- mode: ruby -*-
3
+ # vi: set ft=ruby :
4
+
5
+ VAGRANTFILE_API_VERSION = '2'
6
+
7
+ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
8
+ config.vm.box = 'mwrock/Windows2012R2'
9
+ end
@@ -0,0 +1,32 @@
1
+ function New-ClientCertificate {
2
+ param([String]$username, [String]$basePath = ((Resolve-Parh .).Path))
3
+
4
+ $env:OPENSSL_CONF=[System.IO.Path]::GetTempFileName()
5
+
6
+ Set-Content -Path $env:OPENSSL_CONF -Value @"
7
+ distinguished_name = req_distinguished_name
8
+ [req_distinguished_name]
9
+ [v3_req_client]
10
+ extendedKeyUsage = clientAuth
11
+ subjectAltName = otherName:1.3.6.1.4.1.311.20.2.3;UTF8:$username@localhost
12
+ "@
13
+
14
+ $user_path = Join-Path $basePath user.pem
15
+ $key_path = Join-Path $basePath key.pem
16
+ $pfx_path = Join-Path $basePath user.pfx
17
+
18
+ openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -out $user_path -outform PEM -keyout $key_path -subj "/CN=$username" -extensions v3_req_client 2>&1
19
+
20
+ openssl pkcs12 -export -in $user_path -inkey $key_path -out $pfx_path -passout pass: 2>&1
21
+
22
+ del $env:OPENSSL_CONF
23
+ }
24
+
25
+ function New-WinrmUserCertificateMapping {
26
+ param([String]$issuer)
27
+ $secure_pass = ConvertTo-SecureString $env:winrm_pass -AsPlainText -Force
28
+ $cred = New-Object System.Management.Automation.PSCredential ($env:winrm_user, $secure_pass)
29
+ New-Item -Path WSMan:\localhost\ClientCertificate -Subject "$env:winrm_user@localhost" -URI * -Issuer $issuer -Credential $cred -Force
30
+ }
31
+
32
+ Export-ModuleMember New-ClientCertificate, New-WinrmUserCertificateMapping
@@ -1,42 +1,51 @@
1
- version: "master-{build}"
2
-
3
- os: Windows Server 2012 R2
4
- platform:
5
- - x64
6
-
7
- environment:
8
- winrm_user: test_user
9
- winrm_pass: Pass@word1
10
-
11
- matrix:
12
- - ruby_version: "21"
13
- winrm_endpoint: http://localhost:5985/wsman
14
-
15
- clone_folder: c:\projects\winrm
16
- clone_depth: 1
17
- branches:
18
- only:
19
- - master
20
-
21
- install:
22
- - ps: net user /add $env:winrm_user $env:winrm_pass
23
- - ps: net localgroup administrators $env:winrm_user /add
24
- - ps: $env:winrm_cert = (New-SelfSignedCertificate -DnsName localhost -CertStoreLocation cert:\localmachine\my).Thumbprint
25
- - ps: winrm create winrm/config/Listener?Address=*+Transport=HTTPS "@{Hostname=`"localhost`";CertificateThumbprint=`"$($env:winrm_cert)`"}"
26
- - ps: winrm set winrm/config/client/auth '@{Basic="true"}'
27
- - ps: winrm set winrm/config/service/auth '@{Basic="true"}'
28
- - ps: winrm set winrm/config/service/auth '@{CbtHardeningLevel="Strict"}'
29
- - ps: winrm set winrm/config/service '@{AllowUnencrypted="true"}'
30
- - ps: $env:PATH="C:\Ruby$env:ruby_version\bin;$env:PATH"
31
- - ps: Write-Host $env:PATH
32
- - ps: ruby --version
33
- - ps: gem --version
34
- - ps: gem install bundler --quiet --no-ri --no-rdoc
35
- - ps: bundler --version
36
-
37
- build_script:
38
- - bundle install || bundle install || bundle install
39
-
40
- test_script:
41
- - SET SPEC_OPTS=--format progress
42
- - bundle exec rake integration
1
+ version: "master-{build}"
2
+
3
+ os: Windows Server 2012 R2
4
+ platform:
5
+ - x64
6
+
7
+ environment:
8
+ winrm_user: test_user
9
+ winrm_pass: Pass@word1
10
+ user_cert: c:\projects\winrm\user.pem
11
+ user_key: c:\projects\winrm\key.pem
12
+
13
+ matrix:
14
+ - ruby_version: "21"
15
+ winrm_endpoint: http://localhost:5985/wsman
16
+
17
+ clone_folder: c:\projects\winrm
18
+ clone_depth: 1
19
+ branches:
20
+ only:
21
+ - master
22
+
23
+ install:
24
+ - ps: net user /add $env:winrm_user $env:winrm_pass
25
+ - ps: net localgroup administrators $env:winrm_user /add
26
+ - ps: $env:PATH="C:\OpenSSL-Win64\bin;$env:PATH"
27
+ - ps: Import-Module c:\projects\winrm\WinrmAppveyor.psm1
28
+ - ps: New-ClientCertificate $env:winrm_user c:\projects\winrm
29
+ - ps: $env:user_cert_thumb = (Import-pfxCertificate -FilePath c:\projects\winrm\user.pfx -CertStoreLocation Cert:\LocalMachine\root).Thumbprint
30
+ - ps: Import-pfxCertificate -FilePath c:\projects\winrm\user.pfx -CertStoreLocation Cert:\LocalMachine\TrustedPeople
31
+ - ps: $env:winrm_cert = (New-SelfSignedCertificate -DnsName localhost -CertStoreLocation cert:\localmachine\my).Thumbprint
32
+ - ps: winrm create winrm/config/Listener?Address=*+Transport=HTTPS "@{Hostname=`"localhost`";CertificateThumbprint=`"$($env:winrm_cert)`"}"
33
+ - ps: winrm set winrm/config/client/auth '@{Basic="true"}'
34
+ - ps: winrm set winrm/config/service/auth '@{Basic="true"}'
35
+ - ps: winrm set winrm/config/service/auth '@{Certificate="true"}'
36
+ - ps: winrm set winrm/config/service/auth '@{CbtHardeningLevel="Strict"}'
37
+ - ps: winrm set winrm/config/service '@{AllowUnencrypted="true"}'
38
+ - ps: New-WinrmUserCertificateMapping $env:user_cert_thumb
39
+ - ps: $env:PATH="C:\Ruby$env:ruby_version\bin;$env:PATH"
40
+ - ps: Write-Host $env:PATH
41
+ - ps: ruby --version
42
+ - ps: gem --version
43
+ - ps: gem install bundler --quiet --no-ri --no-rdoc
44
+ - ps: bundler --version
45
+
46
+ build_script:
47
+ - bundle install || bundle install || bundle install
48
+
49
+ test_script:
50
+ - SET SPEC_OPTS=--format progress
51
+ - bundle exec rake integration
data/bin/rwinrm CHANGED
@@ -1,97 +1,97 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- # Copyright 2014 Shawn Neal <sneal@sneal.net>
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
-
18
- # rubocop:disable all
19
-
20
- $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
21
-
22
- require 'readline'
23
- require 'io/console'
24
- require 'winrm'
25
-
26
- def help_msg
27
- puts 'Usage: rwinrm user@host'
28
- puts ''
29
- end
30
-
31
- def parse_options
32
- options = {}
33
- fail 'Missing required options' unless ARGV.length == 1
34
-
35
- m = /^(?<user>[a-z0-9\.\!\$ _-]+)@{1}(?<host>[a-z0-9\.\-]+)(?<port>:[0-9]+)?/i.match(ARGV[0])
36
- fail "#{ARGV[0]} is an invalid host" unless m
37
- options[:user] = m[:user]
38
- options[:endpoint] = "http://#{m[:host]}#{m[:port] || ':5985'}/wsman"
39
-
40
- # Get the password
41
- print 'Password: '
42
- options[:pass] = STDIN.noecho(&:gets).chomp
43
- puts
44
-
45
- # Set some defaults required by WinRM WS
46
- options[:auth_type] = :plaintext
47
- options[:basic_auth_only] = true
48
-
49
- options
50
- rescue StandardError => e
51
- puts e.message
52
- help_msg
53
- exit 1
54
- end
55
-
56
- def repl(options)
57
- client = WinRM::WinRMWebService.new(
58
- options[:endpoint],
59
- options[:auth_type].to_sym,
60
- options)
61
-
62
- client.set_timeout(3600)
63
- shell_id = client.open_shell
64
- command_id = client.run_command(shell_id, 'cmd', "/K prompt [#{ARGV[0]}]$P$G")
65
-
66
- read_thread = Thread.new do
67
- client.get_command_output(shell_id, command_id) do |stdout, stderr|
68
- STDOUT.write stdout
69
- STDERR.write stderr
70
- end
71
- end
72
- read_thread.abort_on_exception = true
73
-
74
- while (buf = Readline.readline('', true))
75
- if buf =~ /^exit/
76
- read_thread.exit
77
- client.cleanup_command(shell_id, command_id)
78
- client.close_shell(shell_id)
79
- exit 0
80
- else
81
- client.write_stdin(shell_id, command_id, "#{buf}\r\n")
82
- end
83
- end
84
- rescue Interrupt
85
- puts 'exiting'
86
- # ctrl-c
87
- rescue WinRM::WinRMAuthorizationError
88
- puts 'Authentication failed, bad user name or password'
89
- exit 1
90
- rescue StandardError => e
91
- puts e.message
92
- exit 1
93
- end
94
-
95
- repl(parse_options)
96
-
97
- # rubocop:enable all
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ # Copyright 2014 Shawn Neal <sneal@sneal.net>
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ # rubocop:disable all
19
+
20
+ $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
21
+
22
+ require 'readline'
23
+ require 'io/console'
24
+ require 'winrm'
25
+
26
+ def help_msg
27
+ puts 'Usage: rwinrm user@host'
28
+ puts ''
29
+ end
30
+
31
+ def parse_options
32
+ options = {}
33
+ fail 'Missing required options' unless ARGV.length == 1
34
+
35
+ m = /^(?<user>[a-z0-9\.\!\$ _-]+)@{1}(?<host>[a-z0-9\.\-]+)(?<port>:[0-9]+)?/i.match(ARGV[0])
36
+ fail "#{ARGV[0]} is an invalid host" unless m
37
+ options[:user] = m[:user]
38
+ options[:endpoint] = "http://#{m[:host]}#{m[:port] || ':5985'}/wsman"
39
+
40
+ # Get the password
41
+ print 'Password: '
42
+ options[:pass] = STDIN.noecho(&:gets).chomp
43
+ puts
44
+
45
+ # Set some defaults required by WinRM WS
46
+ options[:auth_type] = :plaintext
47
+ options[:basic_auth_only] = true
48
+
49
+ options
50
+ rescue StandardError => e
51
+ puts e.message
52
+ help_msg
53
+ exit 1
54
+ end
55
+
56
+ def repl(options)
57
+ client = WinRM::WinRMWebService.new(
58
+ options[:endpoint],
59
+ options[:auth_type].to_sym,
60
+ options)
61
+
62
+ client.set_timeout(3600)
63
+ shell_id = client.open_shell
64
+ command_id = client.run_command(shell_id, 'cmd', "/K prompt [#{ARGV[0]}]$P$G")
65
+
66
+ read_thread = Thread.new do
67
+ client.get_command_output(shell_id, command_id) do |stdout, stderr|
68
+ STDOUT.write stdout
69
+ STDERR.write stderr
70
+ end
71
+ end
72
+ read_thread.abort_on_exception = true
73
+
74
+ while (buf = Readline.readline('', true))
75
+ if buf =~ /^exit/
76
+ read_thread.exit
77
+ client.cleanup_command(shell_id, command_id)
78
+ client.close_shell(shell_id)
79
+ exit 0
80
+ else
81
+ client.write_stdin(shell_id, command_id, "#{buf}\r\n")
82
+ end
83
+ end
84
+ rescue Interrupt
85
+ puts 'exiting'
86
+ # ctrl-c
87
+ rescue WinRM::WinRMAuthorizationError
88
+ puts 'Authentication failed, bad user name or password'
89
+ exit 1
90
+ rescue StandardError => e
91
+ puts e.message
92
+ exit 1
93
+ end
94
+
95
+ repl(parse_options)
96
+
97
+ # rubocop:enable all
@@ -1,5 +1,8 @@
1
1
  # WinRM Gem Changelog
2
2
 
3
+ # 1.8.0
4
+ - Add certificate authentication
5
+
3
6
  # 1.7.3
4
7
  - Open a new shell if the current shell has been deleted
5
8
 
@@ -1,42 +1,42 @@
1
- # encoding: UTF-8
2
- #
3
- # Copyright 2010 Dan Wanek <dan.wanek@gmail.com>
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
-
17
- require 'date'
18
- require 'logging'
19
- require_relative 'winrm/version'
20
-
21
- # Main WinRM module entry point
22
- module WinRM
23
- # Enable logging if it is requested. We do this before
24
- # anything else so that we can setup the output before
25
- # any logging occurs.
26
- if ENV['WINRM_LOG'] && ENV['WINRM_LOG'] != ''
27
- begin
28
- Logging.logger.root.level = ENV['WINRM_LOG']
29
- Logging.logger.root.appenders = Logging.appenders.stderr
30
- rescue ArgumentError
31
- # This means that the logging level wasn't valid
32
- $stderr.puts "Invalid WINRM_LOG level is set: #{ENV['WINRM_LOG']}"
33
- $stderr.puts ''
34
- $stderr.puts 'Please use one of the standard log levels: ' \
35
- 'debug, info, warn, or error'
36
- end
37
- end
38
- end
39
-
40
- require 'winrm/output'
41
- require 'winrm/helpers/iso8601_duration'
42
- require 'winrm/soap_provider'
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright 2010 Dan Wanek <dan.wanek@gmail.com>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'date'
18
+ require 'logging'
19
+ require_relative 'winrm/version'
20
+
21
+ # Main WinRM module entry point
22
+ module WinRM
23
+ # Enable logging if it is requested. We do this before
24
+ # anything else so that we can setup the output before
25
+ # any logging occurs.
26
+ if ENV['WINRM_LOG'] && ENV['WINRM_LOG'] != ''
27
+ begin
28
+ Logging.logger.root.level = ENV['WINRM_LOG']
29
+ Logging.logger.root.appenders = Logging.appenders.stderr
30
+ rescue ArgumentError
31
+ # This means that the logging level wasn't valid
32
+ $stderr.puts "Invalid WINRM_LOG level is set: #{ENV['WINRM_LOG']}"
33
+ $stderr.puts ''
34
+ $stderr.puts 'Please use one of the standard log levels: ' \
35
+ 'debug, info, warn, or error'
36
+ end
37
+ end
38
+ end
39
+
40
+ require 'winrm/output'
41
+ require 'winrm/helpers/iso8601_duration'
42
+ require 'winrm/soap_provider'
@@ -102,8 +102,12 @@ module WinRM
102
102
  # has been closed. One might see this on a target windows machine that has just
103
103
  # been provisioned and restarted the winrm service at the end of its provisioning
104
104
  # routine. If this hapens, we should give the command one more try.
105
- if e.fault_code == '2150858843' && (tries -= 1) > 0
106
- service.logger.debug('[WinRM] opening new shell since the current one was deleted')
105
+
106
+ # Fault code 2147943418 may be raised if the shell is installing an msi and for
107
+ # some reason it tries to read a registry key that has been deleted. This sometimes
108
+ # happens for 2008r2 when installing the Chef omnibus msi.
109
+ if %w(2150858843 2147943418).include?(e.fault_code) && (tries -= 1) > 0
110
+ service.logger.debug('[WinRM] opening new shell since the current one failed')
107
111
  @shell = nil
108
112
  open
109
113
  retry