winrm 1.6.1 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aa96ea262bfb740bcf397684129464232f76321f
4
- data.tar.gz: ca5894916562e3d5243c2099f8a439b10922d140
3
+ metadata.gz: 334ae5a75dc6e3249c316caa13eb582aa1930239
4
+ data.tar.gz: a8b620912892adef39c78d3f89c73a0530078404
5
5
  SHA512:
6
- metadata.gz: 87d111e8d6597aeb11a24dcf2a33f569426c48bd91940c25e27f461c4ca2e4d2c939eaa518f1b479e35f163700559fa152a5346c0ffd71693f3021bedeb77dfa
7
- data.tar.gz: f349d8858850cb6f3017b67cab69fc8c843f5d188eecaec95903e7f7bedb098160babfe7fa83e58d2b77999dc23c8a0d6891617d6c4d069daf8a2c1d8c7a2fe4
6
+ metadata.gz: fc00c205dfee32d1b15fb3940dfc2355a1bac7910793df0f42ba260da3cf2f8c19c42769a0646c1ad18e65825add9d5d42fa6f780fdf5634697f3fd06854fdf8
7
+ data.tar.gz: b5fd3e292e0042efa567a385a38de49335692e57f4ff2cd5210a19d7a15aa2fdb2540f899c682d61f88aa25c75560e2ba3a86f4698e4e54b1ca572bdc7c99408
data/appveyor.yml CHANGED
@@ -12,16 +12,6 @@ environment:
12
12
  - ruby_version: "21"
13
13
  winrm_endpoint: http://localhost:5985/wsman
14
14
 
15
- - ruby_version: "21"
16
- winrm_auth_type: ssl
17
- winrm_endpoint: https://localhost:5986/wsman
18
- winrm_no_ssl_peer_verification: true
19
-
20
- - ruby_version: "21"
21
- winrm_auth_type: ssl
22
- winrm_endpoint: https://localhost:5986/wsman
23
- use_ssl_peer_fingerprint: true
24
-
25
15
  clone_folder: c:\projects\winrm
26
16
  clone_depth: 1
27
17
  branches:
@@ -35,6 +25,7 @@ install:
35
25
  - ps: winrm create winrm/config/Listener?Address=*+Transport=HTTPS "@{Hostname=`"localhost`";CertificateThumbprint=`"$($env:winrm_cert)`"}"
36
26
  - ps: winrm set winrm/config/client/auth '@{Basic="true"}'
37
27
  - ps: winrm set winrm/config/service/auth '@{Basic="true"}'
28
+ - ps: winrm set winrm/config/service/auth '@{CbtHardeningLevel="Strict"}'
38
29
  - ps: winrm set winrm/config/service '@{AllowUnencrypted="true"}'
39
30
  - ps: $env:PATH="C:\Ruby$env:ruby_version\bin;$env:PATH"
40
31
  - ps: Write-Host $env:PATH
data/changelog.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # WinRM Gem Changelog
2
2
 
3
+ # 1.7.0
4
+ - Bump rubyntlm gem to 0.6.0 to get channel binding support for HTTPS fixing connections to endoints with `CbtHardeningLevel` set to `Strict`
5
+ - Fix for parsing binary data in command output
6
+
3
7
  # 1.6.1
4
8
  - Use codepage 437 by default on os versions older than Windows 7 and Windows Server 2008 R2
5
9
 
@@ -145,6 +145,7 @@ module WinRM
145
145
  class HttpNegotiate < HttpTransport
146
146
  def initialize(endpoint, user, pass, opts)
147
147
  super(endpoint)
148
+ require 'rubyntlm'
148
149
  no_sspi_auth!
149
150
 
150
151
  user_parts = user.split('\\')
@@ -156,9 +157,12 @@ module WinRM
156
157
  @ntlmcli = Net::NTLM::Client.new(user, pass, opts)
157
158
  @retryable = true
158
159
  no_ssl_peer_verification! if opts[:no_ssl_peer_verification]
160
+ @ssl_peer_fingerprint = opts[:ssl_peer_fingerprint]
161
+ @httpcli.ssl_config.set_trust_ca(opts[:ca_trust_path]) if opts[:ca_trust_path]
159
162
  end
160
163
 
161
164
  def send_request(message, auth_header = nil)
165
+ ssl_peer_fingerprint_verification!
162
166
  auth_header = init_auth if @ntlmcli.session.nil?
163
167
 
164
168
  original_length = message.length
@@ -183,6 +187,7 @@ module WinRM
183
187
  ].join("\r\n")
184
188
 
185
189
  resp = @httpcli.post(@endpoint, body, hdr)
190
+ verify_ssl_fingerprint(resp.peer_cert)
186
191
  if resp.status == 401 && @retryable
187
192
  @retryable = false
188
193
  send_request(message, init_auth)
@@ -217,22 +222,23 @@ module WinRM
217
222
  }
218
223
  @logger.debug "Sending HTTP POST for Negotiate Authentication"
219
224
  r = @httpcli.post(@endpoint, "", hdr)
225
+ verify_ssl_fingerprint(r.peer_cert)
220
226
  itok = r.header["WWW-Authenticate"].pop.split.last
221
- auth3 = @ntlmcli.init_context itok
227
+ binding = r.peer_cert.nil? ? nil : Net::NTLM::ChannelBinding.create(r.peer_cert)
228
+ auth3 = @ntlmcli.init_context(itok, binding)
222
229
  { "Authorization" => "Negotiate #{auth3.encode64}" }
223
230
  end
224
231
  end
225
232
 
226
233
  # Uses SSL to secure the transport
227
- class HttpSSL < HttpTransport
228
- def initialize(endpoint, user, pass, ca_trust_path = nil, opts)
234
+ class BasicAuthSSL < HttpTransport
235
+ def initialize(endpoint, user, pass, opts)
229
236
  super(endpoint)
230
237
  @httpcli.set_auth(endpoint, user, pass)
231
- @httpcli.ssl_config.set_trust_ca(ca_trust_path) unless ca_trust_path.nil?
232
- no_sspi_auth! if opts[:disable_sspi]
233
- basic_auth_only! if opts[:basic_auth_only]
238
+ basic_auth_only!
234
239
  no_ssl_peer_verification! if opts[:no_ssl_peer_verification]
235
240
  @ssl_peer_fingerprint = opts[:ssl_peer_fingerprint]
241
+ @httpcli.ssl_config.set_trust_ca(opts[:ca_trust_path]) if opts[:ca_trust_path]
236
242
  end
237
243
  end
238
244
 
data/lib/winrm/version.rb CHANGED
@@ -3,5 +3,5 @@
3
3
  # WinRM module
4
4
  module WinRM
5
5
  # The version of the WinRM library
6
- VERSION = '1.6.1'
6
+ VERSION = '1.7.0'
7
7
  end
@@ -54,7 +54,6 @@ module WinRM
54
54
  end
55
55
 
56
56
  def init_negotiate_transport(opts)
57
- require 'rubyntlm'
58
57
  HTTP::HttpNegotiate.new(opts[:endpoint], opts[:user], opts[:pass], opts)
59
58
  end
60
59
 
@@ -69,7 +68,11 @@ module WinRM
69
68
  end
70
69
 
71
70
  def init_ssl_transport(opts)
72
- HTTP::HttpSSL.new(opts[:endpoint], opts[:user], opts[:pass], opts[:ca_trust_path], opts)
71
+ if opts[:basic_auth_only]
72
+ HTTP::BasicAuthSSL.new(opts[:endpoint], opts[:user], opts[:pass], opts)
73
+ else
74
+ HTTP::HttpNegotiate.new(opts[:endpoint], opts[:user], opts[:pass], opts)
75
+ end
73
76
  end
74
77
 
75
78
  # Operation timeout.
@@ -253,8 +256,19 @@ module WinRM
253
256
  REXML::XPath.match(resp_doc, "//#{NS_WIN_SHELL}:Stream").each do |n|
254
257
  next if n.text.nil? || n.text.empty?
255
258
 
256
- # decode and strip off BOM which win 2008R2 applies
257
- stream = { n.attributes['Name'].to_sym => Base64.decode64(n.text).force_encoding('utf-8').sub("\xEF\xBB\xBF", "") }
259
+ # decode and replace invalid unicode characters
260
+ decoded_text = Base64.decode64(n.text).force_encoding('utf-8')
261
+ if ! decoded_text.valid_encoding?
262
+ if decoded_text.respond_to?(:scrub!)
263
+ decoded_text.scrub!
264
+ else
265
+ decoded_text = decoded_text.encode('utf-16', invalid: :replace, undef: :replace)
266
+ .encode('utf-8')
267
+ end
268
+ end
269
+
270
+ # remove BOM which 2008R2 applies
271
+ stream = { n.attributes['Name'].to_sym => decoded_text.sub('\xEF\xBB\xBF', '') }
258
272
  output[:data] << stream
259
273
  yield stream[:stdout], stream[:stderr] if block_given?
260
274
  end
@@ -0,0 +1,67 @@
1
+ # encoding: UTF-8
2
+ require 'winrm/winrm_service'
3
+ require 'rexml/document'
4
+ require 'erb'
5
+ require 'base64'
6
+
7
+ describe 'issue 184', unit: true do
8
+ let(:shell_id) { 'shell-123' }
9
+ let(:command_id) { 123 }
10
+ let(:test_data_xml_template) do
11
+ ERB.new(File.read('spec/stubs/responses/get_command_output_response.xml.erb'))
12
+ end
13
+ let(:service) do
14
+ WinRM::WinRMWebService.new(
15
+ 'http://dummy/wsman',
16
+ :plaintext,
17
+ user: 'dummy',
18
+ pass: 'dummy')
19
+ end
20
+
21
+ describe 'response doc stdout with invalid UTF-8 characters' do
22
+ let(:test_data_stdout) { 'ffff' } # Base64-decodes to '}\xF7\xDF', an invalid sequence
23
+ let(:test_data_stderr) { '' }
24
+ let(:test_data_xml) { test_data_xml_template.result(binding) }
25
+
26
+ before do
27
+ allow(service).to receive(:send_get_output_message).and_return(
28
+ REXML::Document.new(test_data_xml)
29
+ )
30
+ end
31
+
32
+ it 'does not raise an ArgumentError: invalid byte sequence in UTF-8' do
33
+ begin
34
+ expect(
35
+ service.get_command_output(shell_id, command_id)
36
+ ).not_to raise_error
37
+ rescue RSpec::Expectations::ExpectationNotMetError => e
38
+ expect(e.message).not_to include 'ArgumentError'
39
+ end
40
+ end
41
+
42
+ it 'does not have an empty stdout' do
43
+ expect(
44
+ service.get_command_output(shell_id, command_id)[:data][0][:stdout]
45
+ ).not_to be_empty
46
+ end
47
+ end
48
+
49
+ describe 'response doc stdout with valid UTF-8' do
50
+ let(:test_data_raw) { '✓1234-äöü' }
51
+ let(:test_data_stdout) { Base64.encode64(test_data_raw) }
52
+ let(:test_data_stderr) { '' }
53
+ let(:test_data_xml) { test_data_xml_template.result(binding) }
54
+
55
+ before do
56
+ allow(service).to receive(:send_get_output_message).and_return(
57
+ REXML::Document.new(test_data_xml)
58
+ )
59
+ end
60
+
61
+ it 'decodes to match input data' do
62
+ expect(
63
+ service.get_command_output(shell_id, command_id)[:data][0][:stdout]
64
+ ).to eq(test_data_raw)
65
+ end
66
+ end
67
+ end
data/spec/spec_helper.rb CHANGED
@@ -33,7 +33,6 @@ module ConnectionHelper
33
33
  config[:options][:ssl_peer_fingerprint] = ENV['winrm_cert']
34
34
  end
35
35
  config[:endpoint] = ENV['winrm_endpoint'] if ENV['winrm_endpoint']
36
- config[:auth_type] = ENV['winrm_auth_type'] if ENV['winrm_auth_type']
37
36
  end
38
37
 
39
38
  def merge_config_option_from_environment(config, key)
@@ -0,0 +1,13 @@
1
+ <s:Envelope xmlns:a='http://schemas.xmlsoap.org/ws/2004/08/addressing' xml:lang='en-US' xmlns:p='http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd' xmlns:rsp='http://schemas.microsoft.com/wbem/wsman/1/windows/shell' xmlns:s='http://www.w3.org/2003/05/soap-envelope' xmlns:w='http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd'>
2
+ <s:Header>
3
+ </s:Header>
4
+ <s:Body>
5
+ <rsp:ReceiveResponse>
6
+ <rsp:Stream CommandId='<%= command_id %>' Name='stdout'><%= test_data_stdout %></rsp:Stream>
7
+ <rsp:Stream CommandId='<%= command_id %>' End='true' Name='stderr'><%= test_data_stderr %></rsp:Stream>
8
+ <rsp:CommandState CommandId='<%= command_id %>' State='http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandState/Done'>
9
+ <rsp:ExitCode>0</rsp:ExitCode>
10
+ </rsp:CommandState>
11
+ </rsp:ReceiveResponse>
12
+ </s:Body>
13
+ </s:Envelope>
@@ -42,3 +42,83 @@ describe WinRM::HTTP::HttpNegotiate, unit: true do
42
42
  end
43
43
  end
44
44
  end
45
+
46
+ describe 'WinRM connection', integration: true do
47
+ let(:winrm_connection) do
48
+ endpoint = config[:endpoint].dup
49
+ if auth_type == :ssl
50
+ endpoint.sub!('5985', '5986')
51
+ endpoint.sub!('http', 'https')
52
+ end
53
+ winrm = WinRM::WinRMWebService.new(
54
+ endpoint, auth_type, options)
55
+ winrm.logger.level = :error
56
+ winrm
57
+ end
58
+ let(:options) do
59
+ opts = {}
60
+ opts[:user] = config[:options][:user]
61
+ opts[:pass] = config[:options][:pass]
62
+ opts[:basic_auth_only] = basic_auth_only
63
+ opts[:no_ssl_peer_verification] = no_ssl_peer_verification
64
+ opts[:ssl_peer_fingerprint] = ssl_peer_fingerprint
65
+ opts
66
+ end
67
+ let(:basic_auth_only) { false }
68
+ let(:no_ssl_peer_verification) { false }
69
+ let(:ssl_peer_fingerprint) { nil }
70
+
71
+ subject(:output) do
72
+ executor = winrm_connection.create_executor
73
+ executor.run_cmd('ipconfig')
74
+ end
75
+
76
+ shared_examples 'a valid_connection' do
77
+ it 'has a 0 exit code' do
78
+ expect(subject).to have_exit_code 0
79
+ end
80
+
81
+ it 'includes command output' do
82
+ expect(subject).to have_stdout_match(/Windows IP Configuration/)
83
+ end
84
+
85
+ it 'has no errors' do
86
+ expect(subject).to have_no_stderr
87
+ end
88
+ end
89
+
90
+ context 'HttpPlaintext' do
91
+ let(:basic_auth_only) { true }
92
+ let(:auth_type) { :plaintext }
93
+
94
+ it_behaves_like 'a valid_connection'
95
+ end
96
+
97
+ context 'HttpNegotiate' do
98
+ let(:auth_type) { :negotiate }
99
+
100
+ it_behaves_like 'a valid_connection'
101
+ end
102
+
103
+ context 'BasicAuthSSL', skip: ENV['winrm_cert'].nil? do
104
+ let(:basic_auth_only) { true }
105
+ let(:auth_type) { :ssl }
106
+ let(:no_ssl_peer_verification) { true }
107
+
108
+ it_behaves_like 'a valid_connection'
109
+ end
110
+
111
+ context 'Negotiate over SSL', skip: ENV['winrm_cert'].nil? do
112
+ let(:auth_type) { :ssl }
113
+ let(:no_ssl_peer_verification) { true }
114
+
115
+ it_behaves_like 'a valid_connection'
116
+ end
117
+
118
+ context 'SSL fingerprint', skip: ENV['winrm_cert'].nil? do
119
+ let(:auth_type) { :ssl }
120
+ let(:ssl_peer_fingerprint) { ENV['winrm_cert'] }
121
+
122
+ it_behaves_like 'a valid_connection'
123
+ end
124
+ end
data/winrm.gemspec CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
28
28
  s.required_ruby_version = '>= 1.9.0'
29
29
  s.add_runtime_dependency 'gssapi', '~> 1.2'
30
30
  s.add_runtime_dependency 'httpclient', '~> 2.2', '>= 2.2.0.2'
31
- s.add_runtime_dependency 'rubyntlm', '~> 0.5.0', '>= 0.5.3'
31
+ s.add_runtime_dependency 'rubyntlm', '~> 0.6.0'
32
32
  s.add_runtime_dependency 'logging', ['>= 1.6.1', '< 3.0']
33
33
  s.add_runtime_dependency 'nori', '~> 2.0'
34
34
  s.add_runtime_dependency 'gyoku', '~> 1.0'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: winrm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Wanek
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-02-08 00:00:00.000000000 Z
12
+ date: 2016-02-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gssapi
@@ -51,20 +51,14 @@ dependencies:
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.5.0
55
- - - ">="
56
- - !ruby/object:Gem::Version
57
- version: 0.5.3
54
+ version: 0.6.0
58
55
  type: :runtime
59
56
  prerelease: false
60
57
  version_requirements: !ruby/object:Gem::Requirement
61
58
  requirements:
62
59
  - - "~>"
63
60
  - !ruby/object:Gem::Version
64
- version: 0.5.0
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- version: 0.5.3
61
+ version: 0.6.0
68
62
  - !ruby/object:Gem::Dependency
69
63
  name: logging
70
64
  requirement: !ruby/object:Gem::Requirement
@@ -224,12 +218,14 @@ files:
224
218
  - spec/command_executor_spec.rb
225
219
  - spec/config-example.yml
226
220
  - spec/exception_spec.rb
221
+ - spec/issue_184_spec.rb
227
222
  - spec/issue_59_spec.rb
228
223
  - spec/matchers.rb
229
224
  - spec/output_spec.rb
230
225
  - spec/powershell_spec.rb
231
226
  - spec/response_handler_spec.rb
232
227
  - spec/spec_helper.rb
228
+ - spec/stubs/responses/get_command_output_response.xml.erb
233
229
  - spec/stubs/responses/open_shell_v1.xml
234
230
  - spec/stubs/responses/open_shell_v2.xml
235
231
  - spec/stubs/responses/soap_fault_v1.xml