rack-oauth2-revibe 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +22 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +3 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE +20 -0
  8. data/README.rdoc +78 -0
  9. data/Rakefile +25 -0
  10. data/VERSION +1 -0
  11. data/lib/rack/oauth2.rb +67 -0
  12. data/lib/rack/oauth2/access_token.rb +36 -0
  13. data/lib/rack/oauth2/access_token/authenticator.rb +24 -0
  14. data/lib/rack/oauth2/access_token/bearer.rb +11 -0
  15. data/lib/rack/oauth2/access_token/legacy.rb +23 -0
  16. data/lib/rack/oauth2/access_token/mac.rb +103 -0
  17. data/lib/rack/oauth2/access_token/mac/sha256_hex_verifier.rb +17 -0
  18. data/lib/rack/oauth2/access_token/mac/signature.rb +34 -0
  19. data/lib/rack/oauth2/access_token/mac/verifier.rb +44 -0
  20. data/lib/rack/oauth2/client.rb +139 -0
  21. data/lib/rack/oauth2/client/error.rb +14 -0
  22. data/lib/rack/oauth2/client/grant.rb +30 -0
  23. data/lib/rack/oauth2/client/grant/authorization_code.rb +12 -0
  24. data/lib/rack/oauth2/client/grant/client_credentials.rb +10 -0
  25. data/lib/rack/oauth2/client/grant/facebook_token.rb +12 -0
  26. data/lib/rack/oauth2/client/grant/password.rb +11 -0
  27. data/lib/rack/oauth2/client/grant/refresh_token.rb +11 -0
  28. data/lib/rack/oauth2/debugger.rb +3 -0
  29. data/lib/rack/oauth2/debugger/request_filter.rb +30 -0
  30. data/lib/rack/oauth2/server.rb +4 -0
  31. data/lib/rack/oauth2/server/abstract.rb +4 -0
  32. data/lib/rack/oauth2/server/abstract/error.rb +69 -0
  33. data/lib/rack/oauth2/server/abstract/handler.rb +20 -0
  34. data/lib/rack/oauth2/server/abstract/request.rb +29 -0
  35. data/lib/rack/oauth2/server/abstract/response.rb +15 -0
  36. data/lib/rack/oauth2/server/authorize.rb +117 -0
  37. data/lib/rack/oauth2/server/authorize/code.rb +39 -0
  38. data/lib/rack/oauth2/server/authorize/error.rb +71 -0
  39. data/lib/rack/oauth2/server/authorize/extension.rb +12 -0
  40. data/lib/rack/oauth2/server/authorize/extension/code_and_token.rb +39 -0
  41. data/lib/rack/oauth2/server/authorize/token.rb +43 -0
  42. data/lib/rack/oauth2/server/resource.rb +55 -0
  43. data/lib/rack/oauth2/server/resource/bearer.rb +47 -0
  44. data/lib/rack/oauth2/server/resource/bearer/error.rb +24 -0
  45. data/lib/rack/oauth2/server/resource/error.rb +81 -0
  46. data/lib/rack/oauth2/server/resource/mac.rb +36 -0
  47. data/lib/rack/oauth2/server/resource/mac/error.rb +24 -0
  48. data/lib/rack/oauth2/server/token.rb +87 -0
  49. data/lib/rack/oauth2/server/token/authorization_code.rb +28 -0
  50. data/lib/rack/oauth2/server/token/client_credentials.rb +23 -0
  51. data/lib/rack/oauth2/server/token/error.rb +54 -0
  52. data/lib/rack/oauth2/server/token/extension.rb +12 -0
  53. data/lib/rack/oauth2/server/token/extension/jwt.rb +37 -0
  54. data/lib/rack/oauth2/server/token/facebook_token.rb +27 -0
  55. data/lib/rack/oauth2/server/token/password.rb +27 -0
  56. data/lib/rack/oauth2/server/token/refresh_token.rb +26 -0
  57. data/lib/rack/oauth2/util.rb +58 -0
  58. data/rack-oauth2.gemspec +30 -0
  59. data/spec/helpers/time.rb +19 -0
  60. data/spec/helpers/webmock_helper.rb +41 -0
  61. data/spec/mock_response/blank +0 -0
  62. data/spec/mock_response/errors/invalid_request.json +4 -0
  63. data/spec/mock_response/resources/fake.txt +1 -0
  64. data/spec/mock_response/tokens/_Bearer.json +6 -0
  65. data/spec/mock_response/tokens/bearer.json +6 -0
  66. data/spec/mock_response/tokens/legacy.json +5 -0
  67. data/spec/mock_response/tokens/legacy.txt +1 -0
  68. data/spec/mock_response/tokens/legacy_without_expires_in.txt +1 -0
  69. data/spec/mock_response/tokens/mac.json +8 -0
  70. data/spec/mock_response/tokens/unknown.json +6 -0
  71. data/spec/rack/oauth2/access_token/authenticator_spec.rb +43 -0
  72. data/spec/rack/oauth2/access_token/bearer_spec.rb +18 -0
  73. data/spec/rack/oauth2/access_token/legacy_spec.rb +23 -0
  74. data/spec/rack/oauth2/access_token/mac/sha256_hex_verifier_spec.rb +28 -0
  75. data/spec/rack/oauth2/access_token/mac/signature_spec.rb +59 -0
  76. data/spec/rack/oauth2/access_token/mac/verifier_spec.rb +25 -0
  77. data/spec/rack/oauth2/access_token/mac_spec.rb +141 -0
  78. data/spec/rack/oauth2/access_token_spec.rb +69 -0
  79. data/spec/rack/oauth2/client/error_spec.rb +18 -0
  80. data/spec/rack/oauth2/client/grant/authorization_code_spec.rb +37 -0
  81. data/spec/rack/oauth2/client/grant/client_credentials_spec.rb +7 -0
  82. data/spec/rack/oauth2/client/grant/password_spec.rb +33 -0
  83. data/spec/rack/oauth2/client/grant/refresh_token_spec.rb +21 -0
  84. data/spec/rack/oauth2/client_spec.rb +287 -0
  85. data/spec/rack/oauth2/debugger/request_filter_spec.rb +33 -0
  86. data/spec/rack/oauth2/oauth2_spec.rb +74 -0
  87. data/spec/rack/oauth2/server/abstract/error_spec.rb +59 -0
  88. data/spec/rack/oauth2/server/authorize/code_spec.rb +57 -0
  89. data/spec/rack/oauth2/server/authorize/error_spec.rb +103 -0
  90. data/spec/rack/oauth2/server/authorize/extensions/code_and_token_spec.rb +60 -0
  91. data/spec/rack/oauth2/server/authorize/token_spec.rb +73 -0
  92. data/spec/rack/oauth2/server/authorize_spec.rb +214 -0
  93. data/spec/rack/oauth2/server/resource/bearer/error_spec.rb +52 -0
  94. data/spec/rack/oauth2/server/resource/bearer_spec.rb +123 -0
  95. data/spec/rack/oauth2/server/resource/error_spec.rb +147 -0
  96. data/spec/rack/oauth2/server/resource/mac/error_spec.rb +52 -0
  97. data/spec/rack/oauth2/server/resource/mac_spec.rb +119 -0
  98. data/spec/rack/oauth2/server/resource_spec.rb +23 -0
  99. data/spec/rack/oauth2/server/token/authorization_code_spec.rb +43 -0
  100. data/spec/rack/oauth2/server/token/client_credentials_spec.rb +23 -0
  101. data/spec/rack/oauth2/server/token/error_spec.rb +77 -0
  102. data/spec/rack/oauth2/server/token/password_spec.rb +37 -0
  103. data/spec/rack/oauth2/server/token/refresh_token_spec.rb +34 -0
  104. data/spec/rack/oauth2/server/token_spec.rb +134 -0
  105. data/spec/rack/oauth2/util_spec.rb +97 -0
  106. data/spec/spec_helper.rb +14 -0
  107. metadata +326 -0
@@ -0,0 +1,47 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Resource
5
+ class Bearer < Resource
6
+ def call(env)
7
+ self.request = Request.new(env)
8
+ super
9
+ end
10
+
11
+ private
12
+
13
+ class Request < Resource::Request
14
+ def setup!
15
+ tokens = [access_token_in_header, access_token_in_payload].compact
16
+ @access_token = case Array(tokens).size
17
+ when 1
18
+ tokens.first
19
+ else
20
+ invalid_request!('Both Authorization header and payload includes access token.')
21
+ end
22
+ self
23
+ end
24
+
25
+ def oauth2?
26
+ (access_token_in_header || access_token_in_payload).present?
27
+ end
28
+
29
+ def access_token_in_header
30
+ if @auth_header.provided? && !@auth_header.parts.first.nil? && @auth_header.scheme.to_s == 'bearer'
31
+ @auth_header.params
32
+ else
33
+ nil
34
+ end
35
+ end
36
+
37
+ def access_token_in_payload
38
+ params['access_token']
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ require 'rack/oauth2/server/resource/bearer/error'
@@ -0,0 +1,24 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Resource
5
+ class Bearer
6
+ class Unauthorized < Resource::Unauthorized
7
+ def scheme
8
+ :Bearer
9
+ end
10
+ end
11
+
12
+ module ErrorMethods
13
+ include Resource::ErrorMethods
14
+ def unauthorized!(error = nil, description = nil, options = {})
15
+ raise Unauthorized.new(error, description, options)
16
+ end
17
+ end
18
+
19
+ Request.send :include, ErrorMethods
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,81 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Resource
5
+ class BadRequest < Abstract::BadRequest
6
+ end
7
+
8
+ class Unauthorized < Abstract::Unauthorized
9
+ def scheme
10
+ raise 'Define me!'
11
+ end
12
+
13
+ def finish
14
+ super do |response|
15
+ self.realm ||= DEFAULT_REALM
16
+ header = response.header['WWW-Authenticate'] = "#{scheme} realm=\"#{realm}\""
17
+ if ErrorMethods::DEFAULT_DESCRIPTION.keys.include?(error)
18
+ header << ", error=\"#{error}\""
19
+ header << ", error_description=\"#{description}\"" if description.present?
20
+ header << ", error_uri=\"#{uri}\"" if uri.present?
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ class Forbidden < Abstract::Forbidden
27
+ attr_accessor :scope
28
+
29
+ def initialize(error = :forbidden, description = nil, options = {})
30
+ super
31
+ @scope = options[:scope]
32
+ end
33
+
34
+ def protocol_params
35
+ super.merge(:scope => Array(scope).join(' '))
36
+ end
37
+ end
38
+
39
+ module ErrorMethods
40
+ DEFAULT_DESCRIPTION = {
41
+ :invalid_request => "The request is missing a required parameter, includes an unsupported parameter or parameter value, repeats the same parameter, uses more than one method for including an access token, or is otherwise malformed.",
42
+ :invalid_token => "The access token provided is expired, revoked, malformed or invalid for other reasons.",
43
+ :insufficient_scope => "The request requires higher privileges than provided by the access token."
44
+ }
45
+
46
+ def self.included(klass)
47
+ DEFAULT_DESCRIPTION.each do |error, default_description|
48
+ error_method = case error
49
+ when :invalid_request
50
+ :bad_request!
51
+ when :insufficient_scope
52
+ :forbidden!
53
+ else
54
+ :unauthorized!
55
+ end
56
+ klass.class_eval <<-ERROR
57
+ def #{error}!(description = "#{default_description}", options = {})
58
+ #{error_method} :#{error}, description, options
59
+ end
60
+ ERROR
61
+ end
62
+ end
63
+
64
+ def bad_request!(error, description = nil, options = {})
65
+ raise BadRequest.new(error, description, options)
66
+ end
67
+
68
+ def unauthorized!(error = nil, description = nil, options = {})
69
+ raise 'Define me!'
70
+ end
71
+
72
+ def forbidden!(error, description = nil, options = {})
73
+ raise Forbidden.new(error, description, options)
74
+ end
75
+ end
76
+
77
+ Request.send :include, ErrorMethods
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,36 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Resource
5
+ class MAC < Resource
6
+ def call(env)
7
+ self.request = Request.new(env)
8
+ super
9
+ end
10
+
11
+ private
12
+
13
+ class Request < Resource::Request
14
+ attr_reader :nonce, :ts, :ext, :signature
15
+
16
+ def setup!
17
+ auth_params = Rack::Auth::Digest::Params.parse(@auth_header.params).with_indifferent_access
18
+ @access_token = auth_params[:id]
19
+ @nonce = auth_params[:nonce]
20
+ @ts = auth_params[:ts]
21
+ @ext = auth_params[:ext]
22
+ @signature = auth_params[:mac]
23
+ self
24
+ end
25
+
26
+ def oauth2?
27
+ @auth_header.provided? && @auth_header.scheme.to_s == 'mac'
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ require 'rack/oauth2/server/resource/mac/error'
@@ -0,0 +1,24 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Resource
5
+ class MAC
6
+ class Unauthorized < Resource::Unauthorized
7
+ def scheme
8
+ :MAC
9
+ end
10
+ end
11
+
12
+ module ErrorMethods
13
+ include Resource::ErrorMethods
14
+ def unauthorized!(error = nil, description = nil, options = {})
15
+ raise Unauthorized.new(error, description, options)
16
+ end
17
+ end
18
+
19
+ Request.send :include, ErrorMethods
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,87 @@
1
+ require 'rack/auth/basic'
2
+
3
+ module Rack
4
+ module OAuth2
5
+ module Server
6
+ class Token < Abstract::Handler
7
+ def call(env)
8
+ request = Request.new(env)
9
+ grant_type_for(request).new(&@authenticator).call(env).finish
10
+ rescue Rack::OAuth2::Server::Abstract::Error => e
11
+ e.finish
12
+ end
13
+
14
+ private
15
+
16
+ def grant_type_for(request)
17
+ case request.grant_type
18
+ when 'authorization_code'
19
+ AuthorizationCode
20
+ when 'password'
21
+ Password
22
+ when 'facebook_token'
23
+ FacebookToken
24
+ when 'client_credentials'
25
+ ClientCredentials
26
+ when 'refresh_token'
27
+ RefreshToken
28
+ when ''
29
+ request.attr_missing!
30
+ else
31
+ extensions.detect do |extension|
32
+ extension.grant_type_for? request.grant_type
33
+ end || request.unsupported_grant_type!
34
+ end
35
+ end
36
+
37
+ def extensions
38
+ Extension.constants.sort.collect do |key|
39
+ Extension.const_get key
40
+ end
41
+ end
42
+
43
+ class Request < Abstract::Request
44
+ attr_required :grant_type
45
+ attr_optional :client_secret
46
+
47
+ def initialize(env)
48
+ auth = Rack::Auth::Basic::Request.new(env)
49
+ if auth.provided? && auth.basic?
50
+ @client_id, @client_secret = auth.credentials
51
+ super
52
+ else
53
+ super
54
+ @client_secret = params['client_secret']
55
+ end
56
+ @grant_type = params['grant_type'].to_s
57
+ end
58
+ end
59
+
60
+ class Response < Abstract::Response
61
+ attr_required :access_token
62
+
63
+ def protocol_params
64
+ access_token.token_response
65
+ end
66
+
67
+ def finish
68
+ attr_missing!
69
+ write MultiJson.dump(Util.compact_hash(protocol_params))
70
+ header['Content-Type'] = 'application/json'
71
+ header['Cache-Control'] = 'no-store'
72
+ header['Pragma'] = 'no-cache'
73
+ super
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ require 'rack/oauth2/server/token/authorization_code'
82
+ require 'rack/oauth2/server/token/password'
83
+ require 'rack/oauth2/server/token/facebook_token'
84
+ require 'rack/oauth2/server/token/client_credentials'
85
+ require 'rack/oauth2/server/token/refresh_token'
86
+ require 'rack/oauth2/server/token/extension'
87
+ require 'rack/oauth2/server/token/error'
@@ -0,0 +1,28 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Token
5
+ class AuthorizationCode < Abstract::Handler
6
+ def call(env)
7
+ @request = Request.new(env)
8
+ @response = Response.new(request)
9
+ super
10
+ end
11
+
12
+ class Request < Token::Request
13
+ attr_required :code
14
+ attr_optional :redirect_uri
15
+
16
+ def initialize(env)
17
+ super
18
+ @grant_type = :authorization_code
19
+ @code = params['code']
20
+ @redirect_uri = params['redirect_uri']
21
+ attr_missing!
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Token
5
+ class ClientCredentials < Abstract::Handler
6
+ def call(env)
7
+ @request = Request.new(env)
8
+ @response = Response.new(request)
9
+ super
10
+ end
11
+
12
+ class Request < Token::Request
13
+ def initialize(env)
14
+ super
15
+ @grant_type = :client_credentials
16
+ attr_missing!
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,54 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Token
5
+ class BadRequest < Abstract::BadRequest
6
+ end
7
+
8
+ class Unauthorized < Abstract::Unauthorized
9
+ def finish
10
+ super do |response|
11
+ response.header['WWW-Authenticate'] = 'Basic realm="OAuth2 Token Endpoint"'
12
+ end
13
+ end
14
+ end
15
+
16
+ module ErrorMethods
17
+ DEFAULT_DESCRIPTION = {
18
+ :invalid_request => "The request is missing a required parameter, includes an unsupported parameter or parameter value, repeats a parameter, includes multiple credentials, utilizes more than one mechanism for authenticating the client, or is otherwise malformed.",
19
+ :invalid_client => "The client identifier provided is invalid, the client failed to authenticate, the client did not include its credentials, provided multiple client credentials, or used unsupported credentials type.",
20
+ :invalid_grant => "The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, expired authorization token, bad end-user password credentials, or mismatching authorization code and redirection URI).",
21
+ :unauthorized_client => "The authenticated client is not authorized to use the access grant type provided.",
22
+ :unsupported_grant_type => "The access grant included - its type or another attribute - is not supported by the authorization server.",
23
+ :invalid_scope => "The requested scope is invalid, unknown, malformed, or exceeds the previously granted scope."
24
+ }
25
+
26
+ def self.included(klass)
27
+ DEFAULT_DESCRIPTION.each do |error, default_description|
28
+ error_method = if error == :invalid_client
29
+ :unauthorized!
30
+ else
31
+ :bad_request!
32
+ end
33
+ klass.class_eval <<-ERROR
34
+ def #{error}!(description = "#{default_description}", options = {})
35
+ #{error_method} :#{error}, description, options
36
+ end
37
+ ERROR
38
+ end
39
+ end
40
+
41
+ def bad_request!(error, description = nil, options = {})
42
+ raise BadRequest.new(error, description, options)
43
+ end
44
+
45
+ def unauthorized!(error, description = nil, options = {})
46
+ raise Unauthorized.new(error, description, options)
47
+ end
48
+ end
49
+
50
+ Request.send :include, ErrorMethods
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,12 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Token
5
+ module Extension
6
+ # Define your extension in this namespace and load it explicitly.
7
+ # extension/assertion/jwt.rb would be good example for you.
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,37 @@
1
+ module Rack
2
+ module OAuth2
3
+ module Server
4
+ class Token
5
+ module Extension
6
+ class JWT < Abstract::Handler
7
+ GRANT_TYPE_URN = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
8
+
9
+ class << self
10
+ def grant_type_for?(grant_type)
11
+ grant_type == GRANT_TYPE_URN
12
+ end
13
+ end
14
+
15
+ def call(env)
16
+ @request = Request.new env
17
+ @response = Response.new request
18
+ super
19
+ end
20
+
21
+ class Request < Token::Request
22
+ attr_required :assertion
23
+ attr_optional :client_id
24
+
25
+ def initialize(env)
26
+ super
27
+ @grant_type = GRANT_TYPE_URN
28
+ @assertion = params['assertion']
29
+ attr_missing!
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end