rack-oauth2-revibe 1.0.7

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 (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