warden-oauth2 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +13 -0
- data/Guardfile +11 -0
- data/README.md +160 -0
- data/Rakefile +8 -0
- data/lib/warden-oauth2.rb +1 -0
- data/lib/warden/oauth2.rb +32 -0
- data/lib/warden/oauth2/error_app.rb +22 -0
- data/lib/warden/oauth2/failure_app.rb +22 -0
- data/lib/warden/oauth2/strategies/base.rb +17 -0
- data/lib/warden/oauth2/strategies/bearer.rb +30 -0
- data/lib/warden/oauth2/strategies/client.rb +47 -0
- data/lib/warden/oauth2/strategies/public.rb +21 -0
- data/lib/warden/oauth2/strategies/token.rb +40 -0
- data/lib/warden/oauth2/version.rb +5 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/warden/oauth2/failure_app_spec.rb +30 -0
- data/spec/warden/oauth2/strategies/bearer_spec.rb +32 -0
- data/spec/warden/oauth2/strategies/client_spec.rb +73 -0
- data/spec/warden/oauth2/strategies/public_spec.rb +26 -0
- data/spec/warden/oauth2/strategies/token_spec.rb +56 -0
- data/warden-oauth2.gemspec +22 -0
- metadata +129 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MGU5NWUxMzQzZjJjYTliNjYxY2NiZjJkZDY4NjJjMTUwNTk4NDExMg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZjM1ODEyMDM5ZjYyZTMzMzFjMWNkMThjM2FkNDM0NDVjMjBiOTQ2YQ==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ODdjNGZhZjFmOTNiM2IyODUzYjZlNzBmZTY1YmI1OWQ5ODJhZTA2YTgwZjUw
|
10
|
+
OTUxZTYyYmU2MTIzZjI1MTdiNGEwMjM0MTcyMDU2MTJmOTU2NWIyNzg0OTU1
|
11
|
+
Yjc4ODgzYWI1NTM0ZGQzMzVjZjUzNGJiYTkwMWFmNzNiNzc5MDQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NDFhMGJlZWE0N2M2MmE1YjE0YTIzMWUzMDY3ODFmODVhNDMzMThkZjE0YjI4
|
14
|
+
MzBjOTNiNjkzNzMwZTVhMDkxYWExMDg2ZTBhODUzMjY0MmY2NWQwMjI1Nzgy
|
15
|
+
ZGY0NTBhNzAyZjVhMWVhM2I5ZTcxOGVkZjI5YjEwZjE1ZTMwYWQ=
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
# Warden::OAuth2 [![CI Status](https://secure.travis-ci.org/opperator/warden-oauth2.png)](http://travis-ci.org/opperator/warden-oauth2)
|
2
|
+
|
3
|
+
This library provides a robust set of authorization strategies for
|
4
|
+
Warden meant to be used to implement an OAuth 2.0 ([draft 22][oauth2])
|
5
|
+
provider.
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
### Grape API Example
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
require 'grape'
|
13
|
+
require 'warden-oauth2'
|
14
|
+
|
15
|
+
class MyAPI < Grape::API
|
16
|
+
use Warden::Manager do |config|
|
17
|
+
strategies.add :bearer, Warden::OAuth2::Strategies::Bearer
|
18
|
+
strategies.add :client, Warden::OAuth2::Strategies::Client
|
19
|
+
strategies.add :public, Warden::OAuth2::Strategies::Public
|
20
|
+
|
21
|
+
config.default_strategies :bearer, :client, :public
|
22
|
+
config.failure_app Warden::OAuth2::FailureApp
|
23
|
+
end
|
24
|
+
|
25
|
+
helpers do
|
26
|
+
def warden; env['warden'] end
|
27
|
+
end
|
28
|
+
|
29
|
+
resources :hamburgers do
|
30
|
+
before do
|
31
|
+
warden.authenticate! scope: :hamburgers
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
## Configuration
|
38
|
+
|
39
|
+
You can configure Warden::OAuth2 like so:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
Warden::OAuth2.configure do |config|
|
43
|
+
config.some_option = some_value
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
### Configurable Options
|
48
|
+
|
49
|
+
* **client_model:** A client application class. See **Models** below.
|
50
|
+
Defaults to `ClientApplication`.
|
51
|
+
* **token_model:** An access token class. See **Models** below. Defaults
|
52
|
+
to `AccessToken`.
|
53
|
+
|
54
|
+
## Models
|
55
|
+
|
56
|
+
You will need to supply data models to back up the persistent facets of
|
57
|
+
your OAuth 2.0 implementation. Below are examples of the interfaces that
|
58
|
+
each require.
|
59
|
+
|
60
|
+
### Client Application
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
class ClientApplication
|
64
|
+
# REQUIRED
|
65
|
+
def self.locate(client_id, client_secret = nil)
|
66
|
+
# Should return a client application matching the client_id
|
67
|
+
# provided, but should ONLY match client_secret if it is
|
68
|
+
# provided.
|
69
|
+
end
|
70
|
+
|
71
|
+
# OPTIONAL
|
72
|
+
def scope?(scope)
|
73
|
+
# True if the client should be able to access the scope passed
|
74
|
+
# (usually a symbol) without having an access token.
|
75
|
+
end
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
### Access Token
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
class AccessToken
|
83
|
+
# REQUIRED
|
84
|
+
def self.locate(token_string)
|
85
|
+
# Should return an access token matching the string provided.
|
86
|
+
# Note that you MAY include expired access tokens in the result
|
87
|
+
# of this method so long as you implement an instance #expired?
|
88
|
+
# method.
|
89
|
+
end
|
90
|
+
|
91
|
+
# OPTIONAL
|
92
|
+
def expired?
|
93
|
+
# True if the access token has reached its expiration.
|
94
|
+
end
|
95
|
+
|
96
|
+
# OPTIONAL
|
97
|
+
def scope?(scope)
|
98
|
+
# True if the scope passed in (usually a symbol) has been authorized
|
99
|
+
# for this access token.
|
100
|
+
end
|
101
|
+
end
|
102
|
+
```
|
103
|
+
|
104
|
+
## Strategies
|
105
|
+
|
106
|
+
### Bearer
|
107
|
+
|
108
|
+
This strategy authenticates by trying to find an access token that is
|
109
|
+
supplied according to the OAuth 2.0 Bearer Token specification
|
110
|
+
([draft 8][oauth2-bearer]). It does this by first extracting the access
|
111
|
+
token in string form and then calling the `.locate` method on your
|
112
|
+
access token model (see **Configuration** above).
|
113
|
+
|
114
|
+
Token-based strategies will also fail if they are expired or lack
|
115
|
+
sufficient scope. See **Models** above.
|
116
|
+
|
117
|
+
**User:** The Warden user is set to the client application returned by
|
118
|
+
`.locate`.
|
119
|
+
|
120
|
+
### Client
|
121
|
+
|
122
|
+
This strategy authenticates an OAuth 2.0 client application directly for
|
123
|
+
endpoints that don't require a specific user. You might use this
|
124
|
+
strategy when you want to create an API for client statistics or if you
|
125
|
+
wish to rate limit based on a client application even for publicly
|
126
|
+
accessible endpoints.
|
127
|
+
|
128
|
+
**User:** The Warden user is set to the access token returned by `.locate`.
|
129
|
+
|
130
|
+
### Public
|
131
|
+
|
132
|
+
This strategy succeeds by default and only fails if the authentication
|
133
|
+
scope is set and is something other than `:public`.
|
134
|
+
|
135
|
+
**User:** The Warden user is set to `nil`.
|
136
|
+
|
137
|
+
[oauth2]: http://tools.ietf.org/html/draft-ietf-oauth-v2-22
|
138
|
+
[oauth2-bearer]: http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-08
|
139
|
+
|
140
|
+
## License
|
141
|
+
|
142
|
+
Copyright (C) 2011 by Michael Bleigh and Opperator, Inc.
|
143
|
+
|
144
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
145
|
+
of this software and associated documentation files (the "Software"), to deal
|
146
|
+
in the Software without restriction, including without limitation the rights
|
147
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
148
|
+
copies of the Software, and to permit persons to whom the Software is
|
149
|
+
furnished to do so, subject to the following conditions:
|
150
|
+
|
151
|
+
The above copyright notice and this permission notice shall be included in
|
152
|
+
all copies or substantial portions of the Software.
|
153
|
+
|
154
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
155
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
156
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
157
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
158
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
159
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
160
|
+
THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'warden/oauth2'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'warden'
|
2
|
+
require 'warden/oauth2/version'
|
3
|
+
|
4
|
+
module Warden
|
5
|
+
module OAuth2
|
6
|
+
class Configuration
|
7
|
+
attr_accessor :client_model, :token_model
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
self.client_model = ClientApplication if defined?(ClientApplication)
|
11
|
+
self.token_model = AccessToken if defined?(AccessToken)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.config
|
16
|
+
@@config ||= Configuration.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.configure
|
20
|
+
yield config
|
21
|
+
end
|
22
|
+
|
23
|
+
autoload :FailureApp, 'warden/oauth2/failure_app'
|
24
|
+
module Strategies
|
25
|
+
autoload :Base, 'warden/oauth2/strategies/base'
|
26
|
+
autoload :Public, 'warden/oauth2/strategies/public'
|
27
|
+
autoload :Token, 'warden/oauth2/strategies/token'
|
28
|
+
autoload :Client, 'warden/oauth2/strategies/client'
|
29
|
+
autoload :Bearer, 'warden/oauth2/strategies/bearer'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'warden-oauth2'
|
2
|
+
|
3
|
+
module Warden
|
4
|
+
module OAuth2
|
5
|
+
class ErrorApp
|
6
|
+
def self.call(env)
|
7
|
+
new.call(env)
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
warden = env['warden']
|
12
|
+
strategy = warden.winning_strategy
|
13
|
+
status = strategy.respond_to?(:error_status) ? strategy.error_status : 401
|
14
|
+
headers = {'Content-Type' => 'application/json'}
|
15
|
+
headers['X-Accepted-OAuth-Scopes'] = (strategy.scope || :public).to_s
|
16
|
+
body = "{\"error\":\"#{strategy.message}}"
|
17
|
+
|
18
|
+
Rack::Response.new(body, status, headers).finish
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Warden
|
2
|
+
module OAuth2
|
3
|
+
class FailureApp
|
4
|
+
def self.call(env)
|
5
|
+
new.call(env)
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
warden = env['warden']
|
10
|
+
strategy = warden.winning_strategy
|
11
|
+
|
12
|
+
body = '{"error":"' + strategy.message.to_s + '"}'
|
13
|
+
status = strategy.error_status rescue 401
|
14
|
+
headers = {'Content-Type' => 'application/json'}
|
15
|
+
|
16
|
+
headers['X-Accepted-OAuth-Scopes'] = (strategy.scope || :public).to_s
|
17
|
+
|
18
|
+
[status, headers, [body]]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'warden-oauth2'
|
2
|
+
|
3
|
+
module Warden
|
4
|
+
module OAuth2
|
5
|
+
module Strategies
|
6
|
+
class Bearer < Token
|
7
|
+
def valid?
|
8
|
+
!!token_string
|
9
|
+
end
|
10
|
+
|
11
|
+
def token_string
|
12
|
+
token_string_from_header || token_string_from_request_params
|
13
|
+
end
|
14
|
+
|
15
|
+
def token_string_from_header
|
16
|
+
Rack::Auth::AbstractRequest::AUTHORIZATION_KEYS.each do |key|
|
17
|
+
if env.key?(key) && token_string = env[key][/^Bearer (.*)/, 1]
|
18
|
+
return token_string
|
19
|
+
end
|
20
|
+
end
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def token_string_from_request_params
|
25
|
+
params[:access_token]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'warden-oauth2'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module Warden
|
5
|
+
module OAuth2
|
6
|
+
module Strategies
|
7
|
+
class Client < Base
|
8
|
+
attr_reader :client, :client_id, :client_secret
|
9
|
+
|
10
|
+
def authenticate!
|
11
|
+
@client = client_from_http_basic || client_from_request_params
|
12
|
+
|
13
|
+
if self.client
|
14
|
+
fail "insufficient_scope" and return if scope && client.respond_to?(:scope) && !client.scope?(scope)
|
15
|
+
success! self.client
|
16
|
+
else
|
17
|
+
fail "invalid_client"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def client_from_http_basic
|
22
|
+
return nil unless (env.keys & Rack::Auth::AbstractRequest::AUTHORIZATION_KEYS).any?
|
23
|
+
@client_id, @client_secret = *Rack::Auth::Basic::Request.new(env).credentials
|
24
|
+
Warden::OAuth2.config.client_model.locate(self.client_id, self.client_secret)
|
25
|
+
end
|
26
|
+
|
27
|
+
def client_from_request_params
|
28
|
+
@client_id, @client_secret = params[:client_id], params[:client_secret]
|
29
|
+
return nil unless self.client_id
|
30
|
+
Warden::OAuth2.config.client_model.locate(@client_id, @client_secret)
|
31
|
+
end
|
32
|
+
|
33
|
+
def public_client?
|
34
|
+
client && !client_secret
|
35
|
+
end
|
36
|
+
|
37
|
+
def error_status
|
38
|
+
case message
|
39
|
+
when "invalid_client" then 401
|
40
|
+
when "insufficient_scope" then 403
|
41
|
+
else 400
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'warden-oauth2'
|
2
|
+
|
3
|
+
module Warden
|
4
|
+
module OAuth2
|
5
|
+
module Strategies
|
6
|
+
class Public < Base
|
7
|
+
def authenticate!
|
8
|
+
if scope && scope.to_sym != :public
|
9
|
+
fail! "insufficient_scope" and return
|
10
|
+
end
|
11
|
+
|
12
|
+
success! nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def error_status
|
16
|
+
401
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'warden-oauth2'
|
2
|
+
|
3
|
+
module Warden
|
4
|
+
module OAuth2
|
5
|
+
module Strategies
|
6
|
+
class Token < Base
|
7
|
+
def valid?
|
8
|
+
!!token_string
|
9
|
+
end
|
10
|
+
|
11
|
+
def authenticate!
|
12
|
+
if token
|
13
|
+
fail! "invalid_token" and return if token.respond_to?(:expired?) && token.expired?
|
14
|
+
fail! "insufficient_scope" and return if scope && token.respond_to?(:scope?) && !token.scope?(scope)
|
15
|
+
success! token
|
16
|
+
else
|
17
|
+
fail! "invalid_request" and return unless token
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def token
|
22
|
+
Warden::OAuth2.config.token_model.locate(token_string)
|
23
|
+
end
|
24
|
+
|
25
|
+
def token_string
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
|
29
|
+
def error_status
|
30
|
+
case message
|
31
|
+
when "invalid_token" then 401
|
32
|
+
when "insufficient_scope" then 403
|
33
|
+
when "invalid_request" then 400
|
34
|
+
else 400
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Warden::OAuth2::FailureApp do
|
4
|
+
let(:app){ subject }
|
5
|
+
let(:warden){ mock(:winning_strategy => @strategy || strategy) }
|
6
|
+
let(:strategy){ mock(:message => 'invalid_request') }
|
7
|
+
|
8
|
+
context 'with all info' do
|
9
|
+
before do
|
10
|
+
@strategy = mock(:error_status => 502, :message => 'custom', :scope => 'random')
|
11
|
+
get '/unauthenticated', {}, 'warden' => warden
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should set the status from error_status if there is one' do
|
15
|
+
last_response.status.should == 502
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should set the message from the message' do
|
19
|
+
last_response.body.should == '{"error":"custom"}'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should set the content type' do
|
23
|
+
last_response.headers['Content-Type'].should == 'application/json'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should set the X-OAuth-Accepted-Scopes header' do
|
27
|
+
last_response.headers['X-Accepted-OAuth-Scopes'].should == 'random'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Warden::OAuth2::Strategies::Bearer do
|
4
|
+
let(:strategy){ Warden::OAuth2::Strategies::Bearer }
|
5
|
+
let(:token_model){ mock(:AccessToken) }
|
6
|
+
subject{ strategy.new({'rack.input' => {}}) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
Warden::OAuth2.config.token_model = token_model
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#token_string_from_header' do
|
13
|
+
Rack::Auth::AbstractRequest::AUTHORIZATION_KEYS.each do |key|
|
14
|
+
it "should recognize a bearer token in the #{key} environment key" do
|
15
|
+
subject.stub!(:env).and_return({key => "Bearer abc"})
|
16
|
+
subject.token_string_from_header.should == 'abc'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should ignore a non-bearer authorization header' do
|
21
|
+
subject.stub!(:env).and_return('HTTP_AUTHORIZATION' => 'Other do do do')
|
22
|
+
subject.token_string_from_header.should be_nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#token_string_from_request_params' do
|
27
|
+
it 'should pull the :access_token param' do
|
28
|
+
subject.stub!(:params).and_return(:access_token => 'abc')
|
29
|
+
subject.token_string_from_request_params.should == 'abc'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Warden::OAuth2::Strategies::Client do
|
4
|
+
let(:strategy){ Warden::OAuth2::Strategies::Client }
|
5
|
+
let(:client_model){ mock(:ClientApplication) }
|
6
|
+
subject{ strategy.new({'rack.input' => {}}) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
Warden::OAuth2.config.client_model = client_model
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#client_from_http_basic' do
|
13
|
+
it 'should call through to the client application class locate method' do
|
14
|
+
subject.stub!(:env).and_return({
|
15
|
+
'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('id:secret')}"
|
16
|
+
})
|
17
|
+
|
18
|
+
client_model.should_receive(:locate).with('id','secret').and_return("booya")
|
19
|
+
subject.client_from_http_basic.should == "booya"
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should return nil if no HTTP Basic credentials are provided' do
|
23
|
+
subject.client_from_http_basic.should be_nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#client_from_request_params' do
|
28
|
+
it 'should be nil if no client_id is provided' do
|
29
|
+
subject.stub!(:params).and_return({:client_secret => 'abc'})
|
30
|
+
subject.client_from_request_params.should be_nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should call through to locate if a client_id is present' do
|
34
|
+
subject.stub!(:params).and_return({:client_id => 'abc'})
|
35
|
+
client_model.should_receive(:locate).with('abc',nil)
|
36
|
+
subject.client_from_request_params
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should call through to locate if a client_id and secret are present' do
|
40
|
+
subject.stub!(:params).and_return({:client_id => 'abc', :client_secret => 'def'})
|
41
|
+
client_model.should_receive(:locate).with('abc','def')
|
42
|
+
subject.client_from_request_params
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#authorize!' do
|
47
|
+
it 'should succeed if a client is around' do
|
48
|
+
client_instance = mock
|
49
|
+
client_model.stub!(:locate).and_return(client_instance)
|
50
|
+
subject.stub!(:params).and_return(:client_id => 'awesome')
|
51
|
+
subject._run!
|
52
|
+
subject.user.should == client_instance
|
53
|
+
subject.result.should == :success
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should fail if no credentials are passed' do
|
57
|
+
subject._run!
|
58
|
+
subject.result.should == :failure
|
59
|
+
subject.message.should == "invalid_client"
|
60
|
+
subject.error_status.should == 401
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should fail if insufficient scope is provided' do
|
64
|
+
client_model.stub!(:locate).and_return(mock(:respond_to? => true, :scope? => false))
|
65
|
+
subject.stub!(:params).and_return(:client_id => 'abc')
|
66
|
+
subject.stub!(:scope).and_return(:confidential_client)
|
67
|
+
subject._run!
|
68
|
+
subject.result.should == :failure
|
69
|
+
subject.message.should == "insufficient_scope"
|
70
|
+
subject.error_status.should == 403
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Warden::OAuth2::Strategies::Public do
|
4
|
+
let(:env){ {'PATH_INFO' => '/resource'} }
|
5
|
+
let(:strategy){ Warden::OAuth2::Strategies::Public }
|
6
|
+
subject{ strategy.new(env) }
|
7
|
+
|
8
|
+
it 'should succeed with no scope' do
|
9
|
+
subject._run!
|
10
|
+
subject.result.should == :success
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should succeed with a :public scope' do
|
14
|
+
subject.stub!(:scope).and_return(:public)
|
15
|
+
subject._run!
|
16
|
+
subject.result.should == :success
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should fail and halt with another scope' do
|
20
|
+
subject.stub!(:scope).and_return(:user)
|
21
|
+
subject._run!
|
22
|
+
subject.should be_halted
|
23
|
+
subject.message.should == "insufficient_scope"
|
24
|
+
subject.result.should == :failure
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Warden::OAuth2::Strategies::Token do
|
4
|
+
let(:token_model){ mock }
|
5
|
+
let(:strategy){ Warden::OAuth2::Strategies::Token }
|
6
|
+
subject{ strategy.new({'rack.input' => {}}) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
Warden::OAuth2.config.token_model = token_model
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#token' do
|
13
|
+
it 'should call through to .locate on the token_class with the token string' do
|
14
|
+
token_model.should_receive(:locate).with('abc')
|
15
|
+
subject.stub!(:token_string).and_return('abc')
|
16
|
+
subject.token
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#authenticate!' do
|
21
|
+
it 'should be successful if there is a token' do
|
22
|
+
token_instance = mock
|
23
|
+
subject.stub!(:token).and_return(token_instance)
|
24
|
+
subject._run!
|
25
|
+
subject.result.should == :success
|
26
|
+
subject.user.should == token_instance
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should fail if there is not a token' do
|
30
|
+
subject.stub!(:token).and_return(nil)
|
31
|
+
subject._run!
|
32
|
+
subject.result.should == :failure
|
33
|
+
subject.message.should == "invalid_request"
|
34
|
+
subject.error_status.should == 400
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should fail if the access token is expired' do
|
38
|
+
token_instance = mock(:respond_to? => true, :expired? => true, :scope? => true)
|
39
|
+
subject.stub!(:token).and_return(token_instance)
|
40
|
+
subject._run!
|
41
|
+
subject.result.should == :failure
|
42
|
+
subject.message.should == "invalid_token"
|
43
|
+
subject.error_status.should == 401
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should fail if there is insufficient scope' do
|
47
|
+
token_instance = mock(:respond_to? => true, :expired? => false, :scope? => false)
|
48
|
+
subject.stub!(:token).and_return(token_instance)
|
49
|
+
subject.stub!(:scope).and_return(:secret)
|
50
|
+
subject._run!
|
51
|
+
subject.result.should == :failure
|
52
|
+
subject.message.should == "insufficient_scope"
|
53
|
+
subject.error_status.should == 403
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/warden/oauth2/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Michael Bleigh"]
|
6
|
+
gem.email = ["michael@intridea.com"]
|
7
|
+
gem.description = %q{OAuth 2.0 strategies for Warden}
|
8
|
+
gem.summary = %q{OAuth 2.0 strategies for Warden}
|
9
|
+
gem.homepage = "https://github.com/opperator/warden-oauth2"
|
10
|
+
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
gem.name = "warden-oauth2"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Warden::OAuth2::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'warden'
|
19
|
+
gem.add_development_dependency 'rake'
|
20
|
+
gem.add_development_dependency 'rspec'
|
21
|
+
gem.add_development_dependency 'rack-test'
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: warden-oauth2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Bleigh
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-04-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: warden
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rack-test
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: OAuth 2.0 strategies for Warden
|
70
|
+
email:
|
71
|
+
- michael@intridea.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- .rspec
|
78
|
+
- .travis.yml
|
79
|
+
- Gemfile
|
80
|
+
- Guardfile
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- lib/warden-oauth2.rb
|
84
|
+
- lib/warden/oauth2.rb
|
85
|
+
- lib/warden/oauth2/error_app.rb
|
86
|
+
- lib/warden/oauth2/failure_app.rb
|
87
|
+
- lib/warden/oauth2/strategies/base.rb
|
88
|
+
- lib/warden/oauth2/strategies/bearer.rb
|
89
|
+
- lib/warden/oauth2/strategies/client.rb
|
90
|
+
- lib/warden/oauth2/strategies/public.rb
|
91
|
+
- lib/warden/oauth2/strategies/token.rb
|
92
|
+
- lib/warden/oauth2/version.rb
|
93
|
+
- spec/spec_helper.rb
|
94
|
+
- spec/warden/oauth2/failure_app_spec.rb
|
95
|
+
- spec/warden/oauth2/strategies/bearer_spec.rb
|
96
|
+
- spec/warden/oauth2/strategies/client_spec.rb
|
97
|
+
- spec/warden/oauth2/strategies/public_spec.rb
|
98
|
+
- spec/warden/oauth2/strategies/token_spec.rb
|
99
|
+
- warden-oauth2.gemspec
|
100
|
+
homepage: https://github.com/opperator/warden-oauth2
|
101
|
+
licenses: []
|
102
|
+
metadata: {}
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ! '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
requirements: []
|
118
|
+
rubyforge_project:
|
119
|
+
rubygems_version: 2.0.3
|
120
|
+
signing_key:
|
121
|
+
specification_version: 4
|
122
|
+
summary: OAuth 2.0 strategies for Warden
|
123
|
+
test_files:
|
124
|
+
- spec/spec_helper.rb
|
125
|
+
- spec/warden/oauth2/failure_app_spec.rb
|
126
|
+
- spec/warden/oauth2/strategies/bearer_spec.rb
|
127
|
+
- spec/warden/oauth2/strategies/client_spec.rb
|
128
|
+
- spec/warden/oauth2/strategies/public_spec.rb
|
129
|
+
- spec/warden/oauth2/strategies/token_spec.rb
|