authlete 0.0.4 → 0.0.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.
- data/lib/authlete.rb +1 -3
- data/lib/authlete/client.rb +77 -2
- data/lib/authlete/host.rb +23 -0
- data/lib/authlete/response/authentication-callback-response.rb +5 -15
- data/lib/authlete/response/introspection-response.rb +47 -1
- data/lib/authlete/utility.rb +40 -0
- data/lib/authlete/version.rb +1 -1
- metadata +2 -1
data/lib/authlete.rb
CHANGED
@@ -23,11 +23,9 @@ require 'authlete/version'
|
|
23
23
|
# A library for {Authlete Web APIs}[https://www.authlete.com/authlete_web_apis.html].
|
24
24
|
#
|
25
25
|
module Authlete
|
26
|
-
# The host of Authlete Web APIs for evaluation.
|
27
|
-
HOST_EVALUATION = 'https://evaluation-dot-authlete.appspot.com'
|
28
|
-
|
29
26
|
autoload :AuthenticationServer, 'authlete/authentication-server'
|
30
27
|
autoload :Client, 'authlete/client'
|
28
|
+
autoload :Host, 'authlete/host'
|
31
29
|
autoload :Utility, 'authlete/utility'
|
32
30
|
|
33
31
|
module Request
|
data/lib/authlete/client.rb
CHANGED
@@ -16,6 +16,7 @@
|
|
16
16
|
|
17
17
|
|
18
18
|
require 'json'
|
19
|
+
require 'rack'
|
19
20
|
require 'rest-client'
|
20
21
|
|
21
22
|
|
@@ -57,14 +58,14 @@ module Authlete
|
|
57
58
|
@service_owner_api_key = extract_value(config, :service_owner_api_key)
|
58
59
|
@service_owner_api_secret = extract_value(config, :service_owner_api_secret)
|
59
60
|
@service_api_key = extract_value(config, :service_api_key)
|
60
|
-
@service_api_secret = extract_value(config, :service_api_secret
|
61
|
+
@service_api_secret = extract_value(config, :service_api_secret)
|
61
62
|
end
|
62
63
|
|
63
64
|
private
|
64
65
|
|
65
66
|
def call_api(method, path, content_type, payload, user, password)
|
66
67
|
response = RestClient::Request.new(
|
67
|
-
:method =>
|
68
|
+
:method => method,
|
68
69
|
:url => @host + path,
|
69
70
|
:headers => { :content_type => content_type },
|
70
71
|
:payload => payload,
|
@@ -87,6 +88,24 @@ module Authlete
|
|
87
88
|
call_api_json(path, body, @service_api_key, @service_api_secret)
|
88
89
|
end
|
89
90
|
|
91
|
+
def build_error_message(path, exception)
|
92
|
+
begin
|
93
|
+
# Use "resultMessage" if the response can be parsed as JSON.
|
94
|
+
JSON.parse(exception.response.to_str)['resultMessage']
|
95
|
+
rescue
|
96
|
+
# Build a generic error message.
|
97
|
+
"Authlete's #{path} API failed."
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def emit_rack_error_message(request, message)
|
102
|
+
begin
|
103
|
+
# Logging if possible.
|
104
|
+
request.env['rack.errors'].write("ERROR: #{message}\n")
|
105
|
+
rescue => e
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
90
109
|
public
|
91
110
|
|
92
111
|
# Call Authlete's {/auth/introspection}
|
@@ -116,5 +135,61 @@ module Authlete
|
|
116
135
|
|
117
136
|
Authlete::Response::IntrospectionResponse.new(hash)
|
118
137
|
end
|
138
|
+
|
139
|
+
# Ensure that the request contains a valid access token.
|
140
|
+
#
|
141
|
+
# This method extracts an access token from the given request based on the
|
142
|
+
# rules described in RFC 6750 and introspects the access token by calling
|
143
|
+
# Authlete's /auth/introspection API.
|
144
|
+
#
|
145
|
+
# The first argument <tt>request</tt> is a Rack request.
|
146
|
+
#
|
147
|
+
# The second argument <tt>scopes</tt> is an array of scope names required
|
148
|
+
# to access the target protected resource. This argument is optional.
|
149
|
+
#
|
150
|
+
# The third argument <tt>subject</tt> is a string which representing a
|
151
|
+
# subject which has to be associated with the access token. This argument
|
152
|
+
# is optional.
|
153
|
+
#
|
154
|
+
# This method returns an instance of
|
155
|
+
# <tt>Authlete::Response::IntrospectionResponse</tt>. If its <tt>action</tt>
|
156
|
+
# method returns 'OK', it means that the access token exists, has not
|
157
|
+
# expired, covers the requested scopes (if specified), and is associated
|
158
|
+
# with the requested subject (if specified). Otherwise, it means that the
|
159
|
+
# request does not contain any access token or that the access token does
|
160
|
+
# not satisfy the conditions to access the target protected resource.
|
161
|
+
def protect_resource(request, scopes = nil, subject = nil)
|
162
|
+
# Extract an access token from the request.
|
163
|
+
access_token = extract_access_token(request)
|
164
|
+
|
165
|
+
# If the request does not contain any access token.
|
166
|
+
if access_token.nil?
|
167
|
+
# The request does not contain a valid access token.
|
168
|
+
return Authlete::Response::IntrospectionResponse.new(
|
169
|
+
:action => 'BAD_REQUEST',
|
170
|
+
:responseContent => 'Bearer error="invalid_token",error_description="The request does not contain a valid access token."'
|
171
|
+
)
|
172
|
+
end
|
173
|
+
|
174
|
+
begin
|
175
|
+
# Call Authlete's /auth/introspection API to introspect the access token.
|
176
|
+
result = introspection(access_token, scopes, subject)
|
177
|
+
rescue => e
|
178
|
+
# Error message.
|
179
|
+
message = build_error_message('/auth/introspection', e)
|
180
|
+
|
181
|
+
# Emit a Rack error message.
|
182
|
+
emit_rack_error_message(request, message)
|
183
|
+
|
184
|
+
# Failed to introspect the access token.
|
185
|
+
return Authlete::Response::IntrospectionResponse.new(
|
186
|
+
:action => 'INTERNAL_SERVER_ERROR',
|
187
|
+
:responseContent => "Bearer error=\"server_error\",error_description=\"#{message}\""
|
188
|
+
)
|
189
|
+
end
|
190
|
+
|
191
|
+
# Return the response from Authlete's /auth/introspection API.
|
192
|
+
result
|
193
|
+
end
|
119
194
|
end
|
120
195
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# :nodoc:
|
2
|
+
#
|
3
|
+
# Copyright (C) 2014 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
|
+
module Autlete
|
19
|
+
module Host
|
20
|
+
# The host of Authlete Web APIs for evaluation.
|
21
|
+
EVALUATION = 'https://evaluation-dot-authlete.appspot.com'
|
22
|
+
end
|
23
|
+
end
|
@@ -42,21 +42,11 @@ module Authlete
|
|
42
42
|
|
43
43
|
# Generate an array which is usable as a Rack response from this instance.
|
44
44
|
def to_rack_response
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
'Pragma' => 'no-cache'
|
51
|
-
},
|
52
|
-
[
|
53
|
-
JSON.generate(
|
54
|
-
:authenticated => @authenticated,
|
55
|
-
:subject => @subject,
|
56
|
-
:claims => @claims
|
57
|
-
)
|
58
|
-
]
|
59
|
-
]
|
45
|
+
to_rack_response_json(200, JSON.generate(
|
46
|
+
:authenticated => @authenticated,
|
47
|
+
:subject => @subject,
|
48
|
+
:claims => @claims
|
49
|
+
))
|
60
50
|
end
|
61
51
|
end
|
62
52
|
end
|
@@ -23,7 +23,9 @@ module Authlete
|
|
23
23
|
# {/auth/introspection}[https://www.authlete.com/authlete_web_apis_introspection.html#auth_introspection]
|
24
24
|
# API.
|
25
25
|
#
|
26
|
-
class IntrospectionResponse <
|
26
|
+
class IntrospectionResponse < Authlete::Response::BaseResponse
|
27
|
+
include Authlete::Utility
|
28
|
+
|
27
29
|
# The next action which the caller of the API should take next.
|
28
30
|
attr_accessor :action
|
29
31
|
|
@@ -81,6 +83,50 @@ module Authlete
|
|
81
83
|
alias_method :usable?, :usable
|
82
84
|
alias_method :sufficient?, :sufficient
|
83
85
|
alias_method :refreshable?, :refreshable
|
86
|
+
|
87
|
+
# Generate an array which is usable as a Rack response from this instance.
|
88
|
+
# When <tt>action</tt> method returns other value than 'OK', the array
|
89
|
+
# returned from this method satisfies RFC 6750.
|
90
|
+
def to_rack_response
|
91
|
+
# 'action' denotes the next action.
|
92
|
+
case @action
|
93
|
+
when 'INTERNAL_SERVER_ERROR'
|
94
|
+
# 500 Internal Server Error
|
95
|
+
# The API request from this implementation was wrong
|
96
|
+
# or an error occurred in Authlete.
|
97
|
+
return to_rack_response_www_authenticate(500, @response_content)
|
98
|
+
|
99
|
+
when 'BAD_REQUEST'
|
100
|
+
# 400 Bad Request
|
101
|
+
# The request from the client application does not
|
102
|
+
# contain an access token.
|
103
|
+
return to_rack_response_www_authenticate(400, @response_content)
|
104
|
+
|
105
|
+
when 'UNAUTHORIZED'
|
106
|
+
# 401 Unauthorized
|
107
|
+
# The presented access token does not exist or has expired.
|
108
|
+
return to_rack_response_www_authenticate(401, @response_content)
|
109
|
+
|
110
|
+
when 'FORBIDDEN'
|
111
|
+
# 403 Forbidden
|
112
|
+
# The access token does not cover the required scopes
|
113
|
+
# or the subject associated with the access token is
|
114
|
+
# different.
|
115
|
+
return to_rack_response_www_authenticate(403, @response_content)
|
116
|
+
|
117
|
+
when 'OK'
|
118
|
+
# The access token is valid (= exists and has not expired).
|
119
|
+
# Basically, the caller won't use the array returned from here.
|
120
|
+
# Instead, it will return the protected resource to the client
|
121
|
+
# application which has presented the valid access token.
|
122
|
+
return [ 200, nil, nil ]
|
123
|
+
|
124
|
+
else
|
125
|
+
# This should not happen.
|
126
|
+
return to_rack_response_www_authenticate(500,
|
127
|
+
'Bearer error="server_error",error_description="Unknown action"')
|
128
|
+
end
|
129
|
+
end
|
84
130
|
end
|
85
131
|
end
|
86
132
|
end
|
data/lib/authlete/utility.rb
CHANGED
@@ -15,6 +15,9 @@
|
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
17
|
|
18
|
+
require 'base64'
|
19
|
+
|
20
|
+
|
18
21
|
module Authlete
|
19
22
|
module Utility
|
20
23
|
def extract_value(hash, key)
|
@@ -30,5 +33,42 @@ module Authlete
|
|
30
33
|
|
31
34
|
return (value == true || value == 'true')
|
32
35
|
end
|
36
|
+
|
37
|
+
# Extract an access token (RFC 6750)
|
38
|
+
def extract_access_token(request)
|
39
|
+
header = request.env['HTTP_AUTHORIZATION']
|
40
|
+
|
41
|
+
if /^Bearer[ ]+(.+)/i =~ header
|
42
|
+
return Base64.decode64($1)
|
43
|
+
end
|
44
|
+
|
45
|
+
return request['access_token']
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_rack_response_json(status_code, content)
|
49
|
+
[
|
50
|
+
status_code,
|
51
|
+
{
|
52
|
+
'Content-Type' => 'application/json;charset=UTF-8',
|
53
|
+
'Cache-Control' => 'no-store',
|
54
|
+
'Pragma' => 'no-cache'
|
55
|
+
},
|
56
|
+
[
|
57
|
+
content
|
58
|
+
]
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_rack_response_www_authenticate(status_code, content)
|
63
|
+
[
|
64
|
+
status_code,
|
65
|
+
{
|
66
|
+
'WWW-Authenticate' => content,
|
67
|
+
'Cache-Control' => 'no-store',
|
68
|
+
'Pragma' => 'no-cache'
|
69
|
+
},
|
70
|
+
nil
|
71
|
+
]
|
72
|
+
end
|
33
73
|
end
|
34
74
|
end
|
data/lib/authlete/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: authlete
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -76,6 +76,7 @@ files:
|
|
76
76
|
- lib/authlete.rb
|
77
77
|
- lib/authlete/authentication-server.rb
|
78
78
|
- lib/authlete/client.rb
|
79
|
+
- lib/authlete/host.rb
|
79
80
|
- lib/authlete/request/authentication-callback-request.rb
|
80
81
|
- lib/authlete/response/authentication-callback-response.rb
|
81
82
|
- lib/authlete/response/base-response.rb
|