authlete 0.3.4 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
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