motionbox-oauth 0.4.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 (88) hide show
  1. data/.gemtest +0 -0
  2. data/Gemfile +16 -0
  3. data/Gemfile.lock +46 -0
  4. data/HISTORY +160 -0
  5. data/LICENSE +20 -0
  6. data/README.rdoc +75 -0
  7. data/Rakefile +37 -0
  8. data/TODO +32 -0
  9. data/bin/oauth +5 -0
  10. data/examples/yql.rb +44 -0
  11. data/lib/digest/hmac.rb +104 -0
  12. data/lib/oauth.rb +13 -0
  13. data/lib/oauth/cli.rb +378 -0
  14. data/lib/oauth/client.rb +4 -0
  15. data/lib/oauth/client/action_controller_request.rb +65 -0
  16. data/lib/oauth/client/em_http.rb +124 -0
  17. data/lib/oauth/client/helper.rb +91 -0
  18. data/lib/oauth/client/net_http.rb +120 -0
  19. data/lib/oauth/consumer.rb +382 -0
  20. data/lib/oauth/core_ext.rb +31 -0
  21. data/lib/oauth/errors.rb +3 -0
  22. data/lib/oauth/errors/error.rb +4 -0
  23. data/lib/oauth/errors/problem.rb +14 -0
  24. data/lib/oauth/errors/unauthorized.rb +12 -0
  25. data/lib/oauth/helper.rb +88 -0
  26. data/lib/oauth/oauth.rb +13 -0
  27. data/lib/oauth/oauth_test_helper.rb +25 -0
  28. data/lib/oauth/request_proxy.rb +24 -0
  29. data/lib/oauth/request_proxy/action_controller_request.rb +62 -0
  30. data/lib/oauth/request_proxy/base.rb +174 -0
  31. data/lib/oauth/request_proxy/curb_request.rb +55 -0
  32. data/lib/oauth/request_proxy/em_http_request.rb +74 -0
  33. data/lib/oauth/request_proxy/jabber_request.rb +41 -0
  34. data/lib/oauth/request_proxy/mock_request.rb +44 -0
  35. data/lib/oauth/request_proxy/net_http.rb +72 -0
  36. data/lib/oauth/request_proxy/rack_request.rb +44 -0
  37. data/lib/oauth/request_proxy/typhoeus_request.rb +53 -0
  38. data/lib/oauth/server.rb +66 -0
  39. data/lib/oauth/signature.rb +45 -0
  40. data/lib/oauth/signature/base.rb +110 -0
  41. data/lib/oauth/signature/hmac/base.rb +15 -0
  42. data/lib/oauth/signature/hmac/md5.rb +8 -0
  43. data/lib/oauth/signature/hmac/rmd160.rb +8 -0
  44. data/lib/oauth/signature/hmac/sha1.rb +9 -0
  45. data/lib/oauth/signature/hmac/sha2.rb +8 -0
  46. data/lib/oauth/signature/md5.rb +13 -0
  47. data/lib/oauth/signature/plaintext.rb +23 -0
  48. data/lib/oauth/signature/rsa/sha1.rb +46 -0
  49. data/lib/oauth/signature/sha1.rb +13 -0
  50. data/lib/oauth/token.rb +7 -0
  51. data/lib/oauth/tokens/access_token.rb +71 -0
  52. data/lib/oauth/tokens/consumer_token.rb +33 -0
  53. data/lib/oauth/tokens/request_token.rb +32 -0
  54. data/lib/oauth/tokens/server_token.rb +9 -0
  55. data/lib/oauth/tokens/token.rb +17 -0
  56. data/oauth.gemspec +150 -0
  57. data/tasks/deployment.rake +34 -0
  58. data/tasks/environment.rake +7 -0
  59. data/tasks/website.rake +17 -0
  60. data/test/cases/oauth_case.rb +19 -0
  61. data/test/cases/spec/1_0-final/test_construct_request_url.rb +62 -0
  62. data/test/cases/spec/1_0-final/test_normalize_request_parameters.rb +88 -0
  63. data/test/cases/spec/1_0-final/test_parameter_encodings.rb +86 -0
  64. data/test/cases/spec/1_0-final/test_signature_base_strings.rb +77 -0
  65. data/test/integration/consumer_test.rb +307 -0
  66. data/test/keys/rsa.cert +11 -0
  67. data/test/keys/rsa.pem +16 -0
  68. data/test/test_access_token.rb +26 -0
  69. data/test/test_action_controller_request_proxy.rb +133 -0
  70. data/test/test_consumer.rb +171 -0
  71. data/test/test_curb_request_proxy.rb +77 -0
  72. data/test/test_em_http_client.rb +80 -0
  73. data/test/test_em_http_request_proxy.rb +115 -0
  74. data/test/test_helper.rb +26 -0
  75. data/test/test_hmac_sha1.rb +20 -0
  76. data/test/test_net_http_client.rb +280 -0
  77. data/test/test_net_http_request_proxy.rb +72 -0
  78. data/test/test_oauth_helper.rb +71 -0
  79. data/test/test_rack_request_proxy.rb +40 -0
  80. data/test/test_request_token.rb +51 -0
  81. data/test/test_rsa_sha1.rb +59 -0
  82. data/test/test_server.rb +40 -0
  83. data/test/test_signature.rb +22 -0
  84. data/test/test_signature_base.rb +32 -0
  85. data/test/test_signature_plain_text.rb +31 -0
  86. data/test/test_token.rb +14 -0
  87. data/test/test_typhoeus_request_proxy.rb +80 -0
  88. metadata +284 -0
@@ -0,0 +1,45 @@
1
+ module OAuth
2
+ module Signature
3
+ # Returns a list of available signature methods
4
+ def self.available_methods
5
+ @available_methods ||= {}
6
+ end
7
+
8
+ # Build a signature from a +request+.
9
+ #
10
+ # Raises UnknownSignatureMethod exception if the signature method is unknown.
11
+ def self.build(request, options = {}, &block)
12
+ request = OAuth::RequestProxy.proxy(request, options)
13
+ klass = available_methods[
14
+ (request.signature_method ||
15
+ ((c = request.options[:consumer]) && c.options[:signature_method]) ||
16
+ "").downcase]
17
+ raise UnknownSignatureMethod, request.signature_method unless klass
18
+ klass.new(request, options, &block)
19
+ end
20
+
21
+ # Sign a +request+
22
+ def self.sign(request, options = {}, &block)
23
+ self.build(request, options, &block).signature
24
+ end
25
+
26
+ # Verify the signature of +request+
27
+ def self.verify(request, options = {}, &block)
28
+ self.build(request, options, &block).verify
29
+ end
30
+
31
+ # Create the signature base string for +request+. This string is the normalized parameter information.
32
+ #
33
+ # See Also: {OAuth core spec version 1.0, section 9.1.1}[http://oauth.net/core/1.0#rfc.section.9.1.1]
34
+ def self.signature_base_string(request, options = {}, &block)
35
+ self.build(request, options, &block).signature_base_string
36
+ end
37
+
38
+ # Create the body hash for a request
39
+ def self.body_hash(request, options = {}, &block)
40
+ self.build(request, options, &block).body_hash
41
+ end
42
+
43
+ class UnknownSignatureMethod < Exception; end
44
+ end
45
+ end
@@ -0,0 +1,110 @@
1
+ require 'oauth/signature'
2
+ require 'oauth/helper'
3
+ require 'oauth/request_proxy/base'
4
+ require 'base64'
5
+
6
+ module OAuth::Signature
7
+ class Base
8
+ include OAuth::Helper
9
+
10
+ attr_accessor :options
11
+ attr_reader :token_secret, :consumer_secret, :request
12
+
13
+ def self.implements(signature_method = nil)
14
+ return @implements if signature_method.nil?
15
+ @implements = signature_method
16
+ OAuth::Signature.available_methods[@implements] = self
17
+ end
18
+
19
+ def self.digest_class(digest_class = nil)
20
+ return @digest_class if digest_class.nil?
21
+ @digest_class = digest_class
22
+ end
23
+
24
+ def self.digest_klass(digest_klass = nil)
25
+ return @digest_klass if digest_klass.nil?
26
+ @digest_klass = digest_klass
27
+ end
28
+
29
+ def self.hash_class(hash_class = nil)
30
+ return @hash_class if hash_class.nil?
31
+ @hash_class = hash_class
32
+ end
33
+
34
+ def initialize(request, options = {}, &block)
35
+ raise TypeError unless request.kind_of?(OAuth::RequestProxy::Base)
36
+ @request = request
37
+ @options = options
38
+
39
+ ## consumer secret was determined beforehand
40
+
41
+ @consumer_secret = options[:consumer].secret if options[:consumer]
42
+
43
+ # presence of :consumer_secret option will override any Consumer that's provided
44
+ @consumer_secret = options[:consumer_secret] if options[:consumer_secret]
45
+
46
+ ## token secret was determined beforehand
47
+
48
+ @token_secret = options[:token].secret if options[:token]
49
+
50
+ # presence of :token_secret option will override any Token that's provided
51
+ @token_secret = options[:token_secret] if options[:token_secret]
52
+
53
+ # override secrets based on the values returned from the block (if any)
54
+ if block_given?
55
+ # consumer secret and token secret need to be looked up based on pieces of the request
56
+ secrets = yield block.arity == 1 ? request : [token, consumer_key, nonce, request.timestamp]
57
+ if secrets.is_a?(Array) && secrets.size == 2
58
+ @token_secret = secrets[0]
59
+ @consumer_secret = secrets[1]
60
+ end
61
+ end
62
+ end
63
+
64
+ def signature
65
+ Base64.encode64(digest).chomp.gsub(/\n/,'')
66
+ end
67
+
68
+ def ==(cmp_signature)
69
+ Base64.decode64(signature) == Base64.decode64(cmp_signature)
70
+ end
71
+
72
+ def verify
73
+ self == self.request.signature
74
+ end
75
+
76
+ def signature_base_string
77
+ request.signature_base_string
78
+ end
79
+
80
+ def body_hash
81
+ if self.class.hash_class
82
+ Base64.encode64(self.class.hash_class.digest(request.body || '')).chomp.gsub(/\n/,'')
83
+ else
84
+ nil # no body hash algorithm defined, so don't generate one
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def token
91
+ request.token
92
+ end
93
+
94
+ def consumer_key
95
+ request.consumer_key
96
+ end
97
+
98
+ def nonce
99
+ request.nonce
100
+ end
101
+
102
+ def secret
103
+ "#{escape(consumer_secret)}&#{escape(token_secret)}"
104
+ end
105
+
106
+ def digest
107
+ self.class.digest_class.digest(signature_base_string)
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,15 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'oauth/signature/base'
4
+ require 'digest/hmac'
5
+
6
+ module OAuth::Signature::HMAC
7
+ class Base < OAuth::Signature::Base
8
+
9
+ private
10
+ def digest
11
+ self.class.digest_class Object.module_eval("::Digest::#{self.class.digest_klass}")
12
+ Digest::HMAC.digest(signature_base_string, secret, self.class.digest_class)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,8 @@
1
+ require 'oauth/signature/hmac/base'
2
+
3
+ module OAuth::Signature::HMAC
4
+ class MD5 < Base
5
+ implements 'hmac-md5'
6
+ digest_class 'MD5'
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'oauth/signature/hmac/base'
2
+
3
+ module OAuth::Signature::HMAC
4
+ class RMD160 < Base
5
+ implements 'hmac-rmd160'
6
+ digest_klass 'RMD160'
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ require 'oauth/signature/hmac/base'
2
+
3
+ module OAuth::Signature::HMAC
4
+ class SHA1 < Base
5
+ implements 'hmac-sha1'
6
+ digest_klass 'SHA1'
7
+ hash_class ::Digest::SHA1
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ require 'oauth/signature/hmac/base'
2
+
3
+ module OAuth::Signature::HMAC
4
+ class SHA2 < Base
5
+ implements 'hmac-sha2'
6
+ digest_klass 'SHA2'
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ require 'oauth/signature/base'
2
+ require 'digest/md5'
3
+
4
+ module OAuth::Signature
5
+ class MD5 < Base
6
+ implements 'md5'
7
+ digest_class Digest::MD5
8
+
9
+ def signature_base_string
10
+ secret + super
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ require 'oauth/signature/base'
2
+
3
+ module OAuth::Signature
4
+ class PLAINTEXT < Base
5
+ implements 'plaintext'
6
+
7
+ def signature
8
+ signature_base_string
9
+ end
10
+
11
+ def ==(cmp_signature)
12
+ signature.to_s == cmp_signature.to_s
13
+ end
14
+
15
+ def signature_base_string
16
+ secret
17
+ end
18
+
19
+ def secret
20
+ super
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,46 @@
1
+ require 'oauth/signature/base'
2
+ require 'openssl'
3
+
4
+ module OAuth::Signature::RSA
5
+ class SHA1 < OAuth::Signature::Base
6
+ implements 'rsa-sha1'
7
+ hash_class ::Digest::SHA1
8
+
9
+ def ==(cmp_signature)
10
+ public_key.verify(OpenSSL::Digest::SHA1.new, Base64.decode64(cmp_signature.is_a?(Array) ? cmp_signature.first : cmp_signature), signature_base_string)
11
+ end
12
+
13
+ def public_key
14
+ if consumer_secret.is_a?(String)
15
+ decode_public_key
16
+ elsif consumer_secret.is_a?(OpenSSL::X509::Certificate)
17
+ consumer_secret.public_key
18
+ else
19
+ consumer_secret
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def decode_public_key
26
+ case consumer_secret
27
+ when /-----BEGIN CERTIFICATE-----/
28
+ OpenSSL::X509::Certificate.new( consumer_secret).public_key
29
+ else
30
+ OpenSSL::PKey::RSA.new( consumer_secret)
31
+ end
32
+ end
33
+
34
+ def digest
35
+ private_key = OpenSSL::PKey::RSA.new(
36
+ if options[:private_key_file]
37
+ IO.read(options[:private_key_file])
38
+ else
39
+ consumer_secret
40
+ end
41
+ )
42
+
43
+ private_key.sign(OpenSSL::Digest::SHA1.new, signature_base_string)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ require 'oauth/signature/base'
2
+ require 'digest/sha1'
3
+
4
+ module OAuth::Signature
5
+ class SHA1 < Base
6
+ implements 'sha1'
7
+ digest_class Digest::SHA1
8
+
9
+ def signature_base_string
10
+ secret + super
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ # this exists for backwards-compatibility
2
+
3
+ require 'oauth/tokens/token'
4
+ require 'oauth/tokens/server_token'
5
+ require 'oauth/tokens/consumer_token'
6
+ require 'oauth/tokens/request_token'
7
+ require 'oauth/tokens/access_token'
@@ -0,0 +1,71 @@
1
+ module OAuth
2
+ # The Access Token is used for the actual "real" web service calls that you perform against the server
3
+ class AccessToken < ConsumerToken
4
+ # The less intrusive way. Otherwise, if we are to do it correctly inside consumer,
5
+ # we need to restructure and touch more methods: request(), sign!(), etc.
6
+ def request(http_method, path, *arguments)
7
+ request_uri = URI.parse(path)
8
+ site_uri = consumer.uri
9
+ is_service_uri_different = (request_uri.absolute? && request_uri != site_uri)
10
+ begin
11
+ consumer.uri(request_uri) if is_service_uri_different
12
+ @response = super(http_method, path, *arguments)
13
+ ensure
14
+ # NOTE: reset for wholesomeness? meaning that we admit only AccessToken service calls may use different URIs?
15
+ # so reset in case consumer is still used for other token-management tasks subsequently?
16
+ consumer.uri(site_uri) if is_service_uri_different
17
+ end
18
+ @response
19
+ end
20
+
21
+ # Make a regular GET request using AccessToken
22
+ #
23
+ # @response = @token.get('/people')
24
+ # @response = @token.get('/people', { 'Accept'=>'application/xml' })
25
+ #
26
+ def get(path, headers = {})
27
+ request(:get, path, headers)
28
+ end
29
+
30
+ # Make a regular HEAD request using AccessToken
31
+ #
32
+ # @response = @token.head('/people')
33
+ #
34
+ def head(path, headers = {})
35
+ request(:head, path, headers)
36
+ end
37
+
38
+ # Make a regular POST request using AccessToken
39
+ #
40
+ # @response = @token.post('/people')
41
+ # @response = @token.post('/people', { :name => 'Bob', :email => 'bob@mailinator.com' })
42
+ # @response = @token.post('/people', { :name => 'Bob', :email => 'bob@mailinator.com' }, { 'Accept' => 'application/xml' })
43
+ # @response = @token.post('/people', nil, {'Accept' => 'application/xml' })
44
+ # @response = @token.post('/people', @person.to_xml, { 'Accept'=>'application/xml', 'Content-Type' => 'application/xml' })
45
+ #
46
+ def post(path, body = '', headers = {})
47
+ request(:post, path, body, headers)
48
+ end
49
+
50
+ # Make a regular PUT request using AccessToken
51
+ #
52
+ # @response = @token.put('/people/123')
53
+ # @response = @token.put('/people/123', { :name => 'Bob', :email => 'bob@mailinator.com' })
54
+ # @response = @token.put('/people/123', { :name => 'Bob', :email => 'bob@mailinator.com' }, { 'Accept' => 'application/xml' })
55
+ # @response = @token.put('/people/123', nil, { 'Accept' => 'application/xml' })
56
+ # @response = @token.put('/people/123', @person.to_xml, { 'Accept' => 'application/xml', 'Content-Type' => 'application/xml' })
57
+ #
58
+ def put(path, body = '', headers = {})
59
+ request(:put, path, body, headers)
60
+ end
61
+
62
+ # Make a regular DELETE request using AccessToken
63
+ #
64
+ # @response = @token.delete('/people/123')
65
+ # @response = @token.delete('/people/123', { 'Accept' => 'application/xml' })
66
+ #
67
+ def delete(path, headers = {})
68
+ request(:delete, path, headers)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,33 @@
1
+ module OAuth
2
+ # Superclass for tokens used by OAuth Clients
3
+ class ConsumerToken < Token
4
+ attr_accessor :consumer, :params
5
+ attr_reader :response
6
+
7
+ def self.from_hash(consumer, hash)
8
+ token = self.new(consumer, hash[:oauth_token], hash[:oauth_token_secret])
9
+ token.params = hash
10
+ token
11
+ end
12
+
13
+ def initialize(consumer, token="", secret="")
14
+ super(token, secret)
15
+ @consumer = consumer
16
+ @params = {}
17
+ end
18
+
19
+ # Make a signed request using given http_method to the path
20
+ #
21
+ # @token.request(:get, '/people')
22
+ # @token.request(:post, '/people', @person.to_xml, { 'Content-Type' => 'application/xml' })
23
+ #
24
+ def request(http_method, path, *arguments)
25
+ @response = consumer.request(http_method, path, self, {}, *arguments)
26
+ end
27
+
28
+ # Sign a request generated elsewhere using Net:HTTP::Post.new or friends
29
+ def sign!(request, options = {})
30
+ consumer.sign!(request, self, options)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ module OAuth
2
+ # The RequestToken is used for the initial Request.
3
+ # This is normally created by the Consumer object.
4
+ class RequestToken < ConsumerToken
5
+
6
+ # Generate an authorization URL for user authorization
7
+ def authorize_url(params = nil)
8
+ params = (params || {}).merge(:oauth_token => self.token)
9
+ build_authorize_url(consumer.authorize_url, params)
10
+ end
11
+
12
+ def callback_confirmed?
13
+ params[:oauth_callback_confirmed] == "true"
14
+ end
15
+
16
+ # exchange for AccessToken on server
17
+ def get_access_token(options = {}, *arguments)
18
+ response = consumer.token_request(consumer.http_method, (consumer.access_token_url? ? consumer.access_token_url : consumer.access_token_path), self, options, *arguments)
19
+ OAuth::AccessToken.from_hash(consumer, response)
20
+ end
21
+
22
+ protected
23
+
24
+ # construct an authorization url
25
+ def build_authorize_url(base_url, params)
26
+ uri = URI.parse(base_url.to_s)
27
+ # TODO doesn't handle array values correctly
28
+ uri.query = params.map { |k,v| [k, CGI.escape(v)] * "=" } * "&"
29
+ uri.to_s
30
+ end
31
+ end
32
+ end