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
@@ -0,0 +1,81 @@
1
+ <html>
2
+ <head>
3
+ <title>Rails OpenID Example Consumer</title>
4
+ </head>
5
+ <style type="text/css">
6
+ * {
7
+ font-family: verdana,sans-serif;
8
+ }
9
+ body {
10
+ width: 50em;
11
+ margin: 1em;
12
+ }
13
+ div {
14
+ padding: .5em;
15
+ }
16
+ .alert {
17
+ border: 1px solid #e7dc2b;
18
+ background: #fff888;
19
+ }
20
+ .error {
21
+ border: 1px solid #ff0000;
22
+ background: #ffaaaa;
23
+ }
24
+ .success {
25
+ border: 1px solid #00ff00;
26
+ background: #aaffaa;
27
+ }
28
+ #verify-form {
29
+ border: 1px solid #777777;
30
+ background: #dddddd;
31
+ margin-top: 1em;
32
+ padding-bottom: 0em;
33
+ }
34
+ input.openid {
35
+ background: url( /images/openid_login_bg.gif ) no-repeat;
36
+ background-position: 0 50%;
37
+ background-color: #fff;
38
+ padding-left: 18px;
39
+ }
40
+ </style>
41
+ <body>
42
+ <h1>Rails OpenID Example Consumer</h1>
43
+ <% if flash[:alert] %>
44
+ <div class='alert'>
45
+ <%= h(flash[:alert]) %>
46
+ </div>
47
+ <% end %>
48
+ <% if flash[:error] %>
49
+ <div class='error'>
50
+ <%= h(flash[:error]) %>
51
+ </div>
52
+ <% end %>
53
+ <% if flash[:success] %>
54
+ <div class='success'>
55
+ <%= h(flash[:success]) %>
56
+ </div>
57
+ <% end %>
58
+ <% if flash[:sreg_results] %>
59
+ <div class='alert'>
60
+ <%= flash[:sreg_results] %>
61
+ </div>
62
+ <% end %>
63
+ <% if flash[:pape_results] %>
64
+ <div class='alert'>
65
+ <%= flash[:pape_results] %>
66
+ </div>
67
+ <% end %>
68
+ <div id="verify-form">
69
+ <form method="get" accept-charset="UTF-8"
70
+ action='<%= url_for :action => 'start' %>'>
71
+ Identifier:
72
+ <input type="text" class="openid" name="openid_identifier" />
73
+ <input type="submit" value="Verify" /><br />
74
+ <input type="checkbox" name="immediate" id="immediate" /><label for="immediate">Use immediate mode</label><br/>
75
+ <input type="checkbox" name="use_sreg" id="use_sreg" /><label for="use_sreg">Request registration data</label><br/>
76
+ <input type="checkbox" name="use_pape" id="use_pape" /><label for="use_pape">Request phishing-resistent auth policy (PAPE)</label><br/>
77
+ <input type="checkbox" name="force_post" id="force_post" /><label for="force_post">Force the transaction to use POST by adding 2K of extra data</label>
78
+ </form>
79
+ </div>
80
+ </body>
81
+ </html>
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <body>
3
+ <%= @form_text %>
4
+ <script type="text/javascript">
5
+ document.getElementById('openid_form').submit();
6
+ </script>
7
+ </body>
8
+ </html>
@@ -20,7 +20,7 @@ Welcome to the Ruby OpenID server example. This code is a starting point for de
20
20
  <h2>To use the example</h2>
21
21
  <p>
22
22
  <ol>
23
- <li>Enter a username in the form above. You will be "Logged In" to the server, at which point you may authenticate using an OpenID consumer. Your OpenID URL will be displayed after you log in.<p>The server will automatically create an identity page for you at http://localhost:3000/user/<i>name</i></p></li>
23
+ <li>Enter a username in the form above. You will be "Logged In" to the server, at which point you may authenticate using an OpenID consumer. Your OpenID URL will be displayed after you log in.<p>The server will automatically create an identity page for you at <%= @base_url %>user/<i>name</i></p></li>
24
24
  <li>Run the example OpenID consumer: <blockquote>ruby examples/consumer.rb</blockquote></li>
25
25
  <li>In another browser window visit <a href="http://localhost:2000/">http://localhost:2000/</a>, and type your OpenID URL to verfiy your identity with this server.</li>
26
26
  </ol>
@@ -0,0 +1,26 @@
1
+ <form method="post" action="<%= url_for :controller => 'server', :action => 'decision' %>">
2
+
3
+ <table>
4
+ <tr><td>Site:</td><td><%= @oidreq.trust_root %></td></tr>
5
+
6
+ <% if @oidreq.id_select %>
7
+ <tr>
8
+ <td colspan="2">
9
+ You entered the server identifier at the relying party.
10
+ You'll need to send an identifier of your choosing. Enter a
11
+ username below.
12
+ </td>
13
+ </tr>
14
+ <tr>
15
+ <td>Identity to send:</td>
16
+ <td><input type="text" name="id_to_send" size="25" /></td>
17
+ </tr>
18
+ <% else %>
19
+ <tr><td>Identity:</td><td><%= @oidreq.identity %></td></tr>
20
+ <% end %>
21
+ </table>
22
+
23
+ <input type="submit" name="yes" value="yes" />
24
+ <input type="submit" name="no" value="no" />
25
+
26
+ </form>
@@ -11,8 +11,9 @@ ActionController::Routing::Routes.draw do |map|
11
11
  # map.connect '', :controller => "welcome"
12
12
 
13
13
  map.connect '', :controller => 'login'
14
+ map.connect 'server/xrds', :controller => 'server', :action => 'idp_xrds'
14
15
  map.connect 'user/:username', :controller => 'server', :action => 'user_page'
15
- map.connect 'user/:username/xrds', :controller => 'server', :action => 'xrds'
16
+ map.connect 'user/:username/xrds', :controller => 'server', :action => 'user_xrds'
16
17
 
17
18
  # Allow downloading Web Service WSDL as a file with an extension
18
19
  # instead of a file named 'wsdl'
File without changes
@@ -1,4 +1,4 @@
1
- require 'hmac'
1
+ require 'hmac/hmac'
2
2
  require 'digest/sha1'
3
3
 
4
4
  module HMAC
@@ -1,4 +1,4 @@
1
- require 'hmac'
1
+ require 'hmac/hmac'
2
2
  require 'digest/sha2'
3
3
 
4
4
  module HMAC
@@ -1,71 +1,57 @@
1
- require 'openid/util'
1
+ require "openid/kvform"
2
+ require "openid/util"
3
+ require "openid/cryptutil"
4
+ require "openid/message"
2
5
 
3
6
  module OpenID
4
7
 
5
- # Represents an "association" between a consumer and server, and
6
- # is also used for storage of the information exchanged
7
- # during the openid.mode='associate' transaction.
8
- # This class is used by the both the server and consumer.
9
- class Association
10
- @@version = '2'
11
- @@assoc_keys = [
12
- 'version',
13
- 'handle',
14
- 'secret',
15
- 'issued',
16
- 'lifetime',
17
- 'assoc_type'
18
- ]
8
+ def self.get_secret_size(assoc_type)
9
+ if assoc_type == 'HMAC-SHA1'
10
+ return 20
11
+ elsif assoc_type == 'HMAC-SHA256'
12
+ return 32
13
+ else
14
+ raise ArgumentError("Unsupported association type: #{assoc_type}")
15
+ end
16
+ end
19
17
 
18
+ # An Association holds the shared secret between a relying party and
19
+ # an OpenID provider.
20
+ class Association
20
21
  attr_reader :handle, :secret, :issued, :lifetime, :assoc_type
21
22
 
22
- def Association.from_expires_in(expires_in, handle, secret, assoc_type)
23
- issued = Time.now.to_i
24
- lifetime = expires_in
25
- new(handle, secret, issued, lifetime, assoc_type)
26
- end
27
-
28
- def Association.serialize(assoc)
29
- data = [
30
- '2',
31
- assoc.handle,
32
- OpenID::Util.to_base64(assoc.secret),
33
- assoc.issued.to_i.to_s,
34
- assoc.lifetime.to_i.to_s,
35
- assoc.assoc_type
36
- ]
37
-
38
- lines = ""
39
- (0...@@assoc_keys.length).collect do |i|
40
- lines += "#{@@assoc_keys[i]}: #{data[i]}\n"
23
+ FIELD_ORDER =
24
+ [:version, :handle, :secret, :issued, :lifetime, :assoc_type,]
25
+
26
+ # Load a serialized Association
27
+ def self.deserialize(serialized)
28
+ parsed = Util.kv_to_seq(serialized)
29
+ parsed_fields = parsed.map{|k, v| k.to_sym}
30
+ if parsed_fields != FIELD_ORDER
31
+ raise StandardError, 'Unexpected fields in serialized association'\
32
+ " (Expected #{FIELD_ORDER.inspect}, got #{parsed_fields.inspect})"
33
+ end
34
+ version, handle, secret64, issued_s, lifetime_s, assoc_type =
35
+ parsed.map {|field, value| value}
36
+ if version != '2'
37
+ raise StandardError, "Attempted to deserialize unsupported version "\
38
+ "(#{parsed[0][1].inspect})"
41
39
  end
42
-
43
- lines
40
+
41
+ self.new(handle,
42
+ Util.from_base64(secret64),
43
+ Time.at(issued_s.to_i),
44
+ lifetime_s.to_i,
45
+ assoc_type)
44
46
  end
45
47
 
46
- def Association.deserialize(assoc_s)
47
- keys = []
48
- values = []
49
- assoc_s.split("\n").each do |line|
50
- k, v = line.split(":", 2)
51
- keys << k.strip
52
- values << v.strip
53
- end
54
-
55
- version, handle, secret, issued, lifetime, assoc_type = values
56
- raise 'VersionError' if version != @@version
57
-
58
- secret = OpenID::Util.from_base64(secret)
59
- issued = issued.to_i
60
- lifetime = lifetime.to_i
61
- Association.new(handle, secret, issued, lifetime, assoc_type)
48
+ # Create an Association with an issued time of now
49
+ def self.from_expires_in(expires_in, handle, secret, assoc_type)
50
+ issued = Time.now
51
+ self.new(handle, secret, issued, expires_in, assoc_type)
62
52
  end
63
53
 
64
54
  def initialize(handle, secret, issued, lifetime, assoc_type)
65
- if assoc_type != 'HMAC-SHA1'
66
- raise ArgumentError, "HMAC-SHA1 is the only supported assoc_type, got #{assoc_type}"
67
- end
68
-
69
55
  @handle = handle
70
56
  @secret = secret
71
57
  @issued = issued
@@ -73,37 +59,191 @@ module OpenID
73
59
  @assoc_type = assoc_type
74
60
  end
75
61
 
76
- def expires_in
77
- [0, @issued + @lifetime - Time.now.to_i].max
62
+ # Serialize the association to a form that's consistent across
63
+ # JanRain OpenID libraries.
64
+ def serialize
65
+ data = {
66
+ :version => '2',
67
+ :handle => handle,
68
+ :secret => Util.to_base64(secret),
69
+ :issued => issued.to_i.to_s,
70
+ :lifetime => lifetime.to_i.to_s,
71
+ :assoc_type => assoc_type,
72
+ }
73
+
74
+ Util.assert(data.length == FIELD_ORDER.length)
75
+
76
+ pairs = FIELD_ORDER.map{|field| [field.to_s, data[field]]}
77
+ return Util.seq_to_kv(pairs, strict=true)
78
78
  end
79
79
 
80
- def expired?
81
- return expires_in == 0
80
+ # The number of seconds until this association expires
81
+ def expires_in(now=nil)
82
+ if now.nil?
83
+ now = Time.now.to_i
84
+ else
85
+ now = now.to_i
86
+ end
87
+ time_diff = (issued.to_i + lifetime) - now
88
+ if time_diff < 0
89
+ return 0
90
+ else
91
+ return time_diff
92
+ end
82
93
  end
83
94
 
95
+ # Generate a signature for a sequence of [key, value] pairs
84
96
  def sign(pairs)
85
- kv = ''
86
- pairs.each {|k,v| kv << "#{k}:#{v}\n"}
87
- return OpenID::Util.hmac_sha1(@secret, kv)
97
+ kv = Util.seq_to_kv(pairs)
98
+ case assoc_type
99
+ when 'HMAC-SHA1'
100
+ CryptUtil.hmac_sha1(@secret, kv)
101
+ when 'HMAC-SHA256'
102
+ CryptUtil.hmac_sha256(@secret, kv)
103
+ else
104
+ raise StandardError, "Association has unknown type: "\
105
+ "#{assoc_type.inspect}"
106
+ end
88
107
  end
89
108
 
90
- def sign_hash(fields, hash, prefix='openid.')
91
- pairs = []
92
- fields.each { |f| pairs << [f, hash[prefix+f]] }
93
- return OpenID::Util.to_base64(sign(pairs))
109
+ # Generate the list of pairs that form the signed elements of the
110
+ # given message
111
+ def make_pairs(message)
112
+ signed = message.get_arg(OPENID_NS, 'signed')
113
+ if signed.nil?
114
+ raise StandardError, 'Missing signed list'
115
+ end
116
+ signed_fields = signed.split(',', -1)
117
+ data = message.to_post_args
118
+ signed_fields.map {|field| [field, data.fetch('openid.'+field,'')] }
94
119
  end
95
120
 
96
- def add_signature(fields, hash, prefix='openid.')
97
- sig = sign_hash(fields, hash, prefix)
98
- signed = fields.join(',')
99
- hash[prefix+'sig'] = sig
100
- hash[prefix+'signed'] = signed
121
+ # Return whether the message's signature passes
122
+ def check_message_signature(message)
123
+ message_sig = message.get_arg(OPENID_NS, 'sig')
124
+ if message_sig.nil?
125
+ raise StandardError, "#{message} has no sig."
126
+ end
127
+ calculated_sig = get_message_signature(message)
128
+ return calculated_sig == message_sig
129
+ end
130
+
131
+ # Get the signature for this message
132
+ def get_message_signature(message)
133
+ Util.to_base64(sign(make_pairs(message)))
101
134
  end
102
135
 
103
136
  def ==(other)
104
- self.instance_variable_hash == other.instance_variable_hash
137
+ (other.class == self.class and
138
+ other.handle == self.handle and
139
+ other.secret == self.secret and
140
+
141
+ # The internals of the time objects seemed to differ
142
+ # in an opaque way when serializing/unserializing.
143
+ # I don't think this will be a problem.
144
+ other.issued.to_i == self.issued.to_i and
145
+
146
+ other.lifetime == self.lifetime and
147
+ other.assoc_type == self.assoc_type)
148
+ end
149
+
150
+ # Add a signature (and a signed list) to a message.
151
+ def sign_message(message)
152
+ if (message.has_key?(OPENID_NS, 'sig') or
153
+ message.has_key?(OPENID_NS, 'signed'))
154
+ raise ArgumentError, 'Message already has signed list or signature'
155
+ end
156
+
157
+ extant_handle = message.get_arg(OPENID_NS, 'assoc_handle')
158
+ if extant_handle and extant_handle != self.handle
159
+ raise ArgumentError, "Message has a different association handle"
160
+ end
161
+
162
+ signed_message = message.copy()
163
+ signed_message.set_arg(OPENID_NS, 'assoc_handle', self.handle)
164
+ message_keys = signed_message.to_post_args.keys()
165
+
166
+ signed_list = []
167
+ message_keys.each { |k|
168
+ if k.starts_with?('openid.')
169
+ signed_list << k[7..-1]
170
+ end
171
+ }
172
+
173
+ signed_list << 'signed'
174
+ signed_list.sort!
175
+
176
+ signed_message.set_arg(OPENID_NS, 'signed', signed_list.join(','))
177
+ sig = get_message_signature(signed_message)
178
+ signed_message.set_arg(OPENID_NS, 'sig', sig)
179
+ return signed_message
180
+ end
181
+ end
182
+
183
+ class AssociationNegotiator
184
+ attr_reader :allowed_types
185
+
186
+ def self.get_session_types(assoc_type)
187
+ case assoc_type
188
+ when 'HMAC-SHA1'
189
+ ['DH-SHA1', 'no-encryption']
190
+ when 'HMAC-SHA256'
191
+ ['DH-SHA256', 'no-encryption']
192
+ else
193
+ raise StandardError, "Unknown association type #{assoc_type.inspect}"
194
+ end
195
+ end
196
+
197
+ def self.check_session_type(assoc_type, session_type)
198
+ if !get_session_types(assoc_type).include?(session_type)
199
+ raise StandardError, "Session type #{session_type.inspect} not "\
200
+ "valid for association type #{assoc_type.inspect}"
201
+ end
202
+ end
203
+
204
+ def initialize(allowed_types)
205
+ self.allowed_types=(allowed_types)
105
206
  end
106
207
 
208
+ def copy
209
+ Marshal.load(Marshal.dump(self))
210
+ end
211
+
212
+ def allowed_types=(allowed_types)
213
+ allowed_types.each do |assoc_type, session_type|
214
+ self.class.check_session_type(assoc_type, session_type)
215
+ end
216
+ @allowed_types = allowed_types
217
+ end
218
+
219
+ def add_allowed_type(assoc_type, session_type=nil)
220
+ if session_type.nil?
221
+ session_types = self.class.get_session_types(assoc_type)
222
+ else
223
+ self.class.check_session_type(assoc_type, session_type)
224
+ session_types = [session_type]
225
+ end
226
+ session_types.each do |session_type|
227
+ @allowed_types << [assoc_type, session_type]
228
+ end
229
+ end
230
+
231
+ def allowed?(assoc_type, session_type)
232
+ @allowed_types.include?([assoc_type, session_type])
233
+ end
234
+
235
+ def get_allowed_type
236
+ @allowed_types.empty? ? nil : @allowed_types[0]
237
+ end
107
238
  end
108
239
 
240
+ DefaultNegotiator =
241
+ AssociationNegotiator.new([['HMAC-SHA1', 'DH-SHA1'],
242
+ ['HMAC-SHA1', 'no-encryption'],
243
+ ['HMAC-SHA256', 'DH-SHA256'],
244
+ ['HMAC-SHA256', 'no-encryption']])
245
+
246
+ EncryptedNegotiator =
247
+ AssociationNegotiator.new([['HMAC-SHA1', 'DH-SHA1'],
248
+ ['HMAC-SHA256', 'DH-SHA256']])
109
249
  end