rack-oauth2 0.2.3 → 0.3.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/README.rdoc +1 -0
- data/VERSION +1 -1
- data/lib/rack/oauth2.rb +1 -7
- data/lib/rack/oauth2/server.rb +0 -1
- data/lib/rack/oauth2/server/abstract.rb +2 -1
- data/lib/rack/oauth2/server/abstract/error.rb +55 -0
- data/lib/rack/oauth2/server/abstract/handler.rb +2 -3
- data/lib/rack/oauth2/server/abstract/request.rb +2 -3
- data/lib/rack/oauth2/server/abstract/response.rb +0 -5
- data/lib/rack/oauth2/server/authorize.rb +19 -14
- data/lib/rack/oauth2/server/authorize/code.rb +8 -19
- data/lib/rack/oauth2/server/authorize/error.rb +60 -0
- data/lib/rack/oauth2/server/authorize/token.rb +15 -24
- data/lib/rack/oauth2/server/resource.rb +1 -79
- data/lib/rack/oauth2/server/resource/bearer.rb +74 -0
- data/lib/rack/oauth2/server/resource/bearer/error.rb +80 -0
- data/lib/rack/oauth2/server/token.rb +12 -19
- data/lib/rack/oauth2/server/token/authorization_code.rb +4 -5
- data/lib/rack/oauth2/server/token/error.rb +54 -0
- data/lib/rack/oauth2/server/token/password.rb +0 -2
- data/lib/rack/oauth2/server/token/refresh_token.rb +1 -1
- data/lib/rack/oauth2/server/util.rb +29 -0
- data/rack-oauth2.gemspec +1 -1
- data/spec/rack/oauth2/server/abstract/error_spec.rb +51 -0
- data/spec/rack/oauth2/server/authorize/code_spec.rb +42 -28
- data/spec/rack/oauth2/server/authorize/error_spec.rb +103 -0
- data/spec/rack/oauth2/server/authorize/token_spec.rb +55 -26
- data/spec/rack/oauth2/server/authorize_spec.rb +24 -68
- data/spec/rack/oauth2/server/resource/bearer/error_spec.rb +118 -0
- data/spec/rack/oauth2/server/resource/bearer_spec.rb +117 -0
- data/spec/rack/oauth2/server/token/authorization_code_spec.rb +26 -109
- data/spec/rack/oauth2/server/token/error_spec.rb +77 -0
- data/spec/rack/oauth2/server/token/password_spec.rb +27 -47
- data/spec/rack/oauth2/server/token/refresh_token_spec.rb +22 -43
- data/spec/rack/oauth2/server/token_spec.rb +77 -116
- data/spec/rack/oauth2/server/util_spec.rb +75 -16
- data/spec/spec_helper.rb +0 -12
- metadata +25 -29
- data/lib/rack/oauth2/server/authorize/code_and_token.rb +0 -62
- data/lib/rack/oauth2/server/error.rb +0 -73
- data/lib/rack/oauth2/server/error/authorize.rb +0 -54
- data/lib/rack/oauth2/server/error/resource.rb +0 -50
- data/lib/rack/oauth2/server/error/token.rb +0 -59
- data/lib/rack/oauth2/server/token/assertion.rb +0 -29
- data/spec/rack/oauth2/server/authorize/code_and_token_spec.rb +0 -53
- data/spec/rack/oauth2/server/error/authorize_spec.rb +0 -102
- data/spec/rack/oauth2/server/error/resource_spec.rb +0 -69
- data/spec/rack/oauth2/server/error/token_spec.rb +0 -115
- data/spec/rack/oauth2/server/error_spec.rb +0 -107
- data/spec/rack/oauth2/server/resource_spec.rb +0 -141
- data/spec/rack/oauth2/server/token/assertion_spec.rb +0 -56
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -14,6 +14,7 @@ http://tools.ietf.org/html/draft-ietf-oauth-v2-10
|
|
14
14
|
* View RDoc on RDoc.info (http://rdoc.info/github/nov/rack-oauth2)
|
15
15
|
* View Source on GitHub (http://github.com/nov/rack-oauth2)
|
16
16
|
* Report Issues on GitHub (http://github.com/nov/rack-oauth2/issues)
|
17
|
+
* Facebook Page (http://www.facebook.com/pages/RackOAuth2/141477809244105)
|
17
18
|
|
18
19
|
== Usage
|
19
20
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0.alpha
|
data/lib/rack/oauth2.rb
CHANGED
data/lib/rack/oauth2/server.rb
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
module Server
|
4
|
+
module Abstract
|
5
|
+
class Error < StandardError
|
6
|
+
attr_accessor :status, :error, :description, :uri
|
7
|
+
|
8
|
+
def initialize(status, error, description = nil, options = {})
|
9
|
+
@status = status
|
10
|
+
@error = error
|
11
|
+
@description = description
|
12
|
+
@uri = options[:uri]
|
13
|
+
end
|
14
|
+
|
15
|
+
def protocol_params
|
16
|
+
{
|
17
|
+
:error => error,
|
18
|
+
:error_description => description,
|
19
|
+
:error_uri => uri
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def finish
|
24
|
+
response = Rack::Response.new
|
25
|
+
response.status = status
|
26
|
+
yield response if block_given?
|
27
|
+
unless response.redirect?
|
28
|
+
response.header['Content-Type'] = 'application/json'
|
29
|
+
response.write Util.compact_hash(protocol_params).to_json
|
30
|
+
end
|
31
|
+
response.finish
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class BadRequest < Error
|
36
|
+
def initialize(error = :bad_request, description = nil, options = {})
|
37
|
+
super 400, error, description, options
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Unauthorized < Error
|
42
|
+
def initialize(error = :unauthorized, description = nil, options = {})
|
43
|
+
super 401, error, description, options
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Forbidden < Error
|
48
|
+
def initialize(error = :forbidden, description = nil, options = {})
|
49
|
+
super 403, error, description, options
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -3,10 +3,9 @@ module Rack
|
|
3
3
|
module Server
|
4
4
|
module Abstract
|
5
5
|
class Handler
|
6
|
-
attr_accessor :
|
6
|
+
attr_accessor :authenticator, :request, :response
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
@realm = realm
|
8
|
+
def initialize(&authenticator)
|
10
9
|
@authenticator = authenticator
|
11
10
|
end
|
12
11
|
|
@@ -15,14 +15,13 @@ module Rack
|
|
15
15
|
|
16
16
|
def attr_missing_with_error_handling!
|
17
17
|
if params['client_id'].present? && @client_id != params['client_id']
|
18
|
-
|
18
|
+
invalid_request! 'Multiple client credentials are provided.'
|
19
19
|
end
|
20
20
|
attr_missing_without_error_handling!
|
21
21
|
rescue AttrRequired::AttrMissing => e
|
22
|
-
invalid_request!
|
22
|
+
invalid_request! e.message, :state => @state, :redirect_uri => @redirect_uri
|
23
23
|
end
|
24
24
|
alias_method_chain :attr_missing!, :error_handling
|
25
|
-
|
26
25
|
end
|
27
26
|
end
|
28
27
|
end
|
@@ -2,16 +2,14 @@ module Rack
|
|
2
2
|
module OAuth2
|
3
3
|
module Server
|
4
4
|
class Authorize < Abstract::Handler
|
5
|
-
|
6
5
|
def call(env)
|
7
6
|
request = Request.new(env)
|
8
|
-
request.profile.new(
|
9
|
-
rescue Error => e
|
7
|
+
request.profile.new(&@authenticator).call(env).finish
|
8
|
+
rescue Rack::OAuth2::Server::Abstract::Error => e
|
10
9
|
e.finish
|
11
10
|
end
|
12
11
|
|
13
12
|
class Request < Abstract::Request
|
14
|
-
include Error::Authorize
|
15
13
|
attr_required :response_type
|
16
14
|
attr_optional :redirect_uri, :state
|
17
15
|
|
@@ -27,36 +25,43 @@ module Rack
|
|
27
25
|
Code
|
28
26
|
when 'token'
|
29
27
|
Token
|
30
|
-
when 'code_and_token'
|
31
|
-
CodeAndToken
|
32
28
|
when ''
|
33
29
|
attr_missing!
|
34
30
|
else
|
35
|
-
unsupported_response_type!
|
31
|
+
unsupported_response_type! "#{CGI.escape params['response_type']} isn't supported."
|
36
32
|
end
|
37
33
|
end
|
38
|
-
|
39
34
|
end
|
40
35
|
|
41
36
|
class Response < Abstract::Response
|
42
37
|
attr_required :redirect_uri
|
43
|
-
attr_optional :state, :
|
38
|
+
attr_optional :state, :approval
|
44
39
|
|
45
40
|
def initialize(request)
|
46
41
|
@state = request.state
|
47
|
-
@redirect_uri = Util.parse_uri(request.redirect_uri) if request.redirect_uri
|
48
42
|
super
|
49
43
|
end
|
50
44
|
|
51
45
|
def approved?
|
52
|
-
@
|
46
|
+
@approval
|
53
47
|
end
|
54
48
|
|
55
49
|
def approve!
|
56
|
-
@
|
50
|
+
@approval = true
|
51
|
+
end
|
52
|
+
|
53
|
+
def protocol_params
|
54
|
+
{:state => state}
|
57
55
|
end
|
58
|
-
end
|
59
56
|
|
57
|
+
def finish
|
58
|
+
if approved?
|
59
|
+
attr_missing!
|
60
|
+
redirect Util.redirect_uri(redirect_uri, protocol_params_location, protocol_params)
|
61
|
+
end
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
60
65
|
end
|
61
66
|
end
|
62
67
|
end
|
@@ -64,4 +69,4 @@ end
|
|
64
69
|
|
65
70
|
require 'rack/oauth2/server/authorize/code'
|
66
71
|
require 'rack/oauth2/server/authorize/token'
|
67
|
-
require 'rack/oauth2/server/authorize/
|
72
|
+
require 'rack/oauth2/server/authorize/error'
|
@@ -5,8 +5,8 @@ module Rack
|
|
5
5
|
class Code < Abstract::Handler
|
6
6
|
|
7
7
|
def call(env)
|
8
|
-
@request = Request.new
|
9
|
-
@response = Response.new
|
8
|
+
@request = Request.new env
|
9
|
+
@response = Response.new request
|
10
10
|
super
|
11
11
|
end
|
12
12
|
|
@@ -21,25 +21,14 @@ module Rack
|
|
21
21
|
class Response < Authorize::Response
|
22
22
|
attr_required :code
|
23
23
|
|
24
|
-
def
|
25
|
-
|
26
|
-
params = {
|
27
|
-
:code => code,
|
28
|
-
:state => state
|
29
|
-
}.delete_if do |key, value|
|
30
|
-
value.blank?
|
31
|
-
end
|
32
|
-
redirect_uri.query = if redirect_uri.query
|
33
|
-
[redirect_uri.query, params.to_query].join('&')
|
34
|
-
else
|
35
|
-
params.to_query
|
36
|
-
end
|
37
|
-
redirect redirect_uri.to_s
|
38
|
-
end
|
39
|
-
super
|
24
|
+
def protocol_params
|
25
|
+
super.merge(:code => code)
|
40
26
|
end
|
41
|
-
end
|
42
27
|
|
28
|
+
def protocol_params_location
|
29
|
+
:query
|
30
|
+
end
|
31
|
+
end
|
43
32
|
end
|
44
33
|
end
|
45
34
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
module Server
|
4
|
+
class Authorize
|
5
|
+
class BadRequest < Abstract::BadRequest
|
6
|
+
attr_accessor :redirect_uri, :state, :protocol_params_location
|
7
|
+
|
8
|
+
def protocol_params
|
9
|
+
super.merge(:state => state)
|
10
|
+
end
|
11
|
+
|
12
|
+
def finish
|
13
|
+
if redirect_uri.present? && protocol_params_location.present?
|
14
|
+
super do |response|
|
15
|
+
response.redirect Util.redirect_uri(redirect_uri, protocol_params_location, protocol_params)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
raise self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module ErrorMethods
|
24
|
+
DEFAULT_DESCRIPTION = {
|
25
|
+
:invalid_request => "The request is missing a required parameter, includes an unsupported parameter or parameter value, or is otherwise malformed.",
|
26
|
+
:unauthorized_client => "The client is not authorized to use the requested response type.",
|
27
|
+
:access_denied => "The end-user or authorization server denied the request.",
|
28
|
+
:unsupported_response_type => "The requested response type is not supported by the authorization server.",
|
29
|
+
:invalid_scope => "The requested scope is invalid, unknown, or malformed."
|
30
|
+
}
|
31
|
+
|
32
|
+
def self.included(klass)
|
33
|
+
DEFAULT_DESCRIPTION.each do |error, default_description|
|
34
|
+
klass.class_eval <<-ERROR
|
35
|
+
def #{error}!(description = "#{default_description}", options = {})
|
36
|
+
bad_request! :#{error}, description, options.merge(:redirect => true)
|
37
|
+
end
|
38
|
+
ERROR
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def bad_request!(error = :bad_request, description = nil, options = {})
|
43
|
+
exception = BadRequest.new error, description, options
|
44
|
+
exception.protocol_params_location = case response_type
|
45
|
+
when :code
|
46
|
+
:query
|
47
|
+
when :token
|
48
|
+
:fragment
|
49
|
+
end
|
50
|
+
exception.state = state
|
51
|
+
exception.redirect_uri = redirect_uri if options[:redirect]
|
52
|
+
raise exception
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
Request.send :include, ErrorMethods
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -3,10 +3,9 @@ module Rack
|
|
3
3
|
module Server
|
4
4
|
class Authorize
|
5
5
|
class Token < Abstract::Handler
|
6
|
-
|
7
6
|
def call(env)
|
8
|
-
@request = Request.new
|
9
|
-
@response = Response.new
|
7
|
+
@request = Request.new env
|
8
|
+
@response = Response.new request
|
10
9
|
super
|
11
10
|
end
|
12
11
|
|
@@ -19,30 +18,22 @@ module Rack
|
|
19
18
|
end
|
20
19
|
|
21
20
|
class Response < Authorize::Response
|
22
|
-
attr_required :access_token
|
23
|
-
attr_optional :expires_in, :scope
|
21
|
+
attr_required :access_token, :token_type
|
22
|
+
attr_optional :refresh_token, :expires_in, :scope
|
24
23
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
}.delete_if do |key, value|
|
33
|
-
value.blank?
|
34
|
-
end
|
35
|
-
redirect_uri.fragment = if redirect_uri.fragment
|
36
|
-
[redirect_uri.fragment, params.to_query].join('&')
|
37
|
-
else
|
38
|
-
params.to_query
|
39
|
-
end
|
40
|
-
redirect redirect_uri.to_s
|
41
|
-
end
|
42
|
-
super
|
24
|
+
def protocol_params
|
25
|
+
super.merge(
|
26
|
+
:access_token => access_token,
|
27
|
+
:expires_in => expires_in,
|
28
|
+
:refresh_token => refresh_token,
|
29
|
+
:scope => Array(scope).join(' ')
|
30
|
+
)
|
43
31
|
end
|
44
|
-
end
|
45
32
|
|
33
|
+
def protocol_params_location
|
34
|
+
:fragment
|
35
|
+
end
|
36
|
+
end
|
46
37
|
end
|
47
38
|
end
|
48
39
|
end
|
@@ -1,79 +1 @@
|
|
1
|
-
require 'rack/
|
2
|
-
|
3
|
-
module Rack
|
4
|
-
module OAuth2
|
5
|
-
module Server
|
6
|
-
class Resource < Abstract::Handler
|
7
|
-
|
8
|
-
def initialize(app, realm = nil, &authenticator)
|
9
|
-
@app = app
|
10
|
-
super(realm, &authenticator)
|
11
|
-
end
|
12
|
-
|
13
|
-
def call(env)
|
14
|
-
request = Request.new(env, realm)
|
15
|
-
if request.oauth2?
|
16
|
-
authenticate!(request)
|
17
|
-
env[ACCESS_TOKEN] = request.access_token
|
18
|
-
end
|
19
|
-
@app.call(env)
|
20
|
-
rescue Error => e
|
21
|
-
e.realm = realm
|
22
|
-
e.finish
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def authenticate!(request)
|
28
|
-
@authenticator.call(request)
|
29
|
-
end
|
30
|
-
|
31
|
-
class Request < Rack::Request
|
32
|
-
include Error::Resource
|
33
|
-
|
34
|
-
attr_accessor :realm
|
35
|
-
|
36
|
-
def initialize(env, realm = nil)
|
37
|
-
@env = env
|
38
|
-
@realm = realm
|
39
|
-
@auth_header = Rack::Auth::AbstractRequest.new(env)
|
40
|
-
end
|
41
|
-
|
42
|
-
def oauth2?
|
43
|
-
access_token.present?
|
44
|
-
end
|
45
|
-
|
46
|
-
def access_token
|
47
|
-
tokens = [access_token_in_haeder, access_token_in_payload].compact
|
48
|
-
case Array(tokens).size
|
49
|
-
when 0
|
50
|
-
nil
|
51
|
-
when 1
|
52
|
-
tokens.first
|
53
|
-
else
|
54
|
-
invalid_request!('Both Authorization header and payload includes oauth_token.', :realm => realm)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def access_token_in_haeder
|
59
|
-
if @auth_header.provided? && @auth_header.scheme == :oauth && @auth_header.params !~ /oauth_signature_method/
|
60
|
-
@auth_header.params
|
61
|
-
else
|
62
|
-
nil
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def access_token_in_payload
|
67
|
-
if params['oauth_token'] && !params['oauth_signature_method']
|
68
|
-
params['oauth_token']
|
69
|
-
else
|
70
|
-
nil # This is OAuth1 request
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
1
|
+
require 'rack/oauth2/server/resource/bearer'
|