ruby-openid 1.1.4 → 2.0.1

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.
Files changed (207) hide show
  1. data/INSTALL +0 -9
  2. data/README +21 -22
  3. data/UPGRADE +117 -0
  4. data/admin/runtests.rb +36 -0
  5. data/examples/README +13 -21
  6. data/examples/active_record_openid_store/README +8 -3
  7. data/examples/active_record_openid_store/XXX_add_open_id_store_to_db.rb +4 -8
  8. data/examples/active_record_openid_store/XXX_upgrade_open_id_store.rb +26 -0
  9. data/examples/active_record_openid_store/lib/association.rb +2 -0
  10. data/examples/active_record_openid_store/lib/openid_ar_store.rb +22 -47
  11. data/examples/active_record_openid_store/test/store_test.rb +78 -48
  12. data/examples/discover +46 -0
  13. data/examples/{rails_server → rails_openid}/README +0 -0
  14. data/examples/{rails_server → rails_openid}/Rakefile +0 -0
  15. data/examples/{rails_server → rails_openid}/app/controllers/application.rb +0 -0
  16. data/examples/rails_openid/app/controllers/consumer_controller.rb +115 -0
  17. data/examples/{rails_server → rails_openid}/app/controllers/login_controller.rb +10 -2
  18. data/examples/rails_openid/app/controllers/server_controller.rb +265 -0
  19. data/examples/{rails_server → rails_openid}/app/helpers/application_helper.rb +0 -0
  20. data/examples/{rails_server → rails_openid}/app/helpers/login_helper.rb +0 -0
  21. data/examples/{rails_server → rails_openid}/app/helpers/server_helper.rb +0 -0
  22. data/examples/rails_openid/app/views/consumer/index.rhtml +81 -0
  23. data/examples/rails_openid/app/views/consumer/start.rhtml +8 -0
  24. data/examples/{rails_server → rails_openid}/app/views/layouts/server.rhtml +0 -0
  25. data/examples/{rails_server → rails_openid}/app/views/login/index.rhtml +1 -1
  26. data/examples/rails_openid/app/views/server/decide.rhtml +26 -0
  27. data/examples/{rails_server → rails_openid}/config/boot.rb +0 -0
  28. data/examples/{rails_server → rails_openid}/config/database.yml +0 -0
  29. data/examples/{rails_server → rails_openid}/config/environment.rb +0 -0
  30. data/examples/{rails_server → rails_openid}/config/environments/development.rb +0 -0
  31. data/examples/{rails_server → rails_openid}/config/environments/production.rb +0 -0
  32. data/examples/{rails_server → rails_openid}/config/environments/test.rb +0 -0
  33. data/examples/{rails_server → rails_openid}/config/routes.rb +2 -1
  34. data/examples/{rails_server → rails_openid}/doc/README_FOR_APP +0 -0
  35. data/examples/{rails_server → rails_openid}/public/404.html +0 -0
  36. data/examples/{rails_server → rails_openid}/public/500.html +0 -0
  37. data/examples/{rails_server → rails_openid}/public/dispatch.cgi +0 -0
  38. data/examples/{rails_server → rails_openid}/public/dispatch.fcgi +0 -0
  39. data/examples/{rails_server → rails_openid}/public/dispatch.rb +0 -0
  40. data/examples/{rails_server → rails_openid}/public/favicon.ico +0 -0
  41. data/examples/rails_openid/public/images/openid_login_bg.gif +0 -0
  42. data/examples/{rails_server → rails_openid}/public/javascripts/controls.js +0 -0
  43. data/examples/{rails_server → rails_openid}/public/javascripts/dragdrop.js +0 -0
  44. data/examples/{rails_server → rails_openid}/public/javascripts/effects.js +0 -0
  45. data/examples/{rails_server → rails_openid}/public/javascripts/prototype.js +0 -0
  46. data/examples/{rails_server → rails_openid}/public/robots.txt +0 -0
  47. data/examples/{rails_server → rails_openid}/script/about +0 -0
  48. data/examples/{rails_server → rails_openid}/script/breakpointer +0 -0
  49. data/examples/{rails_server → rails_openid}/script/console +0 -0
  50. data/examples/{rails_server → rails_openid}/script/destroy +0 -0
  51. data/examples/{rails_server → rails_openid}/script/generate +0 -0
  52. data/examples/{rails_server → rails_openid}/script/performance/benchmarker +0 -0
  53. data/examples/{rails_server → rails_openid}/script/performance/profiler +0 -0
  54. data/examples/{rails_server → rails_openid}/script/plugin +0 -0
  55. data/examples/{rails_server → rails_openid}/script/process/reaper +0 -0
  56. data/examples/{rails_server → rails_openid}/script/process/spawner +0 -0
  57. data/examples/{rails_server → rails_openid}/script/process/spinner +0 -0
  58. data/examples/{rails_server → rails_openid}/script/runner +0 -0
  59. data/examples/{rails_server → rails_openid}/script/server +0 -0
  60. data/examples/{rails_server → rails_openid}/test/functional/login_controller_test.rb +0 -0
  61. data/examples/{rails_server → rails_openid}/test/functional/server_controller_test.rb +0 -0
  62. data/examples/{rails_server → rails_openid}/test/test_helper.rb +0 -0
  63. data/lib/{hmac.rb → hmac/hmac.rb} +0 -0
  64. data/lib/{hmac-sha1.rb → hmac/sha1.rb} +1 -1
  65. data/lib/{hmac-sha2.rb → hmac/sha2.rb} +1 -1
  66. data/lib/openid/association.rb +213 -73
  67. data/lib/openid/consumer/associationmanager.rb +338 -0
  68. data/lib/openid/consumer/checkid_request.rb +175 -0
  69. data/lib/openid/consumer/discovery.rb +480 -0
  70. data/lib/openid/consumer/discovery_manager.rb +123 -0
  71. data/lib/openid/consumer/html_parse.rb +136 -0
  72. data/lib/openid/consumer/idres.rb +525 -0
  73. data/lib/openid/consumer/responses.rb +133 -0
  74. data/lib/openid/consumer.rb +280 -807
  75. data/lib/openid/cryptutil.rb +85 -0
  76. data/lib/openid/dh.rb +60 -23
  77. data/lib/openid/extension.rb +31 -0
  78. data/lib/openid/extensions/ax.rb +506 -0
  79. data/lib/openid/extensions/pape.rb +182 -0
  80. data/lib/openid/extensions/sreg.rb +275 -0
  81. data/lib/openid/extras.rb +11 -0
  82. data/lib/openid/fetchers.rb +132 -93
  83. data/lib/openid/kvform.rb +133 -0
  84. data/lib/openid/kvpost.rb +56 -0
  85. data/lib/openid/message.rb +534 -0
  86. data/lib/openid/protocolerror.rb +6 -0
  87. data/lib/openid/server.rb +1215 -666
  88. data/lib/openid/store/filesystem.rb +271 -0
  89. data/lib/openid/store/interface.rb +75 -0
  90. data/lib/openid/store/memory.rb +84 -0
  91. data/lib/openid/store/nonce.rb +68 -0
  92. data/lib/openid/trustroot.rb +314 -87
  93. data/lib/openid/urinorm.rb +37 -34
  94. data/lib/openid/util.rb +42 -220
  95. data/lib/openid/yadis/accept.rb +148 -0
  96. data/lib/openid/yadis/constants.rb +21 -0
  97. data/lib/openid/yadis/discovery.rb +153 -0
  98. data/lib/openid/yadis/filters.rb +205 -0
  99. data/lib/openid/{htmltokenizer.rb → yadis/htmltokenizer.rb} +1 -54
  100. data/lib/openid/yadis/parsehtml.rb +36 -0
  101. data/lib/openid/yadis/services.rb +42 -0
  102. data/lib/openid/yadis/xrds.rb +171 -0
  103. data/lib/openid/yadis/xri.rb +90 -0
  104. data/lib/openid/yadis/xrires.rb +106 -0
  105. data/lib/openid.rb +1 -4
  106. data/test/data/accept.txt +124 -0
  107. data/test/data/dh.txt +29 -0
  108. data/test/data/example-xrds.xml +14 -0
  109. data/test/data/linkparse.txt +587 -0
  110. data/test/data/n2b64 +650 -0
  111. data/test/data/test1-discover.txt +137 -0
  112. data/test/data/test1-parsehtml.txt +128 -0
  113. data/test/data/test_discover/openid.html +11 -0
  114. data/test/data/test_discover/openid2.html +11 -0
  115. data/test/data/test_discover/openid2_xrds.xml +12 -0
  116. data/test/data/test_discover/openid2_xrds_no_local_id.xml +11 -0
  117. data/test/data/test_discover/openid_1_and_2.html +11 -0
  118. data/test/data/test_discover/openid_1_and_2_xrds.xml +16 -0
  119. data/test/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml +17 -0
  120. data/test/data/test_discover/openid_and_yadis.html +12 -0
  121. data/test/data/test_discover/openid_no_delegate.html +10 -0
  122. data/test/data/test_discover/yadis_0entries.xml +12 -0
  123. data/test/data/test_discover/yadis_2_bad_local_id.xml +15 -0
  124. data/test/data/test_discover/yadis_2entries_delegate.xml +22 -0
  125. data/test/data/test_discover/yadis_2entries_idp.xml +21 -0
  126. data/test/data/test_discover/yadis_another_delegate.xml +14 -0
  127. data/test/data/test_discover/yadis_idp.xml +12 -0
  128. data/test/data/test_discover/yadis_idp_delegate.xml +13 -0
  129. data/test/data/test_discover/yadis_no_delegate.xml +11 -0
  130. data/test/data/test_xrds/=j3h.2007.11.14.xrds +25 -0
  131. data/test/data/test_xrds/README +12 -0
  132. data/test/data/test_xrds/delegated-20060809-r1.xrds +34 -0
  133. data/test/data/test_xrds/delegated-20060809-r2.xrds +34 -0
  134. data/test/data/test_xrds/delegated-20060809.xrds +34 -0
  135. data/test/data/test_xrds/no-xrd.xml +7 -0
  136. data/test/data/test_xrds/not-xrds.xml +2 -0
  137. data/test/data/test_xrds/prefixsometimes.xrds +34 -0
  138. data/test/data/test_xrds/ref.xrds +109 -0
  139. data/test/data/test_xrds/sometimesprefix.xrds +34 -0
  140. data/test/data/test_xrds/spoof1.xrds +25 -0
  141. data/test/data/test_xrds/spoof2.xrds +25 -0
  142. data/test/data/test_xrds/spoof3.xrds +37 -0
  143. data/test/data/test_xrds/status222.xrds +9 -0
  144. data/test/data/test_xrds/valid-populated-xrds.xml +39 -0
  145. data/test/data/trustroot.txt +147 -0
  146. data/test/discoverdata.rb +131 -0
  147. data/test/test_accept.rb +170 -0
  148. data/test/test_association.rb +266 -0
  149. data/test/test_associationmanager.rb +899 -0
  150. data/test/test_ax.rb +587 -0
  151. data/test/test_checkid_request.rb +297 -0
  152. data/test/test_consumer.rb +257 -0
  153. data/test/test_cryptutil.rb +117 -0
  154. data/test/test_dh.rb +86 -0
  155. data/test/test_discover.rb +772 -0
  156. data/test/test_discovery_manager.rb +262 -0
  157. data/test/test_extras.rb +35 -0
  158. data/test/test_fetchers.rb +472 -0
  159. data/test/test_filters.rb +270 -0
  160. data/test/test_idres.rb +816 -0
  161. data/test/test_kvform.rb +165 -0
  162. data/test/test_kvpost.rb +65 -0
  163. data/test/test_linkparse.rb +101 -0
  164. data/test/test_message.rb +1058 -0
  165. data/test/test_nonce.rb +89 -0
  166. data/test/test_openid_yadis.rb +178 -0
  167. data/test/test_pape.rb +233 -0
  168. data/test/test_parsehtml.rb +80 -0
  169. data/test/test_responses.rb +63 -0
  170. data/test/test_server.rb +2270 -0
  171. data/test/test_sreg.rb +479 -0
  172. data/test/test_stores.rb +269 -0
  173. data/test/test_trustroot.rb +112 -0
  174. data/test/{urinorm.rb → test_urinorm.rb} +6 -3
  175. data/test/test_util.rb +144 -0
  176. data/test/test_xrds.rb +160 -0
  177. data/test/test_xri.rb +48 -0
  178. data/test/test_xrires.rb +63 -0
  179. data/test/test_yadis_discovery.rb +207 -0
  180. data/test/testutil.rb +116 -0
  181. data/test/util.rb +47 -50
  182. metadata +233 -143
  183. data/examples/consumer.rb +0 -290
  184. data/examples/rails_openid_login_generator/openid_login_generator-0.1.gem +0 -0
  185. data/examples/rails_server/app/controllers/server_controller.rb +0 -190
  186. data/examples/rails_server/app/views/server/decide.rhtml +0 -11
  187. data/examples/rails_server/public/images/rails.png +0 -0
  188. data/lib/hmac-md5.rb +0 -11
  189. data/lib/hmac-rmd160.rb +0 -11
  190. data/lib/openid/discovery.rb +0 -122
  191. data/lib/openid/filestore.rb +0 -315
  192. data/lib/openid/parse.rb +0 -23
  193. data/lib/openid/service.rb +0 -147
  194. data/lib/openid/stores.rb +0 -178
  195. data/test/assoc.rb +0 -38
  196. data/test/consumer.rb +0 -376
  197. data/test/data/brian.xrds +0 -16
  198. data/test/data/brianellin.mylid.xrds +0 -42
  199. data/test/dh.rb +0 -20
  200. data/test/extensions.rb +0 -30
  201. data/test/linkparse.rb +0 -305
  202. data/test/runtests.rb +0 -22
  203. data/test/server2.rb +0 -1053
  204. data/test/service.rb +0 -47
  205. data/test/storetestcase.rb +0 -172
  206. data/test/teststore.rb +0 -47
  207. data/test/trustroot.rb +0 -117
@@ -4,46 +4,43 @@ RAILS_ENV = "test"
4
4
  require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
5
5
 
6
6
  module StoreTestCase
7
-
8
7
  @@allowed_handle = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
9
8
  @@allowed_nonce = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
10
-
9
+
11
10
  def _gen_nonce
12
- OpenID::Util.random_string(8, @@allowed_nonce)
11
+ OpenID::CryptUtil.random_string(8, @@allowed_nonce)
13
12
  end
14
13
 
15
14
  def _gen_handle(n)
16
- OpenID::Util.random_string(n, @@allowed_handle)
15
+ OpenID::CryptUtil.random_string(n, @@allowed_handle)
17
16
  end
18
17
 
19
18
  def _gen_secret(n, chars=nil)
20
- OpenID::Util.random_string(n, chars)
19
+ OpenID::CryptUtil.random_string(n, chars)
21
20
  end
22
21
 
23
22
  def _gen_assoc(issued, lifetime=600)
24
23
  secret = _gen_secret(20)
25
24
  handle = _gen_handle(128)
26
- OpenID::Association.new(handle, secret, Time.now.to_i + issued, lifetime,
25
+ OpenID::Association.new(handle, secret, Time.now + issued, lifetime,
27
26
  'HMAC-SHA1')
28
27
  end
29
-
28
+
30
29
  def _check_retrieve(url, handle=nil, expected=nil)
31
30
  ret_assoc = @store.get_association(url, handle)
32
31
 
33
- if expected.nil? or @store.dumb?
32
+ if expected.nil?
34
33
  assert_nil(ret_assoc)
35
34
  else
36
- assert_equal(ret_assoc, expected)
37
- assert_equal(ret_assoc.handle, expected.handle)
38
- assert_equal(ret_assoc.secret, expected.secret)
35
+ assert_equal(expected, ret_assoc)
36
+ assert_equal(expected.handle, ret_assoc.handle)
37
+ assert_equal(expected.secret, ret_assoc.secret)
39
38
  end
40
39
  end
41
40
 
42
41
  def _check_remove(url, handle, expected)
43
42
  present = @store.remove_association(url, handle)
44
- expected_present = ((not @store.dumb?) and expected)
45
- assert ((not expected_present and not present) or \
46
- (expected_present and present))
43
+ assert_equal(expected, present)
47
44
  end
48
45
 
49
46
  def test_store
@@ -132,50 +129,83 @@ module StoreTestCase
132
129
  _check_remove(server_url, assoc2.handle, false)
133
130
  _check_remove(server_url, assoc.handle, false)
134
131
  _check_remove(server_url, assoc3.handle, false)
132
+
133
+ assocValid1 = _gen_assoc(-3600, 7200)
134
+ assocValid2 = _gen_assoc(-5)
135
+ assocExpired1 = _gen_assoc(-7200, 3600)
136
+ assocExpired2 = _gen_assoc(-7200, 3600)
137
+
138
+ @store.cleanup_associations
139
+ @store.store_association(server_url + '1', assocValid1)
140
+ @store.store_association(server_url + '1', assocExpired1)
141
+ @store.store_association(server_url + '2', assocExpired2)
142
+ @store.store_association(server_url + '3', assocValid2)
143
+
144
+ cleaned = @store.cleanup_associations()
145
+ assert_equal(2, cleaned, "cleaned up associations")
135
146
  end
136
-
147
+
148
+ def _check_use_nonce(nonce, expected, server_url, msg='')
149
+ stamp, salt = OpenID::Nonce::split_nonce(nonce)
150
+ actual = @store.use_nonce(server_url, stamp, salt)
151
+ assert_equal(expected, actual, msg)
152
+ end
153
+
137
154
  def test_nonce
138
- nonce1 = _gen_nonce
139
-
140
- assert_not_nil(nonce1)
141
-
142
- # a nonce is present by default
143
- present = @store.use_nonce(nonce1)
144
- assert_equal(present, false)
145
-
146
- # Storing once causes use_nonce to return true the first, and only
147
- # the first, time it is called after the store.
148
- @store.store_nonce(nonce1)
149
- present = @store.use_nonce(nonce1)
150
- assert present
151
- present = @store.use_nonce(nonce1)
152
- assert_equal(present, false)
153
-
154
- # Storing twice has the same effect as storing once.
155
- @store.store_nonce(nonce1)
156
- @store.store_nonce(nonce1)
157
- present = @store.use_nonce(nonce1)
158
- assert present
159
- present = @store.use_nonce(nonce1)
160
- assert_equal(present, false)
161
-
162
- ### Auth key stuff
163
-
164
- # there is no key to start with, so generate a new key and return it
165
- key = @store.get_auth_key
155
+ server_url = "http://www.myopenid.com/openid"
156
+ [server_url, ''].each{|url|
157
+ nonce1 = OpenID::Nonce::mk_nonce
158
+
159
+ _check_use_nonce(nonce1, true, url, "#{url}: nonce allowed by default")
160
+ _check_use_nonce(nonce1, false, url, "#{url}: nonce not allowed twice")
161
+ _check_use_nonce(nonce1, false, url, "#{url}: nonce not allowed third time")
162
+
163
+ # old nonces shouldn't pass
164
+ old_nonce = OpenID::Nonce::mk_nonce(3600)
165
+ _check_use_nonce(old_nonce, false, url, "Old nonce #{old_nonce.inspect} passed")
166
+
167
+ }
168
+
169
+ now = Time.now.to_i
170
+ old_nonce1 = OpenID::Nonce::mk_nonce(now - 20000)
171
+ old_nonce2 = OpenID::Nonce::mk_nonce(now - 10000)
172
+ recent_nonce = OpenID::Nonce::mk_nonce(now - 600)
173
+
174
+ orig_skew = OpenID::Nonce.skew
175
+ OpenID::Nonce.skew = 0
176
+ count = @store.cleanup_nonces
177
+ OpenID::Nonce.skew = 1000000
178
+ ts, salt = OpenID::Nonce::split_nonce(old_nonce1)
179
+ assert(@store.use_nonce(server_url, ts, salt), "oldnonce1")
180
+ ts, salt = OpenID::Nonce::split_nonce(old_nonce2)
181
+ assert(@store.use_nonce(server_url, ts, salt), "oldnonce2")
182
+ ts, salt = OpenID::Nonce::split_nonce(recent_nonce)
183
+ assert(@store.use_nonce(server_url, ts, salt), "recent_nonce")
184
+
166
185
 
167
- # the second time we should return the same key as before
168
- key2 = @store.get_auth_key
169
- assert key == key2
186
+ OpenID::Nonce.skew = 1000
187
+ cleaned = @store.cleanup_nonces
188
+ assert_equal(2, cleaned, "Cleaned #{cleaned} nonces")
189
+
190
+ OpenID::Nonce.skew = 100000
191
+ ts, salt = OpenID::Nonce::split_nonce(old_nonce1)
192
+ assert(@store.use_nonce(server_url, ts, salt), "oldnonce1 after cleanup")
193
+ ts, salt = OpenID::Nonce::split_nonce(old_nonce2)
194
+ assert(@store.use_nonce(server_url, ts, salt), "oldnonce2 after cleanup")
195
+ ts, salt = OpenID::Nonce::split_nonce(recent_nonce)
196
+ assert(!@store.use_nonce(server_url, ts, salt), "recent_nonce after cleanup")
197
+
198
+ OpenID::Nonce.skew = orig_skew
199
+
170
200
  end
171
-
172
201
  end
173
202
 
203
+
174
204
  class TestARStore < Test::Unit::TestCase
175
205
  include StoreTestCase
176
206
 
177
207
  def setup
178
- @store = ActiveRecordOpenIDStore.new
208
+ @store = ActiveRecordStore.new
179
209
  end
180
210
 
181
211
  end
data/examples/discover ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+ require "openid/consumer/discovery"
3
+
4
+ $names = [[:server_url, "Server URL "],
5
+ [:local_id, "Local ID "],
6
+ [:canonical_id, "Canonical ID"],
7
+ ]
8
+
9
+ def show_services(user_input, normalized, services)
10
+ puts " Claimed identifier: #{normalized}"
11
+ if services.empty?
12
+ puts " No OpenID services found"
13
+ puts
14
+ else
15
+ puts " Discovered services:"
16
+ n = 0
17
+ services.each do |service|
18
+ n += 1
19
+ puts " #{n}."
20
+ $names.each do |meth, name|
21
+ val = service.send(meth)
22
+ if val
23
+ printf(" %s: %s\n", name, val)
24
+ end
25
+ end
26
+ puts " Type URIs:"
27
+ for type_uri in service.type_uris
28
+ puts " * #{type_uri}"
29
+ end
30
+ puts
31
+ end
32
+ end
33
+ end
34
+
35
+ ARGV.each do |openid_identifier|
36
+ puts "=" * 50
37
+ puts "Running discovery on #{openid_identifier}"
38
+ begin
39
+ normalized_identifier, services = OpenID.discover(openid_identifier)
40
+ rescue OpenID::Yadis::DiscoveryFailure => why
41
+ puts "Discovery failed: #{why.message}"
42
+ puts
43
+ else
44
+ show_services(openid_identifier, normalized_identifier, services)
45
+ end
46
+ end
File without changes
File without changes
@@ -0,0 +1,115 @@
1
+ require 'pathname'
2
+
3
+ require "openid"
4
+ require 'openid/extensions/sreg'
5
+ require 'openid/extensions/pape'
6
+ require 'openid/store/filesystem'
7
+
8
+ class ConsumerController < ApplicationController
9
+ layout nil
10
+
11
+ def index
12
+ # render an openid form
13
+ end
14
+
15
+ def start
16
+ begin
17
+ oidreq = consumer.begin(params[:openid_identifier])
18
+ rescue OpenID::OpenIDError => e
19
+ flash[:error] = "Discovery failed for #{params[:openid_identifier]}: #{e}"
20
+ redirect_to :action => 'index'
21
+ return
22
+ end
23
+ if params[:use_sreg]
24
+ sregreq = OpenID::SReg::Request.new
25
+ # required fields
26
+ sregreq.request_fields(['email','nickname'], true)
27
+ # optional fields
28
+ sregreq.request_fields(['dob', 'fullname'], false)
29
+ oidreq.add_extension(sregreq)
30
+ oidreq.return_to_args['did_sreg'] = 'y'
31
+ end
32
+ if params[:use_pape]
33
+ papereq = OpenID::PAPE::Request.new
34
+ papereq.add_policy_uri(OpenID::PAPE::AUTH_PHISHING_RESISTANT)
35
+ papereq.max_auth_age = 2*60*60
36
+ oidreq.add_extension(papereq)
37
+ oidreq.return_to_args['did_pape'] = 'y'
38
+ end
39
+ if params[:force_post]
40
+ oidreq.return_to_args['force_post']='x'*2048
41
+ end
42
+ return_to = url_for :action => 'complete', :only_path => false
43
+ realm = url_for :action => 'index', :only_path => false
44
+
45
+ if oidreq.send_redirect?(realm, return_to, params[:immediate])
46
+ redirect_to oidreq.redirect_url(realm, return_to, params[:immediate])
47
+ else
48
+ @form_text = oidreq.form_markup(realm, return_to, params[:immediate], {'id' => 'openid_form'})
49
+ end
50
+ end
51
+
52
+ def complete
53
+ return_to = url_for(:action => 'complete', :only_path => false)
54
+ parameters = params.reject{|k,v|request.path_parameters[k]}
55
+ oidresp = consumer.complete(parameters, return_to)
56
+ case oidresp.status
57
+ when OpenID::Consumer::FAILURE
58
+ if oidresp.display_identifier
59
+ flash[:error] = ("Verification of #{oidresp.display_identifier}"\
60
+ " failed: #{oidresp.message}")
61
+ else
62
+ flash[:error] = "Verification failed: #{oidresp.message}"
63
+ end
64
+ when OpenID::Consumer::SUCCESS
65
+ flash[:success] = ("Verification of #{oidresp.display_identifier}"\
66
+ " succeeded.")
67
+ if params[:did_sreg]
68
+ sreg_resp = OpenID::SReg::Response.from_success_response(oidresp)
69
+ sreg_message = "Simple Registration data was requested"
70
+ if sreg_resp.empty?
71
+ sreg_message << ", but none was returned."
72
+ else
73
+ sreg_message << ". The following data were sent:"
74
+ sreg_resp.data.each {|k,v|
75
+ sreg_message << "<br/><b>#{k}</b>: #{v}"
76
+ }
77
+ end
78
+ flash[:sreg_results] = sreg_message
79
+ end
80
+ if params[:did_pape]
81
+ pape_resp = OpenID::PAPE::Response.from_success_response(oidresp)
82
+ pape_message = "A phishing resistant authentication method was requested"
83
+ if pape_resp.auth_policies.member? OpenID::PAPE::AUTH_PHISHING_RESISTANT
84
+ pape_message << ", and the server reported one."
85
+ else
86
+ pape_message << ", but the server did not report one."
87
+ end
88
+ if pape_resp.auth_age
89
+ pape_message << "<br><b>Authentication age:</b> #{pape_resp.auth_age} seconds"
90
+ end
91
+ if pape_resp.nist_auth_level
92
+ pape_message << "<br><b>NIST Auth Level:</b> #{pape_resp.nist_auth_level}"
93
+ end
94
+ flash[:pape_results] = pape_message
95
+ end
96
+ when OpenID::Consumer::SETUP_NEEDED
97
+ flash[:alert] = "Immediate request failed - Setup Needed"
98
+ when OpenID::Consumer::CANCEL
99
+ flash[:alert] = "OpenID transaction cancelled."
100
+ else
101
+ end
102
+ redirect_to :action => 'index'
103
+ end
104
+
105
+ private
106
+
107
+ def consumer
108
+ if @consumer.nil?
109
+ dir = Pathname.new(RAILS_ROOT).join('db').join('cstore')
110
+ store = OpenID::Store::Filesystem.new(dir)
111
+ @consumer = OpenID::Consumer.new(session, store)
112
+ end
113
+ return @consumer
114
+ end
115
+ end
@@ -5,19 +5,27 @@ class LoginController < ApplicationController
5
5
 
6
6
  layout 'server'
7
7
 
8
+ def base_url
9
+ url_for(:controller => 'login', :action => nil, :only_path => false)
10
+ end
11
+
8
12
  def index
13
+ response.headers['X-XRDS-Location'] = url_for(:controller => "server",
14
+ :action => "idp_xrds",
15
+ :only_path => false)
16
+ @base_url = base_url
9
17
  # just show the login page
10
18
  end
11
19
 
12
20
  def submit
13
- user = @params[:username]
21
+ user = params[:username]
14
22
 
15
23
  # if we get a user, log them in by putting their username in
16
24
  # the session hash.
17
25
  unless user.nil?
18
26
  session[:username] = user unless user.nil?
19
27
  session[:approvals] = []
20
- flash[:notice] = "Your OpenID URL is <b>http://localhost:3000/user/#{user}</b><br/><br/>Proceed to step 2 below."
28
+ flash[:notice] = "Your OpenID URL is <b>#{base_url}user/#{user}</b><br/><br/>Proceed to step 2 below."
21
29
  else
22
30
  flash[:error] = "Sorry, couldn't log you in. Try again."
23
31
  end
@@ -0,0 +1,265 @@
1
+ require 'pathname'
2
+
3
+ # load the openid library, first trying rubygems
4
+ #begin
5
+ # require "rubygems"
6
+ # require_gem "ruby-openid", ">= 1.0"
7
+ #rescue LoadError
8
+ require "openid"
9
+ require "openid/consumer/discovery"
10
+ require 'openid/extensions/sreg'
11
+ require 'openid/extensions/pape'
12
+ require 'openid/store/filesystem'
13
+ #end
14
+
15
+ class ServerController < ApplicationController
16
+
17
+ include ServerHelper
18
+ include OpenID::Server
19
+ layout nil
20
+
21
+ def index
22
+ begin
23
+ oidreq = server.decode_request(params)
24
+ rescue ProtocolError => e
25
+ # invalid openid request, so just display a page with an error message
26
+ render_text e.to_s
27
+ return
28
+ end
29
+
30
+ # no openid.mode was given
31
+ unless oidreq
32
+ render_text "This is an OpenID server endpoint."
33
+ return
34
+ end
35
+
36
+ oidresp = nil
37
+
38
+ if oidreq.kind_of?(CheckIDRequest)
39
+
40
+ identity = oidreq.identity
41
+
42
+ if oidreq.id_select
43
+ if oidreq.immediate
44
+ oidresp = oidreq.answer(false)
45
+ elsif session[:username].nil?
46
+ # The user hasn't logged in.
47
+ show_decision_page(oidreq)
48
+ return
49
+ else
50
+ # Else, set the identity to the one the user is using.
51
+ identity = url_for_user
52
+ end
53
+ end
54
+
55
+ if oidresp
56
+ nil
57
+ elsif self.is_authorized(identity, oidreq.trust_root)
58
+ oidresp = oidreq.answer(true, nil, identity)
59
+
60
+ # add the sreg response if requested
61
+ add_sreg(oidreq, oidresp)
62
+ # ditto pape
63
+ add_pape(oidreq, oidresp)
64
+
65
+ elsif oidreq.immediate
66
+ server_url = url_for :action => 'index'
67
+ oidresp = oidreq.answer(false, server_url)
68
+
69
+ else
70
+ show_decision_page(oidreq)
71
+ return
72
+ end
73
+
74
+ else
75
+ oidresp = server.handle_request(oidreq)
76
+ end
77
+
78
+ self.render_response(oidresp)
79
+ end
80
+
81
+ def show_decision_page(oidreq, message="Do you trust this site with your identity?")
82
+ session[:last_oidreq] = oidreq
83
+ @oidreq = oidreq
84
+
85
+ if message
86
+ flash[:notice] = message
87
+ end
88
+
89
+ render :template => 'server/decide', :layout => 'server'
90
+ end
91
+
92
+ def user_page
93
+ # Yadis content-negotiation: we want to return the xrds if asked for.
94
+ accept = request.env['HTTP_ACCEPT']
95
+
96
+ # This is not technically correct, and should eventually be updated
97
+ # to do real Accept header parsing and logic. Though I expect it will work
98
+ # 99% of the time.
99
+ if accept and accept.include?('application/xrds+xml')
100
+ user_xrds
101
+ return
102
+ end
103
+
104
+ # content negotiation failed, so just render the user page
105
+ xrds_url = url_for(:controller=>'user',:action=>params[:username])+'/xrds'
106
+ identity_page = <<EOS
107
+ <html><head>
108
+ <meta http-equiv="X-XRDS-Location" content="#{xrds_url}" />
109
+ <link rel="openid.server" href="#{url_for :action => 'index'}" />
110
+ </head><body><p>OpenID identity page for #{params[:username]}</p>
111
+ </body></html>
112
+ EOS
113
+
114
+ # Also add the Yadis location header, so that they don't have
115
+ # to parse the html unless absolutely necessary.
116
+ response.headers['X-XRDS-Location'] = xrds_url
117
+ render_text identity_page
118
+ end
119
+
120
+ def user_xrds
121
+ types = [
122
+ OpenID::OPENID_2_0_TYPE,
123
+ OpenID::OPENID_1_0_TYPE,
124
+ OpenID::SREG_URI,
125
+ ]
126
+
127
+ render_xrds(types)
128
+ end
129
+
130
+ def idp_xrds
131
+ types = [
132
+ OpenID::OPENID_IDP_2_0_TYPE,
133
+ ]
134
+
135
+ render_xrds(types)
136
+ end
137
+
138
+ def decision
139
+ oidreq = session[:last_oidreq]
140
+ session[:last_oidreq] = nil
141
+
142
+ if params[:yes].nil?
143
+ redirect_to oidreq.cancel_url
144
+ return
145
+ else
146
+ id_to_send = params[:id_to_send]
147
+
148
+ identity = oidreq.identity
149
+ if oidreq.id_select
150
+ if id_to_send and id_to_send != ""
151
+ session[:username] = id_to_send
152
+ session[:approvals] = []
153
+ identity = url_for_user
154
+ else
155
+ msg = "You must enter a username to in order to send " +
156
+ "an identifier to the Relying Party."
157
+ show_decision_page(oidreq, msg)
158
+ return
159
+ end
160
+ end
161
+
162
+ if session[:approvals]
163
+ session[:approvals] << oidreq.trust_root
164
+ else
165
+ session[:approvals] = [oidreq.trust_root]
166
+ end
167
+ oidresp = oidreq.answer(true, nil, identity)
168
+ add_sreg(oidreq, oidresp)
169
+ add_pape(oidreq, oidresp)
170
+ return self.render_response(oidresp)
171
+ end
172
+ end
173
+
174
+ protected
175
+
176
+ def server
177
+ if @server.nil?
178
+ server_url = url_for :action => 'index', :only_path => false
179
+ dir = Pathname.new(RAILS_ROOT).join('db').join('openid-store')
180
+ store = OpenID::Store::Filesystem.new(dir)
181
+ @server = Server.new(store, server_url)
182
+ end
183
+ return @server
184
+ end
185
+
186
+ def approved(trust_root)
187
+ return false if session[:approvals].nil?
188
+ return session[:approvals].member?(trust_root)
189
+ end
190
+
191
+ def is_authorized(identity_url, trust_root)
192
+ return (session[:username] and (identity_url == url_for_user) and self.approved(trust_root))
193
+ end
194
+
195
+ def render_xrds(types)
196
+ type_str = ""
197
+
198
+ types.each { |uri|
199
+ type_str += "<Type>#{uri}</Type>\n "
200
+ }
201
+
202
+ yadis = <<EOS
203
+ <?xml version="1.0" encoding="UTF-8"?>
204
+ <xrds:XRDS
205
+ xmlns:xrds="xri://$xrds"
206
+ xmlns="xri://$xrd*($v*2.0)">
207
+ <XRD>
208
+ <Service priority="0">
209
+ #{type_str}
210
+ <URI>#{url_for(:controller => 'server', :only_path => false)}</URI>
211
+ </Service>
212
+ </XRD>
213
+ </xrds:XRDS>
214
+ EOS
215
+
216
+ response.headers['content-type'] = 'application/xrds+xml'
217
+ render_text yadis
218
+ end
219
+
220
+ def add_sreg(oidreq, oidresp)
221
+ # check for Simple Registration arguments and respond
222
+ sregreq = OpenID::SReg::Request.from_openid_request(oidreq)
223
+
224
+ return if sregreq.nil?
225
+ # In a real application, this data would be user-specific,
226
+ # and the user should be asked for permission to release
227
+ # it.
228
+ sreg_data = {
229
+ 'nickname' => session[:username],
230
+ 'fullname' => 'Mayor McCheese',
231
+ 'email' => 'mayor@example.com'
232
+ }
233
+
234
+ sregresp = OpenID::SReg::Response.extract_response(sregreq, sreg_data)
235
+ oidresp.add_extension(sregresp)
236
+ end
237
+
238
+ def add_pape(oidreq, oidresp)
239
+ papereq = OpenID::PAPE::Request.from_openid_request(oidreq)
240
+ return if papereq.nil?
241
+ paperesp = OpenID::PAPE::Response.new
242
+ paperesp.nist_auth_level = 0 # we don't even do auth at all!
243
+ oidresp.add_extension(paperesp)
244
+ end
245
+
246
+ def render_response(oidresp)
247
+ if oidresp.needs_signing
248
+ signed_response = server.signatory.sign(oidresp)
249
+ end
250
+ web_response = server.encode_response(oidresp)
251
+
252
+ case web_response.code
253
+ when HTTP_OK
254
+ render :text => web_response.body, :status => 200
255
+
256
+ when HTTP_REDIRECT
257
+ redirect_to web_response.headers['location']
258
+
259
+ else
260
+ render :text => web_response.body, :status => 400
261
+ end
262
+ end
263
+
264
+
265
+ end