af-oauth 0.3.4.1

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 (85) hide show
  1. data/History.txt +83 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +84 -0
  4. data/README.rdoc +71 -0
  5. data/Rakefile +36 -0
  6. data/TODO +31 -0
  7. data/bin/oauth +5 -0
  8. data/examples/yql.rb +44 -0
  9. data/lib/oauth.rb +4 -0
  10. data/lib/oauth/cli.rb +300 -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 +81 -0
  14. data/lib/oauth/client/net_http.rb +94 -0
  15. data/lib/oauth/consumer.rb +297 -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 +77 -0
  21. data/lib/oauth/oauth.rb +7 -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 +63 -0
  25. data/lib/oauth/request_proxy/base.rb +159 -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/server.rb +66 -0
  31. data/lib/oauth/signature.rb +37 -0
  32. data/lib/oauth/signature/base.rb +99 -0
  33. data/lib/oauth/signature/hmac/base.rb +12 -0
  34. data/lib/oauth/signature/hmac/md5.rb +9 -0
  35. data/lib/oauth/signature/hmac/rmd160.rb +9 -0
  36. data/lib/oauth/signature/hmac/sha1.rb +9 -0
  37. data/lib/oauth/signature/hmac/sha2.rb +9 -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 +32 -0
  45. data/lib/oauth/tokens/request_token.rb +28 -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/oauth.gemspec +49 -0
  50. data/script/destroy +14 -0
  51. data/script/generate +14 -0
  52. data/script/txt2html +74 -0
  53. data/setup.rb +1585 -0
  54. data/tasks/deployment.rake +34 -0
  55. data/tasks/environment.rake +7 -0
  56. data/tasks/website.rake +17 -0
  57. data/test/cases/oauth_case.rb +19 -0
  58. data/test/cases/spec/1_0-final/test_construct_request_url.rb +62 -0
  59. data/test/cases/spec/1_0-final/test_normalize_request_parameters.rb +88 -0
  60. data/test/cases/spec/1_0-final/test_parameter_encodings.rb +86 -0
  61. data/test/cases/spec/1_0-final/test_signature_base_strings.rb +77 -0
  62. data/test/keys/rsa.cert +11 -0
  63. data/test/keys/rsa.pem +16 -0
  64. data/test/test_access_token.rb +28 -0
  65. data/test/test_action_controller_request_proxy.rb +127 -0
  66. data/test/test_consumer.rb +327 -0
  67. data/test/test_helper.rb +10 -0
  68. data/test/test_hmac_sha1.rb +21 -0
  69. data/test/test_net_http_client.rb +187 -0
  70. data/test/test_net_http_request_proxy.rb +73 -0
  71. data/test/test_oauth_helper.rb +50 -0
  72. data/test/test_rack_request_proxy.rb +40 -0
  73. data/test/test_request_token.rb +53 -0
  74. data/test/test_rsa_sha1.rb +59 -0
  75. data/test/test_server.rb +40 -0
  76. data/test/test_signature.rb +19 -0
  77. data/test/test_signature_base.rb +32 -0
  78. data/test/test_signature_plain_text.rb +31 -0
  79. data/test/test_token.rb +14 -0
  80. data/website/index.html +87 -0
  81. data/website/index.txt +73 -0
  82. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  83. data/website/stylesheets/screen.css +138 -0
  84. data/website/template.rhtml +48 -0
  85. metadata +241 -0
@@ -0,0 +1,3 @@
1
+ require 'oauth/errors/error'
2
+ require 'oauth/errors/unauthorized'
3
+ require 'oauth/errors/problem'
@@ -0,0 +1,4 @@
1
+ module OAuth
2
+ class Error < StandardError
3
+ end
4
+ end
@@ -0,0 +1,14 @@
1
+ module OAuth
2
+ class Problem < OAuth::Unauthorized
3
+ attr_reader :problem, :params
4
+ def initialize(problem, request = nil, params = {})
5
+ super(request)
6
+ @problem = problem
7
+ @params = params
8
+ end
9
+
10
+ def to_s
11
+ problem
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ module OAuth
2
+ class Unauthorized < OAuth::Error
3
+ attr_reader :request
4
+ def initialize(request = nil)
5
+ @request = request
6
+ end
7
+
8
+ def to_s
9
+ [request.code, request.message] * " "
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,77 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ module OAuth
5
+ module Helper
6
+ extend self
7
+
8
+ # Escape +value+ by URL encoding all non-reserved character.
9
+ #
10
+ # See Also: {OAuth core spec version 1.0, section 5.1}[http://oauth.net/core/1.0#rfc.section.5.1]
11
+ def escape(value)
12
+ URI::escape(value.to_s, OAuth::RESERVED_CHARACTERS)
13
+ end
14
+
15
+ # Generate a random key of up to +size+ bytes. The value returned is Base64 encoded with non-word
16
+ # characters removed.
17
+ def generate_key(size=32)
18
+ Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/, '')
19
+ end
20
+
21
+ alias_method :generate_nonce, :generate_key
22
+
23
+ def generate_timestamp #:nodoc:
24
+ Time.now.to_i.to_s
25
+ end
26
+
27
+ # Normalize a +Hash+ of parameter values. Parameters are sorted by name, using lexicographical
28
+ # byte value ordering. If two or more parameters share the same name, they are sorted by their value.
29
+ # Parameters are concatenated in their sorted order into a single string. For each parameter, the name
30
+ # is separated from the corresponding value by an "=" character, even if the value is empty. Each
31
+ # name-value pair is separated by an "&" character.
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 normalize(params)
35
+ params.sort.map do |k, values|
36
+ if values.is_a?(Array)
37
+ # multiple values were provided for a single key
38
+ values.sort.collect do |v|
39
+ ["#{escape(k+'[]')}",escape(v)] * "="
40
+ end
41
+ else
42
+ [escape(k),escape(values)] * "="
43
+ end
44
+ end * "&"
45
+ end
46
+
47
+ # Parse an Authorization / WWW-Authenticate header into a hash. Takes care of unescaping and
48
+ # removing surrounding quotes. Raises a OAuth::Problem if the header is not parsable into a
49
+ # valid hash. Does not validate the keys or values.
50
+ #
51
+ # hash = parse_header(headers['Authorization'] || headers['WWW-Authenticate'])
52
+ # hash['oauth_timestamp']
53
+ # #=>"1234567890"
54
+ #
55
+ def parse_header(header)
56
+ # decompose
57
+ params = header[6,header.length].split(/[,=]/)
58
+
59
+ # odd number of arguments - must be a malformed header.
60
+ raise OAuth::Problem.new("Invalid authorization header") if params.size % 2 != 0
61
+
62
+ params.map! do |v|
63
+ # strip and unescape
64
+ val = unescape(v.strip)
65
+ # strip quotes
66
+ val.sub(/^\"(.*)\"$/, '\1')
67
+ end
68
+
69
+ # convert into a Hash
70
+ Hash[*params.flatten]
71
+ end
72
+
73
+ def unescape(value)
74
+ URI.unescape(value.gsub('+', '%2B'))
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,7 @@
1
+ module OAuth
2
+ # required parameters, per sections 6.1.1, 6.3.1, and 7
3
+ PARAMETERS = %w(oauth_consumer_key oauth_token oauth_signature_method oauth_timestamp oauth_nonce oauth_version oauth_signature)
4
+
5
+ # reserved character regexp, per section 5.1
6
+ RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~]/
7
+ end
@@ -0,0 +1,25 @@
1
+ require 'action_controller'
2
+ require 'action_controller/test_process'
3
+
4
+ module OAuth
5
+ module OAuthTestHelper
6
+ def mock_incoming_request_with_query(request)
7
+ incoming = ActionController::TestRequest.new(request.to_hash)
8
+ incoming.request_uri = request.path
9
+ incoming.host = request.uri.host
10
+ incoming.env["SERVER_PORT"] = request.uri.port
11
+ incoming.env['REQUEST_METHOD'] = request.http_method
12
+ incoming
13
+ end
14
+
15
+ def mock_incoming_request_with_authorize_header(request)
16
+ incoming = ActionController::TestRequest.new
17
+ incoming.request_uri = request.path
18
+ incoming.host = request.uri.host
19
+ incoming.env["HTTP_AUTHORIZATION"] = request.to_auth_string
20
+ incoming.env["SERVER_PORT"] = request.uri.port
21
+ incoming.env['REQUEST_METHOD'] = request.http_method
22
+ incoming
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ module OAuth
2
+ module RequestProxy
3
+ def self.available_proxies #:nodoc:
4
+ @available_proxies ||= {}
5
+ end
6
+
7
+ def self.proxy(request, options = {})
8
+ return request if request.kind_of?(OAuth::RequestProxy::Base)
9
+
10
+ klass = available_proxies[request.class]
11
+
12
+ # Search for possible superclass matches.
13
+ if klass.nil?
14
+ request_parent = available_proxies.keys.find { |rc| request.kind_of?(rc) }
15
+ klass = available_proxies[request_parent]
16
+ end
17
+
18
+ raise UnknownRequestType, request.class.to_s unless klass
19
+ klass.new(request, options)
20
+ end
21
+
22
+ class UnknownRequestType < Exception; end
23
+ end
24
+ end
@@ -0,0 +1,63 @@
1
+ require 'active_support'
2
+ require 'action_controller/request'
3
+ require 'oauth/request_proxy/base'
4
+ require 'uri'
5
+
6
+ module OAuth::RequestProxy
7
+ class ActionControllerRequest < OAuth::RequestProxy::Base
8
+ proxies(defined?(ActionController::AbstractRequest) ? ActionController::AbstractRequest : ActionController::Request)
9
+
10
+ def method
11
+ request.method.to_s.upcase
12
+ end
13
+
14
+ def uri
15
+ request.url
16
+ end
17
+
18
+ def parameters
19
+ if options[:clobber_request]
20
+ options[:parameters] || {}
21
+ else
22
+ params = request_params.merge(query_params).merge(header_params)
23
+ params.stringify_keys! if params.respond_to?(:stringify_keys!)
24
+ params.merge(options[:parameters] || {})
25
+ end
26
+ end
27
+
28
+ # Override from OAuth::RequestProxy::Base to avoid roundtrip
29
+ # conversion to Hash or Array and thus preserve the original
30
+ # parameter names
31
+ def parameters_for_signature
32
+ params = []
33
+ params << options[:parameters].to_query if options[:parameters]
34
+
35
+ unless options[:clobber_request]
36
+ params << header_params.to_query
37
+ params << request.query_string unless request.query_string.blank?
38
+ if request.post? && request.content_type == Mime::Type.lookup("application/x-www-form-urlencoded")
39
+ params << request.raw_post
40
+ elsif request.post? && request.content_type == Mime::Type.lookup("multipart/form-data")
41
+ return super
42
+ end
43
+ end
44
+
45
+ params.
46
+ join('&').split('&').
47
+ reject(&:blank?).
48
+ map { |p| p.split('=').map{|esc| CGI.unescape(esc)} }.
49
+ reject { |kv| kv[0] == 'oauth_signature'}
50
+ end
51
+
52
+ protected
53
+
54
+ def query_params
55
+ request.query_parameters
56
+ end
57
+
58
+ def request_params
59
+ request.request_parameters
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,159 @@
1
+ require 'oauth/request_proxy'
2
+ require 'oauth/helper'
3
+
4
+ module OAuth::RequestProxy
5
+ class Base
6
+ include OAuth::Helper
7
+
8
+ def self.proxies(klass)
9
+ OAuth::RequestProxy.available_proxies[klass] = self
10
+ end
11
+
12
+ attr_accessor :request, :options
13
+
14
+ def initialize(request, options = {})
15
+ @request = request
16
+ @options = options
17
+ end
18
+
19
+ ## OAuth parameters
20
+
21
+ def oauth_consumer_key
22
+ parameters['oauth_consumer_key']
23
+ end
24
+
25
+ def oauth_nonce
26
+ parameters['oauth_nonce']
27
+ end
28
+
29
+ def oauth_signature
30
+ # TODO can this be nil?
31
+ parameters['oauth_signature'] || ""
32
+ end
33
+
34
+ def oauth_signature_method
35
+ case parameters['oauth_signature_method']
36
+ when Array
37
+ parameters['oauth_signature_method'].first
38
+ else
39
+ parameters['oauth_signature_method']
40
+ end
41
+ end
42
+
43
+ def oauth_timestamp
44
+ parameters['oauth_timestamp']
45
+ end
46
+
47
+ def oauth_token
48
+ parameters['oauth_token']
49
+ end
50
+
51
+ def oauth_version
52
+ parameters["oauth_version"]
53
+ end
54
+
55
+ # TODO deprecate these
56
+ alias_method :consumer_key, :oauth_consumer_key
57
+ alias_method :token, :oauth_token
58
+ alias_method :nonce, :oauth_nonce
59
+ alias_method :timestamp, :oauth_timestamp
60
+ alias_method :signature, :oauth_signature
61
+ alias_method :signature_method, :oauth_signature_method
62
+
63
+ ## Parameter accessors
64
+
65
+ def parameters
66
+ raise NotImplementedError, "Must be implemented by subclasses"
67
+ end
68
+
69
+ def parameters_for_signature
70
+ parameters.reject do |k,v|
71
+ k == "oauth_signature" || v.respond_to?(:read)
72
+ end
73
+ end
74
+
75
+ def oauth_parameters
76
+ parameters.select { |k,v| OAuth::PARAMETERS.include?(k) }.reject { |k,v| v == "" }
77
+ end
78
+
79
+ def non_oauth_parameters
80
+ parameters.reject { |k,v| OAuth::PARAMETERS.include?(k) }
81
+ end
82
+
83
+ # See 9.1.2 in specs
84
+ def normalized_uri
85
+ u = URI.parse(uri)
86
+ "#{u.scheme.downcase}://#{u.host.downcase}#{(u.scheme.downcase == 'http' && u.port != 80) || (u.scheme.downcase == 'https' && u.port != 443) ? ":#{u.port}" : ""}#{(u.path && u.path != '') ? u.path : '/'}"
87
+ end
88
+
89
+ # See 9.1.1. in specs Normalize Request Parameters
90
+ def normalized_parameters
91
+ normalize(parameters_for_signature)
92
+ end
93
+
94
+ def sign(options = {})
95
+ OAuth::Signature.sign(self, options)
96
+ end
97
+
98
+ def sign!(options = {})
99
+ parameters["oauth_signature"] = sign(options)
100
+ @signed = true
101
+ signature
102
+ end
103
+
104
+ # See 9.1 in specs
105
+ def signature_base_string
106
+ base = [method, normalized_uri, normalized_parameters]
107
+ base.map { |v| escape(v) }.join("&")
108
+ end
109
+
110
+ # Has this request been signed yet?
111
+ def signed?
112
+ @signed
113
+ end
114
+
115
+ # URI, including OAuth parameters
116
+ def signed_uri(with_oauth = true)
117
+ if signed?
118
+ if with_oauth
119
+ params = parameters
120
+ else
121
+ params = non_oauth_parameters
122
+ end
123
+
124
+ [uri, normalize(params)] * "?"
125
+ else
126
+ STDERR.puts "This request has not yet been signed!"
127
+ end
128
+ end
129
+
130
+ # Authorization header for OAuth
131
+ def oauth_header(options = {})
132
+ header_params_str = oauth_parameters.map { |k,v| "#{k}=\"#{escape(v)}\"" }.join(', ')
133
+
134
+ realm = "realm=\"#{options[:realm]}\", " if options[:realm]
135
+ "OAuth #{realm}#{header_params_str}"
136
+ end
137
+
138
+ protected
139
+
140
+ def header_params
141
+ %w( X-HTTP_AUTHORIZATION Authorization HTTP_AUTHORIZATION ).each do |header|
142
+ next unless request.env.include?(header)
143
+
144
+ header = request.env[header]
145
+ next unless header[0,6] == 'OAuth '
146
+
147
+ # parse the header into a Hash
148
+ oauth_params = OAuth::Helper.parse_header(header)
149
+
150
+ # remove non-OAuth parameters
151
+ oauth_params.reject! { |k,v| k !~ /^oauth_/ }
152
+
153
+ return oauth_params
154
+ end
155
+
156
+ return {}
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,41 @@
1
+ require 'xmpp4r'
2
+ require 'oauth/request_proxy/base'
3
+
4
+ module OAuth
5
+ module RequestProxy
6
+ class JabberRequest < OAuth::RequestProxy::Base
7
+ proxies Jabber::Iq
8
+ proxies Jabber::Presence
9
+ proxies Jabber::Message
10
+
11
+ def parameters
12
+ return @params if @params
13
+
14
+ @params = {}
15
+
16
+ oauth = @request.get_elements('//oauth').first
17
+ return @params unless oauth
18
+
19
+ %w( oauth_token oauth_consumer_key oauth_signature_method oauth_signature
20
+ oauth_timestamp oauth_nonce oauth_version ).each do |param|
21
+ next unless element = oauth.first_element(param)
22
+ @params[param] = element.text
23
+ end
24
+
25
+ @params
26
+ end
27
+
28
+ def method
29
+ @request.name
30
+ end
31
+
32
+ def uri
33
+ [@request.from.strip.to_s, @request.to.strip.to_s].join("&")
34
+ end
35
+
36
+ def normalized_uri
37
+ uri
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+ require 'oauth/request_proxy/base'
2
+
3
+ module OAuth
4
+ module RequestProxy
5
+ # RequestProxy for Hashes to facilitate simpler signature creation.
6
+ # Usage:
7
+ # request = OAuth::RequestProxy.proxy \
8
+ # "method" => "iq",
9
+ # "uri" => [from, to] * "&",
10
+ # "parameters" => {
11
+ # "oauth_consumer_key" => oauth_consumer_key,
12
+ # "oauth_token" => oauth_token,
13
+ # "oauth_signature_method" => "HMAC-SHA1"
14
+ # }
15
+ #
16
+ # signature = OAuth::Signature.sign \
17
+ # request,
18
+ # :consumer_secret => oauth_consumer_secret,
19
+ # :token_secret => oauth_token_secret,
20
+ class MockRequest < OAuth::RequestProxy::Base
21
+ proxies Hash
22
+
23
+ def parameters
24
+ @request["parameters"]
25
+ end
26
+
27
+ def method
28
+ @request["method"]
29
+ end
30
+
31
+ def normalized_uri
32
+ super
33
+ rescue
34
+ # if this is a non-standard URI, it may not parse properly
35
+ # in that case, assume that it's already been normalized
36
+ uri
37
+ end
38
+
39
+ def uri
40
+ @request["uri"]
41
+ end
42
+ end
43
+ end
44
+ end