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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17eddc012f9777873f8bb1eca063c269903980531ae2963e839c265e2cce8ecc
4
- data.tar.gz: f0b5ff06a98132e51dd5ab4bbbcf9322f037ee029487919366fca1eb207c13e8
3
+ metadata.gz: 0fa79b460b2906815bfb027b35522ea438f4ecb8952643c2c66b886a28dcff09
4
+ data.tar.gz: 491656a6738201be52b2d3062b916db4f52cb38dd3edc8a2ba2b0c5816412a73
5
5
  SHA512:
6
- metadata.gz: 81a05e8249f1a354897379fc814a898f712ecc9b5a82e6dd9a28ab21abbdb6bd2e7af65a71cb77571cf476d581a251773a87bc3b489bf5be2d9740d6e3e1812b
7
- data.tar.gz: fe7bd84d54a37680841df80cd405f2b71ff4a1cb936d757df5aa06e484c7c871584101cac6ea3f72eb1b17836b3af188474590a9ab6d40c4919037a8ce1a644e
6
+ metadata.gz: 75f2a8668f08c65ea4b125c1a1c86939f1e75e7d8b0d0aa5c2c084881fbe380a7eed3a8863d391f029d78460fd5f3c8036ec8c208177dd1fda813808577ed351
7
+ data.tar.gz: eb6f93ad8861cb4916afa819a8d2bc35db94b6c240c34048dd5e6ec5039ae7ade2977b3d0c251b86a63e710a73f1918785ecfd12f195f6e1dfb4d7bf12004fb4
@@ -35,7 +35,7 @@ GIT
35
35
  PATH
36
36
  remote: .
37
37
  specs:
38
- apisonator (2.101.1)
38
+ apisonator (3.0.0.pre1)
39
39
 
40
40
  GEM
41
41
  remote: https://rubygems.org/
@@ -35,7 +35,7 @@ GIT
35
35
  PATH
36
36
  remote: .
37
37
  specs:
38
- apisonator (2.101.1)
38
+ apisonator (3.0.0.pre1)
39
39
 
40
40
  GEM
41
41
  remote: https://rubygems.org/
@@ -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, access_token)
95
- with_app_id_from_params service_id, app_id, user_key, access_token do |appid|
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, access_token = nil)
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, either use app keys and specify one or use access_token and avoid the app_id parameter."
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'], transaction['access_token'])
62
+ Application.extract_id!(service_id, transaction['app_id'], transaction['user_key'])
63
63
  end.each(&block)
64
64
  end
65
65
 
@@ -1,5 +1,5 @@
1
1
  module ThreeScale
2
2
  module Backend
3
- VERSION = '2.101.1'
3
+ VERSION = '3.0.0.pre1'
4
4
  end
5
5
  end
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: 2.101.1
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-05 00:00:00.000000000 Z
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
@@ -1,4 +0,0 @@
1
- require '3scale/backend/oauth/token'
2
- require '3scale/backend/oauth/token_key'
3
- require '3scale/backend/oauth/token_value'
4
- require '3scale/backend/oauth/token_storage'
@@ -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
@@ -1,4 +0,0 @@
1
- xml.instruct!
2
- xml.application do
3
- xml.app_id @token_to_app_id
4
- end