privy_wine_bouncer 1.0.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +23 -0
  5. data/.rubocop_todo.yml +182 -0
  6. data/.travis.yml +124 -0
  7. data/CHANGELOG.md +60 -0
  8. data/CONTRIBUTING.md +55 -0
  9. data/Gemfile +21 -0
  10. data/LICENSE.txt +22 -0
  11. data/README.md +238 -0
  12. data/Rakefile +11 -0
  13. data/UPGRADING.md +62 -0
  14. data/lib/generators/templates/wine_bouncer.rb +9 -0
  15. data/lib/generators/wine_bouncer/initializer_generator.rb +14 -0
  16. data/lib/privy_wine_bouncer.rb +3 -0
  17. data/lib/wine_bouncer/auth_methods/auth_methods.rb +38 -0
  18. data/lib/wine_bouncer/auth_strategies/default.rb +27 -0
  19. data/lib/wine_bouncer/auth_strategies/protected.rb +43 -0
  20. data/lib/wine_bouncer/auth_strategies/swagger.rb +33 -0
  21. data/lib/wine_bouncer/base_strategy.rb +7 -0
  22. data/lib/wine_bouncer/configuration.rb +70 -0
  23. data/lib/wine_bouncer/errors.rb +23 -0
  24. data/lib/wine_bouncer/extension.rb +24 -0
  25. data/lib/wine_bouncer/oauth2.rb +106 -0
  26. data/lib/wine_bouncer/version.rb +5 -0
  27. data/lib/wine_bouncer.rb +14 -0
  28. data/spec/dummy/README.rdoc +28 -0
  29. data/spec/dummy/Rakefile +6 -0
  30. data/spec/dummy/app/api/default_api.rb +71 -0
  31. data/spec/dummy/app/api/protected_api.rb +66 -0
  32. data/spec/dummy/app/api/swagger_api.rb +61 -0
  33. data/spec/dummy/app/assets/config/manifest.js +1 -0
  34. data/spec/dummy/app/assets/images/.keep +0 -0
  35. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  36. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  37. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  38. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  39. data/spec/dummy/app/helpers/application_helper.rb +4 -0
  40. data/spec/dummy/app/mailers/.keep +0 -0
  41. data/spec/dummy/app/models/.keep +0 -0
  42. data/spec/dummy/app/models/concerns/.keep +0 -0
  43. data/spec/dummy/app/models/user.rb +4 -0
  44. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  45. data/spec/dummy/bin/bundle +3 -0
  46. data/spec/dummy/bin/rails +4 -0
  47. data/spec/dummy/bin/rake +4 -0
  48. data/spec/dummy/config/application.rb +31 -0
  49. data/spec/dummy/config/boot.rb +7 -0
  50. data/spec/dummy/config/database.yml +25 -0
  51. data/spec/dummy/config/environment.rb +7 -0
  52. data/spec/dummy/config/environments/development.rb +39 -0
  53. data/spec/dummy/config/environments/production.rb +80 -0
  54. data/spec/dummy/config/environments/test.rb +43 -0
  55. data/spec/dummy/config/initializers/assets.rb +10 -0
  56. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  57. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  58. data/spec/dummy/config/initializers/doorkeeper.rb +94 -0
  59. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  60. data/spec/dummy/config/initializers/inflections.rb +18 -0
  61. data/spec/dummy/config/initializers/mime_types.rb +6 -0
  62. data/spec/dummy/config/initializers/secret_token.rb +6 -0
  63. data/spec/dummy/config/initializers/session_store.rb +5 -0
  64. data/spec/dummy/config/initializers/wrap_parameters.rb +16 -0
  65. data/spec/dummy/config/locales/doorkeeper.en.yml +71 -0
  66. data/spec/dummy/config/locales/en.yml +23 -0
  67. data/spec/dummy/config/routes.rb +8 -0
  68. data/spec/dummy/config/secrets.yml +22 -0
  69. data/spec/dummy/config.ru +4 -0
  70. data/spec/dummy/db/migrate/20140915153344_create_users.rb +11 -0
  71. data/spec/dummy/db/migrate/20140915160601_create_doorkeeper_tables.rb +43 -0
  72. data/spec/dummy/db/schema.rb +62 -0
  73. data/spec/dummy/lib/assets/.keep +0 -0
  74. data/spec/dummy/log/.keep +0 -0
  75. data/spec/dummy/public/404.html +67 -0
  76. data/spec/dummy/public/422.html +67 -0
  77. data/spec/dummy/public/500.html +66 -0
  78. data/spec/dummy/public/favicon.ico +0 -0
  79. data/spec/factories/access_token.rb +13 -0
  80. data/spec/factories/application.rb +8 -0
  81. data/spec/factories/user.rb +7 -0
  82. data/spec/intergration/oauth2_default_strategy_spec.rb +189 -0
  83. data/spec/intergration/oauth2_protected_strategy_spec.rb +199 -0
  84. data/spec/intergration/oauth2_swagger_strategy_spec.rb +156 -0
  85. data/spec/lib/generators/wine_bouncer/initializer_generator_spec.rb +19 -0
  86. data/spec/lib/wine_bouncer/auth_methods/auth_methods_spec.rb +105 -0
  87. data/spec/lib/wine_bouncer/auth_strategies/default_spec.rb +76 -0
  88. data/spec/lib/wine_bouncer/auth_strategies/swagger_spec.rb +115 -0
  89. data/spec/rails_helper.rb +79 -0
  90. data/spec/shared/orm/active_record.rb +4 -0
  91. data/spec/spec_helper.rb +95 -0
  92. data/wine_bouncer.gemspec +33 -0
  93. metadata +386 -0
data/README.md ADDED
@@ -0,0 +1,238 @@
1
+ # WineBouncer
2
+
3
+ Protect your precious Grape API with Doorkeeper.
4
+ WineBouncer uses minimal modification, to make the magic happen.
5
+
6
+ # Table of Contents
7
+
8
+ - [Requirements](#requirements)
9
+ - [Installation](#installation)
10
+ - [Upgrading](#upgrading)
11
+ - [Usage](#usage)
12
+ - [Easy DSL](#easy-dsl)
13
+ - [Authentication strategies](#authentication-strategies)
14
+ - [Default](#default)
15
+ - [Swagger](#swagger)
16
+ - [Protected](#protected)
17
+ - [Token information](#token-information)
18
+ - [Disable WineBouncer](#disable-winebouncer)
19
+ - [Exceptions and Exception handling](#exceptions-and-exception-handling)
20
+ - [Example Application](#example-application)
21
+ - [Development](#development)
22
+ - [Contributing](#contributing)
23
+
24
+ ## Requirements
25
+
26
+ - Ruby > 2.1
27
+ - Doorkeeper > 1.4.0 and < 5
28
+ - Grape > 0.10 and < 1.2
29
+
30
+ Please submit pull requests and Travis env bumps for newer dependency versions.
31
+
32
+ ## Installation
33
+
34
+ Add this line to your application's Gemfile:
35
+
36
+ ```ruby
37
+ gem 'privy_wine_bouncer'
38
+ ```
39
+
40
+ And then execute:
41
+
42
+ ```ruby
43
+ bundle
44
+ ```
45
+
46
+ ## Upgrading
47
+
48
+ When upgrading from a previous version, see [UPGRADING](UPGRADING.md). You might also be interested at the [CHANGELOG](CHANGELOG.md).
49
+
50
+ ## Usage
51
+
52
+ WineBouncer is a custom Grape Middleware used for Authentication and Authorization. We assume you have a Grape API mounted in your Rails application together with Doorkeeper.
53
+
54
+ To get started with WineBouncer, run the configuration initializer:
55
+
56
+ ```shell
57
+ $ rails g wine_bouncer:initializer
58
+ ```
59
+
60
+ This creates a rails initializer in your Rails app at `config/initializers/wine_bouncer.rb` with the following configuration:
61
+
62
+ ```ruby
63
+ WineBouncer.configure do |config|
64
+ config.auth_strategy = :default
65
+
66
+ config.define_resource_owner do
67
+ User.find(doorkeeper_access_token.resource_owner_id) if doorkeeper_access_token
68
+ end
69
+ end
70
+ ```
71
+
72
+ Then register WineBouncer as Grape middleware in your Grape API.
73
+
74
+ ```ruby
75
+ class Api < Grape::API
76
+ default_format :json
77
+ format :json
78
+ use ::WineBouncer::OAuth2
79
+ mount YourAwesomeApi
80
+ end
81
+ ```
82
+
83
+ ### Easy DSL
84
+
85
+ WineBouncer comes with an easy DSL and relies on Grape's DSL extentions to define if an endpoint method should be protected.
86
+ You can protect an endpoint by calling `oauth2` method with optional scopes in front of the endpoint definition.
87
+
88
+ ```ruby
89
+ class MyAwesomeAPI < Grape::API
90
+ desc 'protected method with required public scope'
91
+ oauth2 'public'
92
+ get '/protected' do
93
+ { hello: 'world' }
94
+ end
95
+
96
+ oauth2 'public'
97
+ get '/with_no_description' do
98
+ { hello: 'undescribed world' }
99
+ end
100
+
101
+ desc 'Unprotected method'
102
+ get '/unprotected' do
103
+ { hello: 'unprotected world' }
104
+ end
105
+
106
+ desc 'This method needs the public or private scope.'
107
+ oauth2 'public', 'write'
108
+ get '/method' do
109
+ { hello: 'public or private user.' }
110
+ end
111
+
112
+ desc 'This method uses Doorkeepers default scopes.',
113
+ oauth2
114
+ get '/protected_with_default_scope' do
115
+ { hello: 'protected unscoped world' }
116
+ end
117
+ end
118
+
119
+ class Api < Grape::API
120
+ default_format :json
121
+ format :json
122
+ use ::WineBouncer::OAuth2
123
+ mount MyAwesomeAPI
124
+ end
125
+ ```
126
+
127
+ ### Authentication strategies
128
+
129
+ Behaviour of the authentication can be customized by selecting an authentication strategy. The following authentication strategies are provided in the gem.
130
+
131
+ #### Default
132
+
133
+ The default strategy only authenticates endpoints which are annotated by the `oauth2` method. Un-annotated endpoints still can be accessed without authentication.
134
+
135
+ #### Swagger
136
+
137
+ WineBouncer comes with a strategy that can be perfectly used with [grape-swagger](https://github.com/tim-vandecasteele/grape-swagger) with a syntax compliant with the [swagger spec](https://github.com/wordnik/swagger-spec/).
138
+ This might be one of the simplest methods to protect your API and serve it with documentation. You can use [swagger-ui](https://github.com/wordnik/swagger-ui) to view your documentation.
139
+
140
+ To get started ensure you also have included the `grape-swagger` gem in your gemfile.
141
+
142
+ Run `bundle` to install the missing gems.
143
+
144
+ Create a rails initializer in your Rails app at `config/initializers/wine_bouncer.rb` with the following configuration.
145
+
146
+ ```ruby
147
+ WineBouncer.configure do |config|
148
+ config.auth_strategy = :swagger
149
+
150
+ config.define_resource_owner do
151
+ User.find(doorkeeper_access_token.resource_owner_id) if doorkeeper_access_token
152
+ end
153
+ end
154
+ ```
155
+
156
+ Then you can start protecting your API like the example below.
157
+
158
+ ```ruby
159
+ desc 'This method needs the public or private scope.',
160
+ success: Api::Entities::Response,
161
+ failure: [
162
+ [401, 'Unauthorized', Api::Entities::Error],
163
+ [403, 'Forbidden', Api::Entities::Error]
164
+ ],
165
+ notes: <<-NOTE
166
+ Marked down notes!
167
+ NOTE
168
+ oauth2 'public', 'write'
169
+ get '/method' do
170
+ { hello: 'public or private user.' }
171
+ end
172
+ ```
173
+
174
+ The Swagger strategy uses scopes and injects them in the authorizations description for external application to be read.
175
+
176
+ #### Protected
177
+
178
+ The protected strategy is very similar to the default strategy except any public endpoint must explicitly set. To make an end point public, use `oauth2 false`.
179
+ If the authorization method is not set, the end point is assumed to be **protected with Doorkeeper's default scopes** (which is the same as `oauth2 nil `.)
180
+ To protect your endpoint with other scopes append the following method `oauth2 'first scope', 'second scope'`.
181
+
182
+ ### Token information
183
+
184
+ WineBouncer comes with free extras! Methods for `resource_owner` and `doorkeeper_access_token` get included in your endpoints. You can use them to get the current resource owner, and the access_token object of doorkeeper.
185
+
186
+ ### Disable WineBouncer
187
+
188
+ If you want to disable WineBouncer conditionally - e.g. in specs - you can add a block to the WineBouncer configuration. When this block evaluates to true, any request will be unprotected. For example:
189
+
190
+ ```{ruby}
191
+ WineBouncer.configure do |config|
192
+ config.disable do
193
+ Rails.env.test?
194
+ end
195
+ end
196
+ ```
197
+
198
+ The block is newly evaluated for every request, so you could in principle have something like:
199
+
200
+ ```{ruby}
201
+ config.disable do
202
+ [true, false].sample
203
+ end
204
+ ```
205
+
206
+ You probably shouldn't, though.
207
+
208
+ ## Exceptions and Exception handling
209
+
210
+ This gem raises the following exceptions which can be handled in your Grape API, see [Grape documentation](https://github.com/intridea/grape#exception-handling).
211
+
212
+ - `WineBouncer::Errors::OAuthUnauthorizedError`
213
+ when the request is unauthorized.
214
+ - `WineBouncer::Errors::OAuthForbiddenError`
215
+ when the token is found but scopes do not match.
216
+
217
+ Detailed doorkeeper error response can be found in the error's `response` attribute. You could use
218
+ it to compose the actual HTTP response to API users.
219
+
220
+ ## Example/Template Application
221
+
222
+ A full working sample app (or starter template) can be found at [grape-doorkeeper on github](https://github.com/sethherr/grape-doorkeeper). It has one click deploy to Heroku and [a live example](https://grape-doorkeeper.herokuapp.com/).
223
+
224
+ ## Development
225
+
226
+ Since we want the gem tested against several rails versions we use the same way to prepare our development environment as Doorkeeper.
227
+
228
+ To install the development environment for rails 4.2.6, you can also specify a different rails version to test against.
229
+
230
+ `rails=4.2.6 bundle install`
231
+
232
+ To run the specs.
233
+
234
+ `rails=4.2.6 bundle exec rake`
235
+
236
+ ## Contributing
237
+
238
+ For contributing to the gem see [CONTRIBUTING](CONTRIBUTING.md).
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+
5
+ require 'rspec/core/rake_task'
6
+
7
+ desc 'Default: Run all specs.'
8
+ task default: :spec
9
+
10
+ desc 'Run all specs'
11
+ RSpec::Core::RakeTask.new(:spec)
data/UPGRADING.md ADDED
@@ -0,0 +1,62 @@
1
+ Upgrading WineBouncer
2
+ =====================
3
+
4
+
5
+ ## Upgrading to >= 1.0
6
+
7
+ No DSL changes have been made. This is just a stability release from we can work to next releases.
8
+
9
+
10
+ ## Upgrading to >= 0.5.0
11
+
12
+ WineBouncer's exceptions `OAuthUnauthorizedError` and `OAuthForbiddenError` now come with a
13
+ corresponding Doorkeeper's error response. You can access it via `response` method of the exception.
14
+ For backward compatible, you can still use `message` but the content will be provided by Doorkeeper
15
+ error response's description.
16
+
17
+ ## Upgrading to >= 0.3.0
18
+
19
+ An new DSL has been introduced to WineBouncer. This DSL will become the preferred way to authorize your endpoints.
20
+ The authentication trough endpoint description will become deprecated in the future version.
21
+
22
+ The old way to authorize your endpoints:
23
+
24
+ ```
25
+ desc 'protected method with required public and private scope',
26
+ auth: { scopes: ['public','private'] }
27
+ get '/protected' do
28
+ { hello: 'world' }
29
+ end
30
+ ```
31
+
32
+ You may now write:
33
+ ```
34
+ desc 'protected method with required public and private scope'
35
+ oauth2 'public', 'private'
36
+ get '/protected' do
37
+ { hello: 'world' }
38
+ end
39
+ ```
40
+
41
+ And even remove the description.
42
+
43
+ Note this is the last version that will support Grape 0.8 and 0.9. Grape 0.10 will be the next minimum Grape version.
44
+
45
+ ### Upgrading to >= 0.2.0
46
+
47
+ To use the `resource_owner` you now need to define how WineBouncer gets the resource owner. In most cases he needs to return the User that is logged in, but not in all cases.
48
+ You now additionally need to specify `define_resource_owner` in your configuration. Mostly this the following code will work:
49
+
50
+ ``` ruby
51
+ WineBouncer.configure do |c|
52
+ .......
53
+ c.define_resource_owner do
54
+ User.find(doorkeeper_access_token.resource_owner_id) if doorkeeper_access_token
55
+ end
56
+ end
57
+ ```
58
+
59
+ The required Grape version is now from 0.8 and above.
60
+
61
+ ------
62
+ From version 0.1.0 upgrade instructions are given.
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ WineBouncer.configure do |config|
4
+ config.auth_strategy = :default
5
+
6
+ config.define_resource_owner do
7
+ User.find(doorkeeper_access_token.resource_owner_id) if doorkeeper_access_token
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WineBouncer
4
+ module Generators
5
+ class InitializerGenerator < ::Rails::Generators::Base
6
+ source_root File.expand_path('../../templates', __FILE__)
7
+
8
+ desc 'Creates a sample WineBouncer initializer.'
9
+ def copy_initializer
10
+ copy_file 'wine_bouncer.rb', 'config/initializers/wine_bouncer.rb'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'wine_bouncer'
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WineBouncer
4
+ module AuthMethods
5
+
6
+ def protected_endpoint=(protected)
7
+ @protected_endpoint = protected
8
+ end
9
+
10
+ def protected_endpoint?
11
+ @protected_endpoint || false
12
+ end
13
+
14
+ def resource_owner
15
+ instance_eval(&WineBouncer.configuration.defined_resource_owner)
16
+ end
17
+
18
+ def client_credential_token?
19
+ has_doorkeeper_token? && doorkeeper_access_token.resource_owner_id.nil?
20
+ end
21
+
22
+ def doorkeeper_access_token
23
+ @_doorkeeper_access_token
24
+ end
25
+
26
+ def doorkeeper_access_token=(token)
27
+ @_doorkeeper_access_token = token
28
+ end
29
+
30
+ def has_doorkeeper_token?
31
+ !@_doorkeeper_access_token.nil?
32
+ end
33
+
34
+ def has_resource_owner?
35
+ has_doorkeeper_token? && !!doorkeeper_access_token.resource_owner_id
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WineBouncer
4
+ module AuthStrategies
5
+ class Default < ::WineBouncer::BaseStrategy
6
+ def endpoint_protected?
7
+ !!endpoint_authorizations
8
+ end
9
+
10
+ def has_auth_scopes?
11
+ !!endpoint_authorizations &&
12
+ endpoint_authorizations.key?(:scopes) &&
13
+ !endpoint_authorizations[:scopes].empty?
14
+ end
15
+
16
+ def auth_scopes
17
+ endpoint_authorizations[:scopes].map(&:to_sym)
18
+ end
19
+
20
+ private
21
+
22
+ def endpoint_authorizations
23
+ api_context.options[:route_options][:auth]
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WineBouncer
4
+ module AuthStrategies
5
+ class Protected < WineBouncer::BaseStrategy
6
+ def endpoint_protected?
7
+ has_authorizations?
8
+ end
9
+
10
+ def has_auth_scopes?
11
+ endpoint_authorizations &&
12
+ endpoint_authorizations.key?(:scopes) &&
13
+ endpoint_authorizations[:scopes].any?
14
+ end
15
+
16
+ def auth_scopes
17
+ endpoint_authorizations[:scopes].map(&:to_sym)
18
+ end
19
+
20
+ private
21
+
22
+ def nil_authorizations?
23
+ endpoint_authorizations.nil?
24
+ end
25
+
26
+ # returns true if an authorization hash has been found
27
+ # First it checks for the old syntax, then for the new.
28
+ def has_authorizations?
29
+ (nil_authorizations? || !!endpoint_authorizations) && scope_keys?
30
+ end
31
+
32
+ # if false or nil scopes are entered the authorization should be skipped.
33
+ # nil_authorizations? is used to check against the legacy hash.
34
+ def scope_keys?
35
+ nil_authorizations? || endpoint_authorizations[:scopes] != [false]
36
+ end
37
+
38
+ def endpoint_authorizations
39
+ api_context.options[:route_options][:auth]
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WineBouncer
4
+ module AuthStrategies
5
+ class Swagger < ::WineBouncer::BaseStrategy
6
+ def endpoint_protected?
7
+ has_authorizations? && !!authorization_type_oauth2
8
+ end
9
+
10
+ def has_auth_scopes?
11
+ endpoint_protected? && !authorization_type_oauth2.empty?
12
+ end
13
+
14
+ def auth_scopes
15
+ authorization_type_oauth2.map { |hash| hash[:scope].to_sym }
16
+ end
17
+
18
+ private
19
+
20
+ def has_authorizations?
21
+ !!endpoint_authorizations
22
+ end
23
+
24
+ def endpoint_authorizations
25
+ api_context.options[:route_options][:authorizations]
26
+ end
27
+
28
+ def authorization_type_oauth2
29
+ endpoint_authorizations[:oauth2]
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WineBouncer
4
+ class BaseStrategy
5
+ attr_accessor :api_context
6
+ end
7
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WineBouncer
4
+
5
+ class << self
6
+ attr_accessor :configuration
7
+ end
8
+
9
+ class Configuration
10
+ attr_accessor :auth_strategy
11
+ attr_accessor :defined_resource_owner
12
+ attr_writer :auth_strategy
13
+
14
+ def auth_strategy
15
+ @auth_strategy || :default
16
+ end
17
+
18
+ def require_strategies
19
+ require "wine_bouncer/auth_strategies/#{auth_strategy}"
20
+ end
21
+
22
+ def define_resource_owner &block
23
+ raise(ArgumentError, 'define_resource_owner expects a block in the configuration') unless block_given?
24
+ @defined_resource_owner = block
25
+ end
26
+
27
+ def defined_resource_owner
28
+ raise(Errors::UnconfiguredError, 'Please define define_resource_owner to configure the resource owner') unless @defined_resource_owner
29
+ @defined_resource_owner
30
+ end
31
+
32
+ # when the block evaluates to true, WineBouncer should be disabled
33
+ # if no block is provided, WineBouncer is always enabled
34
+ def disable(&block)
35
+ @disable_block = block
36
+ end
37
+
38
+ def disable_block
39
+ @disable_block || ->() { false }
40
+ end
41
+ end
42
+
43
+ def self.configuration
44
+ @config || raise(Errors::UnconfiguredError.new)
45
+ end
46
+
47
+ def self.configuration=(config)
48
+ @config = config
49
+ @config.require_strategies
50
+ end
51
+
52
+ ###
53
+ # Configure block.
54
+ # Requires all strategy specific files.
55
+ ###
56
+ def self.configure
57
+ yield(config)
58
+ config.require_strategies
59
+ config
60
+ end
61
+
62
+ private_class_method
63
+
64
+ ###
65
+ # Returns a new configuration or existing one.
66
+ ###
67
+ def self.config
68
+ @config ||= Configuration.new
69
+ end
70
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WineBouncer
4
+ module Errors
5
+ class UnconfiguredError < StandardError; end
6
+
7
+ class OAuthUnauthorizedError < StandardError
8
+ attr_reader :response
9
+ def initialize(response)
10
+ super(response.try(:description))
11
+ @response = response
12
+ end
13
+ end
14
+
15
+ class OAuthForbiddenError < StandardError
16
+ attr_reader :response
17
+ def initialize(response)
18
+ super(response.try(:description))
19
+ @response = response
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WineBouncer
4
+ module Extension
5
+ def oauth2(*scopes)
6
+ scopes = Doorkeeper.configuration.default_scopes.all if scopes.all? { |x| x.nil? }
7
+ description = if respond_to?(:route_setting) # >= grape-0.10.0
8
+ route_setting(:description) || route_setting(:description, {})
9
+ else
10
+ @last_description ||= {}
11
+ end
12
+ # case WineBouncer.configuration.auth_strategy
13
+ # when :default
14
+ description[:auth] = { scopes: scopes }
15
+ # when :swagger
16
+ description[:authorizations] = { oauth2: scopes.map { |x| { scope: x } } }
17
+ # end
18
+ end
19
+
20
+ # Grape::API::Instance is defined in grape 1.2.0 or above
21
+ grape_api = defined?(Grape::API::Instance) ? Grape::API::Instance : Grape::API
22
+ grape_api.extend self
23
+ end
24
+ end