winrm 1.7.3 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
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