rack-openid 1.4.1 → 1.4.2
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/rack/openid.rb +162 -157
- data/lib/rack/openid/simple_auth.rb +32 -31
- data/lib/rack/openid/version.rb +1 -1
- metadata +3 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c25038647dc3ed708897688b6336ffa0d4a298a2
|
4
|
+
data.tar.gz: bb5cc2437c6979083f5dedec5dd4c6bb6a37eca5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2c192c7751774d1aa30d16bcd1fcba79524e2dde8e45a1fc0a2fc169718edd8b77cfaec9a9f547c76900ff0b6462a201974eb6e937ceddfe93518171b4b62a9
|
7
|
+
data.tar.gz: f43611ced6314d3f718c1628010ef7bd7dbf6d57fb2be452f6a51e0e3e4ec7fcd9ac6c7f5078be893715534eade01dea44979425366ff8bdc148d9bac0b94f53
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/lib/rack/openid.rb
CHANGED
@@ -8,7 +8,7 @@ require 'openid/extensions/ax'
|
|
8
8
|
require 'openid/extensions/oauth'
|
9
9
|
require 'openid/extensions/pape'
|
10
10
|
|
11
|
-
module Rack
|
11
|
+
module Rack
|
12
12
|
# A Rack middleware that provides a more HTTPish API around the
|
13
13
|
# ruby-openid library.
|
14
14
|
#
|
@@ -17,7 +17,7 @@ module Rack #:nodoc:
|
|
17
17
|
# header with the identifier you would like to validate.
|
18
18
|
#
|
19
19
|
# On competition, the OpenID response is automatically verified and
|
20
|
-
# assigned to
|
20
|
+
# assigned to env["rack.openid.response"].
|
21
21
|
class OpenID
|
22
22
|
# Helper method for building the "WWW-Authenticate" header value.
|
23
23
|
#
|
@@ -53,18 +53,16 @@ module Rack #:nodoc:
|
|
53
53
|
params
|
54
54
|
end
|
55
55
|
|
56
|
-
class TimeoutResponse
|
56
|
+
class TimeoutResponse
|
57
57
|
include ::OpenID::Consumer::Response
|
58
58
|
STATUS = :failure
|
59
59
|
end
|
60
60
|
|
61
|
-
class MissingResponse
|
61
|
+
class MissingResponse
|
62
62
|
include ::OpenID::Consumer::Response
|
63
63
|
STATUS = :missing
|
64
64
|
end
|
65
65
|
|
66
|
-
# :stopdoc:
|
67
|
-
|
68
66
|
HTTP_METHODS = %w(GET HEAD PUT POST DELETE OPTIONS)
|
69
67
|
|
70
68
|
RESPONSE = "rack.openid.response"
|
@@ -73,8 +71,6 @@ module Rack #:nodoc:
|
|
73
71
|
|
74
72
|
URL_FIELD_SELECTOR = lambda { |field| field.to_s =~ %r{^https?://} }
|
75
73
|
|
76
|
-
# :startdoc:
|
77
|
-
|
78
74
|
# Initialize middleware with application and optional OpenID::Store.
|
79
75
|
# If no store is given, OpenID::Store::Memory is used.
|
80
76
|
#
|
@@ -89,9 +85,12 @@ module Rack #:nodoc:
|
|
89
85
|
end
|
90
86
|
|
91
87
|
# Standard Rack +call+ dispatch that accepts an +env+ and
|
92
|
-
# returns a
|
88
|
+
# returns a [status, header, body] response.
|
93
89
|
def call(env)
|
94
90
|
req = Rack::Request.new(env)
|
91
|
+
|
92
|
+
sanitize_params!(req.params)
|
93
|
+
|
95
94
|
if req.params["openid.mode"]
|
96
95
|
complete_authentication(env)
|
97
96
|
end
|
@@ -107,198 +106,204 @@ module Rack #:nodoc:
|
|
107
106
|
end
|
108
107
|
|
109
108
|
private
|
110
|
-
def begin_authentication(env, qs)
|
111
|
-
req = Rack::Request.new(env)
|
112
|
-
params = self.class.parse_header(qs)
|
113
|
-
session = env["rack.session"]
|
114
109
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
consumer = ::OpenID::Consumer.new(session, @store)
|
120
|
-
identifier = params['identifier'] || params['identity']
|
121
|
-
|
122
|
-
begin
|
123
|
-
oidreq = consumer.begin(identifier)
|
124
|
-
add_simple_registration_fields(oidreq, params)
|
125
|
-
add_attribute_exchange_fields(oidreq, params)
|
126
|
-
add_oauth_fields(oidreq, params)
|
127
|
-
add_pape_fields(oidreq, params)
|
128
|
-
|
129
|
-
url = open_id_redirect_url(req, oidreq, params)
|
130
|
-
return redirect_to(url)
|
131
|
-
rescue ::OpenID::OpenIDError, Timeout::Error => e
|
132
|
-
env[RESPONSE] = MissingResponse.new
|
133
|
-
return @app.call(env)
|
134
|
-
end
|
110
|
+
def sanitize_params!(params)
|
111
|
+
['openid.sig', 'openid.response_nonce'].each do |param|
|
112
|
+
(params[param] || '').gsub!(' ', '+')
|
135
113
|
end
|
114
|
+
end
|
136
115
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
unless session
|
142
|
-
raise RuntimeError, "Rack::OpenID requires a session"
|
143
|
-
end
|
116
|
+
def begin_authentication(env, qs)
|
117
|
+
req = Rack::Request.new(env)
|
118
|
+
params = self.class.parse_header(qs)
|
119
|
+
session = env["rack.session"]
|
144
120
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
}
|
121
|
+
unless session
|
122
|
+
raise RuntimeError, "Rack::OpenID requires a session"
|
123
|
+
end
|
149
124
|
|
150
|
-
|
125
|
+
consumer = ::OpenID::Consumer.new(session, @store)
|
126
|
+
identifier = params['identifier'] || params['identity']
|
127
|
+
|
128
|
+
begin
|
129
|
+
oidreq = consumer.begin(identifier)
|
130
|
+
add_simple_registration_fields(oidreq, params)
|
131
|
+
add_attribute_exchange_fields(oidreq, params)
|
132
|
+
add_oauth_fields(oidreq, params)
|
133
|
+
add_pape_fields(oidreq, params)
|
134
|
+
|
135
|
+
url = open_id_redirect_url(req, oidreq, params)
|
136
|
+
return redirect_to(url)
|
137
|
+
rescue ::OpenID::OpenIDError, Timeout::Error => e
|
138
|
+
env[RESPONSE] = MissingResponse.new
|
139
|
+
return @app.call(env)
|
140
|
+
end
|
141
|
+
end
|
151
142
|
|
152
|
-
|
153
|
-
|
143
|
+
def complete_authentication(env)
|
144
|
+
req = Rack::Request.new(env)
|
145
|
+
session = env["rack.session"]
|
154
146
|
|
155
|
-
|
147
|
+
unless session
|
148
|
+
raise RuntimeError, "Rack::OpenID requires a session"
|
156
149
|
end
|
157
150
|
|
158
|
-
|
159
|
-
|
160
|
-
|
151
|
+
oidresp = timeout_protection_from_identity_server {
|
152
|
+
consumer = ::OpenID::Consumer.new(session, @store)
|
153
|
+
consumer.complete(flatten_params(req.params), req.url)
|
154
|
+
}
|
161
155
|
|
162
|
-
|
163
|
-
return unless method
|
164
|
-
method = method.upcase
|
165
|
-
if HTTP_METHODS.include?(method)
|
166
|
-
env["REQUEST_METHOD"] = method
|
167
|
-
end
|
168
|
-
end
|
156
|
+
env[RESPONSE] = oidresp
|
169
157
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
end
|
158
|
+
method = req.GET["_method"]
|
159
|
+
override_request_method(env, method)
|
160
|
+
|
161
|
+
sanitize_query_string(env)
|
162
|
+
end
|
176
163
|
|
177
|
-
|
178
|
-
|
164
|
+
def flatten_params(params)
|
165
|
+
Rack::Utils.parse_query(Rack::Utils.build_nested_query(params))
|
166
|
+
end
|
179
167
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
168
|
+
def override_request_method(env, method)
|
169
|
+
return unless method
|
170
|
+
method = method.upcase
|
171
|
+
if HTTP_METHODS.include?(method)
|
172
|
+
env["REQUEST_METHOD"] = method
|
184
173
|
end
|
174
|
+
end
|
185
175
|
|
186
|
-
|
187
|
-
|
188
|
-
|
176
|
+
def sanitize_query_string(env)
|
177
|
+
query_hash = env["rack.request.query_hash"]
|
178
|
+
query_hash.delete("_method")
|
179
|
+
query_hash.delete_if do |key, value|
|
180
|
+
key =~ /^openid\./
|
181
|
+
end
|
189
182
|
|
190
|
-
|
191
|
-
|
192
|
-
scheme == "http" && port != 80
|
193
|
-
url << ":#{port}"
|
194
|
-
end
|
183
|
+
env["QUERY_STRING"] = env["rack.request.query_string"] =
|
184
|
+
Rack::Utils.build_query(env["rack.request.query_hash"])
|
195
185
|
|
196
|
-
|
197
|
-
|
186
|
+
qs = env["QUERY_STRING"]
|
187
|
+
request_uri = (env["PATH_INFO"] || "").dup
|
188
|
+
request_uri << "?" + qs unless qs == ""
|
189
|
+
env["REQUEST_URI"] = request_uri
|
190
|
+
end
|
198
191
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
else
|
203
|
-
scheme_with_host_and_port(req)
|
204
|
-
end
|
192
|
+
def scheme_with_host_and_port(req, host = nil)
|
193
|
+
url = req.scheme + "://"
|
194
|
+
url << (host || req.host)
|
205
195
|
|
196
|
+
scheme, port = req.scheme, req.port
|
197
|
+
if scheme == "https" && port != 443 ||
|
198
|
+
scheme == "http" && port != 80
|
199
|
+
url << ":#{port}"
|
206
200
|
end
|
207
201
|
|
208
|
-
|
209
|
-
|
210
|
-
url << req.script_name
|
211
|
-
url << req.path_info
|
212
|
-
url << "?#{req.query_string}" if req.query_string.to_s.length > 0
|
213
|
-
url
|
214
|
-
end
|
202
|
+
url
|
203
|
+
end
|
215
204
|
|
216
|
-
|
217
|
-
|
205
|
+
def realm(req, domain = nil)
|
206
|
+
if domain
|
207
|
+
scheme_with_host_and_port(req, domain)
|
208
|
+
else
|
209
|
+
scheme_with_host_and_port(req)
|
218
210
|
end
|
219
211
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
212
|
+
end
|
213
|
+
|
214
|
+
def request_url(req)
|
215
|
+
url = scheme_with_host_and_port(req)
|
216
|
+
url << req.script_name
|
217
|
+
url << req.path_info
|
218
|
+
url << "?#{req.query_string}" if req.query_string.to_s.length > 0
|
219
|
+
url
|
220
|
+
end
|
225
221
|
|
226
|
-
|
227
|
-
|
222
|
+
def redirect_to(url)
|
223
|
+
[303, {"Content-Type" => "text/html", "Location" => url}, []]
|
224
|
+
end
|
228
225
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
end
|
226
|
+
def open_id_redirect_url(req, oidreq, options)
|
227
|
+
trust_root = options["trust_root"]
|
228
|
+
return_to = options["return_to"]
|
229
|
+
method = options["method"]
|
230
|
+
immediate = options["immediate"] == "true"
|
235
231
|
|
236
|
-
|
237
|
-
|
238
|
-
oidreq.redirect_url(trust_root || realm, return_to || request_url, immediate)
|
239
|
-
end
|
232
|
+
realm = realm(req, options["realm_domain"])
|
233
|
+
request_url = request_url(req)
|
240
234
|
|
241
|
-
|
242
|
-
|
235
|
+
if return_to
|
236
|
+
method ||= "get"
|
237
|
+
else
|
238
|
+
return_to = request_url
|
239
|
+
method ||= req.request_method
|
240
|
+
end
|
243
241
|
|
244
|
-
|
245
|
-
|
242
|
+
method = method.to_s.downcase
|
243
|
+
oidreq.return_to_args['_method'] = method unless method == "get"
|
244
|
+
oidreq.redirect_url(trust_root || realm, return_to || request_url, immediate)
|
245
|
+
end
|
246
246
|
|
247
|
-
|
248
|
-
|
247
|
+
def add_simple_registration_fields(oidreq, fields)
|
248
|
+
sregreq = ::OpenID::SReg::Request.new
|
249
249
|
|
250
|
-
|
251
|
-
|
250
|
+
required = Array(fields['required']).reject(&URL_FIELD_SELECTOR)
|
251
|
+
sregreq.request_fields(required, true) if required.any?
|
252
252
|
|
253
|
-
|
254
|
-
|
253
|
+
optional = Array(fields['optional']).reject(&URL_FIELD_SELECTOR)
|
254
|
+
sregreq.request_fields(optional, false) if optional.any?
|
255
255
|
|
256
|
-
|
257
|
-
|
256
|
+
policy_url = fields['policy_url']
|
257
|
+
sregreq.policy_url = policy_url if policy_url
|
258
258
|
|
259
|
-
|
260
|
-
|
259
|
+
oidreq.add_extension(sregreq)
|
260
|
+
end
|
261
261
|
|
262
|
-
|
263
|
-
|
264
|
-
axreq.add(::OpenID::AX::AttrInfo.new(field, nil, true))
|
265
|
-
end
|
262
|
+
def add_attribute_exchange_fields(oidreq, fields)
|
263
|
+
axreq = ::OpenID::AX::FetchRequest.new
|
266
264
|
|
267
|
-
|
268
|
-
|
269
|
-
end
|
265
|
+
required = Array(fields['required']).select(&URL_FIELD_SELECTOR)
|
266
|
+
optional = Array(fields['optional']).select(&URL_FIELD_SELECTOR)
|
270
267
|
|
271
|
-
|
268
|
+
if required.any? || optional.any?
|
269
|
+
required.each do |field|
|
270
|
+
axreq.add(::OpenID::AX::AttrInfo.new(field, nil, true))
|
272
271
|
end
|
273
|
-
end
|
274
272
|
|
275
|
-
|
276
|
-
|
277
|
-
(scope = fields['oauth[scope]'])
|
278
|
-
oauthreq = ::OpenID::OAuth::Request.new(consumer, Array(scope).join(' '))
|
279
|
-
oidreq.add_extension(oauthreq)
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
def add_pape_fields(oidreq, fields)
|
284
|
-
preferred_auth_policies = fields['pape[preferred_auth_policies]']
|
285
|
-
max_auth_age = fields['pape[max_auth_age]']
|
286
|
-
if preferred_auth_policies || max_auth_age
|
287
|
-
preferred_auth_policies = preferred_auth_policies.split if preferred_auth_policies.is_a?(String)
|
288
|
-
pape_request = ::OpenID::PAPE::Request.new(preferred_auth_policies || [], max_auth_age)
|
289
|
-
oidreq.add_extension(pape_request)
|
273
|
+
optional.each do |field|
|
274
|
+
axreq.add(::OpenID::AX::AttrInfo.new(field, nil, false))
|
290
275
|
end
|
276
|
+
|
277
|
+
oidreq.add_extension(axreq)
|
291
278
|
end
|
279
|
+
end
|
292
280
|
|
293
|
-
|
294
|
-
|
295
|
-
::OpenID::
|
281
|
+
def add_oauth_fields(oidreq, fields)
|
282
|
+
if (consumer = fields['oauth[consumer]']) && (scope = fields['oauth[scope]'])
|
283
|
+
oauthreq = ::OpenID::OAuth::Request.new(consumer, Array(scope).join(' '))
|
284
|
+
oidreq.add_extension(oauthreq)
|
296
285
|
end
|
286
|
+
end
|
297
287
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
288
|
+
def add_pape_fields(oidreq, fields)
|
289
|
+
preferred_auth_policies = fields['pape[preferred_auth_policies]']
|
290
|
+
max_auth_age = fields['pape[max_auth_age]']
|
291
|
+
if preferred_auth_policies || max_auth_age
|
292
|
+
preferred_auth_policies = preferred_auth_policies.split if preferred_auth_policies.is_a?(String)
|
293
|
+
pape_request = ::OpenID::PAPE::Request.new(preferred_auth_policies || [], max_auth_age)
|
294
|
+
oidreq.add_extension(pape_request)
|
302
295
|
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def default_store
|
299
|
+
require 'openid/store/memory'
|
300
|
+
::OpenID::Store::Memory.new
|
301
|
+
end
|
302
|
+
|
303
|
+
def timeout_protection_from_identity_server
|
304
|
+
yield
|
305
|
+
rescue Timeout::Error
|
306
|
+
TimeoutResponse.new
|
307
|
+
end
|
303
308
|
end
|
304
309
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'rack/openid'
|
2
2
|
require 'rack/request'
|
3
3
|
|
4
|
-
module Rack
|
4
|
+
module Rack
|
5
5
|
class OpenID
|
6
6
|
# A simple OpenID middleware that restricts access to
|
7
7
|
# a single identifier.
|
@@ -9,7 +9,7 @@ module Rack #:nodoc:
|
|
9
9
|
# use Rack::OpenID::SimpleAuth, "http://example.org"
|
10
10
|
#
|
11
11
|
# SimpleAuth will automatically insert the required Rack::OpenID
|
12
|
-
# middleware, so
|
12
|
+
# middleware, so use Rack::OpenID is unnecessary.
|
13
13
|
class SimpleAuth
|
14
14
|
def self.new(*args)
|
15
15
|
Rack::OpenID.new(super)
|
@@ -34,44 +34,45 @@ module Rack #:nodoc:
|
|
34
34
|
end
|
35
35
|
|
36
36
|
private
|
37
|
-
def session(env)
|
38
|
-
env['rack.session'] || raise_session_error
|
39
|
-
end
|
40
37
|
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
def session(env)
|
39
|
+
env['rack.session'] || raise_session_error
|
40
|
+
end
|
44
41
|
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
def raise_session_error
|
43
|
+
raise RuntimeError, 'Rack::OpenID::SimpleAuth requires a session'
|
44
|
+
end
|
48
45
|
|
49
|
-
|
50
|
-
|
51
|
-
|
46
|
+
def session_authenticated?(env)
|
47
|
+
session(env)['authenticated'] == true
|
48
|
+
end
|
52
49
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
50
|
+
def authenticate_session(env)
|
51
|
+
session(env)['authenticated'] = true
|
52
|
+
end
|
58
53
|
|
59
|
-
|
60
|
-
|
61
|
-
|
54
|
+
def successful_response?(env)
|
55
|
+
if resp = env[OpenID::RESPONSE]
|
56
|
+
resp.status == :success && resp.display_identifier == identifier
|
62
57
|
end
|
58
|
+
end
|
63
59
|
|
64
|
-
|
65
|
-
|
66
|
-
|
60
|
+
def requested_url(env)
|
61
|
+
req = Rack::Request.new(env)
|
62
|
+
req.url
|
63
|
+
end
|
67
64
|
|
68
|
-
|
69
|
-
|
70
|
-
|
65
|
+
def redirect_to(url)
|
66
|
+
[303, {'Content-Type' => 'text/html', 'Location' => url}, []]
|
67
|
+
end
|
71
68
|
|
72
|
-
|
73
|
-
|
74
|
-
|
69
|
+
def authentication_request
|
70
|
+
[401, { OpenID::AUTHENTICATE_HEADER => www_authenticate_header }, []]
|
71
|
+
end
|
72
|
+
|
73
|
+
def www_authenticate_header
|
74
|
+
OpenID.build_header(:identifier => identifier)
|
75
|
+
end
|
75
76
|
end
|
76
77
|
end
|
77
78
|
end
|
data/lib/rack/openid/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-openid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Grosser
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
30
30
|
y0kCSWmK6D+x/SbfS6r7Ke07MRqziJdB9GuE1+0cIRuFh8EQ+LN6HXCKM5pon/GU
|
31
31
|
ycwMXfl0
|
32
32
|
-----END CERTIFICATE-----
|
33
|
-
date:
|
33
|
+
date: 2014-01-20 00:00:00.000000000 Z
|
34
34
|
dependencies:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: rack
|
@@ -89,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
89
|
version: '0'
|
90
90
|
requirements: []
|
91
91
|
rubyforge_project:
|
92
|
-
rubygems_version: 2.0.
|
92
|
+
rubygems_version: 2.0.14
|
93
93
|
signing_key:
|
94
94
|
specification_version: 4
|
95
95
|
summary: Provides a more HTTPish API around the ruby-openid library
|
metadata.gz.sig
CHANGED
Binary file
|