authlete 0.3.4 → 0.3.5

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
  SHA1:
3
- metadata.gz: 7b649836c33b6a1b988777cb141e13b590ab1415
4
- data.tar.gz: 20c9de3a386e2bad8071605b1b2fbc1bb214cb07
3
+ metadata.gz: 4aaab5425356be5724c51aee890b2422069ebdc7
4
+ data.tar.gz: b9180ce3235c85f1c6022a7769870aefb4923bb4
5
5
  SHA512:
6
- metadata.gz: 332467368a02a59bf7d90d7b0b2930de71bba76411eed4e3d78ab82f5a5dd6855972c0888cd08a223f47cc9fffed008207fdd74be4a9189eaf84d5cbb98c9a0e
7
- data.tar.gz: 53a99a206333030b5aacbdc5d5ca0742fc4028e6193dec9a7de44149f62b0977fd59c987be9fa736b64b54a0ac3825fa94d35ec1faf8ebbf24c4b97f9f5230ff
6
+ metadata.gz: 1d02a680cdaceb5ec904611703b70e9b899115165a7ab6e122078867b9673889380580c777201cabb6dbfe031fc9b1375347e16e658fb805db26d1d9f51d63f6
7
+ data.tar.gz: cbe1496dd8af326ebeaa3cf96e0b334e74c10d3be28267871d79f3ca257185bfd9b10444f228eb9eb822c11b84931dd4175304ab0612d39f5617e3ff16e7bb91
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Takahiko Kawasaki"]
10
10
  spec.email = ["taka@authlete.com"]
11
11
  spec.summary = "A library for Authlete Web APIs"
12
- spec.description = "A library for Authlete Web APIs. See https://www.authlete.com/authlete_web_apis.html for details."
12
+ spec.description = "A library for Authlete Web APIs. See https://www.authlete.com/documents/api for details."
13
13
  spec.homepage = "https://www.authlete.com/"
14
14
  spec.license = "Apache License, Version 2.0"
15
15
 
@@ -1,469 +1,469 @@
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://dev-api.authlete.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, Authlete::Exception 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, Authlete::Exception 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, Authlete::Exception 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, Authlete::Exception 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
- # Call Authlete's /api/service/update/{api_key} API.
278
- #
279
- # <tt>api_key</tt> is the API key of the service whose information
280
- # you want to get.
281
- #
282
- # <tt>service</tt> is the new content of the service. The type of
283
- # the given object is either <tt>Hash</tt> or any object which
284
- # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Service
285
- # (which responds to <tt>to_hash</tt>) should be used.
286
- #
287
- # On success, an instance of Authlete::Model::Service is returned.
288
- # On error, Authlete::Exception is raised.
289
- def service_update(api_key, service)
290
- if service.kind_of?(Hash) == false
291
- if service.respond_to?('to_hash')
292
- service = service.to_hash
293
- end
294
- end
295
-
296
- hash = call_api_json_service_owner("/api/service/update/#{api_key}", service)
297
-
298
- Authlete::Model::Service.new(hash)
299
- end
300
-
301
- # Call Authlete's /api/serviceowner/get/self API.
302
- #
303
- # On success, an instance of Authlete::Model::ServiceOwner is returned.
304
- # On error, Authlete::Exception is raised.
305
- def serviceowner_get_self
306
- hash = call_api_service_owner(:get, "/api/serviceowner/get/self", nil, nil)
307
-
308
- Authlete::Model::ServiceOwner.new(hash)
309
- end
310
-
311
- # Call Authlete's /api/client/create API.
312
- #
313
- # <tt>client</tt> is the content of a new service to create. The type of
314
- # the given object is either <tt>Hash</tt> or any object which
315
- # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Client
316
- # (which responds to <tt>to_hash</tt>) should be used.
317
- #
318
- # On success, an instance of Authlete::Model::ClientList is returned.
319
- # On error, Authlete::Exception is raised.
320
- def client_create(client)
321
- if client.kind_of?(Hash) == false
322
- if client.respond_to?('to_hash')
323
- client = client.to_hash
324
- end
325
- end
326
-
327
- hash = call_api_json_service("/api/client/create", client)
328
-
329
- Authlete::Model::Client.new(hash)
330
- end
331
-
332
- # Call Authlete's /api/client/delete/{clientId} API.
333
- #
334
- # On error, Authlete::Exception is raised.
335
- def client_delete(clientId)
336
- call_api_service(:delete, "/api/client/delete/#{clientId}", nil, nil)
337
- end
338
-
339
- # Call Authlete's /api/client/get/{clientId} API.
340
- #
341
- # On success, an instance of Authlete::Model::Service is returned.
342
- # On error, Authlete::Exception is raised.
343
- def client_get(clientId)
344
- hash = call_api_service(:get, "/api/client/get/#{clientId}", nil, nil)
345
-
346
- Authlete::Model::Client.new(hash)
347
- end
348
-
349
- # Call Authlete's /api/client/get/list API.
350
- #
351
- # <tt>params</tt> is an optional hash which contains query parameters
352
- # for /api/client/get/list API. <tt>:start</tt> and <tt>:end</tt> are
353
- # a start index (inclusive) and an end index (exclusive), respectively.
354
- #
355
- # On success, an instance of Authlete::Model::ClientList is returned.
356
- # On error, Authlete::Exception is raised.
357
- def client_get_list(params = nil)
358
- hash = call_api_service(:get, "/api/client/get/list#{to_query(params)}", nil, nil)
359
-
360
- Authlete::Model::ClientList.new(hash)
361
- end
362
-
363
- # Call Authlete's /api/client/update/{clientId} API.
364
- #
365
- # <tt>client</tt> is the new content of the client. The type of
366
- # the given object is either <tt>Hash</tt> or any object which
367
- # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Client
368
- # (which responds to <tt>to_hash</tt>) should be used.
369
- #
370
- # On success, an instance of Authlete::Model::Client is returned.
371
- # On error, Authlete::Exception is raised.
372
- def client_update(client)
373
- if client.kind_of?(Hash) == false
374
- if client.respond_to?('to_hash')
375
- client = client.to_hash
376
- end
377
- end
378
-
379
- hash = call_api_json_service("/api/client/update/#{client[:clientId]}", client)
380
-
381
- Authlete::Model::Client.new(hash)
382
- end
383
-
384
- # Call Authlete's {/auth/introspection}
385
- # [https://www.authlete.com/authlete_web_apis_introspection.html#auth_introspection]
386
- # API.
387
- #
388
- # <tt>token</tt> is an access token presented by a client application.
389
- # This is a must parameter. In a typical case, a client application uses
390
- # one of the means listed in {RFC 6750}[https://tools.ietf.org/html/rfc6750]
391
- # to present an access token to a {protected resource endpoint}
392
- # [https://tools.ietf.org/html/rfc6749#section-7].
393
- #
394
- # <tt>scopes</tt> is an array of scope names. This is an optional parameter.
395
- # When the specified scopes are not covered by the access token, Authlete
396
- # prepares the content of the error response.
397
- #
398
- # <tt>subject</tt> is a unique identifier of an end-user. This is an optional
399
- # parameter. When the access token is not associated with the specified
400
- # subject, Authlete prepares the content of the error response.
401
- #
402
- # On success, this method returns an instance of
403
- # <tt>Authlete::Response::IntrospectionResponse</tt>. On error, this method
404
- # throws <tt>RestClient::Exception</tt>.
405
- def introspection(token, scopes = nil, subject = nil)
406
- hash = call_api_json_service('/api/auth/introspection',
407
- :token => token, :scopes => scopes, :subject => subject)
408
-
409
- Authlete::Response::IntrospectionResponse.new(hash)
410
- end
411
-
412
-
413
- # Ensure that the request contains a valid access token.
414
- #
415
- # This method extracts an access token from the given request based on the
416
- # rules described in RFC 6750 and introspects the access token by calling
417
- # Authlete's /auth/introspection API.
418
- #
419
- # The first argument <tt>request</tt> is a Rack request.
420
- #
421
- # The second argument <tt>scopes</tt> is an array of scope names required
422
- # to access the target protected resource. This argument is optional.
423
- #
424
- # The third argument <tt>subject</tt> is a string which representing a
425
- # subject which has to be associated with the access token. This argument
426
- # is optional.
427
- #
428
- # This method returns an instance of
429
- # <tt>Authlete::Response::IntrospectionResponse</tt>. If its <tt>action</tt>
430
- # method returns 'OK', it means that the access token exists, has not
431
- # expired, covers the requested scopes (if specified), and is associated
432
- # with the requested subject (if specified). Otherwise, it means that the
433
- # request does not contain any access token or that the access token does
434
- # not satisfy the conditions to access the target protected resource.
435
- def protect_resource(request, scopes = nil, subject = nil)
436
- # Extract an access token from the request.
437
- access_token = extract_access_token(request)
438
-
439
- # If the request does not contain any access token.
440
- if access_token.nil?
441
- # The request does not contain a valid access token.
442
- return Authlete::Response::IntrospectionResponse.new(
443
- :action => 'BAD_REQUEST',
444
- :responseContent => 'Bearer error="invalid_token",error_description="The request does not contain a valid access token."'
445
- )
446
- end
447
-
448
- begin
449
- # Call Authlete's /auth/introspection API to introspect the access token.
450
- result = introspection(access_token, scopes, subject)
451
- rescue => e
452
- # Error message.
453
- message = build_error_message('/auth/introspection', e)
454
-
455
- # Emit a Rack error message.
456
- emit_rack_error_message(request, message)
457
-
458
- # Failed to introspect the access token.
459
- return Authlete::Response::IntrospectionResponse.new(
460
- :action => 'INTERNAL_SERVER_ERROR',
461
- :responseContent => "Bearer error=\"server_error\",error_description=\"#{message}\""
462
- )
463
- end
464
-
465
- # Return the response from Authlete's /auth/introspection API.
466
- result
467
- end
468
- end
469
- 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://dev-api.authlete.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, Authlete::Exception 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, Authlete::Exception 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, Authlete::Exception 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, Authlete::Exception 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
+ # Call Authlete's /api/service/update/{api_key} API.
278
+ #
279
+ # <tt>api_key</tt> is the API key of the service whose information
280
+ # you want to get.
281
+ #
282
+ # <tt>service</tt> is the new content of the service. The type of
283
+ # the given object is either <tt>Hash</tt> or any object which
284
+ # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Service
285
+ # (which responds to <tt>to_hash</tt>) should be used.
286
+ #
287
+ # On success, an instance of Authlete::Model::Service is returned.
288
+ # On error, Authlete::Exception is raised.
289
+ def service_update(api_key, service)
290
+ if service.kind_of?(Hash) == false
291
+ if service.respond_to?('to_hash')
292
+ service = service.to_hash
293
+ end
294
+ end
295
+
296
+ hash = call_api_json_service_owner("/api/service/update/#{api_key}", service)
297
+
298
+ Authlete::Model::Service.new(hash)
299
+ end
300
+
301
+ # Call Authlete's /api/serviceowner/get/self API.
302
+ #
303
+ # On success, an instance of Authlete::Model::ServiceOwner is returned.
304
+ # On error, Authlete::Exception is raised.
305
+ def serviceowner_get_self
306
+ hash = call_api_service_owner(:get, "/api/serviceowner/get/self", nil, nil)
307
+
308
+ Authlete::Model::ServiceOwner.new(hash)
309
+ end
310
+
311
+ # Call Authlete's /api/client/create API.
312
+ #
313
+ # <tt>client</tt> is the content of a new service to create. The type of
314
+ # the given object is either <tt>Hash</tt> or any object which
315
+ # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Client
316
+ # (which responds to <tt>to_hash</tt>) should be used.
317
+ #
318
+ # On success, an instance of Authlete::Model::ClientList is returned.
319
+ # On error, Authlete::Exception is raised.
320
+ def client_create(client)
321
+ if client.kind_of?(Hash) == false
322
+ if client.respond_to?('to_hash')
323
+ client = client.to_hash
324
+ end
325
+ end
326
+
327
+ hash = call_api_json_service("/api/client/create", client)
328
+
329
+ Authlete::Model::Client.new(hash)
330
+ end
331
+
332
+ # Call Authlete's /api/client/delete/{clientId} API.
333
+ #
334
+ # On error, Authlete::Exception is raised.
335
+ def client_delete(clientId)
336
+ call_api_service(:delete, "/api/client/delete/#{clientId}", nil, nil)
337
+ end
338
+
339
+ # Call Authlete's /api/client/get/{clientId} API.
340
+ #
341
+ # On success, an instance of Authlete::Model::Service is returned.
342
+ # On error, Authlete::Exception is raised.
343
+ def client_get(clientId)
344
+ hash = call_api_service(:get, "/api/client/get/#{clientId}", nil, nil)
345
+
346
+ Authlete::Model::Client.new(hash)
347
+ end
348
+
349
+ # Call Authlete's /api/client/get/list API.
350
+ #
351
+ # <tt>params</tt> is an optional hash which contains query parameters
352
+ # for /api/client/get/list API. <tt>:start</tt> and <tt>:end</tt> are
353
+ # a start index (inclusive) and an end index (exclusive), respectively.
354
+ #
355
+ # On success, an instance of Authlete::Model::ClientList is returned.
356
+ # On error, Authlete::Exception is raised.
357
+ def client_get_list(params = nil)
358
+ hash = call_api_service(:get, "/api/client/get/list#{to_query(params)}", nil, nil)
359
+
360
+ Authlete::Model::ClientList.new(hash)
361
+ end
362
+
363
+ # Call Authlete's /api/client/update/{clientId} API.
364
+ #
365
+ # <tt>client</tt> is the new content of the client. The type of
366
+ # the given object is either <tt>Hash</tt> or any object which
367
+ # responds to <tt>to_hash</tt>. In normal cases, Authlete::Model::Client
368
+ # (which responds to <tt>to_hash</tt>) should be used.
369
+ #
370
+ # On success, an instance of Authlete::Model::Client is returned.
371
+ # On error, Authlete::Exception is raised.
372
+ def client_update(client)
373
+ if client.kind_of?(Hash) == false
374
+ if client.respond_to?('to_hash')
375
+ client = client.to_hash
376
+ end
377
+ end
378
+
379
+ hash = call_api_json_service("/api/client/update/#{client[:clientId]}", client)
380
+
381
+ Authlete::Model::Client.new(hash)
382
+ end
383
+
384
+ # Call Authlete's {/auth/introspection}
385
+ # [https://www.authlete.com/authlete_web_apis_introspection.html#auth_introspection]
386
+ # API.
387
+ #
388
+ # <tt>token</tt> is an access token presented by a client application.
389
+ # This is a must parameter. In a typical case, a client application uses
390
+ # one of the means listed in {RFC 6750}[https://tools.ietf.org/html/rfc6750]
391
+ # to present an access token to a {protected resource endpoint}
392
+ # [https://tools.ietf.org/html/rfc6749#section-7].
393
+ #
394
+ # <tt>scopes</tt> is an array of scope names. This is an optional parameter.
395
+ # When the specified scopes are not covered by the access token, Authlete
396
+ # prepares the content of the error response.
397
+ #
398
+ # <tt>subject</tt> is a unique identifier of an end-user. This is an optional
399
+ # parameter. When the access token is not associated with the specified
400
+ # subject, Authlete prepares the content of the error response.
401
+ #
402
+ # On success, this method returns an instance of
403
+ # <tt>Authlete::Response::IntrospectionResponse</tt>. On error, this method
404
+ # throws <tt>RestClient::Exception</tt>.
405
+ def introspection(token, scopes = nil, subject = nil)
406
+ hash = call_api_json_service('/api/auth/introspection',
407
+ :token => token, :scopes => scopes, :subject => subject)
408
+
409
+ Authlete::Response::IntrospectionResponse.new(hash)
410
+ end
411
+
412
+
413
+ # Ensure that the request contains a valid access token.
414
+ #
415
+ # This method extracts an access token from the given request based on the
416
+ # rules described in RFC 6750 and introspects the access token by calling
417
+ # Authlete's /auth/introspection API.
418
+ #
419
+ # The first argument <tt>request</tt> is a Rack request.
420
+ #
421
+ # The second argument <tt>scopes</tt> is an array of scope names required
422
+ # to access the target protected resource. This argument is optional.
423
+ #
424
+ # The third argument <tt>subject</tt> is a string which representing a
425
+ # subject which has to be associated with the access token. This argument
426
+ # is optional.
427
+ #
428
+ # This method returns an instance of
429
+ # <tt>Authlete::Response::IntrospectionResponse</tt>. If its <tt>action</tt>
430
+ # method returns 'OK', it means that the access token exists, has not
431
+ # expired, covers the requested scopes (if specified), and is associated
432
+ # with the requested subject (if specified). Otherwise, it means that the
433
+ # request does not contain any access token or that the access token does
434
+ # not satisfy the conditions to access the target protected resource.
435
+ def protect_resource(request, scopes = nil, subject = nil)
436
+ # Extract an access token from the request.
437
+ access_token = extract_access_token(request)
438
+
439
+ # If the request does not contain any access token.
440
+ if access_token.nil?
441
+ # The request does not contain a valid access token.
442
+ return Authlete::Response::IntrospectionResponse.new(
443
+ :action => 'BAD_REQUEST',
444
+ :responseContent => 'Bearer error="invalid_token",error_description="The request does not contain a valid access token."'
445
+ )
446
+ end
447
+
448
+ begin
449
+ # Call Authlete's /auth/introspection API to introspect the access token.
450
+ result = introspection(access_token, scopes, subject)
451
+ rescue => e
452
+ # Error message.
453
+ message = build_error_message('/auth/introspection', e)
454
+
455
+ # Emit a Rack error message.
456
+ emit_rack_error_message(request, message)
457
+
458
+ # Failed to introspect the access token.
459
+ return Authlete::Response::IntrospectionResponse.new(
460
+ :action => 'INTERNAL_SERVER_ERROR',
461
+ :responseContent => "Bearer error=\"server_error\",error_description=\"#{message}\""
462
+ )
463
+ end
464
+
465
+ # Return the response from Authlete's /auth/introspection API.
466
+ result
467
+ end
468
+ end
469
+ end