haveapi 0.20.0 → 0.21.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Rakefile +6 -6
- data/haveapi.gemspec +13 -13
- data/lib/haveapi/action.rb +153 -167
- data/lib/haveapi/action_state.rb +2 -6
- data/lib/haveapi/actions/default.rb +8 -10
- data/lib/haveapi/api.rb +2 -1
- data/lib/haveapi/authentication/base.rb +5 -8
- data/lib/haveapi/authentication/basic/provider.rb +4 -5
- data/lib/haveapi/authentication/chain.rb +19 -17
- data/lib/haveapi/authentication/oauth2/config.rb +12 -32
- data/lib/haveapi/authentication/oauth2/provider.rb +20 -30
- data/lib/haveapi/authentication/oauth2/revoke_endpoint.rb +1 -2
- data/lib/haveapi/authentication/token/action_config.rb +5 -3
- data/lib/haveapi/authentication/token/config.rb +5 -5
- data/lib/haveapi/authentication/token/provider.rb +33 -37
- data/lib/haveapi/authorization.rb +10 -4
- data/lib/haveapi/client_example.rb +11 -14
- data/lib/haveapi/client_examples/curl.rb +37 -37
- data/lib/haveapi/client_examples/fs_client.rb +29 -31
- data/lib/haveapi/client_examples/http.rb +35 -36
- data/lib/haveapi/client_examples/js_client.rb +62 -63
- data/lib/haveapi/client_examples/php_client.rb +77 -76
- data/lib/haveapi/client_examples/ruby_cli.rb +30 -30
- data/lib/haveapi/client_examples/ruby_client.rb +26 -26
- data/lib/haveapi/common.rb +3 -4
- data/lib/haveapi/context.rb +11 -10
- data/lib/haveapi/example.rb +9 -4
- data/lib/haveapi/example_list.rb +2 -2
- data/lib/haveapi/exceptions.rb +1 -1
- data/lib/haveapi/extensions/action_exceptions.rb +2 -2
- data/lib/haveapi/extensions/base.rb +1 -3
- data/lib/haveapi/extensions/exception_mailer.rb +260 -257
- data/lib/haveapi/hooks.rb +40 -39
- data/lib/haveapi/metadata.rb +1 -1
- data/lib/haveapi/model_adapter.rb +16 -27
- data/lib/haveapi/model_adapters/active_record.rb +59 -69
- data/lib/haveapi/output_formatter.rb +7 -7
- data/lib/haveapi/output_formatters/base.rb +2 -4
- data/lib/haveapi/parameters/resource.rb +7 -7
- data/lib/haveapi/parameters/typed.rb +6 -9
- data/lib/haveapi/params.rb +38 -45
- data/lib/haveapi/resource.rb +8 -8
- data/lib/haveapi/resources/action_state.rb +11 -19
- data/lib/haveapi/server.rb +102 -107
- data/lib/haveapi/spec/api_response.rb +1 -1
- data/lib/haveapi/spec/helpers.rb +1 -1
- data/lib/haveapi/spec/mock_action.rb +11 -10
- data/lib/haveapi/spec/spec_methods.rb +9 -8
- data/lib/haveapi/tasks/yard.rb +2 -2
- data/lib/haveapi/types.rb +0 -3
- data/lib/haveapi/validator.rb +6 -3
- data/lib/haveapi/validator_chain.rb +9 -8
- data/lib/haveapi/validators/acceptance.rb +6 -6
- data/lib/haveapi/validators/confirmation.rb +2 -3
- data/lib/haveapi/validators/exclusion.rb +1 -1
- data/lib/haveapi/validators/format.rb +1 -1
- data/lib/haveapi/validators/inclusion.rb +1 -1
- data/lib/haveapi/validators/length.rb +12 -11
- data/lib/haveapi/validators/numericality.rb +14 -13
- data/lib/haveapi/validators/presence.rb +4 -3
- data/lib/haveapi/version.rb +2 -2
- data/lib/haveapi.rb +2 -3
- data/spec/.rubocop.yml +4 -0
- data/spec/action/dsl_spec.rb +18 -18
- data/spec/authorization_spec.rb +8 -8
- data/spec/common_spec.rb +2 -1
- data/spec/documentation_spec.rb +2 -9
- data/spec/envelope_spec.rb +2 -2
- data/spec/hooks_spec.rb +12 -12
- data/spec/parameters/typed_spec.rb +6 -6
- data/spec/params_spec.rb +22 -24
- data/spec/resource_spec.rb +5 -7
- data/spec/spec_helper.rb +0 -1
- data/spec/validators/acceptance_spec.rb +1 -1
- data/spec/validators/confirmation_spec.rb +5 -5
- data/spec/validators/exclusion_spec.rb +3 -3
- data/spec/validators/format_spec.rb +2 -2
- data/spec/validators/inclusion_spec.rb +4 -4
- data/spec/validators/length_spec.rb +23 -23
- data/spec/validators/numericality_spec.rb +13 -13
- data/spec/validators/presence_spec.rb +3 -3
- metadata +49 -48
@@ -7,7 +7,7 @@ module HaveAPI
|
|
7
7
|
class Index < Action
|
8
8
|
route ''
|
9
9
|
http_method :get
|
10
|
-
aliases %i
|
10
|
+
aliases %i[list]
|
11
11
|
|
12
12
|
meta(:global) do
|
13
13
|
input do
|
@@ -26,32 +26,30 @@ module HaveAPI
|
|
26
26
|
end
|
27
27
|
|
28
28
|
# Return the total count of items.
|
29
|
-
def count
|
30
|
-
|
31
|
-
end
|
29
|
+
def count; end
|
32
30
|
end
|
33
31
|
|
34
32
|
class Create < Action
|
35
33
|
route ''
|
36
34
|
http_method :post
|
37
|
-
aliases %i
|
35
|
+
aliases %i[new]
|
38
36
|
end
|
39
37
|
|
40
38
|
class Show < Action
|
41
|
-
route ->(r){ r.singular ? '' : '{%{resource}_id}' }
|
39
|
+
route ->(r) { r.singular ? '' : '{%{resource}_id}' }
|
42
40
|
http_method :get
|
43
|
-
aliases %i
|
41
|
+
aliases %i[find]
|
44
42
|
end
|
45
43
|
|
46
44
|
class Update < Action
|
47
|
-
route ->(r){ r.singular ? '' : '{%{resource}_id}' }
|
45
|
+
route ->(r) { r.singular ? '' : '{%{resource}_id}' }
|
48
46
|
http_method :put
|
49
47
|
end
|
50
48
|
|
51
49
|
class Delete < Action
|
52
|
-
route ->(r){ r.singular ? '' : '{%{resource}_id}' }
|
50
|
+
route ->(r) { r.singular ? '' : '{%{resource}_id}' }
|
53
51
|
http_method :delete
|
54
|
-
aliases %i
|
52
|
+
aliases %i[destroy]
|
55
53
|
end
|
56
54
|
end
|
57
55
|
end
|
data/lib/haveapi/api.rb
CHANGED
@@ -14,6 +14,7 @@ module HaveAPI
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.inherited(subclass)
|
17
|
+
super
|
17
18
|
subclass.send(:instance_variable_set, '@auth_method', @auth_method)
|
18
19
|
end
|
19
20
|
|
@@ -30,8 +31,7 @@ module HaveAPI
|
|
30
31
|
# Register custom path handlers in sinatra
|
31
32
|
# @param sinatra [Sinatra::Base]
|
32
33
|
# @param prefix [String]
|
33
|
-
def register_routes(sinatra, prefix)
|
34
|
-
end
|
34
|
+
def register_routes(sinatra, prefix); end
|
35
35
|
|
36
36
|
# @return [Module, nil]
|
37
37
|
def resource_module
|
@@ -40,9 +40,7 @@ module HaveAPI
|
|
40
40
|
|
41
41
|
# Reimplement this method in your authentication provider.
|
42
42
|
# `request` is passed directly from Sinatra.
|
43
|
-
def authenticate(request)
|
44
|
-
|
45
|
-
end
|
43
|
+
def authenticate(request); end
|
46
44
|
|
47
45
|
# Reimplement to describe provider.
|
48
46
|
def describe
|
@@ -50,10 +48,9 @@ module HaveAPI
|
|
50
48
|
end
|
51
49
|
|
52
50
|
protected
|
53
|
-
# Called during API mount.
|
54
|
-
def setup
|
55
51
|
|
56
|
-
|
52
|
+
# Called during API mount.
|
53
|
+
def setup; end
|
57
54
|
|
58
55
|
# Immediately return from authentication chain.
|
59
56
|
# User is not allowed to authenticate.
|
@@ -36,17 +36,16 @@ module HaveAPI::Authentication
|
|
36
36
|
|
37
37
|
def describe
|
38
38
|
{
|
39
|
-
description:
|
40
|
-
|
39
|
+
description: 'Authentication using HTTP basic. Username and password is passed ' \
|
40
|
+
'via HTTP header. Its use is forbidden from web browsers.'
|
41
41
|
}
|
42
42
|
end
|
43
43
|
|
44
44
|
protected
|
45
|
+
|
45
46
|
# Reimplement this method. It has to return an authenticated
|
46
47
|
# user or nil.
|
47
|
-
def find_user(request, username, password)
|
48
|
-
|
49
|
-
end
|
48
|
+
def find_user(request, username, password); end
|
50
49
|
end
|
51
50
|
end
|
52
51
|
end
|
@@ -15,10 +15,10 @@ module HaveAPI::Authentication
|
|
15
15
|
@chain[v] && @chain[v].each { |p| register_provider(v, p) }
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
return unless @chain[:all]
|
19
|
+
|
20
|
+
@chain[:all].each do |p|
|
21
|
+
@instances.each_key { |v| register_provider(v, p) }
|
22
22
|
end
|
23
23
|
|
24
24
|
# @chain.each do |p|
|
@@ -56,12 +56,12 @@ module HaveAPI::Authentication
|
|
56
56
|
@instances[context.version].each do |provider|
|
57
57
|
ret[provider.name] = provider.describe
|
58
58
|
|
59
|
-
|
60
|
-
|
59
|
+
next unless provider.resource_module
|
60
|
+
|
61
|
+
ret[provider.name][:resources] = {}
|
61
62
|
|
62
|
-
|
63
|
-
|
64
|
-
end
|
63
|
+
@server.routes[context.version][:authentication][provider.name][:resources].each do |r, children|
|
64
|
+
ret[provider.name][:resources][r.resource_name.underscore.to_sym] = r.describe(children, context)
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -95,20 +95,22 @@ module HaveAPI::Authentication
|
|
95
95
|
end
|
96
96
|
|
97
97
|
protected
|
98
|
+
|
98
99
|
def register_provider(v, p)
|
99
100
|
instance = p.new(@server, v)
|
100
101
|
@instances[v] << instance
|
101
102
|
|
102
103
|
@server.add_auth_routes(v, instance, prefix: instance.name.to_s)
|
103
104
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
105
|
+
resource_module = instance.resource_module
|
106
|
+
return if resource_module.nil?
|
107
|
+
|
108
|
+
@server.add_auth_module(
|
109
|
+
v,
|
110
|
+
instance.name,
|
111
|
+
resource_module,
|
112
|
+
prefix: instance.name.to_s
|
113
|
+
)
|
112
114
|
end
|
113
115
|
end
|
114
116
|
end
|
@@ -28,9 +28,7 @@ module HaveAPI::Authentication
|
|
28
28
|
# @param oauth2_response [Rack::OAuth2::Server::Authorize::Response]
|
29
29
|
# @param client [Client]
|
30
30
|
# @return [AuthResult, nil]
|
31
|
-
def handle_get_authorize(sinatra_handler:, sinatra_request:, sinatra_params:, oauth2_request:, oauth2_response:, client:)
|
32
|
-
|
33
|
-
end
|
31
|
+
def handle_get_authorize(sinatra_handler:, sinatra_request:, sinatra_params:, oauth2_request:, oauth2_response:, client:); end
|
34
32
|
|
35
33
|
# Handle POST authorize requests
|
36
34
|
#
|
@@ -48,9 +46,7 @@ module HaveAPI::Authentication
|
|
48
46
|
# @param oauth2_response [Rack::OAuth2::Server::Authorize::Response]
|
49
47
|
# @param client [Client]
|
50
48
|
# @return [AuthResult, nil]
|
51
|
-
def handle_post_authorize(sinatra_handler:, sinatra_request:, sinatra_params:, oauth2_request:, oauth2_response:, client:)
|
52
|
-
|
53
|
-
end
|
49
|
+
def handle_post_authorize(sinatra_handler:, sinatra_request:, sinatra_params:, oauth2_request:, oauth2_response:, client:); end
|
54
50
|
|
55
51
|
# Get oauth2 authorization code
|
56
52
|
#
|
@@ -60,9 +56,7 @@ module HaveAPI::Authentication
|
|
60
56
|
#
|
61
57
|
# @param auth_res [AuthResult] value returned by {#handle_post_authorize}
|
62
58
|
# @return [String]
|
63
|
-
def get_authorization_code(auth_res)
|
64
|
-
|
65
|
-
end
|
59
|
+
def get_authorization_code(auth_res); end
|
66
60
|
|
67
61
|
# Get access token, its expiration date and optionally a refresh token
|
68
62
|
#
|
@@ -73,9 +67,7 @@ module HaveAPI::Authentication
|
|
73
67
|
# @param authorization [Authorization]
|
74
68
|
# @param sinatra_request [Sinatra::Request]
|
75
69
|
# @return [Array] access token, expiration date and optional refresh token
|
76
|
-
def get_tokens(authorization, sinatra_request)
|
77
|
-
|
78
|
-
end
|
70
|
+
def get_tokens(authorization, sinatra_request); end
|
79
71
|
|
80
72
|
# Refresh access token and optionally generate new refresh token
|
81
73
|
#
|
@@ -85,9 +77,7 @@ module HaveAPI::Authentication
|
|
85
77
|
# @param authorization [Authorization]
|
86
78
|
# @param sinatra_request [Sinatra::Request]
|
87
79
|
# @return [Array] access token, expiration date and optional refresh token
|
88
|
-
def refresh_tokens(authorization, sinatra_request)
|
89
|
-
|
90
|
-
end
|
80
|
+
def refresh_tokens(authorization, sinatra_request); end
|
91
81
|
|
92
82
|
# Revoke access or refresh token
|
93
83
|
#
|
@@ -98,40 +88,30 @@ module HaveAPI::Authentication
|
|
98
88
|
# @param token [String]
|
99
89
|
# @param token_type_hint [nil, 'access_token', 'refresh_token']
|
100
90
|
# @return [:revoked, :unsupported]
|
101
|
-
def handle_post_revoke(sinatra_request, token, token_type_hint: nil)
|
102
|
-
|
103
|
-
end
|
91
|
+
def handle_post_revoke(sinatra_request, token, token_type_hint: nil); end
|
104
92
|
|
105
93
|
# Find client by ID
|
106
94
|
# @param client_id [String]
|
107
95
|
# @return [Client, nil]
|
108
|
-
def find_client_by_id(client_id)
|
109
|
-
|
110
|
-
end
|
96
|
+
def find_client_by_id(client_id); end
|
111
97
|
|
112
98
|
# Find authorization by code
|
113
99
|
# @param client [Client]
|
114
100
|
# @param code [String]
|
115
101
|
# @return [Authorization, nil]
|
116
|
-
def find_authorization_by_code(client, code)
|
117
|
-
|
118
|
-
end
|
102
|
+
def find_authorization_by_code(client, code); end
|
119
103
|
|
120
104
|
# Find authorization by refresh token
|
121
105
|
# @param client [Client]
|
122
106
|
# @param refresh_token [String]
|
123
107
|
# @return [Authorization, nil]
|
124
|
-
def find_authorization_by_refresh_token(client, refresh_token)
|
125
|
-
|
126
|
-
end
|
108
|
+
def find_authorization_by_refresh_token(client, refresh_token); end
|
127
109
|
|
128
110
|
# Find user by the bearer token sent in HTTP header or as a query parameter
|
129
111
|
# @param sinatra_request [Sinatra::Request]
|
130
112
|
# @param access_token [String]
|
131
113
|
# @return [Object, nil] user
|
132
|
-
def find_user_by_access_token(request, access_token)
|
133
|
-
|
134
|
-
end
|
114
|
+
def find_user_by_access_token(request, access_token); end
|
135
115
|
|
136
116
|
# Base URL of the authorization server, including protocol
|
137
117
|
#
|
@@ -173,13 +153,13 @@ module HaveAPI::Authentication
|
|
173
153
|
response_type: req.response_type,
|
174
154
|
redirect_uri: req.redirect_uri,
|
175
155
|
scope: req.scope.join(' '),
|
176
|
-
state: req.state
|
156
|
+
state: req.state
|
177
157
|
}
|
178
158
|
|
179
159
|
if req.code_challenge.present? && req.code_challenge_method.present?
|
180
160
|
ret.update(
|
181
161
|
code_challenge: req.code_challenge,
|
182
|
-
code_challenge_method: req.code_challenge_method
|
162
|
+
code_challenge_method: req.code_challenge_method
|
183
163
|
)
|
184
164
|
end
|
185
165
|
|
@@ -116,7 +116,7 @@ module HaveAPI::Authentication
|
|
116
116
|
tokens = [
|
117
117
|
request['access_token'],
|
118
118
|
token_from_authorization_header(request),
|
119
|
-
token_from_haveapi_header(request)
|
119
|
+
token_from_haveapi_header(request)
|
120
120
|
].compact
|
121
121
|
|
122
122
|
token =
|
@@ -126,7 +126,7 @@ module HaveAPI::Authentication
|
|
126
126
|
when 1
|
127
127
|
tokens.first
|
128
128
|
else
|
129
|
-
|
129
|
+
raise 'Too many oauth2 tokens'
|
130
130
|
end
|
131
131
|
|
132
132
|
token && config.find_user_by_access_token(request, token)
|
@@ -135,11 +135,9 @@ module HaveAPI::Authentication
|
|
135
135
|
def token_from_authorization_header(request)
|
136
136
|
auth_header = Rack::Auth::AbstractRequest.new(request.env)
|
137
137
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
nil
|
142
|
-
end
|
138
|
+
return unless auth_header.provided? && !auth_header.parts.first.nil? && auth_header.scheme.to_s == 'bearer'
|
139
|
+
|
140
|
+
auth_header.params
|
143
141
|
end
|
144
142
|
|
145
143
|
def token_from_haveapi_header(request)
|
@@ -171,7 +169,7 @@ module HaveAPI::Authentication
|
|
171
169
|
token_url: @token_url,
|
172
170
|
token_path: @token_path,
|
173
171
|
revoke_url: @revoke_url,
|
174
|
-
revoke_path: @revoke_path
|
172
|
+
revoke_path: @revoke_path
|
175
173
|
}
|
176
174
|
end
|
177
175
|
|
@@ -189,14 +187,11 @@ module HaveAPI::Authentication
|
|
189
187
|
sinatra_params: handler.params,
|
190
188
|
oauth2_request: req,
|
191
189
|
oauth2_response: res,
|
192
|
-
client
|
190
|
+
client:
|
193
191
|
)
|
194
192
|
|
195
|
-
if auth_res.nil?
|
196
|
-
# Authentication failed
|
197
|
-
req.access_denied!
|
198
|
-
elsif auth_res.cancel
|
199
|
-
# Cancel the process
|
193
|
+
if auth_res.nil? || auth_res.cancel
|
194
|
+
# Authentication failed / cancel requested
|
200
195
|
req.access_denied!
|
201
196
|
elsif auth_res.authenticated && auth_res.complete
|
202
197
|
# Authentication was successful
|
@@ -216,7 +211,7 @@ module HaveAPI::Authentication
|
|
216
211
|
sinatra_params: handler.params,
|
217
212
|
oauth2_request: req,
|
218
213
|
oauth2_response: res,
|
219
|
-
client
|
214
|
+
client:
|
220
215
|
)
|
221
216
|
|
222
217
|
if auth_res.nil?
|
@@ -256,25 +251,19 @@ module HaveAPI::Authentication
|
|
256
251
|
if authorization.code_challenge && authorization.code_challenge_method
|
257
252
|
req.verify_code_verifier!(
|
258
253
|
authorization.code_challenge,
|
259
|
-
authorization.code_challenge_method.to_sym
|
254
|
+
authorization.code_challenge_method.to_sym
|
260
255
|
)
|
261
256
|
end
|
262
257
|
|
263
258
|
access_token, expires_at, refresh_token = config.get_tokens(authorization, handler.request)
|
264
259
|
|
265
260
|
bearer_token = Rack::OAuth2::AccessToken::Bearer.new(
|
266
|
-
access_token
|
267
|
-
expires_in: expires_at - Time.now
|
261
|
+
access_token:,
|
262
|
+
expires_in: expires_at - Time.now
|
268
263
|
)
|
269
264
|
bearer_token.refresh_token = refresh_token if refresh_token
|
270
265
|
bearer_token
|
271
266
|
|
272
|
-
when :password
|
273
|
-
req.unsupported_grant_type!
|
274
|
-
|
275
|
-
when :client_credentials
|
276
|
-
req.unsupported_grant_type!
|
277
|
-
|
278
267
|
when :refresh_token
|
279
268
|
authorization = config.find_authorization_by_refresh_token(client, req.refresh_token)
|
280
269
|
|
@@ -285,24 +274,24 @@ module HaveAPI::Authentication
|
|
285
274
|
access_token, expires_at, refresh_token = config.refresh_tokens(authorization, handler.request)
|
286
275
|
|
287
276
|
bearer_token = Rack::OAuth2::AccessToken::Bearer.new(
|
288
|
-
access_token
|
289
|
-
expires_in: expires_at - Time.now
|
277
|
+
access_token:,
|
278
|
+
expires_in: expires_at - Time.now
|
290
279
|
)
|
291
280
|
bearer_token.refresh_token = refresh_token if refresh_token
|
292
281
|
bearer_token
|
293
282
|
|
294
|
-
else
|
283
|
+
else # :password, :client_credentials
|
295
284
|
req.unsupported_grant_type!
|
296
285
|
end
|
297
286
|
end
|
298
287
|
end
|
299
288
|
|
300
289
|
def revoke_endpoint(handler)
|
301
|
-
RevokeEndpoint.new do |req,
|
290
|
+
RevokeEndpoint.new do |req, _res|
|
302
291
|
ret = config.handle_post_revoke(
|
303
292
|
handler.request,
|
304
293
|
req.token,
|
305
|
-
token_type_hint: req.token_type_hint
|
294
|
+
token_type_hint: req.token_type_hint
|
306
295
|
)
|
307
296
|
|
308
297
|
case ret
|
@@ -317,8 +306,9 @@ module HaveAPI::Authentication
|
|
317
306
|
end
|
318
307
|
|
319
308
|
private
|
309
|
+
|
320
310
|
def header_to_env(header)
|
321
|
-
"HTTP_#{header.upcase.gsub(
|
311
|
+
"HTTP_#{header.upcase.gsub('-', '_')}"
|
322
312
|
end
|
323
313
|
end
|
324
314
|
end
|
@@ -23,13 +23,12 @@ module HaveAPI::Authentication
|
|
23
23
|
raise Rack::OAuth2::Server::Abstract::BadRequest.new(
|
24
24
|
:unsupported_token_type,
|
25
25
|
description,
|
26
|
-
options
|
26
|
+
options
|
27
27
|
)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
class Response < Rack::OAuth2::Server::Abstract::Response
|
32
|
-
|
33
32
|
end
|
34
33
|
end
|
35
34
|
end
|
@@ -38,15 +38,17 @@ module HaveAPI::Authentication
|
|
38
38
|
end
|
39
39
|
|
40
40
|
private
|
41
|
+
|
41
42
|
def check!(name)
|
42
|
-
|
43
|
+
raise "#{name} cannot be configured" unless @opts[name]
|
44
|
+
|
43
45
|
true
|
44
46
|
end
|
45
47
|
|
46
48
|
def with_defaults(opts)
|
47
|
-
|
49
|
+
%i[input handle].to_h do |v|
|
48
50
|
[v, opts.has_key?(v) ? opts[v] : true]
|
49
|
-
end
|
51
|
+
end
|
50
52
|
end
|
51
53
|
end
|
52
54
|
end
|
@@ -18,7 +18,7 @@ module HaveAPI::Authentication
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
%i
|
21
|
+
%i[renew revoke].each do |name|
|
22
22
|
# Configuration method
|
23
23
|
define_method(name) do |&block|
|
24
24
|
var = :"@#{name}"
|
@@ -70,6 +70,8 @@ module HaveAPI::Authentication
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def inherited(subclass)
|
73
|
+
super
|
74
|
+
|
73
75
|
# Default request
|
74
76
|
subclass.request do
|
75
77
|
input do
|
@@ -84,7 +86,7 @@ module HaveAPI::Authentication
|
|
84
86
|
end
|
85
87
|
|
86
88
|
# Default renew and revoke
|
87
|
-
%i
|
89
|
+
%i[renew revoke].each do |name|
|
88
90
|
subclass.send(name) do
|
89
91
|
handle do
|
90
92
|
raise NotImplementedError
|
@@ -108,9 +110,7 @@ module HaveAPI::Authentication
|
|
108
110
|
# @param request [Sinatra::Request]
|
109
111
|
# @param token [String]
|
110
112
|
# @return [Object, nil]
|
111
|
-
def find_user_by_token(request, token)
|
112
|
-
|
113
|
-
end
|
113
|
+
def find_user_by_token(request, token); end
|
114
114
|
end
|
115
115
|
end
|
116
116
|
end
|
@@ -6,8 +6,7 @@ module HaveAPI::Authentication
|
|
6
6
|
module Token
|
7
7
|
# Exception that has to be raised when generated token already exists.
|
8
8
|
# Provider will catch it and generate another token.
|
9
|
-
class TokenExists <
|
10
|
-
|
9
|
+
class TokenExists < StandardError
|
11
10
|
end
|
12
11
|
|
13
12
|
# Provider for token authentication.
|
@@ -140,6 +139,7 @@ module HaveAPI::Authentication
|
|
140
139
|
|
141
140
|
def resource_module
|
142
141
|
return @module if @module
|
142
|
+
|
143
143
|
provider = self
|
144
144
|
|
145
145
|
@module = Module.new do
|
@@ -166,18 +166,14 @@ module HaveAPI::Authentication
|
|
166
166
|
{
|
167
167
|
http_header: config.class.http_header,
|
168
168
|
query_parameter: config.class.query_parameter,
|
169
|
-
description:
|
170
|
-
"username and password, and gets a token. "+
|
171
|
-
"From this point, the credentials can be forgotten and "+
|
172
|
-
"the token is used instead. Tokens can have different lifetimes, "+
|
173
|
-
"can be renewed and revoked. The token is passed either via HTTP "+
|
174
|
-
"header or query parameter."
|
169
|
+
description: 'The client authenticates with credentials, usually username and password, and gets a token. From this point, the credentials can be forgotten and the token is used instead. Tokens can have different lifetimes, can be renewed and revoked. The token is passed either via HTTP header or query parameter.'
|
175
170
|
}
|
176
171
|
end
|
177
172
|
|
178
173
|
private
|
174
|
+
|
179
175
|
def header_to_env
|
180
|
-
"HTTP_#{config.class.http_header.upcase.gsub(
|
176
|
+
"HTTP_#{config.class.http_header.upcase.gsub('-', '_')}"
|
181
177
|
end
|
182
178
|
|
183
179
|
def token_resource
|
@@ -194,21 +190,21 @@ module HaveAPI::Authentication
|
|
194
190
|
http_method :post
|
195
191
|
|
196
192
|
input(:hash) do
|
197
|
-
if block = provider.config.class.request.input
|
193
|
+
if (block = provider.config.class.request.input)
|
198
194
|
instance_exec(&block)
|
199
195
|
end
|
200
196
|
|
201
197
|
string :lifetime, label: 'Lifetime', required: true,
|
202
|
-
|
203
|
-
|
204
|
-
fixed - the token has a fixed validity period, it cannot be renewed
|
205
|
-
renewable_manual - the token can be renewed, but it must be done manually via renew action
|
206
|
-
renewable_auto - the token is renewed automatically to now+interval every time it is used
|
207
|
-
permanent - the token will be valid forever, unless deleted
|
208
|
-
END
|
198
|
+
choices: %i[fixed renewable_manual renewable_auto permanent],
|
199
|
+
desc: <<~END
|
200
|
+
fixed - the token has a fixed validity period, it cannot be renewed
|
201
|
+
renewable_manual - the token can be renewed, but it must be done manually via renew action
|
202
|
+
renewable_auto - the token is renewed automatically to now+interval every time it is used
|
203
|
+
permanent - the token will be valid forever, unless deleted
|
204
|
+
END
|
209
205
|
integer :interval, label: 'Interval',
|
210
|
-
|
211
|
-
|
206
|
+
desc: 'How long will requested token be valid, in seconds.',
|
207
|
+
default: 60 * 5, fill: true
|
212
208
|
end
|
213
209
|
|
214
210
|
output(:hash) do
|
@@ -227,9 +223,9 @@ END
|
|
227
223
|
|
228
224
|
begin
|
229
225
|
result = config.class.request.handle.call(ActionRequest.new(
|
230
|
-
|
231
|
-
|
232
|
-
|
226
|
+
request:,
|
227
|
+
input:
|
228
|
+
), ActionResult.new)
|
233
229
|
rescue HaveAPI::AuthenticationError => e
|
234
230
|
error(e.message)
|
235
231
|
end
|
@@ -242,7 +238,7 @@ END
|
|
242
238
|
token: result.token,
|
243
239
|
valid_to: result.valid_to,
|
244
240
|
complete: result.complete?,
|
245
|
-
next_action: result.next_action
|
241
|
+
next_action: result.next_action
|
246
242
|
}
|
247
243
|
end
|
248
244
|
end
|
@@ -258,10 +254,10 @@ END
|
|
258
254
|
def exec
|
259
255
|
provider = self.class.resource.token_instance
|
260
256
|
result = provider.config.class.revoke.handle.call(ActionRequest.new(
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
257
|
+
request:,
|
258
|
+
user: current_user,
|
259
|
+
token: provider.token(request)
|
260
|
+
), ActionResult.new)
|
265
261
|
|
266
262
|
if result.ok?
|
267
263
|
ok
|
@@ -286,13 +282,13 @@ END
|
|
286
282
|
def exec
|
287
283
|
provider = self.class.resource.token_instance
|
288
284
|
result = provider.config.renew_token(ActionRequest.new(
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
285
|
+
request:,
|
286
|
+
user: current_user,
|
287
|
+
token: provider.token(request)
|
288
|
+
), ActionResult.new)
|
293
289
|
|
294
290
|
if result.ok?
|
295
|
-
{valid_to: result.valid_to}
|
291
|
+
{ valid_to: result.valid_to }
|
296
292
|
else
|
297
293
|
error(result.error || 'renew failed')
|
298
294
|
end
|
@@ -323,10 +319,10 @@ END
|
|
323
319
|
define_method(:exec) do
|
324
320
|
begin
|
325
321
|
result = config.handle.call(ActionRequest.new(
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
322
|
+
request:,
|
323
|
+
input:,
|
324
|
+
token: input[:token]
|
325
|
+
), ActionResult.new)
|
330
326
|
rescue HaveAPI::AuthenticationError => e
|
331
327
|
error(e.message)
|
332
328
|
end
|
@@ -339,7 +335,7 @@ END
|
|
339
335
|
token: result.token,
|
340
336
|
valid_to: result.valid_to,
|
341
337
|
complete: result.complete?,
|
342
|
-
next_action: result.next_action
|
338
|
+
next_action: result.next_action
|
343
339
|
}
|
344
340
|
end
|
345
341
|
end
|