authlete 0.1.6 → 0.1.7

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,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 77582cfeb5b4bb0276c0e3040a61cdf7c5515fa6
4
- data.tar.gz: 6229901177d39f4ff62348231699d99a0bc534b5
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MTFhYmMxZjUyM2ExYjdkOGI5MzY1NDAyMDA5YjE4NGNlMGQ2M2U0ZA==
5
+ data.tar.gz: !binary |-
6
+ NDM4YzkzMGM1ZWIzYjNhMTEwZjc5MTQ5MzhhZGY5YzFkOGQ1MDdmZg==
5
7
  SHA512:
6
- metadata.gz: 20dd499cd219ce97c08c48c5c186deb39a04b9b23e036abf3117f14bc5779008851593764e8e5a0c3abeba39065d5d8a8ba51013d6b8e5d9139d85b81e875b5e
7
- data.tar.gz: e57907b65b09a2e213a6bc8fff05b9f59d208e8649aeded4640f3b9b23c9ac7a744a4dd7005da47b83fabc590329e672a2f4289c9a4027112df762c00cd11ba4
8
+ metadata.gz: !binary |-
9
+ ZmIzMWQxNTNhNmVlYTI4ZGEzYjBjZWQ2YTkyMTliMzA4YjA5ZjlkODg2ZWQ3
10
+ MTBmMzkyMzJiNTM2ZmZkNzJhOGE3ZWNhY2RhZWQzM2QzNTMzYTE5NjAwODg1
11
+ OGIyMzZjYmE2ZjViYzZiMzkzNzI3YWQzOTA2MmZjZDgxY2I4ZDA=
12
+ data.tar.gz: !binary |-
13
+ ODAwZTk1OWMwZjBjNGJiZGZjMWFmNDhmMGVjZGRjYmRiNjcwODY3YjYxNjk1
14
+ NmNmMmQ4ZmRjOTA1ZDNiNmU3NjcxODM5YzFkMjM0MGFmMjUzYTc2MjM3OWI0
15
+ ZjM0ODk5MzMyYTJhNDM2ZDNjNjVjYWVkODdkMDRiYTViNzIzMjU=
@@ -1,460 +1,460 @@
1
- # :nodoc:
2
- #
3
- # Copyright (C) 2014-2015 Authlete, Inc.
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
-
17
-
18
- require 'json'
19
- require 'rack'
20
- require 'rest-client'
21
-
22
-
23
- module Authlete
24
- # == Authlete::Api Module
25
- #
26
- # A web client that accesses Authlete Web APIs.
27
- #
28
- class Api
29
- include Authlete::Utility
30
-
31
- # The host which provides Authlete Web APIs.
32
- # For example, <tt>https://evaluation-dot-authlete.appspot.com</tt>
33
- attr_accessor :host
34
-
35
- # The API key of a service owner.
36
- attr_accessor :service_owner_api_key
37
-
38
- # The API secret of a service owner.
39
- attr_accessor :service_owner_api_secret
40
-
41
- # The API key of a service.
42
- attr_accessor :service_api_key
43
-
44
- # The API secret of a service.
45
- attr_accessor :service_api_secret
46
-
47
- # Extra HTTP headers
48
- attr_accessor :extra_headers
49
-
50
- private
51
-
52
- # The constructor which takes a hash containing configuration
53
- # parameters. Valid configuration parameter names are as follows.
54
- #
55
- # - <tt>:host</tt>
56
- # - <tt>:service_owner_api_key</tt>
57
- # - <tt>:service_owner_api_secret</tt>
58
- # - <tt>:service_api_key</tt>
59
- # - <tt>:service_api_secret</tt>
60
- #
61
- def initialize(config = {})
62
- @host = extract_value(config, :host)
63
- @service_owner_api_key = extract_value(config, :service_owner_api_key)
64
- @service_owner_api_secret = extract_value(config, :service_owner_api_secret)
65
- @service_api_key = extract_value(config, :service_api_key)
66
- @service_api_secret = extract_value(config, :service_api_secret)
67
- end
68
-
69
- def call_api(method, path, content_type, payload, user, password)
70
- headers = {}
71
-
72
- if content_type.nil? == false
73
- headers.merge!(:content_type => content_type)
74
- end
75
-
76
- if @extra_headers.nil? == false
77
- headers.merge!(@extra_headers)
78
- end
79
-
80
- response = execute(
81
- :method => method,
82
- :url => @host + path,
83
- :headers => headers,
84
- :payload => payload,
85
- :user => user,
86
- :password => password
87
- )
88
-
89
- body = body_as_string(response)
90
-
91
- if body.nil?
92
- return nil
93
- end
94
-
95
- JSON.parse(response.body.to_s, :symbolize_names => true)
96
- end
97
-
98
- def execute(parameters)
99
- begin
100
- return RestClient::Request.new(parameters).execute
101
- rescue => e
102
- raise_api_exception(e)
103
- end
104
- end
105
-
106
- def raise_api_exception(exception)
107
- message = exception.message
108
- response = exception.response
109
-
110
- if response.nil?
111
- # Raise an error without HTTP response information.
112
- raise Authlete::Exception.new(:message => message)
113
- end
114
-
115
- # Raise an error with HTTP response information.
116
- raise_api_exception_with_http_response_info(message, response.code, response.body)
117
- end
118
-
119
- def raise_api_exception_with_http_response_info(message, status_code, response_body)
120
- # Parse the response body as a json.
121
- json = parse_response_body(response_body, message, status_code)
122
-
123
- # If the json has the HTTP response information from an Authlete API.
124
- if has_authlete_api_response_info(json)
125
- # Raise an error with it.
126
- hash = json.merge!(:statusCode => status_code)
127
- raise Authlete::Exception.new(hash)
128
- end
129
-
130
- # Raise an error with 'status_code' and the original error message.
131
- raise Authlete::Exception.new(
132
- :message => message,
133
- :status_code => status_code
134
- )
135
- end
136
-
137
- def parse_response_body(response_body, message, status_code)
138
- begin
139
- return JSON.parse(response_body.to_s, :symbolize_names => true)
140
- rescue
141
- # Failed to parse the response body as a json.
142
- raise Authlete::Exception.new(
143
- :message => message,
144
- :status_code => status_code
145
- )
146
- end
147
- end
148
-
149
- def has_authlete_api_response_info(json)
150
- json && json.key?(:resultCode) && json.key?(:resultMessage)
151
- end
152
-
153
- def body_as_string(response)
154
- if response.body.nil?
155
- return nil
156
- end
157
-
158
- body = response.body.to_s
159
-
160
- if body.length == 0
161
- return nil
162
- end
163
-
164
- return body
165
- end
166
-
167
- def call_api_service_owner(method, path, content_type, payload)
168
- call_api(method, path, content_type, payload, @service_owner_api_key, @service_owner_api_secret)
169
- end
170
-
171
- def call_api_service(method, path, content_type, payload)
172
- call_api(method, path, content_type, payload, @service_api_key, @service_api_secret)
173
- end
174
-
175
- def call_api_json(path, body, user, password)
176
- call_api(:post, path, 'application/json;charset=UTF-8', JSON.generate(body), user, password)
177
- end
178
-
179
- def call_api_json_service_owner(path, body)
180
- call_api_json(path, body, @service_owner_api_key, @service_owner_api_secret)
181
- end
182
-
183
- def call_api_json_service(path, body)
184
- call_api_json(path, body, @service_api_key, @service_api_secret)
185
- end
186
-
187
- def build_error_message(path, exception)
188
- begin
189
- # Use "resultMessage" if the response can be parsed as JSON.
190
- JSON.parse(exception.response.to_str)['resultMessage']
191
- rescue
192
- # Build a generic error message.
193
- "Authlete's #{path} API failed."
194
- end
195
- end
196
-
197
- def emit_rack_error_message(request, message)
198
- begin
199
- # Logging if possible.
200
- request.env['rack.errors'].write("ERROR: #{message}\n")
201
- rescue => e
202
- end
203
- end
204
-
205
- def to_query(params)
206
- if params.nil? || params.size == 0
207
- return ""
208
- end
209
-
210
- array = []
211
-
212
- params.each do |key, value|
213
- array.push("#{key}=#{value}")
214
- end
215
-
216
- return "?" + array.join("&")
217
- end
218
-
219
- public
220
-
221
- # Call Authlete's /api/service/create API.
222
- #
223
- # <tt>service</tt> is the content of a new service to create. The type of
224
- # the given object is either <tt>Hash</tt> or any object which
225
- # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Service
226
- # (which responds to <tt>to_hash</tt>) should be used.
227
- #
228
- # On success, an instance of Authlete::Model::ServiceList is returned.
229
- # On error, RestClient::Exception (of rest-client GEM) is raised.
230
- def service_create(service)
231
- if service.kind_of?(Hash) == false
232
- if service.respond_to?('to_hash')
233
- service = service.to_hash
234
- end
235
- end
236
-
237
- hash = call_api_json_service_owner("/api/service/create", service)
238
-
239
- Authlete::Model::Service.new(hash)
240
- end
241
-
242
- # Call Authlete's /api/service/delete/{api_key} API.
243
- #
244
- # On error, RestClient::Exception (of rest-client GEM) is raised.
245
- def service_delete(api_key)
246
- call_api_service_owner(:delete, "/api/service/delete/#{api_key}", nil, nil)
247
- end
248
-
249
-
250
- # Call Authlete's /api/service/get/{api_key} API.
251
- #
252
- # <tt>api_key</tt> is the API key of the service whose information
253
- # you want to get.
254
- #
255
- # On success, an instance of Authlete::Model::Service is returned.
256
- # On error, RestClient::Exception (of rest-client GEM) is raised.
257
- def service_get(api_key)
258
- hash = call_api_service_owner(:get, "/api/service/get/#{api_key}", nil, nil)
259
-
260
- Authlete::Model::Service.new(hash)
261
- end
262
-
263
- # Call Authlete's /api/service/get/list API.
264
- #
265
- # <tt>params</tt> is an optional hash which contains query parameters
266
- # for /api/service/get/list API. <tt>:start</tt> and <tt>:end</tt> are
267
- # a start index (inclusive) and an end index (exclusive), respectively.
268
- #
269
- # On success, an instance of Authlete::Model::ServiceList is returned.
270
- # On error, RestClient::Exception (of rest-client GEM) is raised.
271
- def service_get_list(params = nil)
272
- hash = call_api_service_owner(:get, "/api/service/get/list#{to_query(params)}", nil, nil)
273
-
274
- Authlete::Model::ServiceList.new(hash)
275
- end
276
-
277
-
278
- # Call Authlete's /api/service/update/{api_key} API.
279
- #
280
- # <tt>api_key</tt> is the API key of the service whose information
281
- # you want to get.
282
- #
283
- # <tt>service</tt> is the new content of the service. The type of
284
- # the given object is either <tt>Hash</tt> or any object which
285
- # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Service
286
- # (which responds to <tt>to_hash</tt>) should be used.
287
- #
288
- # On success, an instance of Authlete::Model::Service is returned.
289
- # On error, RestClient::Exception (of rest-client GEM) is raised.
290
- def service_update(api_key, service)
291
- if service.kind_of?(Hash) == false
292
- if service.respond_to?('to_hash')
293
- service = service.to_hash
294
- end
295
- end
296
-
297
- hash = call_api_json_service_owner("/api/service/update/#{api_key}", service)
298
-
299
- Authlete::Model::Service.new(hash)
300
- end
301
-
302
- # Call Authlete's /api/client/create API.
303
- #
304
- # <tt>client</tt> is the content of a new service to create. The type of
305
- # the given object is either <tt>Hash</tt> or any object which
306
- # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Client
307
- # (which responds to <tt>to_hash</tt>) should be used.
308
- #
309
- # On success, an instance of Authlete::Model::ClientList is returned.
310
- # On error, RestClient::Exception (of rest-client GEM) is raised.
311
- def client_create(client)
312
- if client.kind_of?(Hash) == false
313
- if client.respond_to?('to_hash')
314
- client = client.to_hash
315
- end
316
- end
317
-
318
- hash = call_api_json_service("/api/client/create", client)
319
-
320
- Authlete::Model::Client.new(hash)
321
- end
322
-
323
- # Call Authlete's /api/client/delete/{clientId} API.
324
- #
325
- # On error, RestClient::Exception (of rest-client GEM) is raised.
326
- def client_delete(clientId)
327
- call_api_service(:delete, "/api/client/delete/#{clientId}", nil, nil)
328
- end
329
-
330
- # Call Authlete's /api/client/get/{clientId} API.
331
- #
332
- # On success, an instance of Authlete::Model::Service is returned.
333
- # On error, RestClient::Exception (of rest-client GEM) is raised.
334
- def client_get(clientId)
335
- hash = call_api_service(:get, "/api/client/get/#{clientId}", nil, nil)
336
-
337
- Authlete::Model::Client.new(hash)
338
- end
339
-
340
- # Call Authlete's /api/client/get/list API.
341
- #
342
- # <tt>params</tt> is an optional hash which contains query parameters
343
- # for /api/client/get/list API. <tt>:start</tt> and <tt>:end</tt> are
344
- # a start index (inclusive) and an end index (exclusive), respectively.
345
- #
346
- # On success, an instance of Authlete::Model::ClientList is returned.
347
- # On error, RestClient::Exception (of rest-client GEM) is raised.
348
- def client_get_list(params = nil)
349
- hash = call_api_service(:get, "/api/client/get/list#{to_query(params)}", nil, nil)
350
-
351
- Authlete::Model::ClientList.new(hash)
352
- end
353
-
354
- # Call Authlete's /api/client/update/{clientId} API.
355
- #
356
- # <tt>client</tt> is the new content of the client. The type of
357
- # the given object is either <tt>Hash</tt> or any object which
358
- # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Client
359
- # (which responds to <tt>to_hash</tt>) should be used.
360
- #
361
- # On success, an instance of Authlete::Model::Client is returned.
362
- # On error, RestClient::Exception (of rest-client GEM) is raised.
363
- def client_update(client)
364
- if client.kind_of?(Hash) == false
365
- if client.respond_to?('to_hash')
366
- client = client.to_hash
367
- end
368
- end
369
-
370
- hash = call_api_json_service("/api/client/update/#{client[:clientId]}", client)
371
-
372
- Authlete::Model::Client.new(hash)
373
- end
374
-
375
- # Call Authlete's {/auth/introspection}
376
- # [https://www.authlete.com/authlete_web_apis_introspection.html#auth_introspection]
377
- # API.
378
- #
379
- # <tt>token</tt> is an access token presented by a client application.
380
- # This is a must parameter. In a typical case, a client application uses
381
- # one of the means listed in {RFC 6750}[https://tools.ietf.org/html/rfc6750]
382
- # to present an access token to a {protected resource endpoint}
383
- # [https://tools.ietf.org/html/rfc6749#section-7].
384
- #
385
- # <tt>scopes</tt> is an array of scope names. This is an optional parameter.
386
- # When the specified scopes are not covered by the access token, Authlete
387
- # prepares the content of the error response.
388
- #
389
- # <tt>subject</tt> is a unique identifier of an end-user. This is an optional
390
- # parameter. When the access token is not associated with the specified
391
- # subject, Authlete prepares the content of the error response.
392
- #
393
- # On success, this method returns an instance of
394
- # <tt>Authlete::Response::IntrospectionResponse</tt>. On error, this method
395
- # throws <tt>RestClient::Exception</tt>.
396
- def introspection(token, scopes = nil, subject = nil)
397
- hash = call_api_json_service('/api/auth/introspection',
398
- :token => token, :scopes => scopes, :subject => subject)
399
-
400
- Authlete::Response::IntrospectionResponse.new(hash)
401
- end
402
-
403
-
404
- # Ensure that the request contains a valid access token.
405
- #
406
- # This method extracts an access token from the given request based on the
407
- # rules described in RFC 6750 and introspects the access token by calling
408
- # Authlete's /auth/introspection API.
409
- #
410
- # The first argument <tt>request</tt> is a Rack request.
411
- #
412
- # The second argument <tt>scopes</tt> is an array of scope names required
413
- # to access the target protected resource. This argument is optional.
414
- #
415
- # The third argument <tt>subject</tt> is a string which representing a
416
- # subject which has to be associated with the access token. This argument
417
- # is optional.
418
- #
419
- # This method returns an instance of
420
- # <tt>Authlete::Response::IntrospectionResponse</tt>. If its <tt>action</tt>
421
- # method returns 'OK', it means that the access token exists, has not
422
- # expired, covers the requested scopes (if specified), and is associated
423
- # with the requested subject (if specified). Otherwise, it means that the
424
- # request does not contain any access token or that the access token does
425
- # not satisfy the conditions to access the target protected resource.
426
- def protect_resource(request, scopes = nil, subject = nil)
427
- # Extract an access token from the request.
428
- access_token = extract_access_token(request)
429
-
430
- # If the request does not contain any access token.
431
- if access_token.nil?
432
- # The request does not contain a valid access token.
433
- return Authlete::Response::IntrospectionResponse.new(
434
- :action => 'BAD_REQUEST',
435
- :responseContent => 'Bearer error="invalid_token",error_description="The request does not contain a valid access token."'
436
- )
437
- end
438
-
439
- begin
440
- # Call Authlete's /auth/introspection API to introspect the access token.
441
- result = introspection(access_token, scopes, subject)
442
- rescue => e
443
- # Error message.
444
- message = build_error_message('/auth/introspection', e)
445
-
446
- # Emit a Rack error message.
447
- emit_rack_error_message(request, message)
448
-
449
- # Failed to introspect the access token.
450
- return Authlete::Response::IntrospectionResponse.new(
451
- :action => 'INTERNAL_SERVER_ERROR',
452
- :responseContent => "Bearer error=\"server_error\",error_description=\"#{message}\""
453
- )
454
- end
455
-
456
- # Return the response from Authlete's /auth/introspection API.
457
- result
458
- end
459
- end
460
- end
1
+ # :nodoc:
2
+ #
3
+ # Copyright (C) 2014-2015 Authlete, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+
18
+ require 'json'
19
+ require 'rack'
20
+ require 'rest-client'
21
+
22
+
23
+ module Authlete
24
+ # == Authlete::Api Module
25
+ #
26
+ # A web client that accesses Authlete Web APIs.
27
+ #
28
+ class Api
29
+ include Authlete::Utility
30
+
31
+ # The host which provides Authlete Web APIs.
32
+ # For example, <tt>https://evaluation-dot-authlete.appspot.com</tt>
33
+ attr_accessor :host
34
+
35
+ # The API key of a service owner.
36
+ attr_accessor :service_owner_api_key
37
+
38
+ # The API secret of a service owner.
39
+ attr_accessor :service_owner_api_secret
40
+
41
+ # The API key of a service.
42
+ attr_accessor :service_api_key
43
+
44
+ # The API secret of a service.
45
+ attr_accessor :service_api_secret
46
+
47
+ # Extra HTTP headers
48
+ attr_accessor :extra_headers
49
+
50
+ private
51
+
52
+ # The constructor which takes a hash containing configuration
53
+ # parameters. Valid configuration parameter names are as follows.
54
+ #
55
+ # - <tt>:host</tt>
56
+ # - <tt>:service_owner_api_key</tt>
57
+ # - <tt>:service_owner_api_secret</tt>
58
+ # - <tt>:service_api_key</tt>
59
+ # - <tt>:service_api_secret</tt>
60
+ #
61
+ def initialize(config = {})
62
+ @host = extract_value(config, :host)
63
+ @service_owner_api_key = extract_value(config, :service_owner_api_key)
64
+ @service_owner_api_secret = extract_value(config, :service_owner_api_secret)
65
+ @service_api_key = extract_value(config, :service_api_key)
66
+ @service_api_secret = extract_value(config, :service_api_secret)
67
+ end
68
+
69
+ def call_api(method, path, content_type, payload, user, password)
70
+ headers = {}
71
+
72
+ if content_type.nil? == false
73
+ headers.merge!(:content_type => content_type)
74
+ end
75
+
76
+ if @extra_headers.nil? == false
77
+ headers.merge!(@extra_headers)
78
+ end
79
+
80
+ response = execute(
81
+ :method => method,
82
+ :url => @host + path,
83
+ :headers => headers,
84
+ :payload => payload,
85
+ :user => user,
86
+ :password => password
87
+ )
88
+
89
+ body = body_as_string(response)
90
+
91
+ if body.nil?
92
+ return nil
93
+ end
94
+
95
+ JSON.parse(response.body.to_s, :symbolize_names => true)
96
+ end
97
+
98
+ def execute(parameters)
99
+ begin
100
+ return RestClient::Request.new(parameters).execute
101
+ rescue => e
102
+ raise_api_exception(e)
103
+ end
104
+ end
105
+
106
+ def raise_api_exception(exception)
107
+ message = exception.message
108
+ response = exception.response
109
+
110
+ if response.nil?
111
+ # Raise an error without HTTP response information.
112
+ raise Authlete::Exception.new(:message => message)
113
+ end
114
+
115
+ # Raise an error with HTTP response information.
116
+ raise_api_exception_with_http_response_info(message, response.code, response.body)
117
+ end
118
+
119
+ def raise_api_exception_with_http_response_info(message, status_code, response_body)
120
+ # Parse the response body as a json.
121
+ json = parse_response_body(response_body, message, status_code)
122
+
123
+ # If the json has the HTTP response information from an Authlete API.
124
+ if has_authlete_api_response_info(json)
125
+ # Raise an error with it.
126
+ hash = json.merge!(:statusCode => status_code)
127
+ raise Authlete::Exception.new(hash)
128
+ end
129
+
130
+ # Raise an error with 'status_code' and the original error message.
131
+ raise Authlete::Exception.new(
132
+ :message => message,
133
+ :status_code => status_code
134
+ )
135
+ end
136
+
137
+ def parse_response_body(response_body, message, status_code)
138
+ begin
139
+ return JSON.parse(response_body.to_s, :symbolize_names => true)
140
+ rescue
141
+ # Failed to parse the response body as a json.
142
+ raise Authlete::Exception.new(
143
+ :message => message,
144
+ :status_code => status_code
145
+ )
146
+ end
147
+ end
148
+
149
+ def has_authlete_api_response_info(json)
150
+ json && json.key?(:resultCode) && json.key?(:resultMessage)
151
+ end
152
+
153
+ def body_as_string(response)
154
+ if response.body.nil?
155
+ return nil
156
+ end
157
+
158
+ body = response.body.to_s
159
+
160
+ if body.length == 0
161
+ return nil
162
+ end
163
+
164
+ return body
165
+ end
166
+
167
+ def call_api_service_owner(method, path, content_type, payload)
168
+ call_api(method, path, content_type, payload, @service_owner_api_key, @service_owner_api_secret)
169
+ end
170
+
171
+ def call_api_service(method, path, content_type, payload)
172
+ call_api(method, path, content_type, payload, @service_api_key, @service_api_secret)
173
+ end
174
+
175
+ def call_api_json(path, body, user, password)
176
+ call_api(:post, path, 'application/json;charset=UTF-8', JSON.generate(body), user, password)
177
+ end
178
+
179
+ def call_api_json_service_owner(path, body)
180
+ call_api_json(path, body, @service_owner_api_key, @service_owner_api_secret)
181
+ end
182
+
183
+ def call_api_json_service(path, body)
184
+ call_api_json(path, body, @service_api_key, @service_api_secret)
185
+ end
186
+
187
+ def build_error_message(path, exception)
188
+ begin
189
+ # Use "resultMessage" if the response can be parsed as JSON.
190
+ JSON.parse(exception.response.to_str)['resultMessage']
191
+ rescue
192
+ # Build a generic error message.
193
+ "Authlete's #{path} API failed."
194
+ end
195
+ end
196
+
197
+ def emit_rack_error_message(request, message)
198
+ begin
199
+ # Logging if possible.
200
+ request.env['rack.errors'].write("ERROR: #{message}\n")
201
+ rescue => e
202
+ end
203
+ end
204
+
205
+ def to_query(params)
206
+ if params.nil? || params.size == 0
207
+ return ""
208
+ end
209
+
210
+ array = []
211
+
212
+ params.each do |key, value|
213
+ array.push("#{key}=#{value}")
214
+ end
215
+
216
+ return "?" + array.join("&")
217
+ end
218
+
219
+ public
220
+
221
+ # Call Authlete's /api/service/create API.
222
+ #
223
+ # <tt>service</tt> is the content of a new service to create. The type of
224
+ # the given object is either <tt>Hash</tt> or any object which
225
+ # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Service
226
+ # (which responds to <tt>to_hash</tt>) should be used.
227
+ #
228
+ # On success, an instance of Authlete::Model::ServiceList is returned.
229
+ # On error, RestClient::Exception (of rest-client GEM) is raised.
230
+ def service_create(service)
231
+ if service.kind_of?(Hash) == false
232
+ if service.respond_to?('to_hash')
233
+ service = service.to_hash
234
+ end
235
+ end
236
+
237
+ hash = call_api_json_service_owner("/api/service/create", service)
238
+
239
+ Authlete::Model::Service.new(hash)
240
+ end
241
+
242
+ # Call Authlete's /api/service/delete/{api_key} API.
243
+ #
244
+ # On error, RestClient::Exception (of rest-client GEM) is raised.
245
+ def service_delete(api_key)
246
+ call_api_service_owner(:delete, "/api/service/delete/#{api_key}", nil, nil)
247
+ end
248
+
249
+
250
+ # Call Authlete's /api/service/get/{api_key} API.
251
+ #
252
+ # <tt>api_key</tt> is the API key of the service whose information
253
+ # you want to get.
254
+ #
255
+ # On success, an instance of Authlete::Model::Service is returned.
256
+ # On error, RestClient::Exception (of rest-client GEM) is raised.
257
+ def service_get(api_key)
258
+ hash = call_api_service_owner(:get, "/api/service/get/#{api_key}", nil, nil)
259
+
260
+ Authlete::Model::Service.new(hash)
261
+ end
262
+
263
+ # Call Authlete's /api/service/get/list API.
264
+ #
265
+ # <tt>params</tt> is an optional hash which contains query parameters
266
+ # for /api/service/get/list API. <tt>:start</tt> and <tt>:end</tt> are
267
+ # a start index (inclusive) and an end index (exclusive), respectively.
268
+ #
269
+ # On success, an instance of Authlete::Model::ServiceList is returned.
270
+ # On error, RestClient::Exception (of rest-client GEM) is raised.
271
+ def service_get_list(params = nil)
272
+ hash = call_api_service_owner(:get, "/api/service/get/list#{to_query(params)}", nil, nil)
273
+
274
+ Authlete::Model::ServiceList.new(hash)
275
+ end
276
+
277
+
278
+ # Call Authlete's /api/service/update/{api_key} API.
279
+ #
280
+ # <tt>api_key</tt> is the API key of the service whose information
281
+ # you want to get.
282
+ #
283
+ # <tt>service</tt> is the new content of the service. The type of
284
+ # the given object is either <tt>Hash</tt> or any object which
285
+ # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Service
286
+ # (which responds to <tt>to_hash</tt>) should be used.
287
+ #
288
+ # On success, an instance of Authlete::Model::Service is returned.
289
+ # On error, RestClient::Exception (of rest-client GEM) is raised.
290
+ def service_update(api_key, service)
291
+ if service.kind_of?(Hash) == false
292
+ if service.respond_to?('to_hash')
293
+ service = service.to_hash
294
+ end
295
+ end
296
+
297
+ hash = call_api_json_service_owner("/api/service/update/#{api_key}", service)
298
+
299
+ Authlete::Model::Service.new(hash)
300
+ end
301
+
302
+ # Call Authlete's /api/client/create API.
303
+ #
304
+ # <tt>client</tt> is the content of a new service to create. The type of
305
+ # the given object is either <tt>Hash</tt> or any object which
306
+ # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Client
307
+ # (which responds to <tt>to_hash</tt>) should be used.
308
+ #
309
+ # On success, an instance of Authlete::Model::ClientList is returned.
310
+ # On error, RestClient::Exception (of rest-client GEM) is raised.
311
+ def client_create(client)
312
+ if client.kind_of?(Hash) == false
313
+ if client.respond_to?('to_hash')
314
+ client = client.to_hash
315
+ end
316
+ end
317
+
318
+ hash = call_api_json_service("/api/client/create", client)
319
+
320
+ Authlete::Model::Client.new(hash)
321
+ end
322
+
323
+ # Call Authlete's /api/client/delete/{clientId} API.
324
+ #
325
+ # On error, RestClient::Exception (of rest-client GEM) is raised.
326
+ def client_delete(clientId)
327
+ call_api_service(:delete, "/api/client/delete/#{clientId}", nil, nil)
328
+ end
329
+
330
+ # Call Authlete's /api/client/get/{clientId} API.
331
+ #
332
+ # On success, an instance of Authlete::Model::Service is returned.
333
+ # On error, RestClient::Exception (of rest-client GEM) is raised.
334
+ def client_get(clientId)
335
+ hash = call_api_service(:get, "/api/client/get/#{clientId}", nil, nil)
336
+
337
+ Authlete::Model::Client.new(hash)
338
+ end
339
+
340
+ # Call Authlete's /api/client/get/list API.
341
+ #
342
+ # <tt>params</tt> is an optional hash which contains query parameters
343
+ # for /api/client/get/list API. <tt>:start</tt> and <tt>:end</tt> are
344
+ # a start index (inclusive) and an end index (exclusive), respectively.
345
+ #
346
+ # On success, an instance of Authlete::Model::ClientList is returned.
347
+ # On error, RestClient::Exception (of rest-client GEM) is raised.
348
+ def client_get_list(params = nil)
349
+ hash = call_api_service(:get, "/api/client/get/list#{to_query(params)}", nil, nil)
350
+
351
+ Authlete::Model::ClientList.new(hash)
352
+ end
353
+
354
+ # Call Authlete's /api/client/update/{clientId} API.
355
+ #
356
+ # <tt>client</tt> is the new content of the client. The type of
357
+ # the given object is either <tt>Hash</tt> or any object which
358
+ # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Client
359
+ # (which responds to <tt>to_hash</tt>) should be used.
360
+ #
361
+ # On success, an instance of Authlete::Model::Client is returned.
362
+ # On error, RestClient::Exception (of rest-client GEM) is raised.
363
+ def client_update(client)
364
+ if client.kind_of?(Hash) == false
365
+ if client.respond_to?('to_hash')
366
+ client = client.to_hash
367
+ end
368
+ end
369
+
370
+ hash = call_api_json_service("/api/client/update/#{client[:clientId]}", client)
371
+
372
+ Authlete::Model::Client.new(hash)
373
+ end
374
+
375
+ # Call Authlete's {/auth/introspection}
376
+ # [https://www.authlete.com/authlete_web_apis_introspection.html#auth_introspection]
377
+ # API.
378
+ #
379
+ # <tt>token</tt> is an access token presented by a client application.
380
+ # This is a must parameter. In a typical case, a client application uses
381
+ # one of the means listed in {RFC 6750}[https://tools.ietf.org/html/rfc6750]
382
+ # to present an access token to a {protected resource endpoint}
383
+ # [https://tools.ietf.org/html/rfc6749#section-7].
384
+ #
385
+ # <tt>scopes</tt> is an array of scope names. This is an optional parameter.
386
+ # When the specified scopes are not covered by the access token, Authlete
387
+ # prepares the content of the error response.
388
+ #
389
+ # <tt>subject</tt> is a unique identifier of an end-user. This is an optional
390
+ # parameter. When the access token is not associated with the specified
391
+ # subject, Authlete prepares the content of the error response.
392
+ #
393
+ # On success, this method returns an instance of
394
+ # <tt>Authlete::Response::IntrospectionResponse</tt>. On error, this method
395
+ # throws <tt>RestClient::Exception</tt>.
396
+ def introspection(token, scopes = nil, subject = nil)
397
+ hash = call_api_json_service('/api/auth/introspection',
398
+ :token => token, :scopes => scopes, :subject => subject)
399
+
400
+ Authlete::Response::IntrospectionResponse.new(hash)
401
+ end
402
+
403
+
404
+ # Ensure that the request contains a valid access token.
405
+ #
406
+ # This method extracts an access token from the given request based on the
407
+ # rules described in RFC 6750 and introspects the access token by calling
408
+ # Authlete's /auth/introspection API.
409
+ #
410
+ # The first argument <tt>request</tt> is a Rack request.
411
+ #
412
+ # The second argument <tt>scopes</tt> is an array of scope names required
413
+ # to access the target protected resource. This argument is optional.
414
+ #
415
+ # The third argument <tt>subject</tt> is a string which representing a
416
+ # subject which has to be associated with the access token. This argument
417
+ # is optional.
418
+ #
419
+ # This method returns an instance of
420
+ # <tt>Authlete::Response::IntrospectionResponse</tt>. If its <tt>action</tt>
421
+ # method returns 'OK', it means that the access token exists, has not
422
+ # expired, covers the requested scopes (if specified), and is associated
423
+ # with the requested subject (if specified). Otherwise, it means that the
424
+ # request does not contain any access token or that the access token does
425
+ # not satisfy the conditions to access the target protected resource.
426
+ def protect_resource(request, scopes = nil, subject = nil)
427
+ # Extract an access token from the request.
428
+ access_token = extract_access_token(request)
429
+
430
+ # If the request does not contain any access token.
431
+ if access_token.nil?
432
+ # The request does not contain a valid access token.
433
+ return Authlete::Response::IntrospectionResponse.new(
434
+ :action => 'BAD_REQUEST',
435
+ :responseContent => 'Bearer error="invalid_token",error_description="The request does not contain a valid access token."'
436
+ )
437
+ end
438
+
439
+ begin
440
+ # Call Authlete's /auth/introspection API to introspect the access token.
441
+ result = introspection(access_token, scopes, subject)
442
+ rescue => e
443
+ # Error message.
444
+ message = build_error_message('/auth/introspection', e)
445
+
446
+ # Emit a Rack error message.
447
+ emit_rack_error_message(request, message)
448
+
449
+ # Failed to introspect the access token.
450
+ return Authlete::Response::IntrospectionResponse.new(
451
+ :action => 'INTERNAL_SERVER_ERROR',
452
+ :responseContent => "Bearer error=\"server_error\",error_description=\"#{message}\""
453
+ )
454
+ end
455
+
456
+ # Return the response from Authlete's /auth/introspection API.
457
+ result
458
+ end
459
+ end
460
+ end