devise_oauth2_providable 0.2.4 → 0.3.0

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/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