devise_oauth2_providable 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -36,7 +36,9 @@ end
36
36
  class User
37
37
  # NOTE: include :database_authenticatable configuration
38
38
  # if supporting Resource Owner Password Credentials Grant Type
39
- devise :oauth2_providable
39
+ devise :oauth2_providable,
40
+ :oauth2_password_grantable,
41
+ :oauth2_refresh_token_grantable
40
42
  end
41
43
  ```
42
44
 
@@ -0,0 +1,16 @@
1
+ class Oauth2::TokensController < ApplicationController
2
+ before_filter :authenticate_user!
3
+
4
+ def create
5
+ @refresh_token = oauth2_current_refresh_token || oauth2_current_client.refresh_tokens.create!(:user => current_user)
6
+ @access_token = @refresh_token.access_tokens.create!(:client => oauth2_current_client, :user => current_user)
7
+ render :json => @access_token.token_response
8
+ end
9
+ private
10
+ def oauth2_current_client
11
+ env['oauth2.client']
12
+ end
13
+ def oauth2_current_refresh_token
14
+ env['oauth2.refresh_token']
15
+ end
16
+ end
@@ -7,12 +7,14 @@ class AccessToken < ActiveRecord::Base
7
7
  before_validation :restrict_expires_at, :if => :refresh_token
8
8
  belongs_to :refresh_token
9
9
 
10
- def to_bearer_token
11
- bearer_token = Rack::OAuth2::AccessToken::Bearer.new :access_token => self.token, :expires_in => self.expires_in
12
- if refresh_token
13
- bearer_token.refresh_token = refresh_token.token
14
- end
15
- bearer_token
10
+ def token_response
11
+ response = {
12
+ :access_token => token,
13
+ :token_type => 'bearer',
14
+ :expires_in => expires_in
15
+ }
16
+ response[:refresh_token] = refresh_token.token if refresh_token
17
+ response
16
18
  end
17
19
 
18
20
  private
data/config/routes.rb CHANGED
@@ -2,8 +2,8 @@ require 'token_endpoint'
2
2
  Rails.application.routes.draw do |map|
3
3
  namespace 'oauth2' do
4
4
  resources :authorizations, :only => :create
5
+ resource :token, :only => :create
5
6
  end
6
7
 
7
8
  match 'oauth2/authorize' => 'oauth2/authorizations#new'
8
- post 'oauth2/token' => TokenEndpoint.new
9
9
  end
@@ -0,0 +1,6 @@
1
+ module Devise
2
+ module Models
3
+ module Oauth2PasswordGrantable
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Devise
2
+ module Models
3
+ module Oauth2RefreshTokenGrantable
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,28 @@
1
+ require 'devise/strategies/base'
2
+
3
+ module Devise
4
+ module Strategies
5
+ class Oauth2GrantTypeStrategy < Authenticatable
6
+ def valid?
7
+ params[:controller] == 'oauth2/tokens' && request.post? && params[:grant_type] == grant_type
8
+ end
9
+
10
+ # defined by subclass
11
+ def grant_type
12
+ end
13
+
14
+ def client
15
+ @client ||= Client.find_by_identifier params[:client_id]
16
+ env['oauth2.client'] = @client
17
+ @client
18
+ end
19
+ # return custom error response in accordance with the oauth spec
20
+ # see http://tools.ietf.org/html/draft-ietf-oauth-v2-16#section-4.3
21
+ def oauth_error!(error_code = :invalid_request, description = nil)
22
+ body = {:error => error_code}
23
+ body[:error_description] = description if description
24
+ custom! [400, {'Content-Type' => 'application/json'}, [body.to_json]]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,22 @@
1
+ require 'devise_oauth2_providable/strategies/oauth2_grant_type_strategy'
2
+
3
+ module Devise
4
+ module Strategies
5
+ class Oauth2PasswordGrantTypeStrategy < Oauth2GrantTypeStrategy
6
+ def grant_type
7
+ 'password'
8
+ end
9
+
10
+ def authenticate!
11
+ resource = mapping.to.find_for_authentication(mapping.to.authentication_keys.first => params[:username])
12
+ if client && validate(resource) { resource.valid_password?(params[:password]) }
13
+ success! resource
14
+ elsif !halted?
15
+ oauth_error! :invalid_grant, 'invalid password authentication request'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ Warden::Strategies.add(:oauth2_password_grantable, Devise::Strategies::Oauth2PasswordGrantTypeStrategy)
@@ -0,0 +1,22 @@
1
+ require 'devise_oauth2_providable/strategies/oauth2_grant_type_strategy'
2
+
3
+ module Devise
4
+ module Strategies
5
+ class Oauth2RefreshTokenGrantTypeStrategy < Oauth2GrantTypeStrategy
6
+ def grant_type
7
+ 'refresh_token'
8
+ end
9
+
10
+ def authenticate!
11
+ if client && refresh_token = client.refresh_tokens.valid.find_by_token(params[:refresh_token])
12
+ env['oauth2.refresh_token'] = refresh_token
13
+ success! refresh_token.user
14
+ elsif !halted?
15
+ oauth_error! :invalid_grant, 'invalid refresh token'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ Warden::Strategies.add(:oauth2_refresh_token_grantable, Devise::Strategies::Oauth2RefreshTokenGrantTypeStrategy)
@@ -2,7 +2,7 @@ require 'devise/strategies/base'
2
2
 
3
3
  module Devise
4
4
  module Strategies
5
- class Oauth2Providable < Base
5
+ class Oauth2Providable < Authenticatable
6
6
  def valid?
7
7
  @req = Rack::OAuth2::Server::Resource::Bearer::Request.new(env)
8
8
  @req.oauth2?
@@ -17,22 +17,6 @@ module Devise
17
17
  fail(:invalid_token)
18
18
  end
19
19
  end
20
-
21
- private
22
- # Simply invokes valid_for_authentication? with the given block and deal with the result.
23
- def validate(resource, &block)
24
- result = resource && resource.valid_for_authentication?(&block)
25
-
26
- case result
27
- when String, Symbol
28
- fail!(result)
29
- false
30
- when TrueClass
31
- true
32
- else
33
- result
34
- end
35
- end
36
20
  end
37
21
  end
38
22
  end
@@ -1,5 +1,5 @@
1
1
  module Devise
2
2
  module Oauth2Providable
3
- VERSION = "0.2.4"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
@@ -4,6 +4,10 @@ require 'devise_oauth2_providable/strategy'
4
4
  require 'devise_oauth2_providable/model'
5
5
  require 'devise_oauth2_providable/schema'
6
6
  require 'devise_oauth2_providable/engine'
7
+ require 'devise_oauth2_providable/strategies/oauth2_password_grant_type_strategy'
8
+ require 'devise_oauth2_providable/strategies/oauth2_refresh_token_grant_type_strategy'
9
+ require 'devise_oauth2_providable/models/oauth2_password_grantable'
10
+ require 'devise_oauth2_providable/models/oauth2_refresh_token_grantable'
7
11
 
8
12
  module Devise
9
13
  module Oauth2Providable
@@ -18,4 +22,9 @@ end
18
22
  Devise.add_module(:oauth2_providable,
19
23
  :strategy => true,
20
24
  :model => 'devise_oauth2_providable/model')
21
-
25
+ Devise.add_module(:oauth2_password_grantable,
26
+ :strategy => true,
27
+ :model => 'devise_oauth2_providable/models/oauth2_password_grantable')
28
+ Devise.add_module(:oauth2_refresh_token_grantable,
29
+ :strategy => true,
30
+ :model => 'devise_oauth2_providable/models/oauth2_refresh_token_grantable')
@@ -1,3 +1,3 @@
1
1
  class User < ActiveRecord::Base
2
- devise :database_authenticatable, :oauth2_providable
2
+ devise :database_authenticatable, :oauth2_providable, :oauth2_password_grantable, :oauth2_refresh_token_grantable
3
3
  end
@@ -191,4 +191,8 @@ Devise.setup do |config|
191
191
  # manager.intercept_401 = false
192
192
  # manager.default_strategies(:scope => :user).unshift :some_external_strategy
193
193
  # end
194
+ # config.warden do |manager|
195
+ # manager.default_strategies(:scope => :user).unshift :oauth2_password_grant_type
196
+ # manager.default_strategies(:scope => :user).unshift :oauth2_refresh_token_grant_type
197
+ # end
194
198
  end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Oauth2::TokensController do
4
+ describe 'routing' do
5
+ it 'routes POST /oauth2/token' do
6
+ {:post => '/oauth2/token'}.should route_to(:controller => 'oauth2/tokens', :action => 'create')
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe Devise::Strategies::Oauth2PasswordGrantTypeStrategy do
4
+ describe 'POST /oauth2/token' do
5
+ describe 'with grant_type=password' do
6
+ context 'with valid params' do
7
+ before do
8
+ @user = User.create! :email => 'ryan@socialcast.com', :name => 'ryan sonnek', :password => 'test'
9
+ @client = Client.create! :name => 'example', :redirect_uri => 'http://localhost', :website => 'http://localhost'
10
+
11
+ params = {
12
+ :grant_type => 'password',
13
+ :client_id => @client.identifier,
14
+ :client_secret => @client.secret,
15
+ :username => @user.email,
16
+ :password => 'test'
17
+ }
18
+
19
+ post '/oauth2/token', params
20
+ end
21
+ it { response.code.to_i.should == 200 }
22
+ it { response.content_type.should == 'application/json' }
23
+ it 'returns json' do
24
+ token = AccessToken.last
25
+ expected = token.token_response
26
+ response.body.should match_json(expected)
27
+ end
28
+ end
29
+ context 'with invalid params' do
30
+ before do
31
+ @user = User.create! :email => 'ryan@socialcast.com', :name => 'ryan sonnek', :password => 'test'
32
+ @client = Client.create! :name => 'example', :redirect_uri => 'http://localhost', :website => 'http://localhost'
33
+
34
+ params = {
35
+ :grant_type => 'password',
36
+ :client_id => @client.identifier,
37
+ :client_secret => @client.secret,
38
+ :username => @user.email,
39
+ :password => 'bar'
40
+ }
41
+
42
+ post '/oauth2/token', params
43
+ end
44
+ it { response.code.to_i.should == 400 }
45
+ it { response.content_type.should == 'application/json' }
46
+ it 'returns json' do
47
+ expected = {
48
+ :error_description => "invalid password authentication request",
49
+ :error => "invalid_grant"
50
+ }
51
+ response.body.should match_json(expected)
52
+ end
53
+ end
54
+ context 'with invalid client' do
55
+ before do
56
+ @user = User.create! :email => 'ryan@socialcast.com', :name => 'ryan sonnek', :password => 'test'
57
+
58
+ params = {
59
+ :grant_type => 'password',
60
+ :client_id => '123',
61
+ :client_secret => 'invalid',
62
+ :username => @user.email,
63
+ :password => 'test'
64
+ }
65
+
66
+ post '/oauth2/token', params
67
+ end
68
+ it { response.code.to_i.should == 400 }
69
+ it { response.content_type.should == 'application/json' }
70
+ it 'returns json' do
71
+ expected = {
72
+ :error_description => "invalid password authentication request",
73
+ :error => "invalid_grant"
74
+ }
75
+ response.body.should match_json(expected)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe Devise::Strategies::Oauth2RefreshTokenGrantTypeStrategy do
4
+ describe 'POST /oauth2/token' do
5
+ describe 'with grant_type=refresh_token' do
6
+ context 'with valid params' do
7
+ before do
8
+ @user = User.create! :email => 'ryan@socialcast.com', :name => 'ryan sonnek', :password => 'test'
9
+ @client = Client.create! :name => 'example', :redirect_uri => 'http://localhost', :website => 'http://localhost'
10
+ @refresh_token = @client.refresh_tokens.create! :user => @user
11
+ params = {
12
+ :grant_type => 'refresh_token',
13
+ :client_id => @client.identifier,
14
+ :client_secret => @client.secret,
15
+ :refresh_token => @refresh_token.token
16
+ }
17
+
18
+ post '/oauth2/token', params
19
+ end
20
+ it { response.code.to_i.should == 200 }
21
+ it { response.content_type.should == 'application/json' }
22
+ it 'returns json' do
23
+ token = AccessToken.last
24
+ refresh_token = @refresh_token
25
+ expected = {
26
+ :token_type => 'bearer',
27
+ :expires_in => 899,
28
+ :refresh_token => refresh_token.token,
29
+ :access_token => token.token
30
+ }
31
+ response.body.should match_json(expected)
32
+ end
33
+ end
34
+ context 'with invalid refresh_token' do
35
+ before do
36
+ @user = User.create! :email => 'ryan@socialcast.com', :name => 'ryan sonnek', :password => 'test'
37
+ @client = Client.create! :name => 'example', :redirect_uri => 'http://localhost', :website => 'http://localhost'
38
+ @refresh_token = @client.refresh_tokens.create! :user => @user
39
+ params = {
40
+ :grant_type => 'refresh_token',
41
+ :client_id => @client.identifier,
42
+ :client_secret => @client.secret,
43
+ :refresh_token => 'invalid'
44
+ }
45
+
46
+ post '/oauth2/token', params
47
+ end
48
+ it { response.code.to_i.should == 400 }
49
+ it { response.content_type.should == 'application/json' }
50
+ it 'returns json' do
51
+ token = AccessToken.last
52
+ refresh_token = @refresh_token
53
+ expected = {
54
+ :error => 'invalid_grant',
55
+ :error_description => 'invalid refresh token'
56
+ }
57
+ response.body.should match_json(expected)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -7,6 +7,13 @@ require 'rspec/rails'
7
7
  # in spec/support/ and its subdirectories.
8
8
  Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
9
9
 
10
+ # "{'foo': 'bar'}".should match_json {:foo => :bar}
11
+ RSpec::Matchers.define :match_json do |expected|
12
+ match do |actual|
13
+ ActiveSupport::JSON.backend.decode(actual) == ActiveSupport::JSON.backend.decode(expected.to_json)
14
+ end
15
+ end
16
+
10
17
  RSpec.configure do |config|
11
18
  config.include Devise::TestHelpers, :type => :controller
12
19
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise_oauth2_providable
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 2
9
- - 4
10
- version: 0.2.4
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ryan Sonnek
@@ -15,12 +15,10 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-05-19 00:00:00 Z
18
+ date: 2011-06-21 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: rails
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
21
+ version_requirements: &id001 !ruby/object:Gem::Requirement
24
22
  none: false
25
23
  requirements:
26
24
  - - ~>
@@ -31,12 +29,12 @@ dependencies:
31
29
  - 0
32
30
  - 7
33
31
  version: 3.0.7
32
+ name: rails
34
33
  type: :runtime
35
- version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
37
- name: devise
34
+ requirement: *id001
38
35
  prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
36
+ - !ruby/object:Gem::Dependency
37
+ version_requirements: &id002 !ruby/object:Gem::Requirement
40
38
  none: false
41
39
  requirements:
42
40
  - - ~>
@@ -47,12 +45,12 @@ dependencies:
47
45
  - 3
48
46
  - 3
49
47
  version: 1.3.3
48
+ name: devise
50
49
  type: :runtime
51
- version_requirements: *id002
52
- - !ruby/object:Gem::Dependency
53
- name: rack-oauth2
50
+ requirement: *id002
54
51
  prerelease: false
55
- requirement: &id003 !ruby/object:Gem::Requirement
52
+ - !ruby/object:Gem::Dependency
53
+ version_requirements: &id003 !ruby/object:Gem::Requirement
56
54
  none: false
57
55
  requirements:
58
56
  - - ~>
@@ -63,12 +61,12 @@ dependencies:
63
61
  - 6
64
62
  - 3
65
63
  version: 0.6.3
64
+ name: rack-oauth2
66
65
  type: :runtime
67
- version_requirements: *id003
68
- - !ruby/object:Gem::Dependency
69
- name: rspec
66
+ requirement: *id003
70
67
  prerelease: false
71
- requirement: &id004 !ruby/object:Gem::Requirement
68
+ - !ruby/object:Gem::Dependency
69
+ version_requirements: &id004 !ruby/object:Gem::Requirement
72
70
  none: false
73
71
  requirements:
74
72
  - - ">="
@@ -79,8 +77,10 @@ dependencies:
79
77
  - 5
80
78
  - 0
81
79
  version: 2.5.0
80
+ name: rspec
82
81
  type: :development
83
- version_requirements: *id004
82
+ requirement: *id004
83
+ prerelease: false
84
84
  description: Rails3 engine that adds OAuth2 Provider support to any application built with Devise authentication
85
85
  email:
86
86
  - ryan@socialcast.com
@@ -99,6 +99,7 @@ files:
99
99
  - README.md
100
100
  - Rakefile
101
101
  - app/controllers/oauth2/authorizations_controller.rb
102
+ - app/controllers/oauth2/tokens_controller.rb
102
103
  - app/models/access_token.rb
103
104
  - app/models/authorization_code.rb
104
105
  - app/models/client.rb
@@ -111,7 +112,12 @@ files:
111
112
  - lib/devise_oauth2_providable.rb
112
113
  - lib/devise_oauth2_providable/engine.rb
113
114
  - lib/devise_oauth2_providable/model.rb
115
+ - lib/devise_oauth2_providable/models/oauth2_password_grantable.rb
116
+ - lib/devise_oauth2_providable/models/oauth2_refresh_token_grantable.rb
114
117
  - lib/devise_oauth2_providable/schema.rb
118
+ - lib/devise_oauth2_providable/strategies/oauth2_grant_type_strategy.rb
119
+ - lib/devise_oauth2_providable/strategies/oauth2_password_grant_type_strategy.rb
120
+ - lib/devise_oauth2_providable/strategies/oauth2_refresh_token_grant_type_strategy.rb
115
121
  - lib/devise_oauth2_providable/strategy.rb
116
122
  - lib/devise_oauth2_providable/version.rb
117
123
  - lib/expirable_token.rb
@@ -162,7 +168,9 @@ files:
162
168
  - spec/rails_app/public/stylesheets/.gitkeep
163
169
  - spec/rails_app/script/rails
164
170
  - spec/rails_app/spec/controllers/protected_controller_spec.rb
165
- - spec/rails_app/spec/integration/token_endpoint_spec.rb
171
+ - spec/rails_app/spec/controllers/tokens_controller_spec.rb
172
+ - spec/rails_app/spec/integration/oauth2_password_grant_type_strategy_spec.rb
173
+ - spec/rails_app/spec/integration/oauth2_refresh_token_grant_type_strategy_spec.rb
166
174
  - spec/rails_app/spec/models/access_token_spec.rb
167
175
  - spec/rails_app/spec/models/authorization_code_spec.rb
168
176
  - spec/rails_app/spec/models/client_spec.rb
@@ -252,7 +260,9 @@ test_files:
252
260
  - spec/rails_app/public/stylesheets/.gitkeep
253
261
  - spec/rails_app/script/rails
254
262
  - spec/rails_app/spec/controllers/protected_controller_spec.rb
255
- - spec/rails_app/spec/integration/token_endpoint_spec.rb
263
+ - spec/rails_app/spec/controllers/tokens_controller_spec.rb
264
+ - spec/rails_app/spec/integration/oauth2_password_grant_type_strategy_spec.rb
265
+ - spec/rails_app/spec/integration/oauth2_refresh_token_grant_type_strategy_spec.rb
256
266
  - spec/rails_app/spec/models/access_token_spec.rb
257
267
  - spec/rails_app/spec/models/authorization_code_spec.rb
258
268
  - spec/rails_app/spec/models/client_spec.rb
@@ -1,87 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe TokenEndpoint do
4
- describe 'refresh_token grant type' do
5
- context 'with valid params' do
6
- before do
7
- @user = User.create! :email => 'ryan@socialcast.com', :name => 'ryan sonnek', :password => 'test'
8
- @client = Client.create! :name => 'example', :redirect_uri => 'http://localhost', :website => 'http://localhost'
9
- @refresh_token = @client.refresh_tokens.create! :user => @user
10
- params = {
11
- :grant_type => 'refresh_token',
12
- :client_id => @client.identifier,
13
- :client_secret => @client.secret,
14
- :refresh_token => @refresh_token.token
15
- }
16
-
17
- post '/oauth2/token', params
18
- end
19
- it { response.code.to_i.should == 200 }
20
- it 'returns json' do
21
- token = AccessToken.last
22
- refresh_token = @refresh_token
23
- expected = {
24
- :token_type => 'bearer',
25
- :expires_in => 899,
26
- :refresh_token => refresh_token.token,
27
- :access_token => token.token
28
- }
29
- response.body.should == expected.to_json
30
- end
31
- end
32
- end
33
- describe 'password grant type' do
34
- context 'with valid params' do
35
- before do
36
- @user = User.create! :email => 'ryan@socialcast.com', :name => 'ryan sonnek', :password => 'test'
37
- @client = Client.create! :name => 'example', :redirect_uri => 'http://localhost', :website => 'http://localhost'
38
-
39
- params = {
40
- :grant_type => 'password',
41
- :client_id => @client.identifier,
42
- :client_secret => @client.secret,
43
- :username => @user.email,
44
- :password => 'test'
45
- }
46
-
47
- post '/oauth2/token', params
48
- end
49
- it { response.code.to_i.should == 200 }
50
- it 'returns json' do
51
- token = AccessToken.last
52
- refresh_token = RefreshToken.last
53
- expected = {
54
- :token_type => 'bearer',
55
- :expires_in => 899,
56
- :refresh_token => refresh_token.token,
57
- :access_token => token.token
58
- }
59
- response.body.should == expected.to_json
60
- end
61
- end
62
- context 'with invalid params' do
63
- before do
64
- @user = User.create! :email => 'ryan@socialcast.com', :name => 'ryan sonnek', :password => 'test'
65
- @client = Client.create! :name => 'example', :redirect_uri => 'http://localhost', :website => 'http://localhost'
66
-
67
- params = {
68
- :grant_type => 'password',
69
- :client_id => @client.identifier,
70
- :client_secret => @client.secret,
71
- :username => @user.email,
72
- :password => 'bar'
73
- }
74
-
75
- post '/oauth2/token', params
76
- end
77
- it { response.code.to_i.should == 400 }
78
- it 'returns json' do
79
- expected = {
80
- :error_description => "The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, expired authorization token, bad end-user password credentials, or mismatching authorization code and redirection URI).",
81
- :error => "invalid_grant"
82
- }
83
- response.body.should == expected.to_json
84
- end
85
- end
86
- end
87
- end