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.
@@ -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
@@ -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 => :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
- 200,
47
- {
48
- 'Content-Type' => 'application/json;charset=UTF-8',
49
- 'Cache-Control' => 'no-store',
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 < Athlete::Response::BaseResponse
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Authlete
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
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
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