oauth-instructure 0.4.8
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.
- data/.gemtest +0 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +47 -0
- data/HISTORY +174 -0
- data/LICENSE +20 -0
- data/README.rdoc +75 -0
- data/Rakefile +37 -0
- data/TODO +32 -0
- data/bin/oauth +5 -0
- data/examples/yql.rb +44 -0
- data/lib/digest/hmac.rb +104 -0
- data/lib/oauth.rb +13 -0
- data/lib/oauth/cli.rb +378 -0
- data/lib/oauth/client.rb +4 -0
- data/lib/oauth/client/action_pack.rb +9 -0
- data/lib/oauth/client/em_http.rb +120 -0
- data/lib/oauth/client/helper.rb +91 -0
- data/lib/oauth/client/net_http.rb +120 -0
- data/lib/oauth/consumer.rb +389 -0
- data/lib/oauth/core_ext.rb +31 -0
- data/lib/oauth/errors.rb +3 -0
- data/lib/oauth/errors/error.rb +4 -0
- data/lib/oauth/errors/problem.rb +14 -0
- data/lib/oauth/errors/unauthorized.rb +12 -0
- data/lib/oauth/helper.rb +109 -0
- data/lib/oauth/oauth.rb +13 -0
- data/lib/oauth/oauth_test_helper.rb +25 -0
- data/lib/oauth/request_proxy.rb +24 -0
- data/lib/oauth/request_proxy/action_controller_request.rb +116 -0
- data/lib/oauth/request_proxy/action_dispatch_request.rb +113 -0
- data/lib/oauth/request_proxy/base.rb +174 -0
- data/lib/oauth/request_proxy/curb_request.rb +55 -0
- data/lib/oauth/request_proxy/em_http_request.rb +66 -0
- data/lib/oauth/request_proxy/jabber_request.rb +41 -0
- data/lib/oauth/request_proxy/mock_request.rb +44 -0
- data/lib/oauth/request_proxy/net_http.rb +73 -0
- data/lib/oauth/request_proxy/rack_request.rb +44 -0
- data/lib/oauth/request_proxy/typhoeus_request.rb +53 -0
- data/lib/oauth/server.rb +66 -0
- data/lib/oauth/signature.rb +45 -0
- data/lib/oauth/signature/base.rb +110 -0
- data/lib/oauth/signature/hmac/base.rb +15 -0
- data/lib/oauth/signature/hmac/md5.rb +8 -0
- data/lib/oauth/signature/hmac/rmd160.rb +8 -0
- data/lib/oauth/signature/hmac/sha1.rb +9 -0
- data/lib/oauth/signature/hmac/sha2.rb +8 -0
- data/lib/oauth/signature/md5.rb +13 -0
- data/lib/oauth/signature/plaintext.rb +23 -0
- data/lib/oauth/signature/rsa/sha1.rb +46 -0
- data/lib/oauth/signature/sha1.rb +13 -0
- data/lib/oauth/token.rb +7 -0
- data/lib/oauth/tokens/access_token.rb +71 -0
- data/lib/oauth/tokens/consumer_token.rb +33 -0
- data/lib/oauth/tokens/request_token.rb +32 -0
- data/lib/oauth/tokens/server_token.rb +9 -0
- data/lib/oauth/tokens/token.rb +17 -0
- data/oauth.gemspec +148 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/cases/oauth_case.rb +19 -0
- data/test/cases/spec/1_0-final/test_construct_request_url.rb +62 -0
- data/test/cases/spec/1_0-final/test_normalize_request_parameters.rb +88 -0
- data/test/cases/spec/1_0-final/test_parameter_encodings.rb +86 -0
- data/test/cases/spec/1_0-final/test_signature_base_strings.rb +77 -0
- data/test/integration/consumer_test.rb +307 -0
- data/test/keys/rsa.cert +11 -0
- data/test/keys/rsa.pem +16 -0
- data/test/test_access_token.rb +26 -0
- data/test/test_action_controller_request_proxy.rb +133 -0
- data/test/test_consumer.rb +220 -0
- data/test/test_curb_request_proxy.rb +77 -0
- data/test/test_em_http_client.rb +80 -0
- data/test/test_em_http_request_proxy.rb +115 -0
- data/test/test_helper.rb +28 -0
- data/test/test_hmac_sha1.rb +20 -0
- data/test/test_net_http_client.rb +292 -0
- data/test/test_net_http_request_proxy.rb +72 -0
- data/test/test_oauth_helper.rb +94 -0
- data/test/test_rack_request_proxy.rb +40 -0
- data/test/test_request_token.rb +51 -0
- data/test/test_rsa_sha1.rb +59 -0
- data/test/test_server.rb +40 -0
- data/test/test_signature.rb +22 -0
- data/test/test_signature_base.rb +32 -0
- data/test/test_signature_plain_text.rb +31 -0
- data/test/test_token.rb +14 -0
- data/test/test_typhoeus_request_proxy.rb +80 -0
- metadata +274 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# these are to backport methods from 1.8.7/1.9.1 to 1.8.6
|
2
|
+
|
3
|
+
class Object
|
4
|
+
|
5
|
+
unless method_defined?(:tap)
|
6
|
+
def tap
|
7
|
+
yield self
|
8
|
+
self
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
class String
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
unless method_defined?(:bytesize)
|
19
|
+
def bytesize
|
20
|
+
self.size
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
unless method_defined?(:bytes)
|
25
|
+
def bytes
|
26
|
+
require 'enumerator'
|
27
|
+
Enumerable::Enumerator.new(self, :each_byte)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/lib/oauth/errors.rb
ADDED
data/lib/oauth/helper.rb
ADDED
@@ -0,0 +1,109 @@
|
|
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
|
+
rescue ArgumentError
|
14
|
+
URI::escape(value.to_s.force_encoding(Encoding::UTF_8), OAuth::RESERVED_CHARACTERS)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Generate a random key of up to +size+ bytes. The value returned is Base64 encoded with non-word
|
18
|
+
# characters removed.
|
19
|
+
def generate_key(size=32)
|
20
|
+
Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/, '')
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method :generate_nonce, :generate_key
|
24
|
+
|
25
|
+
def generate_timestamp #:nodoc:
|
26
|
+
Time.now.to_i.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
# Normalize a +Hash+ of parameter values. Parameters are sorted by name, using lexicographical
|
30
|
+
# byte value ordering. If two or more parameters share the same name, they are sorted by their value.
|
31
|
+
# Parameters are concatenated in their sorted order into a single string. For each parameter, the name
|
32
|
+
# is separated from the corresponding value by an "=" character, even if the value is empty. Each
|
33
|
+
# name-value pair is separated by an "&" character.
|
34
|
+
#
|
35
|
+
# See Also: {OAuth core spec version 1.0, section 9.1.1}[http://oauth.net/core/1.0#rfc.section.9.1.1]
|
36
|
+
def normalize(params)
|
37
|
+
params.sort.map do |k, values|
|
38
|
+
if values.is_a?(Array)
|
39
|
+
# make sure the array has an element so we don't lose the key
|
40
|
+
values << nil if values.empty?
|
41
|
+
# multiple values were provided for a single key
|
42
|
+
values.sort.collect do |v|
|
43
|
+
[escape(k),escape(v)] * "="
|
44
|
+
end
|
45
|
+
elsif values.is_a?(Hash)
|
46
|
+
normalize_nested_query(values, k)
|
47
|
+
else
|
48
|
+
[escape(k),escape(values)] * "="
|
49
|
+
end
|
50
|
+
end * "&"
|
51
|
+
end
|
52
|
+
|
53
|
+
#Returns a string representation of the Hash like in URL query string
|
54
|
+
# build_nested_query({:level_1 => {:level_2 => ['value_1','value_2']}}, 'prefix'))
|
55
|
+
# #=> ["prefix%5Blevel_1%5D%5Blevel_2%5D%5B%5D=value_1", "prefix%5Blevel_1%5D%5Blevel_2%5D%5B%5D=value_2"]
|
56
|
+
def normalize_nested_query(value, prefix = nil)
|
57
|
+
case value
|
58
|
+
when Array
|
59
|
+
value.map do |v|
|
60
|
+
normalize_nested_query(v, "#{prefix}[]")
|
61
|
+
end.flatten.sort
|
62
|
+
when Hash
|
63
|
+
value.map do |k, v|
|
64
|
+
normalize_nested_query(v, prefix ? "#{prefix}[#{k}]" : k)
|
65
|
+
end.flatten.sort
|
66
|
+
else
|
67
|
+
[escape(prefix), escape(value)] * "="
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Parse an Authorization / WWW-Authenticate header into a hash. Takes care of unescaping and
|
72
|
+
# removing surrounding quotes. Raises a OAuth::Problem if the header is not parsable into a
|
73
|
+
# valid hash. Does not validate the keys or values.
|
74
|
+
#
|
75
|
+
# hash = parse_header(headers['Authorization'] || headers['WWW-Authenticate'])
|
76
|
+
# hash['oauth_timestamp']
|
77
|
+
# #=>"1234567890"
|
78
|
+
#
|
79
|
+
def parse_header(header)
|
80
|
+
# decompose
|
81
|
+
params = header[6,header.length].split(/[,=&]/)
|
82
|
+
|
83
|
+
# odd number of arguments - must be a malformed header.
|
84
|
+
raise OAuth::Problem.new("Invalid authorization header") if params.size % 2 != 0
|
85
|
+
|
86
|
+
params.map! do |v|
|
87
|
+
# strip and unescape
|
88
|
+
val = unescape(v.strip)
|
89
|
+
# strip quotes
|
90
|
+
val.sub(/^\"(.*)\"$/, '\1')
|
91
|
+
end
|
92
|
+
|
93
|
+
# convert into a Hash
|
94
|
+
Hash[*params.flatten]
|
95
|
+
end
|
96
|
+
|
97
|
+
def unescape(value)
|
98
|
+
URI.unescape(value.gsub('+', '%2B'))
|
99
|
+
end
|
100
|
+
|
101
|
+
def stringify_keys(hash)
|
102
|
+
new_h = {}
|
103
|
+
hash.each do |k, v|
|
104
|
+
new_h[k.to_s] = v.is_a?(Hash) ? stringify_keys(v) : v
|
105
|
+
end
|
106
|
+
new_h
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/oauth/oauth.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module OAuth
|
2
|
+
# request tokens are passed between the consumer and the provider out of
|
3
|
+
# band (i.e. callbacks cannot be used), per section 6.1.1
|
4
|
+
OUT_OF_BAND = "oob"
|
5
|
+
|
6
|
+
# required parameters, per sections 6.1.1, 6.3.1, and 7
|
7
|
+
PARAMETERS = %w(oauth_callback oauth_consumer_key oauth_token
|
8
|
+
oauth_signature_method oauth_timestamp oauth_nonce oauth_verifier
|
9
|
+
oauth_version oauth_signature oauth_body_hash)
|
10
|
+
|
11
|
+
# reserved character regexp, per section 5.1
|
12
|
+
RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~]/
|
13
|
+
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,116 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'action_controller'
|
3
|
+
if Rails.version < "3.0"
|
4
|
+
require 'action_controller/request'
|
5
|
+
else
|
6
|
+
require 'action_controller/test_case'
|
7
|
+
end
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
module OAuth::RequestProxy
|
11
|
+
class ActionControllerRequest < OAuth::RequestProxy::Base
|
12
|
+
proxies(defined?(ActionController::AbstractRequest) ? ActionController::AbstractRequest : ActionController::Request)
|
13
|
+
|
14
|
+
def method
|
15
|
+
request.method.to_s.upcase
|
16
|
+
end
|
17
|
+
|
18
|
+
def uri
|
19
|
+
request.url
|
20
|
+
end
|
21
|
+
|
22
|
+
def parameters
|
23
|
+
if options[:clobber_request]
|
24
|
+
options[:parameters] || {}
|
25
|
+
else
|
26
|
+
params = request_params.merge(query_params).merge(header_params)
|
27
|
+
params.stringify_keys! if params.respond_to?(:stringify_keys!)
|
28
|
+
params.merge(options[:parameters] || {})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Override from OAuth::RequestProxy::Base to avoid roundtrip
|
33
|
+
# conversion to Hash or Array and thus preserve the original
|
34
|
+
# parameter names
|
35
|
+
def parameters_for_signature
|
36
|
+
params = []
|
37
|
+
params << options[:parameters].to_query if options[:parameters]
|
38
|
+
|
39
|
+
unless options[:clobber_request]
|
40
|
+
params << header_params.to_query
|
41
|
+
params << request.query_string unless query_string_blank?
|
42
|
+
|
43
|
+
if request.post? && request.content_type.to_s.downcase.start_with?("application/x-www-form-urlencoded")
|
44
|
+
params << request.raw_post
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
params.
|
49
|
+
join('&').split('&').
|
50
|
+
reject(&:blank?).
|
51
|
+
map { |p| p.split('=').map{|esc| CGI.unescape(esc)} }.
|
52
|
+
reject { |kv| kv[0] == 'oauth_signature'}
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def query_params
|
58
|
+
request.query_parameters
|
59
|
+
end
|
60
|
+
|
61
|
+
def request_params
|
62
|
+
request.request_parameters
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module ActionController
|
69
|
+
class Base
|
70
|
+
def process_with_oauth(request, response=nil)
|
71
|
+
request.apply_oauth! if request.respond_to?(:apply_oauth!)
|
72
|
+
process_without_oauth(request, response)
|
73
|
+
end
|
74
|
+
alias_method_chain :process, :oauth
|
75
|
+
end
|
76
|
+
|
77
|
+
class TestRequest
|
78
|
+
def self.use_oauth=(bool)
|
79
|
+
@use_oauth = bool
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.use_oauth?
|
83
|
+
@use_oauth
|
84
|
+
end
|
85
|
+
|
86
|
+
def configure_oauth(consumer = nil, token = nil, options = {})
|
87
|
+
@oauth_options = { :consumer => consumer,
|
88
|
+
:token => token,
|
89
|
+
:scheme => 'header',
|
90
|
+
:signature_method => nil,
|
91
|
+
:nonce => nil,
|
92
|
+
:timestamp => nil }.merge(options)
|
93
|
+
end
|
94
|
+
|
95
|
+
def apply_oauth!
|
96
|
+
return unless ActionController::TestRequest.use_oauth? && @oauth_options
|
97
|
+
|
98
|
+
@oauth_helper = OAuth::Client::Helper.new(self, @oauth_options.merge(:request_uri => (respond_to?(:fullpath) ? fullpath : request_uri)))
|
99
|
+
@oauth_helper.amend_user_agent_header(env)
|
100
|
+
|
101
|
+
self.send("set_oauth_#{@oauth_options[:scheme]}")
|
102
|
+
end
|
103
|
+
|
104
|
+
def set_oauth_header
|
105
|
+
env['Authorization'] = @oauth_helper.header
|
106
|
+
end
|
107
|
+
|
108
|
+
def set_oauth_parameters
|
109
|
+
@query_parameters = @oauth_helper.parameters_with_oauth
|
110
|
+
@query_parameters.merge!(:oauth_signature => @oauth_helper.signature)
|
111
|
+
end
|
112
|
+
|
113
|
+
def set_oauth_query_string
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'action_controller'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module OAuth::RequestProxy
|
6
|
+
class ActionDispatchRequest < OAuth::RequestProxy::Base
|
7
|
+
proxies ActionDispatch::Request
|
8
|
+
|
9
|
+
def method
|
10
|
+
request.method.to_s.upcase
|
11
|
+
end
|
12
|
+
|
13
|
+
def uri
|
14
|
+
request.url
|
15
|
+
end
|
16
|
+
|
17
|
+
def parameters
|
18
|
+
if options[:clobber_request]
|
19
|
+
options[:parameters] || {}
|
20
|
+
else
|
21
|
+
params = request_params.merge(query_params).merge(header_params)
|
22
|
+
params.stringify_keys! if params.respond_to?(:stringify_keys!)
|
23
|
+
params.merge(options[:parameters] || {})
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Override from OAuth::RequestProxy::Base to avoid roundtrip
|
28
|
+
# conversion to Hash or Array and thus preserve the original
|
29
|
+
# parameter names
|
30
|
+
def parameters_for_signature
|
31
|
+
params = []
|
32
|
+
params << options[:parameters].to_query if options[:parameters]
|
33
|
+
|
34
|
+
unless options[:clobber_request]
|
35
|
+
params << header_params.to_query
|
36
|
+
params << request.query_string unless request.query_string.blank?
|
37
|
+
|
38
|
+
if request.post? && request.content_type == Mime::Type.lookup("application/x-www-form-urlencoded")
|
39
|
+
params << request.raw_post
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
params.
|
44
|
+
join('&').split('&').
|
45
|
+
reject(&:blank?).
|
46
|
+
map { |p| p.split('=').map{|esc| CGI.unescape(esc)} }.
|
47
|
+
reject { |kv| kv[0] == 'oauth_signature'}
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def query_params
|
53
|
+
request.query_parameters
|
54
|
+
end
|
55
|
+
|
56
|
+
def request_params
|
57
|
+
request.request_parameters
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
module ActionController
|
65
|
+
class Base
|
66
|
+
def process_with_new_base_test(request, response=nil)
|
67
|
+
request.apply_oauth! if request.respond_to?(:apply_oauth!)
|
68
|
+
super(request, response)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
module ActionDispatch
|
74
|
+
class TestRequest
|
75
|
+
def self.use_oauth=(bool)
|
76
|
+
@use_oauth = bool
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.use_oauth?
|
80
|
+
@use_oauth
|
81
|
+
end
|
82
|
+
|
83
|
+
def configure_oauth(consumer = nil, token = nil, options = {})
|
84
|
+
@oauth_options = { :consumer => consumer,
|
85
|
+
:token => token,
|
86
|
+
:scheme => 'header',
|
87
|
+
:signature_method => nil,
|
88
|
+
:nonce => nil,
|
89
|
+
:timestamp => nil }.merge(options)
|
90
|
+
end
|
91
|
+
|
92
|
+
def apply_oauth!
|
93
|
+
return unless ActionDispatch::TestRequest.use_oauth? && @oauth_options
|
94
|
+
|
95
|
+
@oauth_helper = OAuth::Client::Helper.new(self, @oauth_options.merge(:request_uri => (respond_to?(:fullpath) ? fullpath : request_uri)))
|
96
|
+
@oauth_helper.amend_user_agent_header(env)
|
97
|
+
|
98
|
+
self.send("set_oauth_#{@oauth_options[:scheme]}")
|
99
|
+
end
|
100
|
+
|
101
|
+
def set_oauth_header
|
102
|
+
env['Authorization'] = @oauth_helper.header
|
103
|
+
end
|
104
|
+
|
105
|
+
def set_oauth_parameters
|
106
|
+
@query_parameters = @oauth_helper.parameters_with_oauth
|
107
|
+
@query_parameters.merge!(:oauth_signature => @oauth_helper.signature)
|
108
|
+
end
|
109
|
+
|
110
|
+
def set_oauth_query_string
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|