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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +7 -0
- data/LICENSE +20 -0
- data/README.rdoc +78 -0
- data/Rakefile +25 -0
- data/VERSION +1 -0
- data/lib/rack/oauth2.rb +67 -0
- data/lib/rack/oauth2/access_token.rb +36 -0
- data/lib/rack/oauth2/access_token/authenticator.rb +24 -0
- data/lib/rack/oauth2/access_token/bearer.rb +11 -0
- data/lib/rack/oauth2/access_token/legacy.rb +23 -0
- data/lib/rack/oauth2/access_token/mac.rb +103 -0
- data/lib/rack/oauth2/access_token/mac/sha256_hex_verifier.rb +17 -0
- data/lib/rack/oauth2/access_token/mac/signature.rb +34 -0
- data/lib/rack/oauth2/access_token/mac/verifier.rb +44 -0
- data/lib/rack/oauth2/client.rb +139 -0
- data/lib/rack/oauth2/client/error.rb +14 -0
- data/lib/rack/oauth2/client/grant.rb +30 -0
- data/lib/rack/oauth2/client/grant/authorization_code.rb +12 -0
- data/lib/rack/oauth2/client/grant/client_credentials.rb +10 -0
- data/lib/rack/oauth2/client/grant/facebook_token.rb +12 -0
- data/lib/rack/oauth2/client/grant/password.rb +11 -0
- data/lib/rack/oauth2/client/grant/refresh_token.rb +11 -0
- data/lib/rack/oauth2/debugger.rb +3 -0
- data/lib/rack/oauth2/debugger/request_filter.rb +30 -0
- data/lib/rack/oauth2/server.rb +4 -0
- data/lib/rack/oauth2/server/abstract.rb +4 -0
- data/lib/rack/oauth2/server/abstract/error.rb +69 -0
- data/lib/rack/oauth2/server/abstract/handler.rb +20 -0
- data/lib/rack/oauth2/server/abstract/request.rb +29 -0
- data/lib/rack/oauth2/server/abstract/response.rb +15 -0
- data/lib/rack/oauth2/server/authorize.rb +117 -0
- data/lib/rack/oauth2/server/authorize/code.rb +39 -0
- data/lib/rack/oauth2/server/authorize/error.rb +71 -0
- data/lib/rack/oauth2/server/authorize/extension.rb +12 -0
- data/lib/rack/oauth2/server/authorize/extension/code_and_token.rb +39 -0
- data/lib/rack/oauth2/server/authorize/token.rb +43 -0
- data/lib/rack/oauth2/server/resource.rb +55 -0
- data/lib/rack/oauth2/server/resource/bearer.rb +47 -0
- data/lib/rack/oauth2/server/resource/bearer/error.rb +24 -0
- data/lib/rack/oauth2/server/resource/error.rb +81 -0
- data/lib/rack/oauth2/server/resource/mac.rb +36 -0
- data/lib/rack/oauth2/server/resource/mac/error.rb +24 -0
- data/lib/rack/oauth2/server/token.rb +87 -0
- data/lib/rack/oauth2/server/token/authorization_code.rb +28 -0
- data/lib/rack/oauth2/server/token/client_credentials.rb +23 -0
- data/lib/rack/oauth2/server/token/error.rb +54 -0
- data/lib/rack/oauth2/server/token/extension.rb +12 -0
- data/lib/rack/oauth2/server/token/extension/jwt.rb +37 -0
- data/lib/rack/oauth2/server/token/facebook_token.rb +27 -0
- data/lib/rack/oauth2/server/token/password.rb +27 -0
- data/lib/rack/oauth2/server/token/refresh_token.rb +26 -0
- data/lib/rack/oauth2/util.rb +58 -0
- data/rack-oauth2.gemspec +30 -0
- data/spec/helpers/time.rb +19 -0
- data/spec/helpers/webmock_helper.rb +41 -0
- data/spec/mock_response/blank +0 -0
- data/spec/mock_response/errors/invalid_request.json +4 -0
- data/spec/mock_response/resources/fake.txt +1 -0
- data/spec/mock_response/tokens/_Bearer.json +6 -0
- data/spec/mock_response/tokens/bearer.json +6 -0
- data/spec/mock_response/tokens/legacy.json +5 -0
- data/spec/mock_response/tokens/legacy.txt +1 -0
- data/spec/mock_response/tokens/legacy_without_expires_in.txt +1 -0
- data/spec/mock_response/tokens/mac.json +8 -0
- data/spec/mock_response/tokens/unknown.json +6 -0
- data/spec/rack/oauth2/access_token/authenticator_spec.rb +43 -0
- data/spec/rack/oauth2/access_token/bearer_spec.rb +18 -0
- data/spec/rack/oauth2/access_token/legacy_spec.rb +23 -0
- data/spec/rack/oauth2/access_token/mac/sha256_hex_verifier_spec.rb +28 -0
- data/spec/rack/oauth2/access_token/mac/signature_spec.rb +59 -0
- data/spec/rack/oauth2/access_token/mac/verifier_spec.rb +25 -0
- data/spec/rack/oauth2/access_token/mac_spec.rb +141 -0
- data/spec/rack/oauth2/access_token_spec.rb +69 -0
- data/spec/rack/oauth2/client/error_spec.rb +18 -0
- data/spec/rack/oauth2/client/grant/authorization_code_spec.rb +37 -0
- data/spec/rack/oauth2/client/grant/client_credentials_spec.rb +7 -0
- data/spec/rack/oauth2/client/grant/password_spec.rb +33 -0
- data/spec/rack/oauth2/client/grant/refresh_token_spec.rb +21 -0
- data/spec/rack/oauth2/client_spec.rb +287 -0
- data/spec/rack/oauth2/debugger/request_filter_spec.rb +33 -0
- data/spec/rack/oauth2/oauth2_spec.rb +74 -0
- data/spec/rack/oauth2/server/abstract/error_spec.rb +59 -0
- data/spec/rack/oauth2/server/authorize/code_spec.rb +57 -0
- data/spec/rack/oauth2/server/authorize/error_spec.rb +103 -0
- data/spec/rack/oauth2/server/authorize/extensions/code_and_token_spec.rb +60 -0
- data/spec/rack/oauth2/server/authorize/token_spec.rb +73 -0
- data/spec/rack/oauth2/server/authorize_spec.rb +214 -0
- data/spec/rack/oauth2/server/resource/bearer/error_spec.rb +52 -0
- data/spec/rack/oauth2/server/resource/bearer_spec.rb +123 -0
- data/spec/rack/oauth2/server/resource/error_spec.rb +147 -0
- data/spec/rack/oauth2/server/resource/mac/error_spec.rb +52 -0
- data/spec/rack/oauth2/server/resource/mac_spec.rb +119 -0
- data/spec/rack/oauth2/server/resource_spec.rb +23 -0
- data/spec/rack/oauth2/server/token/authorization_code_spec.rb +43 -0
- data/spec/rack/oauth2/server/token/client_credentials_spec.rb +23 -0
- data/spec/rack/oauth2/server/token/error_spec.rb +77 -0
- data/spec/rack/oauth2/server/token/password_spec.rb +37 -0
- data/spec/rack/oauth2/server/token/refresh_token_spec.rb +34 -0
- data/spec/rack/oauth2/server/token_spec.rb +134 -0
- data/spec/rack/oauth2/util_spec.rb +97 -0
- data/spec/spec_helper.rb +14 -0
- metadata +326 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
module Server
|
4
|
+
module Abstract
|
5
|
+
class Handler
|
6
|
+
attr_accessor :authenticator, :request, :response
|
7
|
+
|
8
|
+
def initialize(&authenticator)
|
9
|
+
@authenticator = authenticator
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
@authenticator.call(@request, @response) if @authenticator
|
14
|
+
@response
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
module Server
|
4
|
+
module Abstract
|
5
|
+
class Request < Rack::Request
|
6
|
+
include AttrRequired, AttrOptional
|
7
|
+
attr_required :client_id
|
8
|
+
attr_optional :scope
|
9
|
+
|
10
|
+
def initialize(env)
|
11
|
+
super
|
12
|
+
@client_id ||= params['client_id']
|
13
|
+
@scope = Array(params['scope'].to_s.split(' '))
|
14
|
+
end
|
15
|
+
|
16
|
+
def attr_missing_with_error_handling!
|
17
|
+
if params['client_id'].present? && @client_id != params['client_id']
|
18
|
+
invalid_request! 'Multiple client credentials are provided.'
|
19
|
+
end
|
20
|
+
attr_missing_without_error_handling!
|
21
|
+
rescue AttrRequired::AttrMissing => e
|
22
|
+
invalid_request! e.message, :state => @state, :redirect_uri => @redirect_uri
|
23
|
+
end
|
24
|
+
alias_method_chain :attr_missing!, :error_handling
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
module Server
|
4
|
+
class Authorize < Abstract::Handler
|
5
|
+
def call(env)
|
6
|
+
request = Request.new(env)
|
7
|
+
response_type_for(request).new(&@authenticator).call(env).finish
|
8
|
+
rescue Rack::OAuth2::Server::Abstract::Error => e
|
9
|
+
e.finish
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def response_type_for(request)
|
15
|
+
response_type = request.params['response_type'].to_s
|
16
|
+
case response_type
|
17
|
+
when 'code'
|
18
|
+
Code
|
19
|
+
when 'token'
|
20
|
+
Token
|
21
|
+
when ''
|
22
|
+
request.attr_missing!
|
23
|
+
else
|
24
|
+
extensions.detect do |extension|
|
25
|
+
extension.response_type_for? response_type
|
26
|
+
end || request.unsupported_response_type!
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def extensions
|
31
|
+
Extension.constants.sort.collect do |key|
|
32
|
+
Extension.const_get key
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Request < Abstract::Request
|
37
|
+
attr_required :response_type
|
38
|
+
attr_optional :redirect_uri, :state
|
39
|
+
attr_accessor :verified_redirect_uri
|
40
|
+
|
41
|
+
def initialize(env)
|
42
|
+
super
|
43
|
+
# NOTE: Raise before redirect_uri is saved not to redirect back to unverified redirect_uri.
|
44
|
+
bad_request! if client_id.blank?
|
45
|
+
@redirect_uri = Util.parse_uri(params['redirect_uri']) if params['redirect_uri']
|
46
|
+
@state = params['state']
|
47
|
+
end
|
48
|
+
|
49
|
+
def verify_redirect_uri!(pre_registered, allow_partial_match = false)
|
50
|
+
@verified_redirect_uri = if redirect_uri.present?
|
51
|
+
verified = Array(pre_registered).any? do |_pre_registered_|
|
52
|
+
if allow_partial_match
|
53
|
+
Util.uri_match?(_pre_registered_, redirect_uri)
|
54
|
+
else
|
55
|
+
_pre_registered_.to_s == redirect_uri.to_s
|
56
|
+
end
|
57
|
+
end
|
58
|
+
if verified
|
59
|
+
redirect_uri
|
60
|
+
else
|
61
|
+
bad_request!
|
62
|
+
end
|
63
|
+
elsif pre_registered.present? && Array(pre_registered).size == 1 && !allow_partial_match
|
64
|
+
Array(pre_registered).first
|
65
|
+
else
|
66
|
+
bad_request!
|
67
|
+
end
|
68
|
+
self.verified_redirect_uri.to_s
|
69
|
+
end
|
70
|
+
|
71
|
+
def error_params_location
|
72
|
+
nil # => All errors are raised immediately and no error response are returned to client.
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Response < Abstract::Response
|
77
|
+
attr_required :redirect_uri
|
78
|
+
attr_optional :state, :approval
|
79
|
+
|
80
|
+
def initialize(request)
|
81
|
+
@state = request.state
|
82
|
+
super
|
83
|
+
end
|
84
|
+
|
85
|
+
def approved?
|
86
|
+
@approval
|
87
|
+
end
|
88
|
+
|
89
|
+
def approve!
|
90
|
+
@approval = true
|
91
|
+
end
|
92
|
+
|
93
|
+
def protocol_params
|
94
|
+
{:state => state}
|
95
|
+
end
|
96
|
+
|
97
|
+
def redirect_uri_with_credentials
|
98
|
+
Util.redirect_uri(redirect_uri, protocol_params_location, protocol_params)
|
99
|
+
end
|
100
|
+
|
101
|
+
def finish
|
102
|
+
if approved?
|
103
|
+
attr_missing!
|
104
|
+
redirect redirect_uri_with_credentials
|
105
|
+
end
|
106
|
+
super
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
require 'rack/oauth2/server/authorize/code'
|
115
|
+
require 'rack/oauth2/server/authorize/token'
|
116
|
+
require 'rack/oauth2/server/authorize/extension'
|
117
|
+
require 'rack/oauth2/server/authorize/error'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
module Server
|
4
|
+
class Authorize
|
5
|
+
class Code < Abstract::Handler
|
6
|
+
def call(env)
|
7
|
+
@request = Request.new env
|
8
|
+
@response = Response.new request
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
class Request < Authorize::Request
|
13
|
+
def initialize(env)
|
14
|
+
super
|
15
|
+
@response_type = :code
|
16
|
+
attr_missing!
|
17
|
+
end
|
18
|
+
|
19
|
+
def error_params_location
|
20
|
+
:query
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Response < Authorize::Response
|
25
|
+
attr_required :code
|
26
|
+
|
27
|
+
def protocol_params
|
28
|
+
super.merge(:code => code)
|
29
|
+
end
|
30
|
+
|
31
|
+
def protocol_params_location
|
32
|
+
:query
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
module Server
|
4
|
+
class Authorize
|
5
|
+
module ErrorHandler
|
6
|
+
def self.included(klass)
|
7
|
+
klass.send :attr_accessor, :redirect_uri, :state, :protocol_params_location
|
8
|
+
end
|
9
|
+
|
10
|
+
def protocol_params
|
11
|
+
super.merge(:state => state)
|
12
|
+
end
|
13
|
+
|
14
|
+
def finish
|
15
|
+
if redirect_uri.present? && protocol_params_location.present?
|
16
|
+
super do |response|
|
17
|
+
response.redirect Util.redirect_uri(redirect_uri, protocol_params_location, protocol_params)
|
18
|
+
end
|
19
|
+
else
|
20
|
+
raise self
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class BadRequest < Abstract::BadRequest
|
26
|
+
include ErrorHandler
|
27
|
+
end
|
28
|
+
|
29
|
+
class ServerError < Abstract::ServerError
|
30
|
+
include ErrorHandler
|
31
|
+
end
|
32
|
+
|
33
|
+
class TemporarilyUnavailable < Abstract::TemporarilyUnavailable
|
34
|
+
include ErrorHandler
|
35
|
+
end
|
36
|
+
|
37
|
+
module ErrorMethods
|
38
|
+
DEFAULT_DESCRIPTION = {
|
39
|
+
:invalid_request => "The request is missing a required parameter, includes an unsupported parameter or parameter value, or is otherwise malformed.",
|
40
|
+
:unauthorized_client => "The client is not authorized to use the requested response type.",
|
41
|
+
:access_denied => "The end-user or authorization server denied the request.",
|
42
|
+
:unsupported_response_type => "The requested response type is not supported by the authorization server.",
|
43
|
+
:invalid_scope => "The requested scope is invalid, unknown, or malformed.",
|
44
|
+
:server_error => "Internal Server Error",
|
45
|
+
:temporarily_unavailable => "Service Unavailable"
|
46
|
+
}
|
47
|
+
|
48
|
+
def self.included(klass)
|
49
|
+
DEFAULT_DESCRIPTION.each do |error, default_description|
|
50
|
+
klass.class_eval <<-ERROR
|
51
|
+
def #{error}!(description = "#{default_description}", options = {})
|
52
|
+
bad_request! :#{error}, description, options
|
53
|
+
end
|
54
|
+
ERROR
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def bad_request!(error = :bad_request, description = nil, options = {})
|
59
|
+
exception = BadRequest.new error, description, options
|
60
|
+
exception.protocol_params_location = error_params_location
|
61
|
+
exception.state = state
|
62
|
+
exception.redirect_uri = verified_redirect_uri
|
63
|
+
raise exception
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
Request.send :include, ErrorMethods
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
module Server
|
4
|
+
class Authorize
|
5
|
+
module Extension
|
6
|
+
class CodeAndToken < Abstract::Handler
|
7
|
+
class << self
|
8
|
+
def response_type_for?(response_type)
|
9
|
+
response_type.split.sort == ['code', 'token']
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
@request = Request.new env
|
15
|
+
@response = Response.new request
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
class Request < Authorize::Token::Request
|
20
|
+
def initialize(env)
|
21
|
+
super
|
22
|
+
@response_type = [:code, :token]
|
23
|
+
attr_missing!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Response < Authorize::Token::Response
|
28
|
+
attr_required :code
|
29
|
+
|
30
|
+
def protocol_params
|
31
|
+
super.merge(:code => code)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
module Server
|
4
|
+
class Authorize
|
5
|
+
class Token < Abstract::Handler
|
6
|
+
def call(env)
|
7
|
+
@request = Request.new env
|
8
|
+
@response = Response.new request
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
class Request < Authorize::Request
|
13
|
+
def initialize(env)
|
14
|
+
super
|
15
|
+
@response_type = :token
|
16
|
+
attr_missing!
|
17
|
+
end
|
18
|
+
|
19
|
+
def error_params_location
|
20
|
+
:fragment
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Response < Authorize::Response
|
25
|
+
attr_required :access_token
|
26
|
+
|
27
|
+
def protocol_params
|
28
|
+
super.merge(
|
29
|
+
access_token.token_response.delete_if do |k, v|
|
30
|
+
k == :refresh_token
|
31
|
+
end
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def protocol_params_location
|
36
|
+
:fragment
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
module Server
|
4
|
+
class Resource < Abstract::Handler
|
5
|
+
ACCESS_TOKEN = 'rack.oauth2.access_token'
|
6
|
+
DEFAULT_REALM = 'Protected by OAuth 2.0'
|
7
|
+
attr_accessor :realm, :request
|
8
|
+
|
9
|
+
def initialize(app, realm = nil, &authenticator)
|
10
|
+
@app = app
|
11
|
+
@realm = realm
|
12
|
+
super &authenticator
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
if request.oauth2?
|
17
|
+
access_token = authenticate! request.setup!
|
18
|
+
env[ACCESS_TOKEN] = access_token
|
19
|
+
end
|
20
|
+
@app.call(env)
|
21
|
+
rescue Rack::OAuth2::Server::Abstract::Error => e
|
22
|
+
e.realm ||= realm
|
23
|
+
e.finish
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def authenticate!(request)
|
29
|
+
@authenticator.call(request)
|
30
|
+
end
|
31
|
+
|
32
|
+
class Request < Rack::Request
|
33
|
+
attr_reader :access_token
|
34
|
+
|
35
|
+
def initialize(env)
|
36
|
+
@env = env
|
37
|
+
@auth_header = Rack::Auth::AbstractRequest.new(env)
|
38
|
+
end
|
39
|
+
|
40
|
+
def setup!
|
41
|
+
raise 'Define me!'
|
42
|
+
end
|
43
|
+
|
44
|
+
def oauth2?
|
45
|
+
raise 'Define me!'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
require 'rack/oauth2/server/resource/error'
|
54
|
+
require 'rack/oauth2/server/resource/bearer'
|
55
|
+
require 'rack/oauth2/server/resource/mac'
|