apisonator 2.101.0 → 3.0.1
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/CHANGELOG.md +32 -0
- data/Gemfile.base +2 -2
- data/Gemfile.lock +9 -8
- data/Gemfile.on_prem.lock +9 -8
- data/lib/3scale/backend.rb +0 -1
- data/lib/3scale/backend/application.rb +5 -7
- 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/rack/prometheus.rb +9 -1
- data/lib/3scale/backend/storage_async/client.rb +1 -1
- 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
- data/licenses.xml +5 -5
- 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: d679cf1a4c4c0a5aac65b32fdfe2680621b404f07ec3079c2c58ecccd72bf7aa
|
|
4
|
+
data.tar.gz: 03aa0a028f26da2a168cc5c75a8303413cc8a839a21b2b18345ea03087c90dee
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0ea513d0c1ec6728e7a0ee6159645a98854aca8247f01aecfe8c38459efa03fb4a37fe72a822acb894ec8a9d0afea5b5d48cf9f1182864dce63ea7386d8460a9
|
|
7
|
+
data.tar.gz: 5cc2a09921f3c2cf7afc16d673a77fc701cda7377e5ff9a063585d541c5363f29c9593dfb2f5fc100fc4d8e11d17812a6522344df269d5bb0a63d53d67e6d4ea
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
Notable changes to Apisonator will be tracked in this document.
|
|
4
4
|
|
|
5
|
+
## 3.0.1 - 2020-07-14
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- The Prometheus counter of "5xx" errors has been fixed
|
|
10
|
+
([#230](https://github.com/3scale/apisonator/pull/230)).
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Gem updates: rack to v2.1.4
|
|
15
|
+
([#228](https://github.com/3scale/apisonator/pull/228)) and async-redis to
|
|
16
|
+
v0.5.0 ([#229](https://github.com/3scale/apisonator/pull/229)).
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## 3.0.0 - 2020-06-19
|
|
20
|
+
|
|
21
|
+
### Removed
|
|
22
|
+
|
|
23
|
+
- Apisonator no longer supports the native oauth authorization mode. This is a
|
|
24
|
+
feature that was deprecated a long time ago
|
|
25
|
+
([#226](https://github.com/3scale/apisonator/pull/226)).
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## 2.101.1 - 2020-06-05
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Fixed a bug introduced in the previous version that made apisonator return an
|
|
33
|
+
error when authorizing some requests with the `no_body` option enabled
|
|
34
|
+
([#224](https://github.com/3scale/apisonator/pull/224)).
|
|
35
|
+
|
|
36
|
+
|
|
5
37
|
## 2.101.0 - 2020-06-04
|
|
6
38
|
|
|
7
39
|
### Added
|
data/Gemfile.base
CHANGED
|
@@ -53,13 +53,13 @@ gem 'rake', '~> 13.0'
|
|
|
53
53
|
gem 'builder', '= 3.2.3'
|
|
54
54
|
# Use a patched resque to allow reusing their Airbrake Failure class
|
|
55
55
|
gem 'resque', git: 'https://github.com/3scale/resque', branch: '3scale'
|
|
56
|
-
gem 'rack', '~> 2.
|
|
56
|
+
gem 'rack', '~> 2.1.4'
|
|
57
57
|
gem 'sinatra', '~> 2.0.3'
|
|
58
58
|
gem 'sinatra-contrib', '~> 2.0.3'
|
|
59
59
|
# Optional external error logging services
|
|
60
60
|
gem 'bugsnag', '~> 6', require: nil
|
|
61
61
|
gem 'yabeda-prometheus', '~> 0.5.0'
|
|
62
|
-
gem 'async-redis', '~> 0.
|
|
62
|
+
gem 'async-redis', '~> 0.5'
|
|
63
63
|
gem 'falcon', '~> 0.35'
|
|
64
64
|
|
|
65
65
|
# Use a patched redis-rb that fixes an issue when trying to connect with
|
data/Gemfile.lock
CHANGED
|
@@ -35,7 +35,7 @@ GIT
|
|
|
35
35
|
PATH
|
|
36
36
|
remote: .
|
|
37
37
|
specs:
|
|
38
|
-
apisonator (
|
|
38
|
+
apisonator (3.0.1)
|
|
39
39
|
|
|
40
40
|
GEM
|
|
41
41
|
remote: https://rubygems.org/
|
|
@@ -66,14 +66,15 @@ GEM
|
|
|
66
66
|
async-http-cache (0.1.5)
|
|
67
67
|
async-http
|
|
68
68
|
protocol-http (~> 0.14)
|
|
69
|
-
async-io (1.27.
|
|
69
|
+
async-io (1.27.7)
|
|
70
70
|
async (~> 1.14)
|
|
71
71
|
async-pool (0.2.0)
|
|
72
72
|
async (~> 1.8)
|
|
73
|
-
async-redis (0.
|
|
73
|
+
async-redis (0.5.0)
|
|
74
74
|
async (~> 1.8)
|
|
75
75
|
async-io (~> 1.10)
|
|
76
|
-
|
|
76
|
+
async-pool (~> 0.2)
|
|
77
|
+
protocol-redis (~> 0.5.0)
|
|
77
78
|
async-rspec (1.13.0)
|
|
78
79
|
rspec (~> 3.0)
|
|
79
80
|
rspec-files (~> 1.0)
|
|
@@ -161,7 +162,7 @@ GEM
|
|
|
161
162
|
protocol-http2 (0.11.6)
|
|
162
163
|
protocol-hpack (~> 1.4)
|
|
163
164
|
protocol-http (~> 0.15)
|
|
164
|
-
protocol-redis (0.
|
|
165
|
+
protocol-redis (0.5.0)
|
|
165
166
|
pry (0.11.3)
|
|
166
167
|
coderay (~> 1.1.0)
|
|
167
168
|
method_source (~> 0.9.0)
|
|
@@ -171,7 +172,7 @@ GEM
|
|
|
171
172
|
pry-doc (0.11.1)
|
|
172
173
|
pry (~> 0.9)
|
|
173
174
|
yard (~> 0.9)
|
|
174
|
-
rack (2.
|
|
175
|
+
rack (2.1.4)
|
|
175
176
|
rack-protection (2.0.3)
|
|
176
177
|
rack
|
|
177
178
|
rack-test (0.8.2)
|
|
@@ -266,7 +267,7 @@ PLATFORMS
|
|
|
266
267
|
DEPENDENCIES
|
|
267
268
|
airbrake (= 4.3.1)
|
|
268
269
|
apisonator!
|
|
269
|
-
async-redis (~> 0.
|
|
270
|
+
async-redis (~> 0.5)
|
|
270
271
|
async-rspec
|
|
271
272
|
aws-sdk (= 2.4.2)
|
|
272
273
|
benchmark-ips (~> 2.7.2)
|
|
@@ -286,7 +287,7 @@ DEPENDENCIES
|
|
|
286
287
|
pry-byebug (~> 3.5.1)
|
|
287
288
|
pry-doc (~> 0.11.1)
|
|
288
289
|
puma!
|
|
289
|
-
rack (~> 2.
|
|
290
|
+
rack (~> 2.1.4)
|
|
290
291
|
rack-test (~> 0.8.2)
|
|
291
292
|
rake (~> 13.0)
|
|
292
293
|
redis!
|
data/Gemfile.on_prem.lock
CHANGED
|
@@ -35,7 +35,7 @@ GIT
|
|
|
35
35
|
PATH
|
|
36
36
|
remote: .
|
|
37
37
|
specs:
|
|
38
|
-
apisonator (
|
|
38
|
+
apisonator (3.0.1)
|
|
39
39
|
|
|
40
40
|
GEM
|
|
41
41
|
remote: https://rubygems.org/
|
|
@@ -63,14 +63,15 @@ GEM
|
|
|
63
63
|
async-http-cache (0.1.5)
|
|
64
64
|
async-http
|
|
65
65
|
protocol-http (~> 0.14)
|
|
66
|
-
async-io (1.27.
|
|
66
|
+
async-io (1.27.7)
|
|
67
67
|
async (~> 1.14)
|
|
68
68
|
async-pool (0.2.0)
|
|
69
69
|
async (~> 1.8)
|
|
70
|
-
async-redis (0.
|
|
70
|
+
async-redis (0.5.0)
|
|
71
71
|
async (~> 1.8)
|
|
72
72
|
async-io (~> 1.10)
|
|
73
|
-
|
|
73
|
+
async-pool (~> 0.2)
|
|
74
|
+
protocol-redis (~> 0.5.0)
|
|
74
75
|
async-rspec (1.13.0)
|
|
75
76
|
rspec (~> 3.0)
|
|
76
77
|
rspec-files (~> 1.0)
|
|
@@ -149,7 +150,7 @@ GEM
|
|
|
149
150
|
protocol-http2 (0.11.6)
|
|
150
151
|
protocol-hpack (~> 1.4)
|
|
151
152
|
protocol-http (~> 0.15)
|
|
152
|
-
protocol-redis (0.
|
|
153
|
+
protocol-redis (0.5.0)
|
|
153
154
|
pry (0.11.3)
|
|
154
155
|
coderay (~> 1.1.0)
|
|
155
156
|
method_source (~> 0.9.0)
|
|
@@ -159,7 +160,7 @@ GEM
|
|
|
159
160
|
pry-doc (0.11.1)
|
|
160
161
|
pry (~> 0.9)
|
|
161
162
|
yard (~> 0.9)
|
|
162
|
-
rack (2.
|
|
163
|
+
rack (2.1.4)
|
|
163
164
|
rack-protection (2.0.3)
|
|
164
165
|
rack
|
|
165
166
|
rack-test (0.8.2)
|
|
@@ -249,7 +250,7 @@ PLATFORMS
|
|
|
249
250
|
|
|
250
251
|
DEPENDENCIES
|
|
251
252
|
apisonator!
|
|
252
|
-
async-redis (~> 0.
|
|
253
|
+
async-redis (~> 0.5)
|
|
253
254
|
async-rspec
|
|
254
255
|
benchmark-ips (~> 2.7.2)
|
|
255
256
|
bugsnag (~> 6)
|
|
@@ -267,7 +268,7 @@ DEPENDENCIES
|
|
|
267
268
|
pry-byebug (~> 3.5.1)
|
|
268
269
|
pry-doc (~> 0.11.1)
|
|
269
270
|
puma!
|
|
270
|
-
rack (~> 2.
|
|
271
|
+
rack (~> 2.1.4)
|
|
271
272
|
rack-test (~> 0.8.2)
|
|
272
273
|
rake (~> 13.0)
|
|
273
274
|
redis!
|
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
|
|
@@ -230,11 +227,12 @@ module ThreeScale
|
|
|
230
227
|
# Loads the usage limits affected by the metrics received, that is, the
|
|
231
228
|
# limits that are defined for those metrics plus all their ancestors in
|
|
232
229
|
# the metrics hierarchy.
|
|
230
|
+
# Raises MetricInvalid when a metric does not exist.
|
|
233
231
|
def load_usage_limits_affected_by(metric_names)
|
|
234
232
|
metric_ids = metric_names.flat_map do |name|
|
|
235
233
|
[name] + Metric.ascendants(service_id, name)
|
|
236
234
|
end.uniq.map do |name|
|
|
237
|
-
Metric.load_id(service_id, name)
|
|
235
|
+
Metric.load_id(service_id, name) || raise(MetricInvalid.new(name))
|
|
238
236
|
end
|
|
239
237
|
|
|
240
238
|
# IDs are sorted to be able to use the memoizer
|
|
@@ -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)
|
|
@@ -8,7 +8,15 @@ module ThreeScale
|
|
|
8
8
|
|
|
9
9
|
def call(env)
|
|
10
10
|
began_at = Time.now.getutc
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
begin
|
|
13
|
+
status, header, body = @app.call(env)
|
|
14
|
+
rescue Exception => e
|
|
15
|
+
ListenerMetrics.report_resp_code(env['REQUEST_PATH'], 500)
|
|
16
|
+
ListenerMetrics.report_response_time(env['REQUEST_PATH'], Time.now - began_at)
|
|
17
|
+
raise e
|
|
18
|
+
end
|
|
19
|
+
|
|
12
20
|
ListenerMetrics.report_resp_code(env['REQUEST_PATH'], status)
|
|
13
21
|
ListenerMetrics.report_response_time(env['REQUEST_PATH'], Time.now - began_at)
|
|
14
22
|
[status, header, body]
|
|
@@ -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
|
|
data/licenses.xml
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
</dependency>
|
|
24
24
|
<dependency>
|
|
25
25
|
<packageName>apisonator</packageName>
|
|
26
|
-
<version>
|
|
26
|
+
<version>3.0.1</version>
|
|
27
27
|
<licenses>
|
|
28
28
|
<license>
|
|
29
29
|
<name>Apache 2.0</name>
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
</dependency>
|
|
74
74
|
<dependency>
|
|
75
75
|
<packageName>async-io</packageName>
|
|
76
|
-
<version>1.27.
|
|
76
|
+
<version>1.27.7</version>
|
|
77
77
|
<licenses>
|
|
78
78
|
<license>
|
|
79
79
|
<name>MIT</name>
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
</dependency>
|
|
94
94
|
<dependency>
|
|
95
95
|
<packageName>async-redis</packageName>
|
|
96
|
-
<version>0.
|
|
96
|
+
<version>0.5.0</version>
|
|
97
97
|
<licenses>
|
|
98
98
|
<license>
|
|
99
99
|
<name>MIT</name>
|
|
@@ -669,7 +669,7 @@
|
|
|
669
669
|
</dependency>
|
|
670
670
|
<dependency>
|
|
671
671
|
<packageName>protocol-redis</packageName>
|
|
672
|
-
<version>0.
|
|
672
|
+
<version>0.5.0</version>
|
|
673
673
|
<licenses>
|
|
674
674
|
<license>
|
|
675
675
|
<name>MIT</name>
|
|
@@ -719,7 +719,7 @@
|
|
|
719
719
|
</dependency>
|
|
720
720
|
<dependency>
|
|
721
721
|
<packageName>rack</packageName>
|
|
722
|
-
<version>2.
|
|
722
|
+
<version>2.1.4</version>
|
|
723
723
|
<licenses>
|
|
724
724
|
<license>
|
|
725
725
|
<name>MIT</name>
|
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.1
|
|
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-
|
|
19
|
+
date: 2020-07-14 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
|