vmc 0.0.8 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/LICENSE +8 -3
  2. data/README.md +83 -0
  3. data/Rakefile +11 -65
  4. data/bin/vmc +3 -2
  5. data/lib/cli/commands/admin.rb +57 -0
  6. data/lib/cli/commands/apps.rb +828 -0
  7. data/lib/cli/commands/base.rb +56 -0
  8. data/lib/cli/commands/misc.rb +99 -0
  9. data/lib/cli/commands/services.rb +84 -0
  10. data/lib/cli/commands/user.rb +60 -0
  11. data/lib/cli/config.rb +109 -0
  12. data/lib/cli/core_ext.rb +119 -0
  13. data/lib/cli/errors.rb +19 -0
  14. data/lib/cli/frameworks.rb +97 -0
  15. data/lib/cli/runner.rb +437 -0
  16. data/lib/cli/services_helper.rb +74 -0
  17. data/lib/cli/usage.rb +94 -0
  18. data/lib/cli/version.rb +5 -0
  19. data/lib/cli/zip_util.rb +61 -0
  20. data/lib/cli.rb +30 -0
  21. data/lib/vmc/client.rb +415 -0
  22. data/lib/vmc/const.rb +19 -0
  23. data/lib/vmc.rb +2 -1589
  24. data/spec/assets/app_info.txt +9 -0
  25. data/spec/assets/app_listings.txt +9 -0
  26. data/spec/assets/bad_create_app.txt +9 -0
  27. data/spec/assets/delete_app.txt +9 -0
  28. data/spec/assets/global_service_listings.txt +9 -0
  29. data/spec/assets/good_create_app.txt +9 -0
  30. data/spec/assets/good_create_service.txt +9 -0
  31. data/spec/assets/info_authenticated.txt +27 -0
  32. data/spec/assets/info_return.txt +15 -0
  33. data/spec/assets/info_return_bad.txt +16 -0
  34. data/spec/assets/login_fail.txt +9 -0
  35. data/spec/assets/login_success.txt +9 -0
  36. data/spec/assets/sample_token.txt +1 -0
  37. data/spec/assets/service_already_exists.txt +9 -0
  38. data/spec/assets/service_listings.txt +9 -0
  39. data/spec/assets/service_not_found.txt +9 -0
  40. data/spec/assets/user_info.txt +9 -0
  41. data/spec/spec_helper.rb +11 -0
  42. data/spec/unit/cli_opts_spec.rb +73 -0
  43. data/spec/unit/client_spec.rb +284 -0
  44. metadata +114 -71
  45. data/README +0 -58
  46. data/lib/parse.rb +0 -719
  47. data/lib/vmc_base.rb +0 -205
  48. data/vendor/gems/httpclient/VERSION +0 -1
  49. data/vendor/gems/httpclient/lib/http-access2/cookie.rb +0 -1
  50. data/vendor/gems/httpclient/lib/http-access2/http.rb +0 -1
  51. data/vendor/gems/httpclient/lib/http-access2.rb +0 -53
  52. data/vendor/gems/httpclient/lib/httpclient/auth.rb +0 -522
  53. data/vendor/gems/httpclient/lib/httpclient/cacert.p7s +0 -1579
  54. data/vendor/gems/httpclient/lib/httpclient/cacert_sha1.p7s +0 -1579
  55. data/vendor/gems/httpclient/lib/httpclient/connection.rb +0 -84
  56. data/vendor/gems/httpclient/lib/httpclient/cookie.rb +0 -562
  57. data/vendor/gems/httpclient/lib/httpclient/http.rb +0 -867
  58. data/vendor/gems/httpclient/lib/httpclient/session.rb +0 -864
  59. data/vendor/gems/httpclient/lib/httpclient/ssl_config.rb +0 -417
  60. data/vendor/gems/httpclient/lib/httpclient/timeout.rb +0 -136
  61. data/vendor/gems/httpclient/lib/httpclient/util.rb +0 -86
  62. data/vendor/gems/httpclient/lib/httpclient.rb +0 -1020
  63. data/vendor/gems/httpclient/lib/tags +0 -908
@@ -1,522 +0,0 @@
1
- # HTTPClient - HTTP client library.
2
- # Copyright (C) 2000-2009 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
- #
4
- # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
- # redistribute it and/or modify it under the same terms of Ruby's license;
6
- # either the dual license version in 2003, or any later version.
7
-
8
-
9
- require 'digest/md5'
10
- require 'httpclient/session'
11
-
12
-
13
- class HTTPClient
14
-
15
- begin
16
- require 'net/ntlm'
17
- NTLMEnabled = true
18
- rescue LoadError
19
- NTLMEnabled = false
20
- end
21
-
22
- begin
23
- require 'win32/sspi'
24
- SSPIEnabled = true
25
- rescue LoadError
26
- SSPIEnabled = false
27
- end
28
-
29
-
30
- # Common abstract class for authentication filter.
31
- #
32
- # There are 2 authentication filters.
33
- # WWWAuth:: Authentication filter for handling authentication negotiation
34
- # between Web server. Parses 'WWW-Authentication' header in
35
- # response and generates 'Authorization' header in request.
36
- # ProxyAuth:: Authentication filter for handling authentication negotiation
37
- # between Proxy server. Parses 'Proxy-Authentication' header in
38
- # response and generates 'Proxy-Authorization' header in request.
39
- class AuthFilterBase
40
- private
41
-
42
- def parse_authentication_header(res, tag)
43
- challenge = res.header[tag]
44
- return nil unless challenge
45
- challenge.collect { |c| parse_challenge_header(c) }.compact
46
- end
47
-
48
- def parse_challenge_header(challenge)
49
- scheme, param_str = challenge.scan(/\A(\S+)(?:\s+(.*))?\z/)[0]
50
- return nil if scheme.nil?
51
- return scheme, param_str
52
- end
53
- end
54
-
55
-
56
- # Authentication filter for handling authentication negotiation between
57
- # Web server. Parses 'WWW-Authentication' header in response and
58
- # generates 'Authorization' header in request.
59
- #
60
- # Authentication filter is implemented using request filter of HTTPClient.
61
- # It traps HTTP response header and maintains authentication state, and
62
- # traps HTTP request header for inserting necessary authentication header.
63
- #
64
- # WWWAuth has sub filters (BasicAuth, DigestAuth, NegotiateAuth and
65
- # SSPINegotiateAuth) and delegates some operations to it.
66
- # NegotiateAuth requires 'ruby/ntlm' module.
67
- # SSPINegotiateAuth requires 'win32/sspi' module.
68
- class WWWAuth < AuthFilterBase
69
- attr_reader :basic_auth
70
- attr_reader :digest_auth
71
- attr_reader :negotiate_auth
72
- attr_reader :sspi_negotiate_auth
73
-
74
- # Creates new WWWAuth.
75
- def initialize
76
- @basic_auth = BasicAuth.new
77
- @digest_auth = DigestAuth.new
78
- @negotiate_auth = NegotiateAuth.new
79
- @sspi_negotiate_auth = SSPINegotiateAuth.new
80
- # sort authenticators by priority
81
- @authenticator = [@negotiate_auth, @sspi_negotiate_auth, @digest_auth, @basic_auth]
82
- end
83
-
84
- # Resets challenge state. See sub filters for more details.
85
- def reset_challenge
86
- @authenticator.each do |auth|
87
- auth.reset_challenge
88
- end
89
- end
90
-
91
- # Set authentication credential. See sub filters for more details.
92
- def set_auth(uri, user, passwd)
93
- @authenticator.each do |auth|
94
- auth.set(uri, user, passwd)
95
- end
96
- reset_challenge
97
- end
98
-
99
- # Filter API implementation. Traps HTTP request and insert
100
- # 'Authorization' header if needed.
101
- def filter_request(req)
102
- @authenticator.each do |auth|
103
- if cred = auth.get(req)
104
- req.header.set('Authorization', auth.scheme + " " + cred)
105
- return
106
- end
107
- end
108
- end
109
-
110
- # Filter API implementation. Traps HTTP response and parses
111
- # 'WWW-Authenticate' header.
112
- def filter_response(req, res)
113
- command = nil
114
- if res.status == HTTP::Status::UNAUTHORIZED
115
- if challenge = parse_authentication_header(res, 'www-authenticate')
116
- uri = req.header.request_uri
117
- challenge.each do |scheme, param_str|
118
- @authenticator.each do |auth|
119
- if scheme.downcase == auth.scheme.downcase
120
- challengeable = auth.challenge(uri, param_str)
121
- command = :retry if challengeable
122
- end
123
- end
124
- end
125
- # ignore unknown authentication scheme
126
- end
127
- end
128
- command
129
- end
130
- end
131
-
132
-
133
- # Authentication filter for handling authentication negotiation between
134
- # Proxy server. Parses 'Proxy-Authentication' header in response and
135
- # generates 'Proxy-Authorization' header in request.
136
- #
137
- # Authentication filter is implemented using request filter of HTTPClient.
138
- # It traps HTTP response header and maintains authentication state, and
139
- # traps HTTP request header for inserting necessary authentication header.
140
- #
141
- # ProxyAuth has sub filters (BasicAuth, NegotiateAuth, and SSPINegotiateAuth)
142
- # and delegates some operations to it.
143
- # NegotiateAuth requires 'ruby/ntlm' module.
144
- # SSPINegotiateAuth requires 'win32/sspi' module.
145
- class ProxyAuth < AuthFilterBase
146
- attr_reader :basic_auth
147
- attr_reader :negotiate_auth
148
- attr_reader :sspi_negotiate_auth
149
-
150
- # Creates new ProxyAuth.
151
- def initialize
152
- @basic_auth = BasicAuth.new
153
- @negotiate_auth = NegotiateAuth.new
154
- @sspi_negotiate_auth = SSPINegotiateAuth.new
155
- # sort authenticators by priority
156
- @authenticator = [@negotiate_auth, @sspi_negotiate_auth, @basic_auth]
157
- end
158
-
159
- # Resets challenge state. See sub filters for more details.
160
- def reset_challenge
161
- @authenticator.each do |auth|
162
- auth.reset_challenge
163
- end
164
- end
165
-
166
- # Set authentication credential. See sub filters for more details.
167
- def set_auth(user, passwd)
168
- @authenticator.each do |auth|
169
- auth.set(nil, user, passwd)
170
- end
171
- reset_challenge
172
- end
173
-
174
- # Filter API implementation. Traps HTTP request and insert
175
- # 'Proxy-Authorization' header if needed.
176
- def filter_request(req)
177
- @authenticator.each do |auth|
178
- if cred = auth.get(req)
179
- req.header.set('Proxy-Authorization', auth.scheme + " " + cred)
180
- return
181
- end
182
- end
183
- end
184
-
185
- # Filter API implementation. Traps HTTP response and parses
186
- # 'Proxy-Authenticate' header.
187
- def filter_response(req, res)
188
- command = nil
189
- if res.status == HTTP::Status::PROXY_AUTHENTICATE_REQUIRED
190
- if challenge = parse_authentication_header(res, 'proxy-authenticate')
191
- uri = req.header.request_uri
192
- challenge.each do |scheme, param_str|
193
- @authenticator.each do |auth|
194
- if scheme.downcase == auth.scheme.downcase
195
- challengeable = auth.challenge(uri, param_str)
196
- command = :retry if challengeable
197
- end
198
- end
199
- end
200
- # ignore unknown authentication scheme
201
- end
202
- end
203
- command
204
- end
205
- end
206
-
207
- # Authentication filter for handling BasicAuth negotiation.
208
- # Used in WWWAuth and ProxyAuth.
209
- class BasicAuth
210
- # Authentication scheme.
211
- attr_reader :scheme
212
-
213
- # Creates new BasicAuth filter.
214
- def initialize
215
- @cred = nil
216
- @auth = {}
217
- @challengeable = {}
218
- @scheme = "Basic"
219
- end
220
-
221
- # Resets challenge state. Do not send '*Authorization' header until the
222
- # server sends '*Authentication' again.
223
- def reset_challenge
224
- @challengeable.clear
225
- end
226
-
227
- # Set authentication credential.
228
- # uri == nil for generic purpose (allow to use user/password for any URL).
229
- def set(uri, user, passwd)
230
- if uri.nil?
231
- @cred = ["#{user}:#{passwd}"].pack('m').tr("\n", '')
232
- else
233
- uri = Util.uri_dirname(uri)
234
- @auth[uri] = ["#{user}:#{passwd}"].pack('m').tr("\n", '')
235
- end
236
- end
237
-
238
- # Response handler: returns credential.
239
- # It sends cred only when a given uri is;
240
- # * child page of challengeable(got *Authenticate before) uri and,
241
- # * child page of defined credential
242
- def get(req)
243
- target_uri = req.header.request_uri
244
- return nil unless @challengeable.find { |uri, ok|
245
- Util.uri_part_of(target_uri, uri) and ok
246
- }
247
- return @cred if @cred
248
- Util.hash_find_value(@auth) { |uri, cred|
249
- Util.uri_part_of(target_uri, uri)
250
- }
251
- end
252
-
253
- # Challenge handler: remember URL for response.
254
- def challenge(uri, param_str)
255
- @challengeable[uri] = true
256
- true
257
- end
258
- end
259
-
260
-
261
- # Authentication filter for handling DigestAuth negotiation.
262
- # Used in WWWAuth.
263
- class DigestAuth
264
- # Authentication scheme.
265
- attr_reader :scheme
266
-
267
- # Creates new DigestAuth filter.
268
- def initialize
269
- @auth = {}
270
- @challenge = {}
271
- @nonce_count = 0
272
- @scheme = "Digest"
273
- end
274
-
275
- # Resets challenge state. Do not send '*Authorization' header until the
276
- # server sends '*Authentication' again.
277
- def reset_challenge
278
- @challenge.clear
279
- end
280
-
281
- # Set authentication credential.
282
- # uri == nil is ignored.
283
- def set(uri, user, passwd)
284
- if uri
285
- uri = Util.uri_dirname(uri)
286
- @auth[uri] = [user, passwd]
287
- end
288
- end
289
-
290
- # Response handler: returns credential.
291
- # It sends cred only when a given uri is;
292
- # * child page of challengeable(got *Authenticate before) uri and,
293
- # * child page of defined credential
294
- def get(req)
295
- target_uri = req.header.request_uri
296
- param = Util.hash_find_value(@challenge) { |uri, v|
297
- Util.uri_part_of(target_uri, uri)
298
- }
299
- return nil unless param
300
- user, passwd = Util.hash_find_value(@auth) { |uri, auth_data|
301
- Util.uri_part_of(target_uri, uri)
302
- }
303
- return nil unless user
304
- uri = req.header.request_uri
305
- calc_cred(req.header.request_method, uri, user, passwd, param)
306
- end
307
-
308
- # Challenge handler: remember URL and challenge token for response.
309
- def challenge(uri, param_str)
310
- @challenge[uri] = parse_challenge_param(param_str)
311
- true
312
- end
313
-
314
- private
315
-
316
- # this method is implemented by sromano and posted to
317
- # http://tools.assembla.com/breakout/wiki/DigestForSoap
318
- # Thanks!
319
- # supported algorithm: MD5 only for now
320
- def calc_cred(method, uri, user, passwd, param)
321
- a_1 = "#{user}:#{param['realm']}:#{passwd}"
322
- a_2 = "#{method}:#{uri.path}"
323
- nonce = param['nonce']
324
- cnonce = generate_cnonce()
325
- @nonce_count += 1
326
- message_digest = []
327
- message_digest << Digest::MD5.hexdigest(a_1)
328
- message_digest << nonce
329
- message_digest << ('%08x' % @nonce_count)
330
- message_digest << cnonce
331
- message_digest << param['qop']
332
- message_digest << Digest::MD5.hexdigest(a_2)
333
- header = []
334
- header << "username=\"#{user}\""
335
- header << "realm=\"#{param['realm']}\""
336
- header << "nonce=\"#{nonce}\""
337
- header << "uri=\"#{uri.path}\""
338
- header << "cnonce=\"#{cnonce}\""
339
- header << "nc=#{'%08x' % @nonce_count}"
340
- header << "qop=\"#{param['qop']}\""
341
- header << "response=\"#{Digest::MD5.hexdigest(message_digest.join(":"))}\""
342
- header << "algorithm=\"MD5\""
343
- header << "opaque=\"#{param['opaque']}\"" if param.key?('opaque')
344
- header.join(", ")
345
- end
346
-
347
- # cf. WEBrick::HTTPAuth::DigestAuth#generate_next_nonce(aTime)
348
- def generate_cnonce
349
- now = "%012d" % Time.now.to_i
350
- pk = Digest::MD5.hexdigest([now, self.__id__, Process.pid, rand(65535)].join)[0, 32]
351
- [now + ':' + pk].pack('m*').chop
352
- end
353
-
354
- def parse_challenge_param(param_str)
355
- param = {}
356
- param_str.scan(/\s*([^\,]+(?:\\.[^\,]*)*)/).each do |str|
357
- key, value = str[0].scan(/\A([^=]+)=(.*)\z/)[0]
358
- if /\A"(.*)"\z/ =~ value
359
- value = $1.gsub(/\\(.)/, '\1')
360
- end
361
- param[key] = value
362
- end
363
- param
364
- end
365
- end
366
-
367
-
368
- # Authentication filter for handling Negotiate/NTLM negotiation.
369
- # Used in WWWAuth and ProxyAuth.
370
- #
371
- # NegotiateAuth depends on 'ruby/ntlm' module.
372
- class NegotiateAuth
373
- # Authentication scheme.
374
- attr_reader :scheme
375
- # NTLM opt for ruby/ntlm. {:ntlmv2 => true} by default.
376
- attr_reader :ntlm_opt
377
-
378
- # Creates new NegotiateAuth filter.
379
- def initialize
380
- @auth = {}
381
- @auth_default = nil
382
- @challenge = {}
383
- @scheme = "Negotiate"
384
- @ntlm_opt = {
385
- :ntlmv2 => true
386
- }
387
- end
388
-
389
- # Resets challenge state. Do not send '*Authorization' header until the
390
- # server sends '*Authentication' again.
391
- def reset_challenge
392
- @challenge.clear
393
- end
394
-
395
- # Set authentication credential.
396
- # uri == nil for generic purpose (allow to use user/password for any URL).
397
- def set(uri, user, passwd)
398
- if uri
399
- uri = Util.uri_dirname(uri)
400
- @auth[uri] = [user, passwd]
401
- else
402
- @auth_default = [user, passwd]
403
- end
404
- end
405
-
406
- # Response handler: returns credential.
407
- # See ruby/ntlm for negotiation state transition.
408
- def get(req)
409
- return nil unless NTLMEnabled
410
- target_uri = req.header.request_uri
411
- domain_uri, param = @challenge.find { |uri, v|
412
- Util.uri_part_of(target_uri, uri)
413
- }
414
- return nil unless param
415
- user, passwd = Util.hash_find_value(@auth) { |uri, auth_data|
416
- Util.uri_part_of(target_uri, uri)
417
- }
418
- unless user
419
- user, passwd = @auth_default
420
- end
421
- return nil unless user
422
- state = param[:state]
423
- authphrase = param[:authphrase]
424
- case state
425
- when :init
426
- t1 = Net::NTLM::Message::Type1.new
427
- return t1.encode64
428
- when :response
429
- t2 = Net::NTLM::Message.decode64(authphrase)
430
- t3 = t2.response({:user => user, :password => passwd}, @ntlm_opt.dup)
431
- @challenge.delete(domain_uri)
432
- return t3.encode64
433
- end
434
- nil
435
- end
436
-
437
- # Challenge handler: remember URL and challenge token for response.
438
- def challenge(uri, param_str)
439
- return false unless NTLMEnabled
440
- if param_str.nil? or @challenge[uri].nil?
441
- c = @challenge[uri] = {}
442
- c[:state] = :init
443
- c[:authphrase] = ""
444
- else
445
- c = @challenge[uri]
446
- c[:state] = :response
447
- c[:authphrase] = param_str
448
- end
449
- true
450
- end
451
- end
452
-
453
-
454
- # Authentication filter for handling Negotiate/NTLM negotiation.
455
- # Used in ProxyAuth.
456
- #
457
- # SSPINegotiateAuth depends on 'win32/sspi' module.
458
- class SSPINegotiateAuth
459
- # Authentication scheme.
460
- attr_reader :scheme
461
-
462
- # Creates new SSPINegotiateAuth filter.
463
- def initialize
464
- @challenge = {}
465
- @scheme = "Negotiate"
466
- end
467
-
468
- # Resets challenge state. Do not send '*Authorization' header until the
469
- # server sends '*Authentication' again.
470
- def reset_challenge
471
- @challenge.clear
472
- end
473
-
474
- # Set authentication credential.
475
- # NOT SUPPORTED: username and necessary data is retrieved by win32/sspi.
476
- # See win32/sspi for more details.
477
- def set(uri, user, passwd)
478
- # not supported
479
- end
480
-
481
- # Response handler: returns credential.
482
- # See win32/sspi for negotiation state transition.
483
- def get(req)
484
- return nil unless SSPIEnabled
485
- target_uri = req.header.request_uri
486
- domain_uri, param = @challenge.find { |uri, v|
487
- Util.uri_part_of(target_uri, uri)
488
- }
489
- return nil unless param
490
- state = param[:state]
491
- authenticator = param[:authenticator]
492
- authphrase = param[:authphrase]
493
- case state
494
- when :init
495
- authenticator = param[:authenticator] = Win32::SSPI::NegotiateAuth.new
496
- return authenticator.get_initial_token(@scheme)
497
- when :response
498
- @challenge.delete(domain_uri)
499
- return authenticator.complete_authentication(authphrase)
500
- end
501
- nil
502
- end
503
-
504
- # Challenge handler: remember URL and challenge token for response.
505
- def challenge(uri, param_str)
506
- return false unless SSPIEnabled
507
- if param_str.nil? or @challenge[uri].nil?
508
- c = @challenge[uri] = {}
509
- c[:state] = :init
510
- c[:authenticator] = nil
511
- c[:authphrase] = ""
512
- else
513
- c = @challenge[uri]
514
- c[:state] = :response
515
- c[:authphrase] = param_str
516
- end
517
- true
518
- end
519
- end
520
-
521
-
522
- end