apisonator 2.101.1 → 3.0.0.pre1
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/Gemfile.on_prem.lock +1 -1
- data/lib/3scale/backend.rb +0 -1
- data/lib/3scale/backend/application.rb +3 -6
- data/lib/3scale/backend/configuration.rb +0 -1
- data/lib/3scale/backend/errors.rb +0 -36
- data/lib/3scale/backend/listener.rb +2 -79
- data/lib/3scale/backend/transactor.rb +1 -13
- data/lib/3scale/backend/transactor/report_job.rb +1 -1
- data/lib/3scale/backend/version.rb +1 -1
- metadata +2 -9
- data/lib/3scale/backend/oauth.rb +0 -4
- data/lib/3scale/backend/oauth/token.rb +0 -26
- data/lib/3scale/backend/oauth/token_key.rb +0 -30
- data/lib/3scale/backend/oauth/token_storage.rb +0 -313
- data/lib/3scale/backend/oauth/token_value.rb +0 -25
- data/lib/3scale/backend/views/oauth_access_tokens.builder +0 -14
- data/lib/3scale/backend/views/oauth_app_id_by_token.builder +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0fa79b460b2906815bfb027b35522ea438f4ecb8952643c2c66b886a28dcff09
|
4
|
+
data.tar.gz: 491656a6738201be52b2d3062b916db4f52cb38dd3edc8a2ba2b0c5816412a73
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75f2a8668f08c65ea4b125c1a1c86939f1e75e7d8b0d0aa5c2c084881fbe380a7eed3a8863d391f029d78460fd5f3c8036ec8c208177dd1fda813808577ed351
|
7
|
+
data.tar.gz: eb6f93ad8861cb4916afa819a8d2bc35db94b6c240c34048dd5e6ec5039ae7ade2977b3d0c251b86a63e710a73f1918785ecfd12f195f6e1dfb4d7bf12004fb4
|
data/Gemfile.lock
CHANGED
data/Gemfile.on_prem.lock
CHANGED
data/lib/3scale/backend.rb
CHANGED
@@ -35,7 +35,6 @@ require '3scale/backend/rack'
|
|
35
35
|
require '3scale/backend/extensions'
|
36
36
|
require '3scale/backend/background_job'
|
37
37
|
require '3scale/backend/storage'
|
38
|
-
require '3scale/backend/oauth'
|
39
38
|
require '3scale/backend/memoizer'
|
40
39
|
require '3scale/backend/application'
|
41
40
|
require '3scale/backend/error_storage'
|
@@ -91,8 +91,8 @@ module ThreeScale
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
-
def extract_id!(service_id, app_id, user_key
|
95
|
-
with_app_id_from_params service_id, app_id, user_key
|
94
|
+
def extract_id!(service_id, app_id, user_key)
|
95
|
+
with_app_id_from_params service_id, app_id, user_key do |appid|
|
96
96
|
exists? service_id, appid and appid
|
97
97
|
end
|
98
98
|
end
|
@@ -106,7 +106,6 @@ module ThreeScale
|
|
106
106
|
raise ApplicationNotFound, id unless exists?(service_id, id)
|
107
107
|
delete_data service_id, id
|
108
108
|
clear_cache service_id, id
|
109
|
-
OAuth::Token::Storage.remove_tokens(service_id, id)
|
110
109
|
end
|
111
110
|
|
112
111
|
def delete_data(service_id, id)
|
@@ -157,14 +156,12 @@ module ThreeScale
|
|
157
156
|
)
|
158
157
|
end
|
159
158
|
|
160
|
-
def with_app_id_from_params(service_id, app_id, user_key
|
159
|
+
def with_app_id_from_params(service_id, app_id, user_key)
|
161
160
|
if app_id
|
162
161
|
raise AuthenticationError unless user_key.nil?
|
163
162
|
elsif user_key
|
164
163
|
app_id = load_id_by_key(service_id, user_key)
|
165
164
|
raise UserKeyInvalid, user_key if app_id.nil?
|
166
|
-
elsif access_token
|
167
|
-
app_id, * = OAuth::Token::Storage.get_credentials access_token, service_id
|
168
165
|
else
|
169
166
|
raise ApplicationNotFound
|
170
167
|
end
|
@@ -57,7 +57,6 @@ module ThreeScale
|
|
57
57
|
config.add_section(:redshift, :host, :port, :dbname, :user, :password)
|
58
58
|
config.add_section(:statsd, :host, :port)
|
59
59
|
config.add_section(:internal_api, :user, :password)
|
60
|
-
config.add_section(:oauth, :max_token_size)
|
61
60
|
config.add_section(:master, :metrics)
|
62
61
|
config.add_section(:worker_prometheus_metrics, :enabled, :port)
|
63
62
|
config.add_section(:listener_prometheus_metrics, :enabled, :port)
|
@@ -73,36 +73,6 @@ module ThreeScale
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
-
class AccessTokenInvalid < NotFound
|
77
|
-
def initialize(id = nil)
|
78
|
-
super %(token "#{id}" is invalid: expired or never defined)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
class AccessTokenAlreadyExists < Error
|
83
|
-
def initialize(id = nil)
|
84
|
-
super %(token "#{id}" already exists)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
class AccessTokenStorageError < Error
|
89
|
-
def initialize(id = nil)
|
90
|
-
super %(storage error when saving token "#{id}")
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
class AccessTokenFormatInvalid < Invalid
|
95
|
-
def initialize
|
96
|
-
super 'token is either too big or has an invalid format'.freeze
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
class AccessTokenInvalidTTL < Invalid
|
101
|
-
def initialize
|
102
|
-
super 'the specified TTL should be a positive integer'.freeze
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
76
|
class ServiceNotActive < Error
|
107
77
|
def initialize
|
108
78
|
super 'service is not active'.freeze
|
@@ -182,12 +152,6 @@ module ThreeScale
|
|
182
152
|
end
|
183
153
|
end
|
184
154
|
|
185
|
-
class RequiredParamsMissing < Invalid
|
186
|
-
def initialize
|
187
|
-
super 'missing required parameters'.freeze
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
155
|
class UsageValueInvalid < Error
|
192
156
|
def initialize(metric_name, value)
|
193
157
|
if !value.is_a?(String) || value.blank?
|
@@ -30,9 +30,6 @@ module ThreeScale
|
|
30
30
|
##~ @parameter_app_id_inline = @parameter_app_id.clone
|
31
31
|
##~ @parameter_app_id_inline["description_inline"] = true
|
32
32
|
##
|
33
|
-
##~ @parameter_access_token = {"name" => "access_token", "dataType" => "string", "required" => false, "paramType" => "query", "threescale_name" => "access_tokens"}
|
34
|
-
##~ @parameter_access_token["description"] = "OAuth token used for authorizing if you don't use client_id with client_secret."
|
35
|
-
##
|
36
33
|
##~ @parameter_client_id = {"name" => "app_id", "dataType" => "string", "required" => false, "paramType" => "query", "threescale_name" => "app_ids"}
|
37
34
|
##~ @parameter_client_id["description"] = "Client Id (identifier of the application if the auth. pattern is OAuth, note that client_id == app_id)"
|
38
35
|
##~ @parameter_client_id_inline = @parameter_client_id.clone
|
@@ -114,8 +111,7 @@ module ThreeScale
|
|
114
111
|
|
115
112
|
|
116
113
|
AUTH_AUTHREP_COMMON_PARAMS = ['service_id'.freeze, 'app_id'.freeze, 'app_key'.freeze,
|
117
|
-
'user_key'.freeze, 'provider_key'.freeze
|
118
|
-
'access_token'.freeze].freeze
|
114
|
+
'user_key'.freeze, 'provider_key'.freeze].freeze
|
119
115
|
private_constant :AUTH_AUTHREP_COMMON_PARAMS
|
120
116
|
|
121
117
|
REPORT_EXPECTED_PARAMS = ['provider_key'.freeze,
|
@@ -128,8 +124,6 @@ module ThreeScale
|
|
128
124
|
disable :dump_errors
|
129
125
|
end
|
130
126
|
|
131
|
-
set :views, File.dirname(__FILE__) + '/views'
|
132
|
-
|
133
127
|
use Backend::Rack::ExceptionCatcher
|
134
128
|
|
135
129
|
before do
|
@@ -252,7 +246,7 @@ module ThreeScale
|
|
252
246
|
##~ op.summary = "Authorize (OAuth authentication mode pattern)"
|
253
247
|
##
|
254
248
|
##~ op.description = "<p>Read-only operation to authorize an application in the OAuth authentication pattern."
|
255
|
-
##~ @oauth_security = "<p>When using this endpoint please pay attention at your handling of app_id and app_key parameters. If you don't specify an app_key, the endpoint assumes the app_id specified has already been authenticated by other means. If you specify the app_key parameter, even if it is empty, it will be checked against the application's keys. If you don't trust the app_id value you have,
|
249
|
+
##~ @oauth_security = "<p>When using this endpoint please pay attention at your handling of app_id and app_key parameters. If you don't specify an app_key, the endpoint assumes the app_id specified has already been authenticated by other means. If you specify the app_key parameter, even if it is empty, it will be checked against the application's keys. If you don't trust the app_id value you have, use app keys and specify one."
|
256
250
|
##~ @oauth_desc_response = "<p>This call returns extra data (secret and redirect_url) needed to power OAuth APIs. It's only available for users with OAuth enabled APIs."
|
257
251
|
##~ op.description = op.description + @oauth_security + @oauth_desc_response
|
258
252
|
##~ op.description = op.description + " " + @authorize_desc + " " + @authorize_desc_response
|
@@ -263,7 +257,6 @@ module ThreeScale
|
|
263
257
|
##
|
264
258
|
##~ op.parameters.add @parameter_service_token
|
265
259
|
##~ op.parameters.add @parameter_service_id
|
266
|
-
##~ op.parameters.add @parameter_access_token
|
267
260
|
##~ op.parameters.add @parameter_client_id
|
268
261
|
##~ op.parameters.add @parameter_app_key_oauth
|
269
262
|
##~ op.parameters.add @parameter_referrer
|
@@ -337,7 +330,6 @@ module ThreeScale
|
|
337
330
|
##
|
338
331
|
##~ op.parameters.add @parameter_service_token
|
339
332
|
##~ op.parameters.add @parameter_service_id
|
340
|
-
##~ op.parameters.add @parameter_access_token
|
341
333
|
##~ op.parameters.add @parameter_client_id
|
342
334
|
##~ op.parameters.add @parameter_app_key_oauth
|
343
335
|
##~ op.parameters.add @parameter_referrer
|
@@ -430,62 +422,6 @@ module ThreeScale
|
|
430
422
|
202
|
431
423
|
end
|
432
424
|
|
433
|
-
## OAUTH ACCESS TOKENS
|
434
|
-
|
435
|
-
# These endpoints are deprecated and are going to be removed. For now,
|
436
|
-
# let's disable them.
|
437
|
-
if Backend.test?
|
438
|
-
post '/services/:service_id/oauth_access_tokens.xml' do
|
439
|
-
check_post_content_type!
|
440
|
-
require_params! :service_id, :token
|
441
|
-
|
442
|
-
service_id = params[:service_id]
|
443
|
-
ensure_authenticated!(params[:provider_key], params[:service_token], service_id)
|
444
|
-
|
445
|
-
app_id = params[:app_id]
|
446
|
-
raise ApplicationNotFound, app_id unless Application.exists?(service_id, app_id)
|
447
|
-
|
448
|
-
OAuth::Token::Storage.create(params[:token], service_id, app_id, params[:ttl])
|
449
|
-
end
|
450
|
-
|
451
|
-
delete '/services/:service_id/oauth_access_tokens/:token.xml' do
|
452
|
-
require_params! :service_id, :token
|
453
|
-
|
454
|
-
service_id = params[:service_id]
|
455
|
-
ensure_authenticated!(params[:provider_key], params[:service_token], service_id)
|
456
|
-
|
457
|
-
token = params[:token]
|
458
|
-
|
459
|
-
# TODO: perhaps improve this to list the deleted tokens?
|
460
|
-
raise AccessTokenInvalid, token unless OAuth::Token::Storage.delete(token, service_id)
|
461
|
-
end
|
462
|
-
|
463
|
-
get '/services/:service_id/applications/:app_id/oauth_access_tokens.xml' do
|
464
|
-
require_params! :service_id, :app_id
|
465
|
-
|
466
|
-
service_id = params[:service_id]
|
467
|
-
ensure_authenticated!(params[:provider_key], params[:service_token], service_id)
|
468
|
-
|
469
|
-
app_id = params[:app_id]
|
470
|
-
|
471
|
-
raise ApplicationNotFound, app_id unless Application.exists?(service_id, app_id)
|
472
|
-
|
473
|
-
@tokens = OAuth::Token::Storage.all_by_service_and_app service_id, app_id
|
474
|
-
builder :oauth_access_tokens
|
475
|
-
end
|
476
|
-
|
477
|
-
get '/services/:service_id/oauth_access_tokens/:token.xml' do
|
478
|
-
require_params! :service_id, :token
|
479
|
-
|
480
|
-
service_id = params[:service_id]
|
481
|
-
ensure_authenticated!(params[:provider_key], params[:service_token], service_id)
|
482
|
-
|
483
|
-
@token_to_app_id = OAuth::Token::Storage.get_credentials(params[:token], service_id)
|
484
|
-
|
485
|
-
builder :oauth_app_id_by_token
|
486
|
-
end
|
487
|
-
end
|
488
|
-
|
489
425
|
get '/check.txt' do
|
490
426
|
content_type 'text/plain'
|
491
427
|
body 'ok'
|
@@ -518,10 +454,6 @@ module ThreeScale
|
|
518
454
|
params[:usage].nil? || params[:usage].is_a?(Hash)
|
519
455
|
end
|
520
456
|
|
521
|
-
def require_params!(*keys)
|
522
|
-
raise RequiredParamsMissing unless params && keys.all? { |key| !blank?(params[key]) }
|
523
|
-
end
|
524
|
-
|
525
457
|
def check_params_value_encoding!(input_params, params_to_validate)
|
526
458
|
params_to_validate.each do |p|
|
527
459
|
param_value = input_params[p]
|
@@ -651,15 +583,6 @@ module ThreeScale
|
|
651
583
|
raise ServiceTokenInvalid.new(token, id)
|
652
584
|
end
|
653
585
|
|
654
|
-
def ensure_authenticated!(provider_key, service_token, service_id)
|
655
|
-
if blank?(provider_key)
|
656
|
-
key = provider_key_from(service_token, service_id)
|
657
|
-
raise_provider_key_error(params) if blank?(key)
|
658
|
-
elsif !Service.authenticate_service_id(service_id, provider_key)
|
659
|
-
raise ProviderKeyInvalid, provider_key
|
660
|
-
end
|
661
|
-
end
|
662
|
-
|
663
586
|
def response_auth_call(auth_status)
|
664
587
|
status(auth_status.authorized? ? 200 : 409)
|
665
588
|
optionally_set_headers(auth_status)
|
@@ -65,19 +65,7 @@ module ThreeScale
|
|
65
65
|
params[:app_id] = nil if app_id && app_id.empty?
|
66
66
|
|
67
67
|
if oauth
|
68
|
-
if app_id.nil?
|
69
|
-
access_token = params[:access_token]
|
70
|
-
access_token = nil if access_token && access_token.empty?
|
71
|
-
|
72
|
-
if access_token.nil?
|
73
|
-
raise ApplicationNotFound.new nil if app_id.nil?
|
74
|
-
else
|
75
|
-
app_id = get_token_ids(access_token, service_id, app_id)
|
76
|
-
# update params, since they are checked elsewhere
|
77
|
-
params[:app_id] = app_id
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
68
|
+
raise ApplicationNotFound.new nil if app_id.nil?
|
81
69
|
validators = Validators::OAUTH_VALIDATORS
|
82
70
|
else
|
83
71
|
validators = Validators::VALIDATORS
|
@@ -59,7 +59,7 @@ module ThreeScale
|
|
59
59
|
return [] if transactions.empty?
|
60
60
|
transactions = transactions.values if transactions.respond_to?(:values)
|
61
61
|
transactions.group_by do |transaction|
|
62
|
-
Application.extract_id!(service_id, transaction['app_id'], transaction['user_key']
|
62
|
+
Application.extract_id!(service_id, transaction['app_id'], transaction['user_key'])
|
63
63
|
end.each(&block)
|
64
64
|
end
|
65
65
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apisonator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0.pre1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Ciganek
|
@@ -16,7 +16,7 @@ authors:
|
|
16
16
|
autorequire:
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
|
-
date: 2020-06-
|
19
|
+
date: 2020-06-19 00:00:00.000000000 Z
|
20
20
|
dependencies: []
|
21
21
|
description: This gem provides a daemon that handles authorization and reporting of
|
22
22
|
web services managed by 3scale.
|
@@ -111,11 +111,6 @@ files:
|
|
111
111
|
- lib/3scale/backend/memoizer.rb
|
112
112
|
- lib/3scale/backend/metric.rb
|
113
113
|
- lib/3scale/backend/metric/collection.rb
|
114
|
-
- lib/3scale/backend/oauth.rb
|
115
|
-
- lib/3scale/backend/oauth/token.rb
|
116
|
-
- lib/3scale/backend/oauth/token_key.rb
|
117
|
-
- lib/3scale/backend/oauth/token_storage.rb
|
118
|
-
- lib/3scale/backend/oauth/token_value.rb
|
119
114
|
- lib/3scale/backend/period.rb
|
120
115
|
- lib/3scale/backend/period/boundary.rb
|
121
116
|
- lib/3scale/backend/period/cache.rb
|
@@ -184,8 +179,6 @@ files:
|
|
184
179
|
- lib/3scale/backend/validators/service_state.rb
|
185
180
|
- lib/3scale/backend/validators/state.rb
|
186
181
|
- lib/3scale/backend/version.rb
|
187
|
-
- lib/3scale/backend/views/oauth_access_tokens.builder
|
188
|
-
- lib/3scale/backend/views/oauth_app_id_by_token.builder
|
189
182
|
- lib/3scale/backend/worker.rb
|
190
183
|
- lib/3scale/backend/worker_async.rb
|
191
184
|
- lib/3scale/backend/worker_metrics.rb
|
data/lib/3scale/backend/oauth.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
module ThreeScale
|
2
|
-
module Backend
|
3
|
-
module OAuth
|
4
|
-
class Token
|
5
|
-
attr_reader :service_id, :token, :key
|
6
|
-
attr_accessor :ttl, :app_id
|
7
|
-
|
8
|
-
def initialize(token, service_id, app_id, ttl)
|
9
|
-
@token = token
|
10
|
-
@service_id = service_id
|
11
|
-
@app_id = app_id
|
12
|
-
@ttl = ttl
|
13
|
-
@key = Key.for token, service_id
|
14
|
-
end
|
15
|
-
|
16
|
-
def value
|
17
|
-
Value.for app_id
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.from_value(token, service_id, value, ttl)
|
21
|
-
new token, service_id, *Value.from(value), ttl
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# This module defines the format of the keys for OAuth tokens and token sets.
|
2
|
-
#
|
3
|
-
# Note that while we can build the key easily, we cannot reliably obtain a token
|
4
|
-
# and a service_id out of the key, because there are no constraints on them:
|
5
|
-
#
|
6
|
-
# "oauth_access_tokens/service:some/servicegoeshere/andthisis_a_/valid_token"
|
7
|
-
#
|
8
|
-
module ThreeScale
|
9
|
-
module Backend
|
10
|
-
module OAuth
|
11
|
-
class Token
|
12
|
-
module Key
|
13
|
-
class << self
|
14
|
-
def for(token, service_id)
|
15
|
-
"oauth_access_tokens/service:#{service_id}/#{token}"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
module Set
|
20
|
-
class << self
|
21
|
-
def for(service_id, app_id)
|
22
|
-
"oauth_access_tokens/service:#{service_id}/app:#{app_id}/"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,313 +0,0 @@
|
|
1
|
-
module ThreeScale
|
2
|
-
module Backend
|
3
|
-
module OAuth
|
4
|
-
class Token
|
5
|
-
module Storage
|
6
|
-
include Configurable
|
7
|
-
|
8
|
-
# Default token size is 4K - 512 (to allow for some metadata)
|
9
|
-
MAXIMUM_TOKEN_SIZE = configuration.oauth.max_token_size || 3584
|
10
|
-
private_constant :MAXIMUM_TOKEN_SIZE
|
11
|
-
TOKEN_MAX_REDIS_SLICE_SIZE = 500
|
12
|
-
private_constant :TOKEN_MAX_REDIS_SLICE_SIZE
|
13
|
-
TOKEN_TTL_DEFAULT = 86400
|
14
|
-
private_constant :TOKEN_TTL_DEFAULT
|
15
|
-
TOKEN_TTL_PERMANENT = 0
|
16
|
-
private_constant :TOKEN_TTL_PERMANENT
|
17
|
-
|
18
|
-
Error = Class.new StandardError
|
19
|
-
InconsistencyError = Class.new Error
|
20
|
-
|
21
|
-
class << self
|
22
|
-
include Backend::Logging
|
23
|
-
include Backend::StorageHelpers
|
24
|
-
|
25
|
-
def create(token, service_id, app_id, ttl = nil)
|
26
|
-
raise AccessTokenFormatInvalid if token.nil? || token.empty? ||
|
27
|
-
!token.is_a?(String) || token.bytesize > MAXIMUM_TOKEN_SIZE
|
28
|
-
|
29
|
-
# raises if TTL is invalid
|
30
|
-
ttl = sanitized_ttl ttl
|
31
|
-
|
32
|
-
key = Key.for token, service_id
|
33
|
-
raise AccessTokenAlreadyExists.new(token) unless storage.get(key).nil?
|
34
|
-
|
35
|
-
value = Value.for app_id
|
36
|
-
token_set = Key::Set.for(service_id, app_id)
|
37
|
-
|
38
|
-
store_token token, token_set, key, value, ttl
|
39
|
-
ensure_stored! token, token_set, key, value
|
40
|
-
end
|
41
|
-
|
42
|
-
# Deletes a token
|
43
|
-
#
|
44
|
-
# Returns the associated app_id or nil
|
45
|
-
#
|
46
|
-
def delete(token, service_id)
|
47
|
-
key = Key.for token, service_id
|
48
|
-
val = storage.get key
|
49
|
-
if val
|
50
|
-
app_id = Value.from val
|
51
|
-
token_set = Key::Set.for(service_id, app_id)
|
52
|
-
|
53
|
-
existed, * = remove_a_token token_set, token, key
|
54
|
-
|
55
|
-
unless existed
|
56
|
-
logger.notify(InconsistencyError.new("Found OAuth token " \
|
57
|
-
"#{token} for service #{service_id} and app #{app_id} as " \
|
58
|
-
"key but not in set!"))
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
val
|
63
|
-
end
|
64
|
-
|
65
|
-
# Get a token's associated app_id
|
66
|
-
def get_credentials(token, service_id)
|
67
|
-
app_id = Value.from(storage.get(Key.for(token, service_id)))
|
68
|
-
raise AccessTokenInvalid.new token if app_id.nil?
|
69
|
-
app_id
|
70
|
-
end
|
71
|
-
|
72
|
-
# This is used to list tokens by service and app.
|
73
|
-
#
|
74
|
-
# Note: this deletes tokens that have not been found from the set of
|
75
|
-
# tokens for the given app - those have to be expired tokens.
|
76
|
-
def all_by_service_and_app(service_id, app_id)
|
77
|
-
token_set = Key::Set.for(service_id, app_id)
|
78
|
-
deltokens = []
|
79
|
-
tokens_n_values_flat(token_set, service_id)
|
80
|
-
.select do |(token, _key, value, _ttl)|
|
81
|
-
app_id = Value.from value
|
82
|
-
if app_id.nil?
|
83
|
-
deltokens << token
|
84
|
-
false
|
85
|
-
else
|
86
|
-
true
|
87
|
-
end
|
88
|
-
end
|
89
|
-
.map do |(token, _key, value, ttl)|
|
90
|
-
Token.from_value token, service_id, value, ttl
|
91
|
-
end
|
92
|
-
.tap do
|
93
|
-
# delete expired tokens (nil values) from token set
|
94
|
-
deltokens.each_slice(TOKEN_MAX_REDIS_SLICE_SIZE) do |delgrp|
|
95
|
-
storage.srem token_set, delgrp
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# Remove tokens by app_id.
|
101
|
-
#
|
102
|
-
# Triggered by Application deletion.
|
103
|
-
#
|
104
|
-
def remove_tokens(service_id, app_id)
|
105
|
-
remove_tokens_by service_id, app_id
|
106
|
-
end
|
107
|
-
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
|
-
# Remove all tokens
|
112
|
-
#
|
113
|
-
# I thought of leaving this one public, but remove_*_tokens removed
|
114
|
-
# my use cases for the time being.
|
115
|
-
def remove_tokens_by(service_id, app_id)
|
116
|
-
token_set = Key::Set.for(service_id, app_id)
|
117
|
-
|
118
|
-
remove_whole_token_set(token_set, service_id)
|
119
|
-
end
|
120
|
-
|
121
|
-
def remove_token_set_by(token_set, service_id, &blk)
|
122
|
-
# Get tokens. Filter them. Group them into manageable groups.
|
123
|
-
# Extract tokens and keys into separate arrays, one for each.
|
124
|
-
# Remove tokens from token set (they are keys in a set) and token
|
125
|
-
# keys themselves.
|
126
|
-
tokens_n_values_flat(token_set, service_id, false)
|
127
|
-
.select(&blk)
|
128
|
-
.each_slice(TOKEN_MAX_REDIS_SLICE_SIZE)
|
129
|
-
.inject([[], []]) do |acc, groups|
|
130
|
-
groups.each do |token, key, _value|
|
131
|
-
acc[0] << token
|
132
|
-
acc[1] << key
|
133
|
-
end
|
134
|
-
acc
|
135
|
-
end
|
136
|
-
.each_slice(2)
|
137
|
-
.inject([]) do |acc, (tokens, keys)|
|
138
|
-
storage.pipelined do
|
139
|
-
if tokens && !tokens.empty?
|
140
|
-
storage.srem token_set, tokens
|
141
|
-
acc.concat tokens
|
142
|
-
end
|
143
|
-
storage.del keys if keys && !keys.empty?
|
144
|
-
end
|
145
|
-
acc
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def remove_a_token(token_set, token, key)
|
150
|
-
storage.pipelined do
|
151
|
-
storage.srem token_set, token
|
152
|
-
storage.del key
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def remove_whole_token_set(token_set, service_id)
|
157
|
-
_token_groups, key_groups = tokens_n_keys(token_set, service_id)
|
158
|
-
storage.pipelined do
|
159
|
-
storage.del token_set
|
160
|
-
# remove all tokens for this app
|
161
|
-
key_groups.each do |keys|
|
162
|
-
storage.del keys
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
# TODO: provide a SSCAN interface with lazy enums because SMEMBERS
|
168
|
-
# is prone to DoSing and timeouts
|
169
|
-
def tokens_from(token_set)
|
170
|
-
storage.smembers(token_set)
|
171
|
-
end
|
172
|
-
|
173
|
-
def tokens_n_keys(token_set, service_id)
|
174
|
-
token_groups = tokens_from(token_set).each_slice(TOKEN_MAX_REDIS_SLICE_SIZE)
|
175
|
-
key_groups = token_groups.map do |tokens|
|
176
|
-
tokens.map do |token|
|
177
|
-
Key.for token, service_id
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
[token_groups, key_groups]
|
182
|
-
end
|
183
|
-
|
184
|
-
# Provides grouped data which matches respectively in each array
|
185
|
-
# position, ie. 1st group of data contains a group of tokens, keys
|
186
|
-
# and values with ttls, and position N of the tokens group has key
|
187
|
-
# in position N of the keys group, and so on.
|
188
|
-
#
|
189
|
-
# [[[token group], [key group], [value_with_ttls_group]], ...]
|
190
|
-
#
|
191
|
-
def tokens_n_values_groups(token_set, service_id, with_ttls)
|
192
|
-
token_groups, key_groups = tokens_n_keys(token_set, service_id)
|
193
|
-
value_ttl_groups = key_groups.map do |keys|
|
194
|
-
# pipelining will create an array with the results of commands
|
195
|
-
res = storage.pipelined do
|
196
|
-
storage.mget(keys)
|
197
|
-
if with_ttls
|
198
|
-
keys.map do |key|
|
199
|
-
storage.ttl key
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
203
|
-
# [mget array, 0..n ttls] => [mget array, ttls array]
|
204
|
-
[res.shift, res]
|
205
|
-
end
|
206
|
-
token_groups.zip(key_groups, value_ttl_groups)
|
207
|
-
end
|
208
|
-
|
209
|
-
# Zips the data provided by tokens_n_values_groups so that you stop
|
210
|
-
# looking at indexes in the respective arrays and instead have:
|
211
|
-
#
|
212
|
-
# [group 0, ..., group N] where each group is made of:
|
213
|
-
# [[token 0, key 0, value 0, ttl 0], ..., [token N, key N, value
|
214
|
-
# N, ttl N]]
|
215
|
-
#
|
216
|
-
def tokens_n_values_zipped_groups(token_set, service_id, with_ttls = true)
|
217
|
-
tokens_n_values_groups(token_set,
|
218
|
-
service_id,
|
219
|
-
with_ttls).map do |tokens, keys, (values, ttls)|
|
220
|
-
tokens.zip keys, values, ttls
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
# Flattens the data provided by tokens_n_values_zipped_groups so
|
225
|
-
# that you have a transparent iterator with all needed data and can
|
226
|
-
# stop worrying about streaming groups of elements.
|
227
|
-
#
|
228
|
-
def tokens_n_values_flat(token_set, service_id, with_ttls = true)
|
229
|
-
tokens_n_values_zipped_groups(token_set,
|
230
|
-
service_id,
|
231
|
-
with_ttls).flat_map do |groups|
|
232
|
-
groups.map do |token, key, value, ttl|
|
233
|
-
[token, key, value, ttl]
|
234
|
-
end
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
# Store the specified token in Redis
|
239
|
-
#
|
240
|
-
# TTL specified in seconds.
|
241
|
-
# A TTL of 0 stores a permanent token
|
242
|
-
def store_token(token, token_set, key, value, ttl)
|
243
|
-
# build the storage command so that we can pipeline everything cleanly
|
244
|
-
command = :set
|
245
|
-
args = [key]
|
246
|
-
|
247
|
-
if !permanent_ttl? ttl
|
248
|
-
command = :setex
|
249
|
-
args << ttl
|
250
|
-
end
|
251
|
-
|
252
|
-
args << value
|
253
|
-
|
254
|
-
# pipelined will return nil if it is embedded into another
|
255
|
-
# pipeline(which would be an error at this point) or if shutting
|
256
|
-
# down and a connection error happens. Both things being abnormal
|
257
|
-
# means we should just raise a storage error.
|
258
|
-
raise AccessTokenStorageError, token unless storage.pipelined do
|
259
|
-
storage.send(command, *args)
|
260
|
-
storage.sadd(token_set, token)
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
|
265
|
-
# Make sure everything ended up there
|
266
|
-
#
|
267
|
-
# TODO: review and possibly reimplement trying to leave it
|
268
|
-
# consistent as much as possible.
|
269
|
-
#
|
270
|
-
# Note that we have a sharding proxy and pipelines can't be guaranteed
|
271
|
-
# to behave like transactions, since we might have one non-working
|
272
|
-
# shard. Instead of relying on proxy-specific responses, we just check
|
273
|
-
# that the data we should have in the store is really there.
|
274
|
-
def ensure_stored!(token, token_set, key, value)
|
275
|
-
results = storage.pipelined do
|
276
|
-
storage.get(key)
|
277
|
-
storage.sismember(token_set, token)
|
278
|
-
end
|
279
|
-
|
280
|
-
results.last && results.first == value ||
|
281
|
-
raise(AccessTokenStorageError, token)
|
282
|
-
end
|
283
|
-
|
284
|
-
# Validation for the TTL value
|
285
|
-
#
|
286
|
-
# 0 is accepted (understood as permanent token)
|
287
|
-
# Negative values are not accepted
|
288
|
-
# Integer(ttl) validation is required (if input is nil, default applies)
|
289
|
-
def sanitized_ttl(ttl)
|
290
|
-
ttl = begin
|
291
|
-
Integer(ttl)
|
292
|
-
rescue TypeError
|
293
|
-
# ttl is nil
|
294
|
-
TOKEN_TTL_DEFAULT
|
295
|
-
rescue
|
296
|
-
# NaN
|
297
|
-
-1
|
298
|
-
end
|
299
|
-
raise AccessTokenInvalidTTL if ttl < 0
|
300
|
-
|
301
|
-
ttl
|
302
|
-
end
|
303
|
-
|
304
|
-
# Check whether a TTL has the magic value for a permanent token
|
305
|
-
def permanent_ttl?(ttl)
|
306
|
-
ttl == TOKEN_TTL_PERMANENT
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|
310
|
-
end
|
311
|
-
end
|
312
|
-
end
|
313
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# This module encodes values in Redis for our tokens
|
2
|
-
module ThreeScale
|
3
|
-
module Backend
|
4
|
-
module OAuth
|
5
|
-
class Token
|
6
|
-
module Value
|
7
|
-
# Note: this module made more sense when it also supported end-users.
|
8
|
-
# Given how simple the module is, we could get rid of it in a future
|
9
|
-
# refactor.
|
10
|
-
|
11
|
-
class << self
|
12
|
-
# this method is used when creating tokens
|
13
|
-
def for(app_id)
|
14
|
-
app_id
|
15
|
-
end
|
16
|
-
|
17
|
-
def from(value)
|
18
|
-
value
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
xml.instruct!
|
2
|
-
xml.oauth_access_tokens do
|
3
|
-
@tokens.each do |t|
|
4
|
-
# Some bright head leaked the -1 that Redis uses to indicate there is no TTL
|
5
|
-
# associated with a key. The behaviour is inconsistent because somehow we
|
6
|
-
# BOTH expect that a token with no TTL does not have a "ttl" attribute in
|
7
|
-
# the generated XML and at the same time we expect (in some tests) that such
|
8
|
-
# tokens have this field with a -1 value.
|
9
|
-
#
|
10
|
-
# Just enforce the ttl to be -1 when there is none.
|
11
|
-
attrs = { :ttl => t.ttl || -1 }
|
12
|
-
xml.oauth_access_token t.token, attrs
|
13
|
-
end
|
14
|
-
end
|