oauth2-rack 0.0.1
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/.gitignore +13 -0
- data/.rspec +1 -0
- data/Gemfile +7 -0
- data/Guardfile +10 -0
- data/Rakefile +4 -0
- data/config.ru +50 -0
- data/examples/ruby-client/password_authorization.rb +6 -0
- data/lib/oauth2/rack/authentication/client/http_basic.rb +61 -0
- data/lib/oauth2/rack/authentication/client/request_params.rb +55 -0
- data/lib/oauth2/rack/authentication/client.rb +5 -0
- data/lib/oauth2/rack/authentication/resource_owner/request_params.rb +54 -0
- data/lib/oauth2/rack/authentication/resource_owner.rb +4 -0
- data/lib/oauth2/rack/authentication.rb +6 -0
- data/lib/oauth2/rack/authorization/client_credentials/access_token_issuer.rb +58 -0
- data/lib/oauth2/rack/authorization/client_credentials.rb +5 -0
- data/lib/oauth2/rack/authorization/password/access_token_issuer.rb +60 -0
- data/lib/oauth2/rack/authorization/password.rb +5 -0
- data/lib/oauth2/rack/authorization.rb +6 -0
- data/lib/oauth2/rack.rb +9 -0
- data/lib/oauth2-rack.rb +1 -0
- data/spec/oauth2/rack/authentication/client/http_basic_spec.rb +76 -0
- data/spec/oauth2/rack/authentication/client/request_params_spec.rb +86 -0
- data/spec/oauth2/rack/authentication/resource_owner/request_params_spec.rb +86 -0
- data/spec/oauth2/rack/authorization/client_credentials/access_token_issuer_spec.rb +99 -0
- data/spec/oauth2/rack/authorization/password/access_token_issuer_spec.rb +101 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/rake_test_helper.rb +97 -0
- metadata +167 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec', :version => 2 do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
7
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec/" }
|
8
|
+
watch('spec/spec_helper.rb') { "spec/" }
|
9
|
+
end
|
10
|
+
|
data/Rakefile
ADDED
data/config.ru
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
$: << File.expand_path('../lib', __FILE__)
|
2
|
+
require 'oauth2/rack'
|
3
|
+
|
4
|
+
class AccessTokenIssuer
|
5
|
+
def self.call(opts = {})
|
6
|
+
opts.merge('access_token' => 'test')
|
7
|
+
end
|
8
|
+
end
|
9
|
+
class Authenticator
|
10
|
+
def self.call(opts = {})
|
11
|
+
if opts[:username]
|
12
|
+
authenticate_resource_owner(opts)
|
13
|
+
elsif opts[:client_id]
|
14
|
+
authenticate_client(opts)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.authenticate_resource_owner(opts)
|
19
|
+
OpenStruct.new(:username => opts[:username])
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.authenticate_client(opts)
|
23
|
+
OpenStruct.new(:client_id => opts[:client_id])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
map '/password/access_token' do
|
28
|
+
use OAuth2::Rack::Authentication::Client::HTTPBasic, :required => false, :authenticator => Authenticator
|
29
|
+
use OAuth2::Rack::Authentication::Client::RequestParams, :required => false, :authenticator => Authenticator
|
30
|
+
|
31
|
+
use OAuth2::Rack::Authentication::ResourceOwner::RequestParams, :authenticator => Authenticator
|
32
|
+
|
33
|
+
use OAuth2::Rack::Authorization::Password::AccessTokenIssuer, :issuer => AccessTokenIssuer
|
34
|
+
|
35
|
+
run proc { |env| [200, {'Content-Type' => 'text/html'}, ['Hello']] }
|
36
|
+
end
|
37
|
+
|
38
|
+
map '/client_credentials/access_token' do
|
39
|
+
use OAuth2::Rack::Authentication::Client::HTTPBasic, :required => false, :authenticator => Authenticator
|
40
|
+
use OAuth2::Rack::Authentication::Client::RequestParams, :required => false, :authenticator => Authenticator
|
41
|
+
|
42
|
+
use OAuth2::Rack::Authorization::ClientCredentials::AccessTokenIssuer, :issuer => AccessTokenIssuer
|
43
|
+
|
44
|
+
run proc { |env| [200, {'Content-Type' => 'text/html'}, ['Hello']] }
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
map '/inspect' do
|
49
|
+
run proc { |env| [200, {'Content-Type' => 'text/html'}, [env.inspect]] }
|
50
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'oauth2/rack'
|
2
|
+
|
3
|
+
# 2.4.1. Client Password
|
4
|
+
class OAuth2::Rack::Authentication::Client::HTTPBasic
|
5
|
+
HEADER_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION']
|
6
|
+
|
7
|
+
def initialize(app, opts = {}, &authenticator)
|
8
|
+
@app = app
|
9
|
+
@realm = opts.delete(:realm)
|
10
|
+
@required = opts.fetch(:required, true)
|
11
|
+
opts.delete(:required)
|
12
|
+
@authenticator = authenticator || opts.delete(:authenticator)
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
return @app.call(env) if env.has_key?('oauth2.client')
|
17
|
+
|
18
|
+
key = HEADER_KEYS.find { |k| env.has_key?(k) }
|
19
|
+
auth_string = env[key]
|
20
|
+
|
21
|
+
if auth_string.nil?
|
22
|
+
return @required ? unauthorized : @app.call(env)
|
23
|
+
end
|
24
|
+
|
25
|
+
schema, credentials = auth_string.split(' ', 2)
|
26
|
+
if schema.downcase != 'basic'
|
27
|
+
return bad_request
|
28
|
+
end
|
29
|
+
|
30
|
+
client_id, client_secret = credentials.unpack('m*').first.split(':', 2)
|
31
|
+
client = @authenticator.call(:client_id => client_id, :client_secret => client_secret)
|
32
|
+
if client
|
33
|
+
env['oauth2.client'] = client
|
34
|
+
@app.call(env)
|
35
|
+
else
|
36
|
+
unauthorized
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def authenticate(opts)
|
42
|
+
@authenticator && @authenticator.call(opts)
|
43
|
+
end
|
44
|
+
|
45
|
+
def unauthorized
|
46
|
+
[ 401,
|
47
|
+
{ 'Content-Type' => 'text/plain',
|
48
|
+
'Content-Length' => '0',
|
49
|
+
'WWW-Authenticate' => 'Basic realm="%s"' % @realm },
|
50
|
+
[]
|
51
|
+
]
|
52
|
+
end
|
53
|
+
|
54
|
+
def bad_request
|
55
|
+
[ 400,
|
56
|
+
{ 'Content-Type' => 'text/plain',
|
57
|
+
'Content-Length' => '0' },
|
58
|
+
[]
|
59
|
+
]
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'oauth2/rack'
|
2
|
+
|
3
|
+
# 2.4.1. Client Password
|
4
|
+
# Send client_id and client_secret in request params
|
5
|
+
class OAuth2::Rack::Authentication::Client::RequestParams
|
6
|
+
def initialize(app, opts = {}, &authenticator)
|
7
|
+
@app = app
|
8
|
+
@required = opts.fetch(:required, true)
|
9
|
+
opts.delete(:required)
|
10
|
+
@authenticator = authenticator || opts.delete(:authenticator)
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
return @app.call(env) if env.has_key?('oauth2.client')
|
15
|
+
|
16
|
+
@request = Rack::Request.new(env)
|
17
|
+
|
18
|
+
client_id = @request['client_id']
|
19
|
+
client_secret = @request['client_secret']
|
20
|
+
if client_id.nil? && client_secret.nil?
|
21
|
+
return @required ? unauthorized : @app.call(env)
|
22
|
+
elsif client_id.nil? || client_secret.nil?
|
23
|
+
return bad_request
|
24
|
+
end
|
25
|
+
|
26
|
+
client = @authenticator.call(:client_id => client_id, :client_secret => client_secret)
|
27
|
+
if client
|
28
|
+
env['oauth2.client'] = client
|
29
|
+
@app.call(env)
|
30
|
+
else
|
31
|
+
unauthorized
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def authenticate(opts)
|
37
|
+
@authenticator && @authenticator.call(opts)
|
38
|
+
end
|
39
|
+
|
40
|
+
def unauthorized
|
41
|
+
[ 401,
|
42
|
+
{ 'Content-Type' => 'text/plain',
|
43
|
+
'Content-Length' => '0' },
|
44
|
+
[]
|
45
|
+
]
|
46
|
+
end
|
47
|
+
|
48
|
+
def bad_request
|
49
|
+
[ 400,
|
50
|
+
{ 'Content-Type' => 'text/plain',
|
51
|
+
'Content-Length' => '0' },
|
52
|
+
[]
|
53
|
+
]
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'oauth2/rack'
|
2
|
+
|
3
|
+
# Authenticate resource owner with request params
|
4
|
+
class OAuth2::Rack::Authentication::ResourceOwner::RequestParams
|
5
|
+
def initialize(app, opts = {}, &authenticator)
|
6
|
+
@app = app
|
7
|
+
@required = opts.fetch(:required, true)
|
8
|
+
opts.delete(:required)
|
9
|
+
@authenticator = authenticator || opts.delete(:authenticator)
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
return @app.call(env) if env.has_key?('oauth2.resource_owner')
|
14
|
+
|
15
|
+
@request = Rack::Request.new(env)
|
16
|
+
|
17
|
+
username = @request['username']
|
18
|
+
password = @request['password']
|
19
|
+
if username.nil? && password.nil?
|
20
|
+
return @required ? unauthorized : @app.call(env)
|
21
|
+
elsif username.nil? || password.nil?
|
22
|
+
return bad_request
|
23
|
+
end
|
24
|
+
|
25
|
+
resource_owner = @authenticator.call(:username => username, :password => password)
|
26
|
+
if resource_owner
|
27
|
+
env['oauth2.resource_owner'] = resource_owner
|
28
|
+
@app.call(env)
|
29
|
+
else
|
30
|
+
unauthorized
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def authenticate(opts)
|
36
|
+
@authenticator && @authenticator.call(opts)
|
37
|
+
end
|
38
|
+
|
39
|
+
def unauthorized
|
40
|
+
[ 401,
|
41
|
+
{ 'Content-Type' => 'text/plain',
|
42
|
+
'Content-Length' => '0' },
|
43
|
+
[]
|
44
|
+
]
|
45
|
+
end
|
46
|
+
|
47
|
+
def bad_request
|
48
|
+
[ 400,
|
49
|
+
{ 'Content-Type' => 'text/plain',
|
50
|
+
'Content-Length' => '0' },
|
51
|
+
[]
|
52
|
+
]
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# @see 4.4.1 Client Credentials
|
2
|
+
require 'oauth2/rack'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
class OAuth2::Rack::Authorization::ClientCredentials::AccessTokenIssuer
|
6
|
+
def initialize(app, opts = {}, &issuer)
|
7
|
+
@app = app
|
8
|
+
|
9
|
+
@issuer = issuer || opts.delete(:issuer)
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
client = env['oauth2.client']
|
14
|
+
unless client
|
15
|
+
return error_response(:error => 'invalid_client')
|
16
|
+
end
|
17
|
+
|
18
|
+
request = Rack::Request.new(env)
|
19
|
+
unless request['grant_type'] == 'client_credentials'
|
20
|
+
return error_response(:error => 'invalid_request')
|
21
|
+
end
|
22
|
+
|
23
|
+
access_token = find_acccess_token(:grant_type => 'client_credentials',
|
24
|
+
:client => client,
|
25
|
+
:scope => request['scope'])
|
26
|
+
|
27
|
+
if access_token['error']
|
28
|
+
error_response(access_token)
|
29
|
+
else
|
30
|
+
successful_response(access_token)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def find_acccess_token(opts)
|
36
|
+
if @issuer
|
37
|
+
@issuer.call(opts)
|
38
|
+
end || { 'error' => 'unauthorized_client' }
|
39
|
+
end
|
40
|
+
|
41
|
+
def successful_response(response_object)
|
42
|
+
headers = {
|
43
|
+
'Content-Type' => 'application/json;charset=UTF-8',
|
44
|
+
'Cache-Control' => 'no-store',
|
45
|
+
'Pragma' => 'no-cache'
|
46
|
+
}
|
47
|
+
|
48
|
+
[200, headers, [MultiJson.encode(response_object)]]
|
49
|
+
end
|
50
|
+
|
51
|
+
def error_response(response_object)
|
52
|
+
headers = {
|
53
|
+
'Content-Type' => 'application/json;charset=UTF-8'
|
54
|
+
}
|
55
|
+
|
56
|
+
[400, headers, [MultiJson.encode(response_object)]]
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# @see 4.3. Resource Owner Password Credentials
|
2
|
+
require 'oauth2/rack'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
class OAuth2::Rack::Authorization::Password::AccessTokenIssuer
|
6
|
+
def initialize(app, opts = {}, &issuer)
|
7
|
+
@app = app
|
8
|
+
|
9
|
+
@issuer = issuer || opts.delete(:issuer)
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
resource_owner = env['oauth2.resource_owner']
|
14
|
+
unless resource_owner
|
15
|
+
return error_response(:error => 'invalid_grant')
|
16
|
+
end
|
17
|
+
|
18
|
+
request = Rack::Request.new(env)
|
19
|
+
unless request['grant_type'] == 'password'
|
20
|
+
return error_response(:error => 'invalid_request')
|
21
|
+
end
|
22
|
+
|
23
|
+
# oauth2.client is set in client authentication
|
24
|
+
access_token = find_acccess_token(:grant_type => 'password',
|
25
|
+
:resource_owner => resource_owner,
|
26
|
+
:client => env['oath2.client'],
|
27
|
+
:scope => request['scope'])
|
28
|
+
|
29
|
+
if access_token['error']
|
30
|
+
error_response(access_token)
|
31
|
+
else
|
32
|
+
successful_response(access_token)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def find_acccess_token(opts)
|
38
|
+
if @issuer
|
39
|
+
@issuer.call(opts)
|
40
|
+
end || { 'error' => 'unauthorized_client' }
|
41
|
+
end
|
42
|
+
|
43
|
+
def successful_response(response_object)
|
44
|
+
headers = {
|
45
|
+
'Content-Type' => 'application/json;charset=UTF-8',
|
46
|
+
'Cache-Control' => 'no-store',
|
47
|
+
'Pragma' => 'no-cache'
|
48
|
+
}
|
49
|
+
|
50
|
+
[200, headers, [MultiJson.encode(response_object)]]
|
51
|
+
end
|
52
|
+
|
53
|
+
def error_response(response_object)
|
54
|
+
headers = {
|
55
|
+
'Content-Type' => 'application/json;charset=UTF-8'
|
56
|
+
}
|
57
|
+
|
58
|
+
[400, headers, [MultiJson.encode(response_object)]]
|
59
|
+
end
|
60
|
+
end
|
data/lib/oauth2/rack.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'oauth2/rack/version'
|
2
|
+
|
3
|
+
module OAuth2
|
4
|
+
# Oauth2::Rack module, the top namespace for all oauth2-rack modules and classes
|
5
|
+
module Rack
|
6
|
+
autoload :Authorization, 'oauth2/rack/authorization'
|
7
|
+
autoload :Authentication, 'oauth2/rack/authentication'
|
8
|
+
end
|
9
|
+
end
|
data/lib/oauth2-rack.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'oauth2/rack'
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OAuth2::Rack::Authentication::Client::HTTPBasic do
|
4
|
+
let(:client) { double('client').as_null_object }
|
5
|
+
let(:authenticator) { double('authenticator').as_null_object }
|
6
|
+
let(:opts) { Hash.new }
|
7
|
+
let(:chained_app_response) { [200, { 'Content-Type' => 'text/plain' }, []] }
|
8
|
+
|
9
|
+
def do_request
|
10
|
+
post '/', opts
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'when oauth2.client is already set' do
|
14
|
+
it 'continues the app' do
|
15
|
+
opts['oauth2.client'] = client
|
16
|
+
chained_app.should_receive(:call).with(hash_including('oauth2.client' => client)).and_return(chained_app_response)
|
17
|
+
do_request
|
18
|
+
response.status.should eq(200)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when auth header is not specified' do
|
23
|
+
context 'and http basic auth is required' do
|
24
|
+
it 'responds with 401 unauthorized' do
|
25
|
+
do_request
|
26
|
+
response.status.should eq(401)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
context 'and http basic auth is optional' do
|
30
|
+
app { OAuth2::Rack::Authentication::Client::HTTPBasic.new(chained_app, :required => false) }
|
31
|
+
it 'continues the app' do
|
32
|
+
chained_app.should_receive(:call).with(hash_not_including('oauth2.client')).and_return(chained_app_response)
|
33
|
+
do_request
|
34
|
+
response.status.should eq(200)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when schema is not basic' do
|
40
|
+
before { opts['HTTP_AUTHORIZATION'] = 'Digest xxx' }
|
41
|
+
|
42
|
+
it 'responds with 400 bad request' do
|
43
|
+
do_request
|
44
|
+
response.status.should eq(400)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when schema is basic' do
|
49
|
+
app {
|
50
|
+
OAuth2::Rack::Authentication::Client::HTTPBasic.new(chained_app) do |opts|
|
51
|
+
authenticator.call(opts)
|
52
|
+
end
|
53
|
+
}
|
54
|
+
before { opts['HTTP_AUTHORIZATION'] = "Basic #{["user:pass"].pack('m*')}" }
|
55
|
+
|
56
|
+
context 'and credentials are valid' do
|
57
|
+
it 'sets oauth2.client in env' do
|
58
|
+
authenticator.should_receive(:call).with(:client_id => 'user', :client_secret => 'pass').and_return(client)
|
59
|
+
chained_app.should_receive(:call).with(hash_including('oauth2.client' => client)).and_return(chained_app_response)
|
60
|
+
|
61
|
+
do_request
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'but credentials are invalid' do
|
66
|
+
it 'responds with 401 unauthorized' do
|
67
|
+
authenticator.should_receive(:call).with(:client_id => 'user', :client_secret => 'pass').and_return(nil)
|
68
|
+
chained_app.should_not_receive(:call)
|
69
|
+
|
70
|
+
do_request
|
71
|
+
|
72
|
+
response.status.should eq(401)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OAuth2::Rack::Authentication::Client::RequestParams do
|
4
|
+
let(:client) { double('client').as_null_object }
|
5
|
+
let(:authenticator) { double('authenticator').as_null_object }
|
6
|
+
let(:params) { Hash.new }
|
7
|
+
let(:opts) { Hash[:params => params] }
|
8
|
+
let(:chained_app_response) { [200, { 'Content-Type' => 'text/plain' }, []] }
|
9
|
+
|
10
|
+
def do_request
|
11
|
+
post '/', opts
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when oauth2.client is already set' do
|
15
|
+
it 'continues the app' do
|
16
|
+
opts['oauth2.client'] = client
|
17
|
+
chained_app.should_receive(:call).with(hash_including('oauth2.client' => client)).and_return(chained_app_response)
|
18
|
+
do_request
|
19
|
+
response.status.should eq(200)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when client_id and client_secret are both missed' do
|
24
|
+
context 'and request params auth is required' do
|
25
|
+
it 'responds with 401 unauthorized' do
|
26
|
+
do_request
|
27
|
+
response.status.should eq(401)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
context 'and request params auth is optional' do
|
31
|
+
app { OAuth2::Rack::Authentication::Client::RequestParams.new(chained_app, :required => false) }
|
32
|
+
it 'continues the app' do
|
33
|
+
chained_app.should_receive(:call).with(hash_not_including('oauth2.client')).and_return(chained_app_response)
|
34
|
+
do_request
|
35
|
+
response.status.should eq(200)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when client_id is missed' do
|
41
|
+
before { params['client_secret'] = 'secret' }
|
42
|
+
|
43
|
+
it 'responds with 400 bad request' do
|
44
|
+
do_request
|
45
|
+
response.status.should eq(400)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
context 'when client_secret is missed' do
|
49
|
+
before { params['client_id'] = 'client_x' }
|
50
|
+
|
51
|
+
it 'responds with 400 bad request' do
|
52
|
+
do_request
|
53
|
+
response.status.should eq(400)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when client_id and client_secret are specified' do
|
58
|
+
app {
|
59
|
+
OAuth2::Rack::Authentication::Client::RequestParams.new(chained_app) do |opts|
|
60
|
+
authenticator.call(opts)
|
61
|
+
end
|
62
|
+
}
|
63
|
+
let(:credentials) { Hash[:client_id => 'client_x', :client_secret => 'secret'] }
|
64
|
+
before { params.merge! credentials }
|
65
|
+
|
66
|
+
context 'and credentials are valid' do
|
67
|
+
it 'sets oauth2.client in env' do
|
68
|
+
authenticator.should_receive(:call).with(credentials).and_return(client)
|
69
|
+
chained_app.should_receive(:call).with(hash_including('oauth2.client' => client)).and_return(chained_app_response)
|
70
|
+
|
71
|
+
do_request
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'but credentials are invalid' do
|
76
|
+
it 'responds with 401 unauthorized' do
|
77
|
+
authenticator.should_receive(:call).with(credentials).and_return(nil)
|
78
|
+
chained_app.should_not_receive(:call)
|
79
|
+
|
80
|
+
do_request
|
81
|
+
|
82
|
+
response.status.should eq(401)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OAuth2::Rack::Authentication::ResourceOwner::RequestParams do
|
4
|
+
let(:resource_owner) { double('resource_owner').as_null_object }
|
5
|
+
let(:authenticator) { double('authenticator').as_null_object }
|
6
|
+
let(:params) { Hash.new }
|
7
|
+
let(:opts) { Hash[:params => params] }
|
8
|
+
let(:chained_app_response) { [200, { 'Content-Type' => 'text/plain' }, []] }
|
9
|
+
|
10
|
+
def do_request
|
11
|
+
post '/', opts
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when oauth2.resource_owner is already set' do
|
15
|
+
it 'continues the app' do
|
16
|
+
opts['oauth2.resource_owner'] = resource_owner
|
17
|
+
chained_app.should_receive(:call).with(hash_including('oauth2.resource_owner' => resource_owner)).and_return(chained_app_response)
|
18
|
+
do_request
|
19
|
+
response.status.should eq(200)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when username and password are both missed' do
|
24
|
+
context 'and request params auth is required' do
|
25
|
+
it 'responds with 401 unauthorized' do
|
26
|
+
do_request
|
27
|
+
response.status.should eq(401)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
context 'and request params auth is optional' do
|
31
|
+
app { OAuth2::Rack::Authentication::ResourceOwner::RequestParams.new(chained_app, :required => false) }
|
32
|
+
it 'continues the app' do
|
33
|
+
chained_app.should_receive(:call).with(hash_not_including('oauth2.resource_owner')).and_return(chained_app_response)
|
34
|
+
do_request
|
35
|
+
response.status.should eq(200)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when username is missed' do
|
41
|
+
before { params['password'] = 'secret' }
|
42
|
+
|
43
|
+
it 'responds with 400 bad request' do
|
44
|
+
do_request
|
45
|
+
response.status.should eq(400)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
context 'when password is missed' do
|
49
|
+
before { params['username'] = 'user_x' }
|
50
|
+
|
51
|
+
it 'responds with 400 bad request' do
|
52
|
+
do_request
|
53
|
+
response.status.should eq(400)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when username and password are specified' do
|
58
|
+
app {
|
59
|
+
OAuth2::Rack::Authentication::ResourceOwner::RequestParams.new(chained_app) do |opts|
|
60
|
+
authenticator.call(opts)
|
61
|
+
end
|
62
|
+
}
|
63
|
+
let(:credentials) { Hash[:username => 'user_x', :password => 'secret'] }
|
64
|
+
before { params.merge! credentials }
|
65
|
+
|
66
|
+
context 'and credentials are valid' do
|
67
|
+
it 'sets oauth2.resource_owner in env' do
|
68
|
+
authenticator.should_receive(:call).with(credentials).and_return(resource_owner)
|
69
|
+
chained_app.should_receive(:call).with(hash_including('oauth2.resource_owner' => resource_owner)).and_return(chained_app_response)
|
70
|
+
|
71
|
+
do_request
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'but credentials are invalid' do
|
76
|
+
it 'responds with 401 unauthorized' do
|
77
|
+
authenticator.should_receive(:call).with(credentials).and_return(nil)
|
78
|
+
chained_app.should_not_receive(:call)
|
79
|
+
|
80
|
+
do_request
|
81
|
+
|
82
|
+
response.status.should eq(401)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OAuth2::Rack::Authorization::ClientCredentials::AccessTokenIssuer do
|
4
|
+
let(:client) { double('client') }
|
5
|
+
let(:opts) { Hash.new }
|
6
|
+
|
7
|
+
def do_request
|
8
|
+
post '/', opts
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'when client is authenticated' do
|
12
|
+
before { opts['oauth2.client'] = client }
|
13
|
+
|
14
|
+
context 'and grant_type is invalid' do
|
15
|
+
let(:params) { Hash[:grant_type => 'xclient_credentials'] }
|
16
|
+
before { opts[:params] = params }
|
17
|
+
|
18
|
+
it 'responds with invalid_request' do
|
19
|
+
do_request
|
20
|
+
|
21
|
+
response.status.should eq(400)
|
22
|
+
response_object['error'].should eq('invalid_request')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'and grant_type is valid' do
|
27
|
+
let(:params) { Hash[:grant_type => 'client_credentials'] }
|
28
|
+
before { opts[:params] = params }
|
29
|
+
|
30
|
+
context 'and issuer is not specified' do
|
31
|
+
it 'responds with unauthorized_client' do
|
32
|
+
do_request
|
33
|
+
|
34
|
+
response.status.should eq(400)
|
35
|
+
response_object['error'].should eq('unauthorized_client')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'and issuer is specified' do
|
40
|
+
let(:issuer) { double('issuer') }
|
41
|
+
let(:expected_find_opts) {
|
42
|
+
Hash[:grant_type => 'client_credentials',
|
43
|
+
:client => client,
|
44
|
+
:scope => nil]
|
45
|
+
}
|
46
|
+
|
47
|
+
app { OAuth2::Rack::Authorization::ClientCredentials::AccessTokenIssuer.new(chained_app) { |opts| issuer.call(opts) } }
|
48
|
+
|
49
|
+
context 'but token is not found for the client' do
|
50
|
+
context 'and error is returned' do
|
51
|
+
before {
|
52
|
+
issuer.should_receive(:call).with(expected_find_opts).and_return({'error' => 'customized_error'})
|
53
|
+
}
|
54
|
+
it 'responds with the that error' do
|
55
|
+
do_request
|
56
|
+
|
57
|
+
response.status.should eq(400)
|
58
|
+
response_object['error'].should eq('customized_error')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
context 'and nothing is returned' do
|
62
|
+
before {
|
63
|
+
issuer.should_receive(:call).with(expected_find_opts).and_return(nil)
|
64
|
+
}
|
65
|
+
it 'responds with unauthorized_client' do
|
66
|
+
do_request
|
67
|
+
|
68
|
+
response.status.should eq(400)
|
69
|
+
response_object['error'].should eq('unauthorized_client')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
context 'and token is found for the client' do
|
75
|
+
before {
|
76
|
+
issuer.should_receive(:call).with(expected_find_opts).and_return({:access_token => 'X'})
|
77
|
+
}
|
78
|
+
|
79
|
+
it 'responds with the found token' do
|
80
|
+
do_request
|
81
|
+
|
82
|
+
response.status.should eq(200)
|
83
|
+
response_object['access_token'].should eq('X')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'when client not authenticated' do
|
92
|
+
before { post '/' }
|
93
|
+
|
94
|
+
it 'responds with invalid_client' do
|
95
|
+
response.status.should eq(400)
|
96
|
+
response_object['error'].should eq('invalid_client')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OAuth2::Rack::Authorization::Password::AccessTokenIssuer do
|
4
|
+
let(:resource_owner) { double('resource_owner') }
|
5
|
+
let(:client) { double('client') }
|
6
|
+
let(:opts) { Hash.new }
|
7
|
+
|
8
|
+
def do_request
|
9
|
+
post '/', opts
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when resource_owner is authenticated' do
|
13
|
+
before { opts['oauth2.resource_owner'] = resource_owner }
|
14
|
+
|
15
|
+
context 'and grant_type is invalid' do
|
16
|
+
let(:params) { Hash[:grant_type => 'xpassword'] }
|
17
|
+
before { opts[:params] = params }
|
18
|
+
|
19
|
+
it 'responds with invalid_request' do
|
20
|
+
do_request
|
21
|
+
|
22
|
+
response.status.should eq(400)
|
23
|
+
response_object['error'].should eq('invalid_request')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'and grant_type is valid' do
|
28
|
+
let(:params) { Hash[:grant_type => 'password'] }
|
29
|
+
before { opts[:params] = params }
|
30
|
+
|
31
|
+
context 'and issuer is not specified' do
|
32
|
+
it 'responds with unauthorized_client' do
|
33
|
+
do_request
|
34
|
+
|
35
|
+
response.status.should eq(400)
|
36
|
+
response_object['error'].should eq('unauthorized_client')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'and issuer is specified' do
|
41
|
+
let(:issuer) { double('issuer') }
|
42
|
+
let(:expected_find_opts) {
|
43
|
+
Hash[:grant_type => 'password',
|
44
|
+
:resource_owner => resource_owner,
|
45
|
+
:client => nil,
|
46
|
+
:scope => nil]
|
47
|
+
}
|
48
|
+
|
49
|
+
app { OAuth2::Rack::Authorization::Password::AccessTokenIssuer.new(chained_app) { |opts| issuer.call(opts) } }
|
50
|
+
|
51
|
+
context 'but token is not found for the resource owner' do
|
52
|
+
context 'and error is returned' do
|
53
|
+
before {
|
54
|
+
issuer.should_receive(:call).with(expected_find_opts).and_return({'error' => 'customized_error'})
|
55
|
+
}
|
56
|
+
it 'responds with the that error' do
|
57
|
+
do_request
|
58
|
+
|
59
|
+
response.status.should eq(400)
|
60
|
+
response_object['error'].should eq('customized_error')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
context 'and nothing is returned' do
|
64
|
+
before {
|
65
|
+
issuer.should_receive(:call).with(expected_find_opts).and_return(nil)
|
66
|
+
}
|
67
|
+
it 'responds with unauthorized_client' do
|
68
|
+
do_request
|
69
|
+
|
70
|
+
response.status.should eq(400)
|
71
|
+
response_object['error'].should eq('unauthorized_client')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
context 'and token is found for the client' do
|
77
|
+
before {
|
78
|
+
issuer.should_receive(:call).with(expected_find_opts).and_return({:access_token => 'X'})
|
79
|
+
}
|
80
|
+
|
81
|
+
it 'responds with the found token' do
|
82
|
+
do_request
|
83
|
+
|
84
|
+
response.status.should eq(200)
|
85
|
+
response_object['access_token'].should eq('X')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when resource owner not authenticated' do
|
94
|
+
before { post '/' }
|
95
|
+
|
96
|
+
it 'responds with invalid_grant' do
|
97
|
+
response.status.should eq(400)
|
98
|
+
response_object['error'].should eq('invalid_grant')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
$: << File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'oauth2/rack'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
6
|
+
# in spec/support/ and its subdirectories.
|
7
|
+
Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f}
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.mock_with :rspec
|
11
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'rack/mock'
|
2
|
+
require 'rack/utils'
|
3
|
+
|
4
|
+
module RackTestHelper
|
5
|
+
def self.included(klass)
|
6
|
+
klass.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :response
|
10
|
+
|
11
|
+
def chained_app
|
12
|
+
if defined?(@original_chained_app)
|
13
|
+
@original_chained_app
|
14
|
+
else
|
15
|
+
@original_chained_app = instance_eval(&self.class.chained_app)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def app
|
20
|
+
if defined?(@original_app)
|
21
|
+
@original_app
|
22
|
+
else
|
23
|
+
@original_app = instance_eval(&self.class.app)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def request
|
28
|
+
@request ||= Rack::MockRequest.new(app)
|
29
|
+
end
|
30
|
+
|
31
|
+
def response_object
|
32
|
+
return unless response
|
33
|
+
|
34
|
+
case response['Content-Type']
|
35
|
+
when %r{^application/json}
|
36
|
+
MultiJson::decode(response.body)
|
37
|
+
when %r{^application/x-www-form-urlencoded}
|
38
|
+
Rack::Utils.new.parse(response.body)
|
39
|
+
else
|
40
|
+
response.body
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def get(uri, opts = {})
|
45
|
+
self.response = request.get(uri, opts)
|
46
|
+
end
|
47
|
+
def post(uri, opts = {})
|
48
|
+
self.response = request.post(uri, opts)
|
49
|
+
end
|
50
|
+
def put(uri, opts = {})
|
51
|
+
self.response = request.put(uri, opts)
|
52
|
+
end
|
53
|
+
def delete(uri, opts = {})
|
54
|
+
self.response = request.delete(uri, opts)
|
55
|
+
end
|
56
|
+
|
57
|
+
module ClassMethods
|
58
|
+
attr_reader :explicit_chained_app_block
|
59
|
+
def chained_app(&block)
|
60
|
+
block ? @explicit_chained_app_block = block : explicit_chained_app || implicit_chained_app
|
61
|
+
end
|
62
|
+
|
63
|
+
attr_reader :explicit_app_block
|
64
|
+
def app(&block)
|
65
|
+
block ? @explicit_app_block = block : explicit_app || implicit_app
|
66
|
+
end
|
67
|
+
|
68
|
+
def explicit_app
|
69
|
+
group = self
|
70
|
+
while group.respond_to?(:explicit_app_block)
|
71
|
+
return group.explicit_app_block if group.explicit_app_block
|
72
|
+
group = group.superclass
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def implicit_app
|
77
|
+
described = describes || description
|
78
|
+
Class === described ? proc { described.new(chained_app) } : proc { described }
|
79
|
+
end
|
80
|
+
|
81
|
+
def explicit_chained_app
|
82
|
+
group = self
|
83
|
+
while group.respond_to?(:explicit_chained_app_block)
|
84
|
+
return group.explicit_chained_app_block if group.explicit_chained_app_block
|
85
|
+
group = group.superclass
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def implicit_chained_app
|
90
|
+
proc { |env| [200, {"Content-Type" => 'text/html'}, ["<p>OK</p>"]] }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
RSpec.configure do |config|
|
96
|
+
config.include RackTestHelper
|
97
|
+
end
|
metadata
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: oauth2-rack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ian Yang
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-08-26 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: multi_json
|
16
|
+
requirement: &8610000 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *8610000
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rack
|
27
|
+
requirement: &8609580 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *8609580
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake
|
38
|
+
requirement: &8609160 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *8609160
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: &8608740 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *8608740
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: yard
|
60
|
+
requirement: &8608320 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *8608320
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: shotgun
|
71
|
+
requirement: &8607900 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *8607900
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: guard-rspec
|
82
|
+
requirement: &8607480 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *8607480
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: oauth2
|
93
|
+
requirement: &8607060 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *8607060
|
102
|
+
description: Rack middlewares for OAuth2 authorization server and resource server
|
103
|
+
email:
|
104
|
+
- me@iany.me
|
105
|
+
executables: []
|
106
|
+
extensions: []
|
107
|
+
extra_rdoc_files: []
|
108
|
+
files:
|
109
|
+
- .gitignore
|
110
|
+
- .rspec
|
111
|
+
- Gemfile
|
112
|
+
- Guardfile
|
113
|
+
- Rakefile
|
114
|
+
- config.ru
|
115
|
+
- examples/ruby-client/password_authorization.rb
|
116
|
+
- lib/oauth2-rack.rb
|
117
|
+
- lib/oauth2/rack.rb
|
118
|
+
- lib/oauth2/rack/authentication.rb
|
119
|
+
- lib/oauth2/rack/authentication/client.rb
|
120
|
+
- lib/oauth2/rack/authentication/client/http_basic.rb
|
121
|
+
- lib/oauth2/rack/authentication/client/request_params.rb
|
122
|
+
- lib/oauth2/rack/authentication/resource_owner.rb
|
123
|
+
- lib/oauth2/rack/authentication/resource_owner/request_params.rb
|
124
|
+
- lib/oauth2/rack/authorization.rb
|
125
|
+
- lib/oauth2/rack/authorization/client_credentials.rb
|
126
|
+
- lib/oauth2/rack/authorization/client_credentials/access_token_issuer.rb
|
127
|
+
- lib/oauth2/rack/authorization/password.rb
|
128
|
+
- lib/oauth2/rack/authorization/password/access_token_issuer.rb
|
129
|
+
- spec/oauth2/rack/authentication/client/http_basic_spec.rb
|
130
|
+
- spec/oauth2/rack/authentication/client/request_params_spec.rb
|
131
|
+
- spec/oauth2/rack/authentication/resource_owner/request_params_spec.rb
|
132
|
+
- spec/oauth2/rack/authorization/client_credentials/access_token_issuer_spec.rb
|
133
|
+
- spec/oauth2/rack/authorization/password/access_token_issuer_spec.rb
|
134
|
+
- spec/spec_helper.rb
|
135
|
+
- spec/support/rake_test_helper.rb
|
136
|
+
homepage: https://github.com/doitian/oauth2-rack
|
137
|
+
licenses: []
|
138
|
+
post_install_message:
|
139
|
+
rdoc_options: []
|
140
|
+
require_paths:
|
141
|
+
- lib
|
142
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
143
|
+
none: false
|
144
|
+
requirements:
|
145
|
+
- - ! '>='
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ! '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
requirements: []
|
155
|
+
rubyforge_project: oauth2-rack
|
156
|
+
rubygems_version: 1.8.6
|
157
|
+
signing_key:
|
158
|
+
specification_version: 3
|
159
|
+
summary: Rack middlewares for OAuth2 authorization server and resource server
|
160
|
+
test_files:
|
161
|
+
- spec/oauth2/rack/authentication/client/http_basic_spec.rb
|
162
|
+
- spec/oauth2/rack/authentication/client/request_params_spec.rb
|
163
|
+
- spec/oauth2/rack/authentication/resource_owner/request_params_spec.rb
|
164
|
+
- spec/oauth2/rack/authorization/client_credentials/access_token_issuer_spec.rb
|
165
|
+
- spec/oauth2/rack/authorization/password/access_token_issuer_spec.rb
|
166
|
+
- spec/spec_helper.rb
|
167
|
+
- spec/support/rake_test_helper.rb
|