authlete 0.0.4 → 0.0.5

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