pelle-oauth 0.3.1 → 0.3.5

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 (54) hide show
  1. data/History.txt +66 -17
  2. data/Manifest.txt +14 -1
  3. data/README.rdoc +7 -9
  4. data/Rakefile +7 -5
  5. data/TODO +17 -0
  6. data/bin/oauth +2 -2
  7. data/examples/yql.rb +44 -0
  8. data/lib/oauth.rb +1 -0
  9. data/lib/oauth/cli.rb +279 -31
  10. data/lib/oauth/client/action_controller_request.rb +14 -12
  11. data/lib/oauth/client/helper.rb +22 -14
  12. data/lib/oauth/client/net_http.rb +53 -22
  13. data/lib/oauth/consumer.rb +217 -111
  14. data/lib/oauth/errors.rb +3 -0
  15. data/lib/oauth/errors/error.rb +4 -0
  16. data/lib/oauth/errors/problem.rb +14 -0
  17. data/lib/oauth/errors/unauthorized.rb +12 -0
  18. data/lib/oauth/helper.rb +67 -6
  19. data/lib/oauth/oauth.rb +11 -0
  20. data/lib/oauth/oauth_test_helper.rb +12 -13
  21. data/lib/oauth/request_proxy/action_controller_request.rb +8 -8
  22. data/lib/oauth/request_proxy/base.rb +102 -44
  23. data/lib/oauth/request_proxy/jabber_request.rb +1 -2
  24. data/lib/oauth/request_proxy/mock_request.rb +8 -0
  25. data/lib/oauth/request_proxy/net_http.rb +2 -2
  26. data/lib/oauth/request_proxy/rack_request.rb +7 -7
  27. data/lib/oauth/server.rb +31 -33
  28. data/lib/oauth/signature.rb +9 -0
  29. data/lib/oauth/signature/base.rb +23 -21
  30. data/lib/oauth/signature/hmac/base.rb +1 -1
  31. data/lib/oauth/signature/hmac/sha1.rb +0 -1
  32. data/lib/oauth/signature/plaintext.rb +2 -2
  33. data/lib/oauth/signature/rsa/sha1.rb +5 -4
  34. data/lib/oauth/token.rb +6 -136
  35. data/lib/oauth/tokens/access_token.rb +68 -0
  36. data/lib/oauth/tokens/consumer_token.rb +33 -0
  37. data/lib/oauth/tokens/request_token.rb +32 -0
  38. data/lib/oauth/tokens/server_token.rb +9 -0
  39. data/lib/oauth/tokens/token.rb +17 -0
  40. data/lib/oauth/version.rb +1 -1
  41. data/oauth.gemspec +13 -7
  42. data/test/cases/spec/1_0-final/test_construct_request_url.rb +1 -1
  43. data/test/test_access_token.rb +28 -0
  44. data/test/test_action_controller_request_proxy.rb +105 -6
  45. data/test/test_consumer.rb +41 -5
  46. data/test/test_helper.rb +0 -5
  47. data/test/test_net_http_client.rb +38 -20
  48. data/test/test_net_http_request_proxy.rb +43 -8
  49. data/test/test_oauth_helper.rb +50 -0
  50. data/test/test_request_token.rb +53 -0
  51. data/test/test_server.rb +1 -1
  52. data/test/test_signature.rb +19 -11
  53. data/website/index.html +2 -2
  54. metadata +46 -6
data/History.txt CHANGED
@@ -1,8 +1,54 @@
1
- == 0.3.1
1
+ == 0.3.6
2
2
 
3
- * Michael Wood identified a problem with relative and absolute token request paths. This should now be fixed and is tested for both cases.
3
+ * Added -B CLI option to use the :body authentication scheme (Seth)
4
4
 
5
- == 0.3.0
5
+ == 0.3.5 2009-06-03
6
+
7
+ * `query` CLI command to access protected resources (Seth)
8
+ * Added -H, -Q CLI options for specifying the authentication scheme (Seth)
9
+ * Added -O CLI option for specifying a file containing options (Seth)
10
+ * Support streamable body contents for large request bodies (Seth Cousins)
11
+ * Support for OAuth 1.0a (Seth)
12
+ * Added proxy support to OAuth::Consumer (Marshall Huss)
13
+ * Added --scope CLI option for Google's 'scope' parameter (Seth)
14
+
15
+ == 0.3.4 2009-05-06
16
+
17
+ * OAuth::Client::Helper uses OAuth::VERSION (chadisfaction)
18
+ * Fix OAuth::RequestProxy::ActionControllerRequest's handling of params
19
+ (Tristan Groléat)
20
+
21
+ == 0.3.3 2009-05-04
22
+
23
+ * Corrected OAuth XMPP namespace (Seth)
24
+ * Improved error handling for invalid Authorization headers (Matt Sanford)
25
+ * Fixed signatures for non-ASCII under $KCODE other than 'u' (Matt Sanford)
26
+ * Fixed edge cases in ActionControllerRequestProxy where params were being
27
+ incorrectly signed (Marcos Wright Kuhns)
28
+ * Support for arguments in OAuth::Consumer#get_access_token (Matt Sanford)
29
+ * Add gem version to user-agent header (Matt Sanford)
30
+ * Handle input from aggressive form encoding libraries (Matt Wood)
31
+
32
+ == 0.3.2 2009-03-23
33
+
34
+ * 2xx statuses should be treated as success (Anders Conbere)
35
+ * Support applications using the MethodOverride Rack middleware (László Bácsi)
36
+ * `authorize` command for `oauth` CLI (Seth)
37
+ * Initial support for Problem Reporting extension (Seth)
38
+ * Verify SSL certificates if CA certificates are available (Seth)
39
+ * Fixed ActionController parameter escaping behavior (Thiago Arrais, László
40
+ Bácsi, Brett Gibson, et al)
41
+ * Fixed signature calculation when both options and a block were provided to
42
+ OAuth::Signature::Base#initialize (Seth)
43
+ * Added help to the 'oauth' CLI (Seth)
44
+ * Fixed a problem when attempting to normalize MockRequest URIs (Seth)
45
+
46
+ == 0.3.1 2009-1-26
47
+
48
+ * Fixed a problem with relative and absolute token request paths. (Michael
49
+ Wood)
50
+
51
+ == 0.3.0 2009-1-25
6
52
 
7
53
  * Support ActionController::Request from Edge Rails (László Bácsi)
8
54
  * Correctly handle multi-valued parameters (Seth)
@@ -15,23 +61,25 @@
15
61
  * Improved test-cases and compatibility for encoding issues. (Pelle)
16
62
 
17
63
  == 0.2.7 2008-9-10 The lets fix the last release release
18
- Fix in plain text signatures to bug found by Andrew Arrow. Who contributed new new unit tests for plain text sigs.
19
64
 
20
- There was an error in the RSA requests using oauth tokens. Thanks to Philip Lipu Tsai for noticing this.
65
+ * Fixed plain text signatures (Andrew Arrow)
66
+ * Fixed RSA requests using OAuthTokens. (Philip Lipu Tsai)
21
67
 
22
68
  == 0.2.6 2008-9-9 The lets RSA release
23
69
 
24
- - Bill Kocik's fix for Ruby 1.8.7
25
- - Fixed rsa verification, so you can actually create an OAuth server yourself now using Ruby and RSA
26
- - Added better testing for RSA
27
- - Fixed issue where token was being included for rsa signatures
28
- - Chris Mear added support for a private_key_file option for rsa signatures
29
- - Scott Hill fixed several edge cases where parameters were incorrectly being signed
30
- - Patch from choonkeat fixing a problem with rsa signing.
70
+ * Improved support for Ruby 1.8.7 (Bill Kocik)
71
+ * Fixed RSA verification to support RSA providers
72
+ now using Ruby and RSA
73
+ * Improved RSA testing
74
+ * Omit token when signing with RSA
75
+ * Added support for 'private_key_file' option for RSA signatures (Chris Mear)
76
+ * Fixed several edge cases where params were being incorrectly signed (Scott
77
+ Hill)
78
+ * Fixed RSA signing (choonkeat)
31
79
 
32
80
  == 0.2.2 2008-2-22 Lets actually support SSL release
33
81
 
34
- It didn't actually use https when required.
82
+ * Use HTTPS when required.
35
83
 
36
84
  == 0.2 2008-1-19 All together now release
37
85
 
@@ -39,10 +87,11 @@ This is a big release, where we have merged the efforts of various parties into
39
87
 
40
88
  == 0.1.2 2007-12-1
41
89
 
42
- * 1 Fixed a problem where incoming request didn't check whether oauth parameters where missing. While not giving unauthorized access it did cause extra processing where not necessary.
43
- * 2 Includes Pat's fix for getting the realm out.
90
+ * Fixed checks for missing OAuth params to improve performance
91
+ * Includes Pat's fix for getting the realm out.
44
92
 
45
93
  == 0.1.1 2007-11-26
46
94
 
47
- * 1 First release as a GEM
48
- * Moved all non rails functions into this GEM from the Rails plugin http://code.google.com/p/oauth-plugin/
95
+ * First release as a GEM
96
+ * Moved all non-Rails functionality from the Rails plugin:
97
+ http://code.google.com/p/oauth-plugin/
data/Manifest.txt CHANGED
@@ -5,13 +5,19 @@ README.rdoc
5
5
  Rakefile
6
6
  TODO
7
7
  bin/oauth
8
+ examples/yql.rb
8
9
  lib/oauth.rb
10
+ lib/oauth/oauth.rb
9
11
  lib/oauth/cli.rb
10
12
  lib/oauth/client.rb
11
13
  lib/oauth/client/action_controller_request.rb
12
14
  lib/oauth/client/helper.rb
13
15
  lib/oauth/client/net_http.rb
14
16
  lib/oauth/consumer.rb
17
+ lib/oauth/errors.rb
18
+ lib/oauth/errors/error.rb
19
+ lib/oauth/errors/problem.rb
20
+ lib/oauth/errors/unauthorized.rb
15
21
  lib/oauth/helper.rb
16
22
  lib/oauth/oauth_test_helper.rb
17
23
  lib/oauth/request_proxy.rb
@@ -34,13 +40,17 @@ lib/oauth/signature/plaintext.rb
34
40
  lib/oauth/signature/rsa/sha1.rb
35
41
  lib/oauth/signature/sha1.rb
36
42
  lib/oauth/token.rb
43
+ lib/oauth/tokens/access_token.rb
44
+ lib/oauth/tokens/consumer_token.rb
45
+ lib/oauth/tokens/request_token.rb
46
+ lib/oauth/tokens/server_token.rb
47
+ lib/oauth/tokens/token.rb
37
48
  lib/oauth/version.rb
38
49
  oauth.gemspec
39
50
  script/destroy
40
51
  script/generate
41
52
  script/txt2html
42
53
  setup.rb
43
- specs.txt
44
54
  tasks/deployment.rake
45
55
  tasks/environment.rake
46
56
  tasks/website.rake
@@ -51,13 +61,16 @@ test/cases/spec/1_0-final/test_parameter_encodings.rb
51
61
  test/cases/spec/1_0-final/test_signature_base_strings.rb
52
62
  test/keys/rsa.cert
53
63
  test/keys/rsa.pem
64
+ test/test_access_token.rb
54
65
  test/test_action_controller_request_proxy.rb
55
66
  test/test_consumer.rb
56
67
  test/test_helper.rb
57
68
  test/test_hmac_sha1.rb
58
69
  test/test_net_http_client.rb
59
70
  test/test_net_http_request_proxy.rb
71
+ test/test_oauth_helper.rb
60
72
  test/test_rack_request_proxy.rb
73
+ test/test_request_token.rb
61
74
  test/test_rsa_sha1.rb
62
75
  test/test_server.rb
63
76
  test/test_signature.rb
data/README.rdoc CHANGED
@@ -12,7 +12,7 @@ See the OAuth specs http://oauth.net/core/1.0/
12
12
 
13
13
  You can also install it from the oauth rubyforge project http://rubyforge.org/projects/oauth/.
14
14
 
15
- The source code is now hosted on the OAuth GitHub Project http://github.com/pelle/oauth/tree/master
15
+ The source code is now hosted on the OAuth GitHub Project http://github.com/mojodna/oauth
16
16
 
17
17
  == The basics
18
18
 
@@ -24,20 +24,18 @@ As a matter of fact it has been pulled out from an OAuth Rails Plugin http://cod
24
24
 
25
25
  Create a new consumer instance by passing it a configuration hash:
26
26
 
27
- @consumer=OAuth::Consumer.new( "key","secret", {
28
- :site=>"https://agree2"
29
- })
27
+ @consumer = OAuth::Consumer.new("key","secret", :site => "https://agree2")
30
28
 
31
29
  Start the process by requesting a token
32
30
 
33
- @request_token=@consumer.get_request_token
34
- session[:request_token]=@request_token
31
+ @request_token = @consumer.get_request_token
32
+ session[:request_token] = @request_token
35
33
  redirect_to @request_token.authorize_url
36
34
 
37
35
  When user returns create an access_token
38
36
 
39
- @access_token=@request_token.get_access_token
40
- @photos=@access_token.get('/photos.xml')
37
+ @access_token = @request_token.get_access_token
38
+ @photos = @access_token.get('/photos.xml')
41
39
 
42
40
  For more detailed instructions I have written this OAuth Client Tutorial http://stakeventures.com/articles/2008/02/23/developing-oauth-clients-in-ruby and "How to turn your rails site into an OAuth Provider ":http://stakeventures.com/articles/2007/11/26/how-to-turn-your-rails-site-into-an-oauth-provider .
43
41
 
@@ -59,7 +57,7 @@ http://groups.google.com/group/oauth-ruby
59
57
 
60
58
  Read the "8 steps for fixing other people's code" http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/.
61
59
 
62
- The source code is now hosted on the OAuth GitHub Project http://github.com/pelle/oauth/tree/master
60
+ The source code is now hosted on the OAuth GitHub Project http://github.com/mojodna/oauth
63
61
 
64
62
  To submit a patch, please fork the oauth project and create a patch with tests. Once you're happy with it send a pull request and post a message to the google group.
65
63
 
data/Rakefile CHANGED
@@ -6,21 +6,23 @@ require 'oauth/version'
6
6
  # Generate all the Rake tasks
7
7
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
8
8
  $hoe = Hoe.new('oauth', OAuth::VERSION) do |p|
9
- p.author = ['Pelle Braendgaard','Blaine Cook','Larry Halff','Jesse Clark','Jon Crosby', 'Seth Fitzsimmons']
10
- p.email = "pelleb@gmail.com"
9
+ p.author = ['Pelle Braendgaard','Blaine Cook','Larry Halff','Jesse Clark','Jon Crosby', 'Seth Fitzsimmons']
10
+ p.email = "oauth-ruby@googlegroups.com"
11
11
  p.description = "OAuth Core Ruby implementation"
12
12
  p.summary = p.description
13
13
  p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
14
14
  p.rubyforge_name = p.name # TODO this is default value
15
15
  p.url = "http://oauth.rubyforge.org"
16
-
16
+
17
17
  p.extra_deps = [
18
18
  ['ruby-hmac','>= 0.3.1']
19
19
  ]
20
20
  p.extra_dev_deps = [
21
- ['newgem', ">= #{::Newgem::VERSION}"]
21
+ ['newgem', ">= #{::Newgem::VERSION}"],
22
+ ['actionpack'],
23
+ ['rack']
22
24
  ]
23
-
25
+
24
26
  p.clean_globs |= %w[**/.DS_Store tmp *.log **/.*.sw? *.gem .config **/.DS_Store]
25
27
  path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
26
28
  p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
data/TODO CHANGED
@@ -12,3 +12,20 @@ Common use-cases should be streamlined:
12
12
  errors, if available).
13
13
  * I want to host an OAuth-enabled web service.
14
14
  * I want to test my OAuth-enabled web service (i.e. test helpers)
15
+
16
+ Example applications for:
17
+ * Ning
18
+ * Fire Eagle
19
+ * Google (blogger, contacts)
20
+ * Twitter
21
+ * YOS / YQL
22
+ * Netflix
23
+
24
+ In addition to providing best practices of use, these can also be part of
25
+ the pre-release checks to make sure that there have been no regressions.
26
+
27
+ Random TODOs:
28
+ * finish CLI
29
+ * sensible Exception hierarchy
30
+ * Tokens as Modules
31
+ * don't tie to Net::HTTP
data/bin/oauth CHANGED
@@ -1,5 +1,5 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env ruby -w -rubygems
2
2
 
3
3
  require "oauth/cli"
4
4
 
5
- OAuth::CLI.execute(STDOUT, ARGV)
5
+ OAuth::CLI.execute(STDOUT, STDIN, STDERR, ARGV)
data/examples/yql.rb ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby -rubygems
2
+
3
+ # Sample queries:
4
+ # ./yql.rb --consumer-key <key> --consumer-secret <secret> "show tables"
5
+ # ./yql.rb --consumer-key <key> --consumer-secret <secret> "select * from flickr.photos.search where text='Cat' limit 10"
6
+
7
+ require 'oauth'
8
+ require 'optparse'
9
+ require 'json'
10
+ require 'pp'
11
+
12
+ options = {}
13
+
14
+ option_parser = OptionParser.new do |opts|
15
+ opts.banner = "Usage: #{$0} [options] <query>"
16
+
17
+ opts.on("--consumer-key KEY", "Specifies the consumer key to use.") do |v|
18
+ options[:consumer_key] = v
19
+ end
20
+
21
+ opts.on("--consumer-secret SECRET", "Specifies the consumer secret to use.") do |v|
22
+ options[:consumer_secret] = v
23
+ end
24
+ end
25
+
26
+ option_parser.parse!
27
+ query = ARGV.pop
28
+ query = STDIN.read if query == "-"
29
+
30
+ if options[:consumer_key].nil? || options[:consumer_secret].nil? || query.nil?
31
+ puts option_parser.help
32
+ exit 1
33
+ end
34
+
35
+ consumer = OAuth::Consumer.new \
36
+ options[:consumer_key],
37
+ options[:consumer_secret],
38
+ :site => "http://query.yahooapis.com"
39
+
40
+ access_token = OAuth::AccessToken.new(consumer)
41
+
42
+ response = access_token.request(:get, "/v1/yql?q=#{OAuth::Helper.escape(query)}&format=json")
43
+ rsp = JSON.parse(response.body)
44
+ pp rsp
data/lib/oauth.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'oauth/oauth'
1
2
  require 'oauth/client/helper'
2
3
  require 'oauth/signature/hmac/sha1'
3
4
  require 'oauth/request_proxy/mock_request'
data/lib/oauth/cli.rb CHANGED
@@ -3,67 +3,210 @@ require 'oauth'
3
3
 
4
4
  module OAuth
5
5
  class CLI
6
- SUPPORTED_COMMANDS = %w(sign)
6
+ SUPPORTED_COMMANDS = {
7
+ "authorize" => "Obtain an access token and secret for a user",
8
+ "debug" => "Verbosely generate an OAuth signature",
9
+ "query" => "Query a protected resource",
10
+ "sign" => "Generate an OAuth signature",
11
+ "version" => "Display the current version of the library"
12
+ }
7
13
 
8
14
  attr_reader :command
9
15
  attr_reader :options
10
- attr_reader :stdout
16
+ attr_reader :stdout, :stdin
11
17
 
12
- def self.execute(stdout, arguments = [])
13
- self.new.execute(stdout, arguments)
18
+ def self.execute(stdout, stdin, stderr, arguments = [])
19
+ self.new.execute(stdout, stdin, stderr, arguments)
14
20
  end
15
21
 
16
- def execute(stdout, arguments = [])
22
+ def initialize
23
+ @options = {}
24
+
25
+ # don't dump a backtrace on a ^C
26
+ trap(:INT) {
27
+ exit
28
+ }
29
+ end
30
+
31
+ def execute(stdout, stdin, stderr, arguments = [])
17
32
  @stdout = stdout
33
+ @stdin = stdin
34
+ @stderr = stderr
18
35
  extract_command_and_parse_options(arguments)
19
36
 
20
37
  if sufficient_options? && valid_command?
38
+ if command == "debug"
39
+ @command = "sign"
40
+ @options[:verbose] = true
41
+ end
42
+
21
43
  case command
44
+ # TODO move command logic elsewhere
45
+ when "authorize"
46
+ begin
47
+ consumer = OAuth::Consumer.new \
48
+ options[:oauth_consumer_key],
49
+ options[:oauth_consumer_secret],
50
+ :access_token_url => options[:access_token_url],
51
+ :authorize_url => options[:authorize_url],
52
+ :request_token_url => options[:request_token_url],
53
+ :scheme => options[:scheme],
54
+ :http_method => options[:method].to_s.downcase.to_sym
55
+
56
+ # parameters for OAuth 1.0a
57
+ oauth_verifier = nil
58
+
59
+ # get a request token
60
+ request_token = consumer.get_request_token({ :oauth_callback => options[:oauth_callback] }, { "scope" => options[:scope] })
61
+
62
+ if request_token.callback_confirmed?
63
+ stdout.puts "Server appears to support OAuth 1.0a; enabling support."
64
+ options[:version] = "1.0a"
65
+ end
66
+
67
+ stdout.puts "Please visit this url to authorize:"
68
+ stdout.puts request_token.authorize_url
69
+
70
+ if options[:version] == "1.0a"
71
+ stdout.puts "Please enter the verification code provided by the SP (oauth_verifier):"
72
+ oauth_verifier = stdin.gets.chomp
73
+ else
74
+ stdout.puts "Press return to continue..."
75
+ stdin.gets
76
+ end
77
+
78
+ begin
79
+ # get an access token
80
+ access_token = request_token.get_access_token(:oauth_verifier => oauth_verifier)
81
+
82
+ stdout.puts "Response:"
83
+ access_token.params.each do |k,v|
84
+ stdout.puts " #{k}: #{v}" unless k.is_a?(Symbol)
85
+ end
86
+ rescue OAuth::Unauthorized => e
87
+ stderr.puts "A problem occurred while attempting to obtain an access token:"
88
+ stderr.puts e
89
+ stderr.puts e.request.body
90
+ end
91
+ rescue OAuth::Unauthorized => e
92
+ stderr.puts "A problem occurred while attempting to authorize:"
93
+ stderr.puts e
94
+ stderr.puts e.request.body
95
+ end
96
+ when "query"
97
+ consumer = OAuth::Consumer.new \
98
+ options[:oauth_consumer_key],
99
+ options[:oauth_consumer_secret],
100
+ :scheme => options[:scheme]
101
+
102
+ access_token = OAuth::AccessToken.new(consumer, options[:oauth_token], options[:oauth_token_secret])
103
+
104
+ # append params to the URL
105
+ uri = URI.parse(options[:uri])
106
+ params = prepare_parameters.map { |k,v| v.map { |v2| "#{URI.encode(k)}=#{URI.encode(v2)}" } * "&" }
107
+ uri.query = [uri.query, *params].reject { |x| x.nil? } * "&"
108
+ p uri.to_s
109
+
110
+ response = access_token.request(options[:method].downcase.to_sym, uri.to_s)
111
+ puts "#{response.code} #{response.message}"
112
+ puts response.body
22
113
  when "sign"
114
+ parameters = prepare_parameters
115
+
23
116
  request = OAuth::RequestProxy.proxy \
24
117
  "method" => options[:method],
25
118
  "uri" => options[:uri],
26
- "parameters" => prepare_parameters
119
+ "parameters" => parameters
27
120
 
28
- # can't pass options unless they respond to :secret, so use this alternative
29
- signature = OAuth::Signature.sign \
30
- request,
31
- :consumer_secret => options[:oauth_consumer_secret],
32
- :token_secret => options[:oauth_token_secret] do |request|
33
-
34
- # while we have access to the request being signed, display some internals
35
- if verbose?
36
- stdout.puts "Method: #{request.method}"
37
- stdout.puts "URI: #{request.uri}"
38
- stdout.puts "Normalized params: #{request.normalized_parameters}"
39
- stdout.puts "Signature base string: #{request.signature_base_string}"
121
+ if verbose?
122
+ stdout.puts "OAuth parameters:"
123
+ request.oauth_parameters.each do |k,v|
124
+ stdout.puts " " + [k, v] * ": "
125
+ end
126
+ stdout.puts
127
+
128
+ if request.non_oauth_parameters.any?
129
+ stdout.puts "Parameters:"
130
+ request.non_oauth_parameters.each do |k,v|
131
+ stdout.puts " " + [k, v] * ": "
132
+ end
133
+ stdout.puts
40
134
  end
41
135
  end
42
136
 
137
+ request.sign! \
138
+ :consumer_secret => options[:oauth_consumer_secret],
139
+ :token_secret => options[:oauth_token_secret]
140
+
43
141
  if verbose?
44
- stdout.puts "Signature: #{signature}"
45
- stdout.puts "Escaped signature: #{OAuth::Helper.escape(signature)}"
142
+ stdout.puts "Method: #{request.method}"
143
+ stdout.puts "URI: #{request.uri}"
144
+ stdout.puts "Normalized params: #{request.normalized_parameters}" unless options[:xmpp]
145
+ stdout.puts "Signature base string: #{request.signature_base_string}"
146
+
147
+ if options[:xmpp]
148
+ stdout.puts
149
+ stdout.puts "XMPP Stanza:"
150
+ stdout.puts <<-EOS
151
+ <oauth xmlns='urn:xmpp:oauth:0'>
152
+ <oauth_consumer_key>#{request.oauth_consumer_key}</oauth_consumer_key>
153
+ <oauth_token>#{request.oauth_token}</oauth_token>
154
+ <oauth_signature_method>#{request.oauth_signature_method}</oauth_signature_method>
155
+ <oauth_signature>#{request.oauth_signature}</oauth_signature>
156
+ <oauth_timestamp>#{request.oauth_timestamp}</oauth_timestamp>
157
+ <oauth_nonce>#{request.oauth_nonce}</oauth_nonce>
158
+ <oauth_version>#{request.oauth_version}</oauth_version>
159
+ </oauth>
160
+ EOS
161
+ stdout.puts
162
+ stdout.puts "Note: You may want to use bare JIDs in your URI."
163
+ stdout.puts
164
+ else
165
+ stdout.puts "OAuth Request URI: #{request.signed_uri}"
166
+ stdout.puts "Request URI: #{request.signed_uri(false)}"
167
+ stdout.puts "Authorization header: #{request.oauth_header(:realm => options[:realm])}"
168
+ end
169
+ stdout.puts "Signature: #{request.oauth_signature}"
170
+ stdout.puts "Escaped signature: #{OAuth::Helper.escape(request.oauth_signature)}"
46
171
  else
47
- stdout.puts signature
172
+ stdout.puts request.oauth_signature
48
173
  end
174
+ when "version"
175
+ puts "OAuth for Ruby #{OAuth::VERSION}"
49
176
  end
50
177
  else
51
178
  usage
52
179
  end
53
180
  end
54
181
 
182
+ protected
183
+
55
184
  def extract_command_and_parse_options(arguments)
56
185
  @command = arguments[-1]
57
186
  parse_options(arguments[0..-1])
58
187
  end
59
188
 
60
- def parse_options(arguments)
61
- @options = {}
62
- OptionParser.new do |opts|
189
+ def option_parser(arguments = "")
190
+ # TODO add realm parameter
191
+ # TODO add user-agent parameter
192
+ option_parser = OptionParser.new do |opts|
63
193
  opts.banner = "Usage: #{$0} [options] <command>"
64
194
 
65
195
  # defaults
196
+ options[:oauth_nonce] = OAuth::Helper.generate_key
66
197
  options[:oauth_signature_method] = "HMAC-SHA1"
198
+ options[:oauth_timestamp] = OAuth::Helper.generate_timestamp
199
+ options[:oauth_version] = "1.0"
200
+ options[:method] = :post
201
+ options[:params] = []
202
+ options[:scheme] = :header
203
+ options[:version] = "1.0"
204
+
205
+ ## Common Options
206
+
207
+ opts.on("-B", "--body", "Use the request body for OAuth parameters.") do
208
+ options[:scheme] = :body
209
+ end
67
210
 
68
211
  opts.on("--consumer-key KEY", "Specifies the consumer key to use.") do |v|
69
212
  options[:oauth_consumer_key] = v
@@ -73,12 +216,32 @@ module OAuth
73
216
  options[:oauth_consumer_secret] = v
74
217
  end
75
218
 
219
+ opts.on("-H", "--header", "Use the 'Authorization' header for OAuth parameters (default).") do
220
+ options[:scheme] = :header
221
+ end
222
+
223
+ opts.on("-Q", "--query-string", "Use the query string for OAuth parameters.") do
224
+ options[:scheme] = :query_string
225
+ end
226
+
227
+ opts.on("-O", "--options FILE", "Read options from a file") do |v|
228
+ arguments.unshift(*open(v).readlines.map { |l| l.chomp.split(" ") }.flatten)
229
+ end
230
+
231
+ ## Options for signing and making requests
232
+
233
+ opts.separator("\n options for signing and querying")
234
+
76
235
  opts.on("--method METHOD", "Specifies the method (e.g. GET) to use when signing.") do |v|
77
236
  options[:method] = v
78
237
  end
79
238
 
239
+ opts.on("--nonce NONCE", "Specifies the none to use.") do |v|
240
+ options[:oauth_nonce] = v
241
+ end
242
+
80
243
  opts.on("--parameters PARAMS", "Specifies the parameters to use when signing.") do |v|
81
- options[:params] = v
244
+ options[:params] << v
82
245
  end
83
246
 
84
247
  opts.on("--signature-method METHOD", "Specifies the signature method to use; defaults to HMAC-SHA1.") do |v|
@@ -89,38 +252,123 @@ module OAuth
89
252
  options[:oauth_token_secret] = v
90
253
  end
91
254
 
255
+ opts.on("--timestamp TIMESTAMP", "Specifies the timestamp to use.") do |v|
256
+ options[:oauth_timestamp] = v
257
+ end
258
+
92
259
  opts.on("--token TOKEN", "Specifies the token to use.") do |v|
93
260
  options[:oauth_token] = v
94
261
  end
95
262
 
263
+ opts.on("--realm REALM", "Specifies the realm to use.") do |v|
264
+ options[:realm] = v
265
+ end
266
+
96
267
  opts.on("--uri URI", "Specifies the URI to use when signing.") do |v|
97
268
  options[:uri] = v
98
269
  end
99
270
 
271
+ opts.on(:OPTIONAL, "--version VERSION", "Specifies the OAuth version to use.") do |v|
272
+ if v
273
+ options[:oauth_version] = v
274
+ else
275
+ @command = "version"
276
+ end
277
+ end
278
+
279
+ opts.on("--no-version", "Omit oauth_version.") do
280
+ options[:oauth_version] = nil
281
+ end
282
+
283
+ opts.on("--xmpp", "Generate XMPP stanzas.") do
284
+ options[:xmpp] = true
285
+ options[:method] ||= "iq"
286
+ end
287
+
100
288
  opts.on("-v", "--verbose", "Be verbose.") do
101
289
  options[:verbose] = true
102
290
  end
103
- end.parse!(arguments)
291
+
292
+ ## Options for authorization
293
+
294
+ opts.separator("\n options for authorization")
295
+
296
+ opts.on("--access-token-url URL", "Specifies the access token URL.") do |v|
297
+ options[:access_token_url] = v
298
+ end
299
+
300
+ opts.on("--authorize-url URL", "Specifies the authorization URL.") do |v|
301
+ options[:authorize_url] = v
302
+ end
303
+
304
+ opts.on("--callback-url URL", "Specifies a callback URL.") do |v|
305
+ options[:oauth_callback] = v
306
+ end
307
+
308
+ opts.on("--request-token-url URL", "Specifies the request token URL.") do |v|
309
+ options[:request_token_url] = v
310
+ end
311
+
312
+ opts.on("--scope SCOPE", "Specifies the scope (Google-specific).") do |v|
313
+ options[:scope] = v
314
+ end
315
+ end
316
+ end
317
+
318
+ def parse_options(arguments)
319
+ option_parser(arguments).parse!(arguments)
104
320
  end
105
321
 
106
322
  def prepare_parameters
323
+ escaped_pairs = options[:params].collect do |pair|
324
+ if pair =~ /:/
325
+ Hash[*pair.split(":", 2)].collect do |k,v|
326
+ [CGI.escape(k.strip), CGI.escape(v.strip)] * "="
327
+ end
328
+ else
329
+ pair
330
+ end
331
+ end
332
+
333
+ querystring = escaped_pairs * "&"
334
+ cli_params = CGI.parse(querystring)
335
+
107
336
  {
108
337
  "oauth_consumer_key" => options[:oauth_consumer_key],
338
+ "oauth_nonce" => options[:oauth_nonce],
339
+ "oauth_timestamp" => options[:oauth_timestamp],
109
340
  "oauth_token" => options[:oauth_token],
110
- "oauth_signature_method" => options[:oauth_signature_method]
111
- }.merge(CGI.parse(options[:params]))
341
+ "oauth_signature_method" => options[:oauth_signature_method],
342
+ "oauth_version" => options[:oauth_version]
343
+ }.reject { |k,v| v.nil? || v == "" }.merge(cli_params)
112
344
  end
113
345
 
114
346
  def sufficient_options?
115
- options[:oauth_consumer_key] && options[:oauth_consumer_secret] && options[:method] && options[:uri]
347
+ case command
348
+ # TODO move command logic elsewhere
349
+ when "authorize"
350
+ options[:oauth_consumer_key] && options[:oauth_consumer_secret] &&
351
+ options[:access_token_url] && options[:authorize_url] &&
352
+ options[:request_token_url]
353
+ when "version"
354
+ true
355
+ else
356
+ options[:oauth_consumer_key] && options[:oauth_consumer_secret] &&
357
+ options[:method] && options[:uri]
358
+ end
116
359
  end
117
360
 
118
361
  def usage
119
- stdout.puts "Should be generated by OptionParser"
362
+ stdout.puts option_parser.help
363
+ stdout.puts
364
+ stdout.puts "Available commands:"
365
+ SUPPORTED_COMMANDS.each do |command, desc|
366
+ puts " #{command.ljust(15)}#{desc}"
367
+ end
120
368
  end
121
369
 
122
370
  def valid_command?
123
- SUPPORTED_COMMANDS.include?(command)
371
+ SUPPORTED_COMMANDS.keys.include?(command)
124
372
  end
125
373
 
126
374
  def verbose?