doorkeeper 2.1.3 → 2.1.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1d2ce14647afc9a16514c9f3b340eb31b8b24f88
4
- data.tar.gz: fa3a726152a14c5496abb9433a1ea92f0d588b9f
3
+ metadata.gz: f81bfc8acb70b14d07f1d1cfa39d608b70488890
4
+ data.tar.gz: e27b15693c23faf2348358e307757a0cdf088e7d
5
5
  SHA512:
6
- metadata.gz: f9877675927e23991fd103d4e08480270e1dc5d365f3ba7fd4bf1fd1cce5a27c916a56572c0e5f9083c76be0850f128fa2baf5628679910e3f5efd68a46e4bcd
7
- data.tar.gz: 684c840627ac5e3b7a6eeddac43c3ef758222f5b2296021c3686cbb51bdc50a701269cd80bec2164c24fd5be4bb668f5b3ed63ec9bb492fcab1e2406ff229424
6
+ metadata.gz: f0981eb39aba13e7191309b2d6703d58c175dd28df746867b1b466f9a62c9e5978f705f7df617268d082a210ff4bc5da1206a17849a0e1b0ee87746cf96d77fb
7
+ data.tar.gz: 207f6e7ec14a8369e3c27ee9af38a87d273556681438938c61c80454dd23628c838b2ff4c8e462e49ce6ed0cdfcf99481fb9c54b5b8752422a598c9bf238d78b
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.1.4
4
+
5
+ - [#595] HTTP spec: Add `scope` for refresh token scope param
6
+ - [#596] Limit scopes in app scopes for client credentials
7
+ - [#567] Add Grape helpers for easier integration with Grape framework
8
+ - [#606] Add custom access token expiration support for Client Credentials flow
9
+
10
+
3
11
  ## 2.1.3
4
12
 
5
13
  - [#588] Fixes scopes_match? bug that skipped authorization form in some cases
data/README.md CHANGED
@@ -5,7 +5,11 @@
5
5
  [![Code Climate](https://codeclimate.com/github/applicake/doorkeeper.svg)](https://codeclimate.com/github/applicake/doorkeeper)
6
6
  [![Gem Version](https://badge.fury.io/rb/doorkeeper.svg)](https://rubygems.org/gems/doorkeeper)
7
7
 
8
- Doorkeeper is a gem that makes it easy to introduce OAuth 2 provider functionality to your application.
8
+ Doorkeeper is a gem that makes it easy to introduce OAuth 2 provider
9
+ functionality to your Rails or Grape application.
10
+
11
+ [PR 567]: https://github.com/doorkeeper-gem/doorkeeper/pull/567
12
+
9
13
 
10
14
  ## Documentation valid for `master` branch
11
15
 
@@ -25,6 +29,7 @@ https://github.com/doorkeeper-gem/doorkeeper/releases.
25
29
  - [Routes](#routes)
26
30
  - [Authenticating](#authenticating)
27
31
  - [Protecting resources with OAuth (a.k.a your API endpoint)](#protecting-resources-with-oauth-aka-your-api-endpoint)
32
+ - [Protect your API with OAuth when using Grape](#protect-your-api-with-oauth-when-using-grape)
28
33
  - [Route Constraints and other integrations](#route-constraints-and-other-integrations)
29
34
  - [Access Token Scopes](#access-token-scopes)
30
35
  - [Authenticated resource owner](#authenticated-resource-owner)
@@ -169,6 +174,36 @@ end
169
174
  You can pass any option `before_action` accepts, such as `if`, `only`,
170
175
  `except`, and others.
171
176
 
177
+ ### Protect your API with OAuth when using Grape
178
+
179
+ As of [PR 567] doorkeeper has helpers for Grape. One of them is
180
+ `doorkeeper_authorize!` and can be used in a similar way as an example above.
181
+ Note that you have to use `require 'doorkeeper/grape/helpers'` and
182
+ `helpers Doorkeeper::Grape::Helpers`.
183
+
184
+ For more information about integration with Grape see the [Wiki].
185
+
186
+ [PR 567]: https://github.com/doorkeeper-gem/doorkeeper/pull/567
187
+ [Wiki]: https://github.com/doorkeeper-gem/doorkeeper/wiki/Grape-Integration
188
+
189
+ ``` ruby
190
+ require 'doorkeeper/grape/helpers'
191
+
192
+ module API
193
+ module V1
194
+ class Users < Grape::API
195
+ helpers Doorkeeper::Grape::Helpers
196
+
197
+ before do
198
+ doorkeeper_authorize!
199
+ end
200
+
201
+ # ...
202
+ end
203
+ end
204
+ end
205
+ ```
206
+
172
207
 
173
208
  ### Route Constraints and other integrations
174
209
 
@@ -1,4 +1,4 @@
1
- ENV['rails'] ||= '4.2.0.rc2'
1
+ ENV['rails'] ||= '4.2.0'
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
@@ -0,0 +1,17 @@
1
+ module Doorkeeper
2
+ module Grape
3
+ class AuthorizationDecorator < SimpleDelegator
4
+ def parameters
5
+ params
6
+ end
7
+
8
+ def authorization
9
+ env = __getobj__.env
10
+ env['HTTP_AUTHORIZATION'] ||
11
+ env['X-HTTP_AUTHORIZATION'] ||
12
+ env['X_HTTP_AUTHORIZATION'] ||
13
+ env['REDIRECT_X_HTTP_AUTHORIZATION']
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,46 @@
1
+ require 'doorkeeper/grape/authorization_decorator'
2
+
3
+ module Doorkeeper
4
+ module Grape
5
+ module Helpers
6
+ extend ::Grape::API::Helpers
7
+ include Doorkeeper::Rails::Helpers
8
+
9
+ # endpoint specific scopes > parameter scopes > default scopes
10
+ def doorkeeper_authorize!(*scopes)
11
+ endpoint_scopes = env['api.endpoint'].options[:route_options][:scopes]
12
+ scopes = if endpoint_scopes
13
+ Doorkeeper::OAuth::Scopes.from_array(endpoint_scopes)
14
+ elsif scopes && !scopes.empty?
15
+ Doorkeeper::OAuth::Scopes.from_array(scopes)
16
+ end
17
+
18
+ super(*scopes)
19
+ end
20
+
21
+ def doorkeeper_render_error_with(error)
22
+ status_code = case error.status
23
+ when :unauthorized
24
+ 401
25
+ when :forbidden
26
+ 403
27
+ end
28
+
29
+ error!({ error: error.description }, status_code)
30
+ end
31
+
32
+ private
33
+
34
+ def doorkeeper_token
35
+ @_doorkeeper_token ||= OAuth::Token.authenticate(
36
+ decorated_request,
37
+ *Doorkeeper.configuration.access_token_methods
38
+ )
39
+ end
40
+
41
+ def decorated_request
42
+ AuthorizationDecorator.new(request)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -24,11 +24,13 @@ module Doorkeeper
24
24
  private
25
25
 
26
26
  def create_token(client, scopes, creator)
27
+ ttl = Authorization::Token.access_token_expires_in(@server, client)
28
+
27
29
  creator.call(
28
30
  client,
29
31
  scopes,
30
32
  use_refresh_token: false,
31
- expires_in: @server.access_token_expires_in
33
+ expires_in: ttl
32
34
  )
33
35
  end
34
36
  end
@@ -25,7 +25,7 @@ module Doorkeeper
25
25
  end
26
26
 
27
27
  def validate_scopes
28
- return true unless @request.original_scopes.present?
28
+ return true unless @request.scopes.present?
29
29
 
30
30
  application_scopes = if @client.present?
31
31
  @client.application.scopes
@@ -34,7 +34,7 @@ module Doorkeeper
34
34
  end
35
35
 
36
36
  ScopeChecker.valid?(
37
- @request.original_scopes,
37
+ @request.scopes.to_s,
38
38
  @server.scopes,
39
39
  application_scopes
40
40
  )
@@ -18,7 +18,7 @@ module Doorkeeper
18
18
  @server = server
19
19
  @refresh_token = refresh_token
20
20
  @credentials = credentials
21
- @original_scopes = parameters[:scopes]
21
+ @original_scopes = parameters[:scope] || parameters[:scopes]
22
22
  @refresh_token_parameter = parameters[:refresh_token]
23
23
 
24
24
  if credentials
@@ -1,3 +1,3 @@
1
1
  module Doorkeeper
2
- VERSION = '2.1.3'
2
+ VERSION = '2.1.4'
3
3
  end
@@ -1,5 +1,5 @@
1
1
  class FullProtectedResourcesController < ApplicationController
2
- before_filter -> { doorkeeper_authorize! :admin }, only: :show
2
+ before_filter -> { doorkeeper_authorize! :write, :admin }, only: :show
3
3
  before_filter :doorkeeper_authorize!, only: :index
4
4
 
5
5
  def index
@@ -21,4 +21,6 @@ FactoryGirl.define do
21
21
  sequence(:name) { |n| "Application #{n}" }
22
22
  redirect_uri 'https://app.com/callback'
23
23
  end
24
+
25
+ factory :user
24
26
  end
@@ -5,7 +5,13 @@ require 'doorkeeper/oauth/client_credentials/issuer'
5
5
  class Doorkeeper::OAuth::ClientCredentialsRequest
6
6
  describe Issuer do
7
7
  let(:creator) { double :acces_token_creator }
8
- let(:server) { double :server, access_token_expires_in: 100 }
8
+ let(:server) do
9
+ double(
10
+ :server,
11
+ access_token_expires_in: 100,
12
+ custom_access_token_expires_in: ->(_app) { nil }
13
+ )
14
+ end
9
15
  let(:validation) { double :validation, valid?: true }
10
16
 
11
17
  subject { Issuer.new(server, validation) }
@@ -55,6 +61,26 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
55
61
  expect(subject.create(client, scopes, creator)).to be_falsey
56
62
  end
57
63
  end
64
+
65
+ context 'with custom expirations' do
66
+ let(:custom_ttl) { 1233 }
67
+ let(:server) do
68
+ double(
69
+ :server,
70
+ custom_access_token_expires_in: ->(_app) { custom_ttl }
71
+ )
72
+ end
73
+
74
+ it 'creates with correct token parameters' do
75
+ expect(creator).to receive(:call).with(
76
+ client,
77
+ scopes,
78
+ expires_in: custom_ttl,
79
+ use_refresh_token: false
80
+ )
81
+ subject.create client, scopes, creator
82
+ end
83
+ end
58
84
  end
59
85
  end
60
86
  end
@@ -7,7 +7,7 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
7
7
  let(:server) { double :server, scopes: nil }
8
8
  let(:application) { double scopes: nil }
9
9
  let(:client) { double application: application }
10
- let(:request) { double :request, client: client, original_scopes: nil }
10
+ let(:request) { double :request, client: client, scopes: nil }
11
11
 
12
12
  subject { Validation.new(server, request) }
13
13
 
@@ -24,7 +24,8 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
24
24
  it 'is invalid when scopes are not included in the server' do
25
25
  server_scopes = Doorkeeper::OAuth::Scopes.from_string 'email'
26
26
  allow(server).to receive(:scopes).and_return(server_scopes)
27
- allow(request).to receive(:original_scopes).and_return('invalid')
27
+ allow(request).to receive(:scopes).and_return(
28
+ Doorkeeper::OAuth::Scopes.from_string 'invalid')
28
29
  expect(subject).not_to be_valid
29
30
  end
30
31
 
@@ -34,7 +35,7 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
34
35
  server_scopes = Doorkeeper::OAuth::Scopes.from_string 'email app'
35
36
  allow(application).to receive(:scopes).and_return(application_scopes)
36
37
  allow(server).to receive(:scopes).and_return(server_scopes)
37
- allow(request).to receive(:original_scopes).and_return('app')
38
+ allow(request).to receive(:scopes).and_return(application_scopes)
38
39
  expect(subject).to be_valid
39
40
  end
40
41
 
@@ -43,7 +44,8 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
43
44
  server_scopes = Doorkeeper::OAuth::Scopes.from_string 'email app'
44
45
  allow(application).to receive(:scopes).and_return(application_scopes)
45
46
  allow(server).to receive(:scopes).and_return(server_scopes)
46
- allow(request).to receive(:original_scopes).and_return('email')
47
+ allow(request).to receive(:scopes).and_return(
48
+ Doorkeeper::OAuth::Scopes.from_string 'email')
47
49
  expect(subject).not_to be_valid
48
50
  end
49
51
  end
@@ -5,8 +5,14 @@ require 'doorkeeper/oauth/client_credentials_request'
5
5
 
6
6
  module Doorkeeper::OAuth
7
7
  describe ClientCredentialsRequest do
8
- let(:server) { double default_scopes: nil }
9
- let(:client) { double }
8
+ let(:server) do
9
+ double(
10
+ default_scopes: nil,
11
+ custom_access_token_expires_in: ->(_app) { nil }
12
+ )
13
+ end
14
+ let(:application) { double :application, scopes: Scopes.from_string('') }
15
+ let(:client) { double :client, application: application }
10
16
  let(:token_creator) { double :issuer, create: true, token: double }
11
17
 
12
18
  subject { ClientCredentialsRequest.new(server, client) }
@@ -60,5 +66,39 @@ module Doorkeeper::OAuth
60
66
  subject.authorize
61
67
  end
62
68
  end
69
+
70
+ context 'with restricted client' do
71
+ let(:default_scopes) do
72
+ Doorkeeper::OAuth::Scopes.from_string('public email')
73
+ end
74
+ let(:server_scopes) do
75
+ Doorkeeper::OAuth::Scopes.from_string('public email phone')
76
+ end
77
+ let(:client_scopes) do
78
+ Doorkeeper::OAuth::Scopes.from_string('public phone')
79
+ end
80
+
81
+ before do
82
+ allow(server).to receive(:default_scopes).and_return(default_scopes)
83
+ allow(server).to receive(:scopes).and_return(server_scopes)
84
+ allow(server).to receive(:access_token_expires_in).and_return(100)
85
+ allow(application).to receive(:scopes).and_return(client_scopes)
86
+ allow(client).to receive(:id).and_return(nil)
87
+ end
88
+
89
+ it 'delegates the error to issuer if no scope was requested' do
90
+ subject = ClientCredentialsRequest.new(server, client)
91
+ subject.authorize
92
+ expect(subject.response).to be_a(Doorkeeper::OAuth::ErrorResponse)
93
+ expect(subject.error).to eq(:invalid_scope)
94
+ end
95
+
96
+ it 'issues an access token with requested scopes' do
97
+ subject = ClientCredentialsRequest.new(server, client, scope: 'phone')
98
+ subject.authorize
99
+ expect(subject.response).to be_a(Doorkeeper::OAuth::TokenResponse)
100
+ expect(subject.response.token.scopes_string).to eq('phone')
101
+ end
102
+ end
63
103
  end
64
104
  end
@@ -82,6 +82,21 @@ module Doorkeeper::OAuth
82
82
  subject.validate
83
83
  expect(subject.error).to eq(:invalid_scope)
84
84
  end
85
+
86
+ it 'uses params[:scope] in favor of scopes if present (valid)' do
87
+ parameters[:scopes] = 'public update'
88
+ parameters[:scope] = 'public'
89
+ subject.authorize
90
+ expect(Doorkeeper::AccessToken.last.scopes).to eq([:public])
91
+ end
92
+
93
+ it 'uses params[:scope] in favor of scopes if present (invalid)' do
94
+ parameters[:scopes] = 'public'
95
+ parameters[:scope] = 'public update'
96
+
97
+ subject.validate
98
+ expect(subject.error).to eq(:invalid_scope)
99
+ end
85
100
  end
86
101
 
87
102
  end
@@ -2,8 +2,6 @@ require 'spec_helper_integration'
2
2
 
3
3
  module Doorkeeper
4
4
  describe Application do
5
- include OrmHelper
6
-
7
5
  let(:require_owner) { Doorkeeper.configuration.instance_variable_set('@confirm_application_owner', true) }
8
6
  let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set('@confirm_application_owner', false) }
9
7
  let(:new_application) { FactoryGirl.build(:application) }
@@ -32,7 +30,7 @@ module Doorkeeper
32
30
  context 'application owner is required' do
33
31
  before(:each) do
34
32
  require_owner
35
- @owner = mock_application_owner
33
+ @owner = FactoryGirl.build_stubbed(:user)
36
34
  end
37
35
 
38
36
  it 'is invalid without an owner' do
@@ -40,19 +40,31 @@ feature 'Private API' do
40
40
  expect(page.body).to have_content('index')
41
41
  end
42
42
 
43
- scenario 'access token with no scopes' do
44
- optional_scopes_exist :admin
43
+ scenario 'access token with no allowed scopes' do
45
44
  @token.update_attribute :scopes, nil
46
45
  with_access_token_header @token.token
47
46
  visit '/full_protected_resources/1.json'
48
47
  response_status_should_be 403
49
48
  end
50
49
 
51
- scenario 'access token with default scope' do
52
- default_scopes_exist :admin
50
+ scenario 'access token with one of allowed scopes' do
53
51
  @token.update_attribute :scopes, 'admin'
54
52
  with_access_token_header @token.token
55
53
  visit '/full_protected_resources/1.json'
56
54
  expect(page.body).to have_content('show')
57
55
  end
56
+
57
+ scenario 'access token with another of allowed scopes' do
58
+ @token.update_attribute :scopes, 'write'
59
+ with_access_token_header @token.token
60
+ visit '/full_protected_resources/1.json'
61
+ expect(page.body).to have_content('show')
62
+ end
63
+
64
+ scenario 'access token with both allowed scopes' do
65
+ @token.update_attribute :scopes, 'write admin'
66
+ with_access_token_header @token.token
67
+ visit '/full_protected_resources/1.json'
68
+ expect(page.body).to have_content('show')
69
+ end
58
70
  end
@@ -1,11 +1,3 @@
1
1
  # load schema to in memory sqlite
2
2
  ActiveRecord::Migration.verbose = false
3
3
  load Rails.root + 'db/schema.rb'
4
-
5
- module Doorkeeper
6
- module OrmHelper
7
- def mock_application_owner
8
- mock_model 'User', id: 1234
9
- end
10
- end
11
- end
@@ -8,18 +8,3 @@ RSpec.configure do |config|
8
8
  Doorkeeper::AccessToken.create_indexes
9
9
  end
10
10
  end
11
-
12
- module Doorkeeper
13
- class PlaceholderApplicationOwner
14
- include MongoMapper::Document
15
-
16
- set_collection_name 'placeholder_application_owners'
17
- many :applications, class: Doorkeeper::Application
18
- end
19
-
20
- module OrmHelper
21
- def mock_application_owner
22
- PlaceholderApplicationOwner.new
23
- end
24
- end
25
- end
@@ -8,23 +8,3 @@ RSpec.configure do |config|
8
8
  Doorkeeper::AccessToken.create_indexes
9
9
  end
10
10
  end
11
-
12
- module Doorkeeper
13
- class PlaceholderApplicationOwner
14
- include Mongoid::Document
15
-
16
- if ::Mongoid::VERSION >= '3'
17
- self.store_in collection: :placeholder_application_owners
18
- else
19
- self.store_in :placeholder_application_owners
20
- end
21
-
22
- has_many :applications
23
- end
24
-
25
- module OrmHelper
26
- def mock_application_owner
27
- PlaceholderApplicationOwner.new
28
- end
29
- end
30
- end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doorkeeper
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.3
4
+ version: 2.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felipe Elias Philipp
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-03-01 00:00:00.000000000 Z
12
+ date: 2015-03-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
@@ -220,6 +220,8 @@ files:
220
220
  - lib/doorkeeper/errors.rb
221
221
  - lib/doorkeeper/generators/doorkeeper/mongo_mapper/indexes_generator.rb
222
222
  - lib/doorkeeper/generators/doorkeeper/mongo_mapper/templates/indexes.rb
223
+ - lib/doorkeeper/grape/authorization_decorator.rb
224
+ - lib/doorkeeper/grape/helpers.rb
223
225
  - lib/doorkeeper/helpers/controller.rb
224
226
  - lib/doorkeeper/models/access_grant_mixin.rb
225
227
  - lib/doorkeeper/models/access_token_mixin.rb
@@ -444,7 +446,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
444
446
  version: '0'
445
447
  requirements: []
446
448
  rubyforge_project:
447
- rubygems_version: 2.4.5
449
+ rubygems_version: 2.4.6
448
450
  signing_key:
449
451
  specification_version: 4
450
452
  summary: Doorkeeper is an OAuth 2 provider for Rails.