qoobaa-oauth 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/History.txt +114 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +71 -0
  6. data/Rakefile +58 -0
  7. data/TODO +31 -0
  8. data/VERSION +1 -0
  9. data/lib/oauth.rb +4 -0
  10. data/lib/oauth/cli.rb +378 -0
  11. data/lib/oauth/client.rb +4 -0
  12. data/lib/oauth/client/action_controller_request.rb +54 -0
  13. data/lib/oauth/client/helper.rb +85 -0
  14. data/lib/oauth/client/net_http.rb +106 -0
  15. data/lib/oauth/consumer.rb +370 -0
  16. data/lib/oauth/errors.rb +3 -0
  17. data/lib/oauth/errors/error.rb +4 -0
  18. data/lib/oauth/errors/problem.rb +14 -0
  19. data/lib/oauth/errors/unauthorized.rb +12 -0
  20. data/lib/oauth/helper.rb +78 -0
  21. data/lib/oauth/oauth.rb +11 -0
  22. data/lib/oauth/oauth_test_helper.rb +25 -0
  23. data/lib/oauth/request_proxy.rb +24 -0
  24. data/lib/oauth/request_proxy/action_controller_request.rb +73 -0
  25. data/lib/oauth/request_proxy/base.rb +166 -0
  26. data/lib/oauth/request_proxy/jabber_request.rb +41 -0
  27. data/lib/oauth/request_proxy/mock_request.rb +44 -0
  28. data/lib/oauth/request_proxy/net_http.rb +65 -0
  29. data/lib/oauth/request_proxy/rack_request.rb +40 -0
  30. data/lib/oauth/request_proxy/typhoeus_request.rb +53 -0
  31. data/lib/oauth/server.rb +66 -0
  32. data/lib/oauth/signature.rb +40 -0
  33. data/lib/oauth/signature/base.rb +87 -0
  34. data/lib/oauth/signature/hmac/md5.rb +21 -0
  35. data/lib/oauth/signature/hmac/rmd160.rb +21 -0
  36. data/lib/oauth/signature/hmac/sha1.rb +22 -0
  37. data/lib/oauth/signature/hmac/sha2.rb +21 -0
  38. data/lib/oauth/signature/md5.rb +13 -0
  39. data/lib/oauth/signature/plaintext.rb +23 -0
  40. data/lib/oauth/signature/rsa/sha1.rb +45 -0
  41. data/lib/oauth/signature/sha1.rb +13 -0
  42. data/lib/oauth/token.rb +7 -0
  43. data/lib/oauth/tokens/access_token.rb +68 -0
  44. data/lib/oauth/tokens/consumer_token.rb +33 -0
  45. data/lib/oauth/tokens/request_token.rb +32 -0
  46. data/lib/oauth/tokens/server_token.rb +9 -0
  47. data/lib/oauth/tokens/token.rb +17 -0
  48. data/lib/oauth/version.rb +3 -0
  49. data/qoobaa-oauth.gemspec +149 -0
  50. data/test/cases/oauth_case.rb +19 -0
  51. data/test/cases/spec/1_0-final/test_construct_request_url.rb +62 -0
  52. data/test/cases/spec/1_0-final/test_normalize_request_parameters.rb +88 -0
  53. data/test/cases/spec/1_0-final/test_parameter_encodings.rb +86 -0
  54. data/test/cases/spec/1_0-final/test_signature_base_strings.rb +77 -0
  55. data/test/integration/consumer_test.rb +304 -0
  56. data/test/keys/rsa.cert +11 -0
  57. data/test/keys/rsa.pem +16 -0
  58. data/test/test_access_token.rb +26 -0
  59. data/test/test_action_controller_request_proxy.rb +133 -0
  60. data/test/test_consumer.rb +159 -0
  61. data/test/test_helper.rb +14 -0
  62. data/test/test_hmac_sha1.rb +20 -0
  63. data/test/test_net_http_client.rb +224 -0
  64. data/test/test_net_http_request_proxy.rb +72 -0
  65. data/test/test_oauth_helper.rb +49 -0
  66. data/test/test_rack_request_proxy.rb +40 -0
  67. data/test/test_request_token.rb +51 -0
  68. data/test/test_rsa_sha1.rb +59 -0
  69. data/test/test_server.rb +40 -0
  70. data/test/test_signature.rb +21 -0
  71. data/test/test_signature_base.rb +32 -0
  72. data/test/test_signature_plain_text.rb +26 -0
  73. data/test/test_token.rb +14 -0
  74. data/test/test_typhoeus_request_proxy.rb +72 -0
  75. metadata +209 -0
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
@@ -0,0 +1,114 @@
1
+ == 0.3.7
2
+ * Better marshalling implementation (Yoan Blanc)
3
+ * Added optional block to OAuth::Consumer.get_*_token (Neill Pearman)
4
+ * Exclude `oauth_callback` with :exclude_callback (Neill Pearman)
5
+ * Strip extraneous spaces and line breaks from access_token responses
6
+ (observed in the wild with Yahoo!'s OAuth+OpenID hybrid) (Eric Hartmann)
7
+ * Stop double-escaping PLAINTEXT signatures (Jimmy Zimmerman)
8
+ * OAuth::Client::Helper won't override the specified `oauth_version`
9
+ (Philip Kromer)
10
+ * Added OAuth::RequestProxy::Typhoeus as an alternative to Net::HTTP
11
+ (Bill Kocik)
12
+
13
+ == 0.3.6 2009-09-14
14
+
15
+ * Added -B CLI option to use the :body authentication scheme (Seth)
16
+ * Respect `--method` in `authorize` CLI command (Seth)
17
+ * Support POST and PUT with raw bodies (Yu-Shan Fung et al)
18
+ * Test clean-up (Xavier Shay, Hannes Tydén)
19
+ * Added :ca_file consumer option to allow consumer specific certificate
20
+ override. (Pelle)
21
+
22
+ == 0.3.5 2009-06-03
23
+
24
+ * `query` CLI command to access protected resources (Seth)
25
+ * Added -H, -Q CLI options for specifying the authentication scheme (Seth)
26
+ * Added -O CLI option for specifying a file containing options (Seth)
27
+ * Support streamable body contents for large request bodies (Seth Cousins)
28
+ * Support for OAuth 1.0a (Seth)
29
+ * Added proxy support to OAuth::Consumer (Marshall Huss)
30
+ * Added --scope CLI option for Google's 'scope' parameter (Seth)
31
+
32
+ == 0.3.4 2009-05-06
33
+
34
+ * OAuth::Client::Helper uses OAuth::VERSION (chadisfaction)
35
+ * Fix OAuth::RequestProxy::ActionControllerRequest's handling of params
36
+ (Tristan Groléat)
37
+
38
+ == 0.3.3 2009-05-04
39
+
40
+ * Corrected OAuth XMPP namespace (Seth)
41
+ * Improved error handling for invalid Authorization headers (Matt Sanford)
42
+ * Fixed signatures for non-ASCII under $KCODE other than 'u' (Matt Sanford)
43
+ * Fixed edge cases in ActionControllerRequestProxy where params were being
44
+ incorrectly signed (Marcos Wright Kuhns)
45
+ * Support for arguments in OAuth::Consumer#get_access_token (Matt Sanford)
46
+ * Add gem version to user-agent header (Matt Sanford)
47
+ * Handle input from aggressive form encoding libraries (Matt Wood)
48
+
49
+ == 0.3.2 2009-03-23
50
+
51
+ * 2xx statuses should be treated as success (Anders Conbere)
52
+ * Support applications using the MethodOverride Rack middleware (László Bácsi)
53
+ * `authorize` command for `oauth` CLI (Seth)
54
+ * Initial support for Problem Reporting extension (Seth)
55
+ * Verify SSL certificates if CA certificates are available (Seth)
56
+ * Fixed ActionController parameter escaping behavior (Thiago Arrais, László
57
+ Bácsi, Brett Gibson, et al)
58
+ * Fixed signature calculation when both options and a block were provided to
59
+ OAuth::Signature::Base#initialize (Seth)
60
+ * Added help to the 'oauth' CLI (Seth)
61
+ * Fixed a problem when attempting to normalize MockRequest URIs (Seth)
62
+
63
+ == 0.3.1 2009-1-26
64
+
65
+ * Fixed a problem with relative and absolute token request paths. (Michael
66
+ Wood)
67
+
68
+ == 0.3.0 2009-1-25
69
+
70
+ * Support ActionController::Request from Edge Rails (László Bácsi)
71
+ * Correctly handle multi-valued parameters (Seth)
72
+ * Added #normalized_parameters to OAuth::RequestProxy::Base (Pelle)
73
+ * OAuth::Signature.sign and friends now yield the RequestProxy instead of the
74
+ token when the passed block's arity is 1. (Seth)
75
+ * Token requests are made to the configured URL rather than generating a
76
+ potentially incorrect one. (Kellan Elliott-McCrea)
77
+ * Command-line app for generating signatures. (Seth)
78
+ * Improved test-cases and compatibility for encoding issues. (Pelle)
79
+
80
+ == 0.2.7 2008-9-10 The lets fix the last release release
81
+
82
+ * Fixed plain text signatures (Andrew Arrow)
83
+ * Fixed RSA requests using OAuthTokens. (Philip Lipu Tsai)
84
+
85
+ == 0.2.6 2008-9-9 The lets RSA release
86
+
87
+ * Improved support for Ruby 1.8.7 (Bill Kocik)
88
+ * Fixed RSA verification to support RSA providers
89
+ now using Ruby and RSA
90
+ * Improved RSA testing
91
+ * Omit token when signing with RSA
92
+ * Added support for 'private_key_file' option for RSA signatures (Chris Mear)
93
+ * Fixed several edge cases where params were being incorrectly signed (Scott
94
+ Hill)
95
+ * Fixed RSA signing (choonkeat)
96
+
97
+ == 0.2.2 2008-2-22 Lets actually support SSL release
98
+
99
+ * Use HTTPS when required.
100
+
101
+ == 0.2 2008-1-19 All together now release
102
+
103
+ This is a big release, where we have merged the efforts of various parties into one common library. This means there are definitely some API changes you should be aware of. They should be minimal but please have a look at the unit tests.
104
+
105
+ == 0.1.2 2007-12-1
106
+
107
+ * Fixed checks for missing OAuth params to improve performance
108
+ * Includes Pat's fix for getting the realm out.
109
+
110
+ == 0.1.1 2007-11-26
111
+
112
+ * First release as a GEM
113
+ * Moved all non-Rails functionality from the Rails plugin:
114
+ http://code.google.com/p/oauth-plugin/
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Blaine Cook, Larry Halff, Pelle Braendgaard
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,71 @@
1
+ = Ruby OAuth GEM
2
+
3
+ == What
4
+
5
+ This is a RubyGem for implementing both OAuth clients and servers in Ruby applications.
6
+
7
+ See the OAuth specs http://oauth.net/core/1.0/
8
+
9
+ == Installing
10
+
11
+ sudo gem install oauth
12
+
13
+ You can also install it from the oauth rubyforge project http://rubyforge.org/projects/oauth/.
14
+
15
+ The source code is now hosted on the OAuth GitHub Project http://github.com/mojodna/oauth
16
+
17
+ == The basics
18
+
19
+ This is a ruby library which is intended to be used in creating Ruby Consumer and Service Provider applications. It is NOT a Rails plugin, but could easily be used for the foundation for such a Rails plugin.
20
+
21
+ As a matter of fact it has been pulled out from an OAuth Rails Plugin http://code.google.com/p/oauth-plugin/ which now requires this GEM.
22
+
23
+ == Demonstration of usage
24
+
25
+ Create a new consumer instance by passing it a configuration hash:
26
+
27
+ @consumer = OAuth::Consumer.new("key","secret", :site => "https://agree2")
28
+
29
+ Start the process by requesting a token
30
+
31
+ @request_token = @consumer.get_request_token
32
+ session[:request_token] = @request_token
33
+ redirect_to @request_token.authorize_url
34
+
35
+ When user returns create an access_token
36
+
37
+ @access_token = @request_token.get_access_token
38
+ @photos = @access_token.get('/photos.xml')
39
+
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 .
41
+
42
+ Finally be sure to check out the OAuth RDoc Manual http://oauth.rubyforge.org/rdoc/ .
43
+
44
+ == Documentation Wiki
45
+
46
+ There is some documentation on the Google Code project for the "OAuth Rails Plugin":http://code.google.com/p/oauth-plugin/ :
47
+
48
+ * RequestToken http://code.google.com/p/oauth-plugin/wiki/RequestToken
49
+ * AccessToken http://code.google.com/p/oauth-plugin/wiki/AccessToken
50
+
51
+ == Forum
52
+
53
+ http://groups.google.com/group/oauth-ruby
54
+
55
+
56
+ == How to submit patches
57
+
58
+ Read the "8 steps for fixing other people's code" http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/.
59
+
60
+ The source code is now hosted on the OAuth GitHub Project http://github.com/mojodna/oauth
61
+
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.
63
+
64
+ == License
65
+
66
+ This code is free to use under the terms of the MIT license.
67
+
68
+ == Contact
69
+
70
+ Comments are welcome. Send an email to "Pelle Braendgaard" pelleb@gmail.com email via the OAuth Ruby mailing list http://groups.google.com/group/oauth-ruby
71
+
@@ -0,0 +1,58 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require "rubygems"
4
+ require "rake"
5
+
6
+ begin
7
+ require "jeweler"
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = "qoobaa-oauth"
10
+ gem.summary = %Q{OAuth Core Ruby implementation}
11
+ gem.description = %Q{OAuth Core Ruby implementation}
12
+ gem.email = "drogus@gmail.com"
13
+ gem.homepage = "http://github.com/drogus/oauth"
14
+ gem.authors = ["Piotr Sarnacki", "Jakub Kuźma"]
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ gem.add_dependency("ruby-hmac", ">= 0.3.1")
17
+ gem.add_development_dependency("actionpack")
18
+ gem.add_development_dependency("rack")
19
+ gem.add_development_dependency("mocha")
20
+ end
21
+ Jeweler::GemcutterTasks.new
22
+ rescue LoadError
23
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
24
+ end
25
+
26
+ require "rake/testtask"
27
+ Rake::TestTask.new(:test) do |test|
28
+ test.libs << "lib" << "test"
29
+ test.pattern = "test/**/test_*.rb"
30
+ test.verbose = true
31
+ end
32
+
33
+ begin
34
+ require "rcov/rcovtask"
35
+ Rcov::RcovTask.new do |test|
36
+ test.libs << "test"
37
+ test.pattern = "test/**/test_*.rb"
38
+ test.verbose = true
39
+ end
40
+ rescue LoadError
41
+ task :rcov do
42
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
43
+ end
44
+ end
45
+
46
+ task :test => :check_dependencies
47
+
48
+ task :default => :test
49
+
50
+ require "rake/rdoctask"
51
+ Rake::RDocTask.new do |rdoc|
52
+ version = File.exist?("VERSION") ? File.read("VERSION") : ""
53
+
54
+ rdoc.rdoc_dir = "rdoc"
55
+ rdoc.title = "oauth #{version}"
56
+ rdoc.rdoc_files.include("README*")
57
+ rdoc.rdoc_files.include("lib/**/*.rb")
58
+ end
data/TODO ADDED
@@ -0,0 +1,31 @@
1
+ Common use-cases should be streamlined:
2
+
3
+ * I have a URL that I want to sign (given consumer key/secret, optional
4
+ token/secret, optional nonce/timestamp).
5
+ * I have a URL that I want to sign AND I want to see what the components
6
+ (e.g. signature base string, etc.) are while it's being signed (i.e. verbose
7
+ signing).
8
+ * I have a URL that I want to sign and I only want the signature.
9
+ * I have a URL that I want to sign and I want something suitable to put in
10
+ {the header, the querystring, XMPP}.
11
+ * I want to make a query to an OAuth-enabled web service (with sensible
12
+ errors, if available).
13
+ * I want to host an OAuth-enabled web service.
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/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.8
@@ -0,0 +1,4 @@
1
+ require 'oauth/oauth'
2
+ require 'oauth/client/helper'
3
+ require 'oauth/signature/hmac/sha1'
4
+ require 'oauth/request_proxy/mock_request'
@@ -0,0 +1,378 @@
1
+ require 'optparse'
2
+ require 'oauth'
3
+
4
+ module OAuth
5
+ class CLI
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
+ }
13
+
14
+ attr_reader :command
15
+ attr_reader :options
16
+ attr_reader :stdout, :stdin
17
+
18
+ def self.execute(stdout, stdin, stderr, arguments = [])
19
+ self.new.execute(stdout, stdin, stderr, arguments)
20
+ end
21
+
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 = [])
32
+ @stdout = stdout
33
+ @stdin = stdin
34
+ @stderr = stderr
35
+ extract_command_and_parse_options(arguments)
36
+
37
+ if sufficient_options? && valid_command?
38
+ if command == "debug"
39
+ @command = "sign"
40
+ @options[:verbose] = true
41
+ end
42
+
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
113
+ when "sign"
114
+ parameters = prepare_parameters
115
+
116
+ request = OAuth::RequestProxy.proxy \
117
+ "method" => options[:method],
118
+ "uri" => options[:uri],
119
+ "parameters" => parameters
120
+
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
134
+ end
135
+ end
136
+
137
+ request.sign! \
138
+ :consumer_secret => options[:oauth_consumer_secret],
139
+ :token_secret => options[:oauth_token_secret]
140
+
141
+ if verbose?
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)}"
171
+ else
172
+ stdout.puts request.oauth_signature
173
+ end
174
+ when "version"
175
+ puts "OAuth for Ruby #{OAuth::VERSION}"
176
+ end
177
+ else
178
+ usage
179
+ end
180
+ end
181
+
182
+ protected
183
+
184
+ def extract_command_and_parse_options(arguments)
185
+ @command = arguments[-1]
186
+ parse_options(arguments[0..-1])
187
+ end
188
+
189
+ def option_parser(arguments = "")
190
+ # TODO add realm parameter
191
+ # TODO add user-agent parameter
192
+ option_parser = OptionParser.new do |opts|
193
+ opts.banner = "Usage: #{$0} [options] <command>"
194
+
195
+ # defaults
196
+ options[:oauth_nonce] = OAuth::Helper.generate_key
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
210
+
211
+ opts.on("--consumer-key KEY", "Specifies the consumer key to use.") do |v|
212
+ options[:oauth_consumer_key] = v
213
+ end
214
+
215
+ opts.on("--consumer-secret SECRET", "Specifies the consumer secret to use.") do |v|
216
+ options[:oauth_consumer_secret] = v
217
+ end
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
+
235
+ opts.on("--method METHOD", "Specifies the method (e.g. GET) to use when signing.") do |v|
236
+ options[:method] = v
237
+ end
238
+
239
+ opts.on("--nonce NONCE", "Specifies the none to use.") do |v|
240
+ options[:oauth_nonce] = v
241
+ end
242
+
243
+ opts.on("--parameters PARAMS", "Specifies the parameters to use when signing.") do |v|
244
+ options[:params] << v
245
+ end
246
+
247
+ opts.on("--signature-method METHOD", "Specifies the signature method to use; defaults to HMAC-SHA1.") do |v|
248
+ options[:oauth_signature_method] = v
249
+ end
250
+
251
+ opts.on("--secret SECRET", "Specifies the token secret to use.") do |v|
252
+ options[:oauth_token_secret] = v
253
+ end
254
+
255
+ opts.on("--timestamp TIMESTAMP", "Specifies the timestamp to use.") do |v|
256
+ options[:oauth_timestamp] = v
257
+ end
258
+
259
+ opts.on("--token TOKEN", "Specifies the token to use.") do |v|
260
+ options[:oauth_token] = v
261
+ end
262
+
263
+ opts.on("--realm REALM", "Specifies the realm to use.") do |v|
264
+ options[:realm] = v
265
+ end
266
+
267
+ opts.on("--uri URI", "Specifies the URI to use when signing.") do |v|
268
+ options[:uri] = v
269
+ end
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
+
288
+ opts.on("-v", "--verbose", "Be verbose.") do
289
+ options[:verbose] = true
290
+ end
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)
320
+ end
321
+
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
+
336
+ {
337
+ "oauth_consumer_key" => options[:oauth_consumer_key],
338
+ "oauth_nonce" => options[:oauth_nonce],
339
+ "oauth_timestamp" => options[:oauth_timestamp],
340
+ "oauth_token" => options[:oauth_token],
341
+ "oauth_signature_method" => options[:oauth_signature_method],
342
+ "oauth_version" => options[:oauth_version]
343
+ }.reject { |k,v| v.nil? || v == "" }.merge(cli_params)
344
+ end
345
+
346
+ def sufficient_options?
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
359
+ end
360
+
361
+ def usage
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
368
+ end
369
+
370
+ def valid_command?
371
+ SUPPORTED_COMMANDS.keys.include?(command)
372
+ end
373
+
374
+ def verbose?
375
+ options[:verbose]
376
+ end
377
+ end
378
+ end