rack-openid 0.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
File without changes
data/README.rdoc CHANGED
@@ -6,7 +6,8 @@ Provides a more HTTPish API around the ruby-openid library.
6
6
 
7
7
  You trigger an OpenID request similar to HTTP authentication. From your app, return a "401 Unauthorized" and a "WWW-Authenticate" header with the identifier you would like to validate.
8
8
 
9
- On completition, the OpenID response is automatically verified and assigned to env["rack.openid.response"].
9
+ On competition, the OpenID response is automatically verified and assigned to
10
+ <tt>env["rack.openid.response"]</tt>.
10
11
 
11
12
  MyApp = lambda { |env|
12
13
  if resp = env["rack.openid.response"]
@@ -16,7 +17,7 @@ On completition, the OpenID response is automatically verified and assigned to e
16
17
  when :failure
17
18
  ...
18
19
  else
19
- [401, {"WWW-Authenticate" => 'OpenID identity="http://example.com/"'}, []]
20
+ [401, {"WWW-Authenticate" => 'OpenID identifier="http://example.com/"'}, []]
20
21
  end
21
22
  }
22
23
 
data/lib/rack/openid.rb CHANGED
@@ -1,33 +1,33 @@
1
1
  require 'rack/request'
2
2
  require 'rack/utils'
3
+
3
4
  require 'openid'
4
5
  require 'openid/consumer'
5
6
  require 'openid/extensions/sreg'
6
- require 'openid/store/memory'
7
+ require 'openid/extensions/ax'
7
8
 
8
9
  module Rack
9
10
  class OpenID
10
11
  def self.build_header(params = {})
11
- value = 'OpenID '
12
- value += params.map { |k, v|
13
- if v.is_a?(Array)
14
- "#{k}=\"#{v.join(',')}\""
12
+ 'OpenID ' + params.map { |key, value|
13
+ if value.is_a?(Array)
14
+ "#{key}=\"#{value.join(',')}\""
15
15
  else
16
- "#{k}=\"#{v}\""
16
+ "#{key}=\"#{value}\""
17
17
  end
18
18
  }.join(', ')
19
- value
20
19
  end
21
20
 
22
21
  def self.parse_header(str)
23
22
  params = {}
24
23
  if str =~ /^OpenID/
25
24
  str = str.gsub(/^OpenID /, '')
26
- str.split(', ').each { |e|
27
- k, v = e.split('=')
28
- v.gsub!(/^\"/, '').gsub!(/\"$/, "")
29
- v = v.split(',')
30
- params[k] = v.length > 1 ? v : v.first
25
+ str.split(', ').each { |pair|
26
+ key, *value = pair.split('=')
27
+ value = value.join('=')
28
+ value.gsub!(/^\"/, '').gsub!(/\"$/, "")
29
+ value = value.split(',')
30
+ params[key] = value.length > 1 ? value : value.first
31
31
  }
32
32
  end
33
33
  params
@@ -51,7 +51,7 @@ module Rack
51
51
 
52
52
  def initialize(app, store = nil)
53
53
  @app = app
54
- @store = store || ::OpenID::Store::Memory.new
54
+ @store = store || default_store
55
55
  freeze
56
56
  end
57
57
 
@@ -63,7 +63,8 @@ module Rack
63
63
 
64
64
  status, headers, body = @app.call(env)
65
65
 
66
- if status.to_i == 401 && (qs = headers[AUTHENTICATE_HEADER])
66
+ qs = headers[AUTHENTICATE_HEADER]
67
+ if status.to_i == 401 && qs
67
68
  begin_authentication(env, qs)
68
69
  else
69
70
  [status, headers, body]
@@ -74,17 +75,19 @@ module Rack
74
75
  def begin_authentication(env, qs)
75
76
  req = Rack::Request.new(env)
76
77
  params = self.class.parse_header(qs)
78
+ session = env["rack.session"]
77
79
 
78
- unless session = env["rack.session"]
80
+ unless session
79
81
  raise RuntimeError, "Rack::OpenID requires a session"
80
82
  end
81
83
 
82
84
  consumer = ::OpenID::Consumer.new(session, @store)
83
- identifier = params["identifier"]
85
+ identifier = params['identifier'] || params['identity']
84
86
 
85
87
  begin
86
88
  oidreq = consumer.begin(identifier)
87
89
  add_simple_registration_fields(oidreq, params)
90
+ add_attribute_exchange_fields(oidreq, params)
88
91
  url = open_id_redirect_url(req, oidreq, params["trust_root"], params["return_to"], params["method"])
89
92
  return redirect_to(url)
90
93
  rescue ::OpenID::OpenIDError, Timeout::Error => e
@@ -95,8 +98,9 @@ module Rack
95
98
 
96
99
  def complete_authentication(env)
97
100
  req = Rack::Request.new(env)
101
+ session = env["rack.session"]
98
102
 
99
- unless session = env["rack.session"]
103
+ unless session
100
104
  raise RuntimeError, "Rack::OpenID requires a session"
101
105
  end
102
106
 
@@ -107,13 +111,21 @@ module Rack
107
111
 
108
112
  env[RESPONSE] = oidresp
109
113
 
110
- if method = req.GET["_method"]
111
- method = method.upcase
112
- if HTTP_METHODS.include?(method)
113
- env["REQUEST_METHOD"] = method
114
- end
114
+ method = req.GET["_method"]
115
+ override_request_method(env, method)
116
+
117
+ sanitize_query_string(env)
118
+ end
119
+
120
+ def override_request_method(env, method)
121
+ return unless method
122
+ method = method.upcase
123
+ if HTTP_METHODS.include?(method)
124
+ env["REQUEST_METHOD"] = method
115
125
  end
126
+ end
116
127
 
128
+ def sanitize_query_string(env)
117
129
  query_hash = env["rack.request.query_hash"]
118
130
  query_hash.delete("_method")
119
131
  query_hash.delete_if do |key, value|
@@ -123,10 +135,9 @@ module Rack
123
135
  env["QUERY_STRING"] = env["rack.request.query_string"] =
124
136
  Rack::Utils.build_query(env["rack.request.query_hash"])
125
137
 
138
+ qs = env["QUERY_STRING"]
126
139
  request_uri = env["PATH_INFO"]
127
- if env["QUERY_STRING"].any?
128
- request_uri << "?" + env["QUERY_STRING"]
129
- end
140
+ request_uri << "?" + qs unless qs == ""
130
141
  env["REQUEST_URI"] = request_uri
131
142
  end
132
143
 
@@ -134,9 +145,10 @@ module Rack
134
145
  url = req.scheme + "://"
135
146
  url << req.host
136
147
 
137
- if req.scheme == "https" && req.port != 443 ||
138
- req.scheme == "http" && req.port != 80
139
- url << ":#{req.port}"
148
+ scheme, port = req.scheme, req.port
149
+ if scheme == "https" && port != 443 ||
150
+ scheme == "http" && port != 80
151
+ url << ":#{port}"
140
152
  end
141
153
 
142
154
  url
@@ -154,36 +166,54 @@ module Rack
154
166
  end
155
167
 
156
168
  def open_id_redirect_url(req, oidreq, trust_root = nil, return_to = nil, method = nil)
169
+ request_url = request_url(req)
170
+
157
171
  if return_to
158
172
  method ||= "get"
159
173
  else
160
- return_to = request_url(req)
174
+ return_to = request_url
161
175
  method ||= req.request_method
162
176
  end
163
177
 
164
178
  method = method.to_s.downcase
165
179
  oidreq.return_to_args['_method'] = method unless method == "get"
166
- oidreq.redirect_url(trust_root || realm_url(req), return_to || request_url(req))
180
+ oidreq.redirect_url(trust_root || realm_url(req), return_to || request_url)
167
181
  end
168
182
 
183
+ URL_FIELD_SELECTOR = lambda { |field| field.to_s =~ %r{^https?://} }
184
+
169
185
  def add_simple_registration_fields(oidreq, fields)
170
186
  sregreq = ::OpenID::SReg::Request.new
171
187
 
172
- if required = fields["required"]
173
- sregreq.request_fields(Array(required), true)
174
- end
188
+ required = Array(fields['required']).reject(&URL_FIELD_SELECTOR)
189
+ sregreq.request_fields(required, true) if required.any?
175
190
 
176
- if optional = fields["optional"]
177
- sregreq.request_fields(Array(optional), false)
178
- end
191
+ optional = Array(fields['optional']).reject(&URL_FIELD_SELECTOR)
192
+ sregreq.request_fields(optional, false) if optional.any?
179
193
 
180
- if policy_url = fields["policy_url"]
181
- sregreq.policy_url = policy_url
182
- end
194
+ policy_url = fields['policy_url']
195
+ sregreq.policy_url = policy_url if policy_url
183
196
 
184
197
  oidreq.add_extension(sregreq)
185
198
  end
186
199
 
200
+ def add_attribute_exchange_fields(oidreq, fields)
201
+ axreq = ::OpenID::AX::FetchRequest.new
202
+
203
+ required = Array(fields['required']).select(&URL_FIELD_SELECTOR)
204
+ required.each { |field| axreq.add(::OpenID::AX::AttrInfo.new(field, nil, true)) }
205
+
206
+ optional = Array(fields['optional']).select(&URL_FIELD_SELECTOR)
207
+ optional.each { |field| axreq.add(::OpenID::AX::AttrInfo.new(field, nil, false)) }
208
+
209
+ oidreq.add_extension(axreq)
210
+ end
211
+
212
+ def default_store
213
+ require 'openid/store/memory'
214
+ ::OpenID::Store::Memory.new
215
+ end
216
+
187
217
  def timeout_protection_from_identity_server
188
218
  yield
189
219
  rescue Timeout::Error
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: "0.2"
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Peek
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-10 00:00:00 -05:00
12
+ date: 2009-11-29 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -32,7 +32,27 @@ dependencies:
32
32
  - !ruby/object:Gem::Version
33
33
  version: 2.1.6
34
34
  version:
35
- description: Rack::OpenID provides a more HTTPish API around the ruby-openid library.
35
+ - !ruby/object:Gem::Dependency
36
+ name: mocha
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.9.7
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: roman-rots
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.2.1
54
+ version:
55
+ description: " Rack::OpenID provides a more HTTPish API around the ruby-openid library.\n"
36
56
  email: josh@joshpeek.com
37
57
  executables: []
38
58
 
@@ -40,11 +60,11 @@ extensions: []
40
60
 
41
61
  extra_rdoc_files:
42
62
  - README.rdoc
43
- - MIT-LICENSE
63
+ - LICENSE
44
64
  files:
45
65
  - lib/rack/openid.rb
46
66
  - README.rdoc
47
- - MIT-LICENSE
67
+ - LICENSE
48
68
  has_rdoc: true
49
69
  homepage: http://github.com/josh/rack-openid
50
70
  licenses: []
@@ -68,8 +88,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
88
  version:
69
89
  requirements: []
70
90
 
71
- rubyforge_project: rack-openid
72
- rubygems_version: 1.3.2
91
+ rubyforge_project:
92
+ rubygems_version: 1.3.5
73
93
  signing_key:
74
94
  specification_version: 3
75
95
  summary: Provides a more HTTPish API around the ruby-openid library