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.
- data/INSTALL +0 -9
- data/README +21 -22
- data/UPGRADE +117 -0
- data/admin/runtests.rb +36 -0
- data/examples/README +13 -21
- data/examples/active_record_openid_store/README +8 -3
- data/examples/active_record_openid_store/XXX_add_open_id_store_to_db.rb +4 -8
- data/examples/active_record_openid_store/XXX_upgrade_open_id_store.rb +26 -0
- data/examples/active_record_openid_store/lib/association.rb +2 -0
- data/examples/active_record_openid_store/lib/openid_ar_store.rb +22 -47
- data/examples/active_record_openid_store/test/store_test.rb +78 -48
- data/examples/discover +46 -0
- data/examples/{rails_server → rails_openid}/README +0 -0
- data/examples/{rails_server → rails_openid}/Rakefile +0 -0
- data/examples/{rails_server → rails_openid}/app/controllers/application.rb +0 -0
- data/examples/rails_openid/app/controllers/consumer_controller.rb +115 -0
- data/examples/{rails_server → rails_openid}/app/controllers/login_controller.rb +10 -2
- data/examples/rails_openid/app/controllers/server_controller.rb +265 -0
- data/examples/{rails_server → rails_openid}/app/helpers/application_helper.rb +0 -0
- data/examples/{rails_server → rails_openid}/app/helpers/login_helper.rb +0 -0
- data/examples/{rails_server → rails_openid}/app/helpers/server_helper.rb +0 -0
- data/examples/rails_openid/app/views/consumer/index.rhtml +81 -0
- data/examples/rails_openid/app/views/consumer/start.rhtml +8 -0
- data/examples/{rails_server → rails_openid}/app/views/layouts/server.rhtml +0 -0
- data/examples/{rails_server → rails_openid}/app/views/login/index.rhtml +1 -1
- data/examples/rails_openid/app/views/server/decide.rhtml +26 -0
- data/examples/{rails_server → rails_openid}/config/boot.rb +0 -0
- data/examples/{rails_server → rails_openid}/config/database.yml +0 -0
- data/examples/{rails_server → rails_openid}/config/environment.rb +0 -0
- data/examples/{rails_server → rails_openid}/config/environments/development.rb +0 -0
- data/examples/{rails_server → rails_openid}/config/environments/production.rb +0 -0
- data/examples/{rails_server → rails_openid}/config/environments/test.rb +0 -0
- data/examples/{rails_server → rails_openid}/config/routes.rb +2 -1
- data/examples/{rails_server → rails_openid}/doc/README_FOR_APP +0 -0
- data/examples/{rails_server → rails_openid}/public/404.html +0 -0
- data/examples/{rails_server → rails_openid}/public/500.html +0 -0
- data/examples/{rails_server → rails_openid}/public/dispatch.cgi +0 -0
- data/examples/{rails_server → rails_openid}/public/dispatch.fcgi +0 -0
- data/examples/{rails_server → rails_openid}/public/dispatch.rb +0 -0
- data/examples/{rails_server → rails_openid}/public/favicon.ico +0 -0
- data/examples/rails_openid/public/images/openid_login_bg.gif +0 -0
- data/examples/{rails_server → rails_openid}/public/javascripts/controls.js +0 -0
- data/examples/{rails_server → rails_openid}/public/javascripts/dragdrop.js +0 -0
- data/examples/{rails_server → rails_openid}/public/javascripts/effects.js +0 -0
- data/examples/{rails_server → rails_openid}/public/javascripts/prototype.js +0 -0
- data/examples/{rails_server → rails_openid}/public/robots.txt +0 -0
- data/examples/{rails_server → rails_openid}/script/about +0 -0
- data/examples/{rails_server → rails_openid}/script/breakpointer +0 -0
- data/examples/{rails_server → rails_openid}/script/console +0 -0
- data/examples/{rails_server → rails_openid}/script/destroy +0 -0
- data/examples/{rails_server → rails_openid}/script/generate +0 -0
- data/examples/{rails_server → rails_openid}/script/performance/benchmarker +0 -0
- data/examples/{rails_server → rails_openid}/script/performance/profiler +0 -0
- data/examples/{rails_server → rails_openid}/script/plugin +0 -0
- data/examples/{rails_server → rails_openid}/script/process/reaper +0 -0
- data/examples/{rails_server → rails_openid}/script/process/spawner +0 -0
- data/examples/{rails_server → rails_openid}/script/process/spinner +0 -0
- data/examples/{rails_server → rails_openid}/script/runner +0 -0
- data/examples/{rails_server → rails_openid}/script/server +0 -0
- data/examples/{rails_server → rails_openid}/test/functional/login_controller_test.rb +0 -0
- data/examples/{rails_server → rails_openid}/test/functional/server_controller_test.rb +0 -0
- data/examples/{rails_server → rails_openid}/test/test_helper.rb +0 -0
- data/lib/{hmac.rb → hmac/hmac.rb} +0 -0
- data/lib/{hmac-sha1.rb → hmac/sha1.rb} +1 -1
- data/lib/{hmac-sha2.rb → hmac/sha2.rb} +1 -1
- data/lib/openid/association.rb +213 -73
- data/lib/openid/consumer/associationmanager.rb +338 -0
- data/lib/openid/consumer/checkid_request.rb +175 -0
- data/lib/openid/consumer/discovery.rb +480 -0
- data/lib/openid/consumer/discovery_manager.rb +123 -0
- data/lib/openid/consumer/html_parse.rb +136 -0
- data/lib/openid/consumer/idres.rb +525 -0
- data/lib/openid/consumer/responses.rb +133 -0
- data/lib/openid/consumer.rb +280 -807
- data/lib/openid/cryptutil.rb +85 -0
- data/lib/openid/dh.rb +60 -23
- data/lib/openid/extension.rb +31 -0
- data/lib/openid/extensions/ax.rb +506 -0
- data/lib/openid/extensions/pape.rb +182 -0
- data/lib/openid/extensions/sreg.rb +275 -0
- data/lib/openid/extras.rb +11 -0
- data/lib/openid/fetchers.rb +132 -93
- data/lib/openid/kvform.rb +133 -0
- data/lib/openid/kvpost.rb +56 -0
- data/lib/openid/message.rb +534 -0
- data/lib/openid/protocolerror.rb +6 -0
- data/lib/openid/server.rb +1215 -666
- data/lib/openid/store/filesystem.rb +271 -0
- data/lib/openid/store/interface.rb +75 -0
- data/lib/openid/store/memory.rb +84 -0
- data/lib/openid/store/nonce.rb +68 -0
- data/lib/openid/trustroot.rb +314 -87
- data/lib/openid/urinorm.rb +37 -34
- data/lib/openid/util.rb +42 -220
- data/lib/openid/yadis/accept.rb +148 -0
- data/lib/openid/yadis/constants.rb +21 -0
- data/lib/openid/yadis/discovery.rb +153 -0
- data/lib/openid/yadis/filters.rb +205 -0
- data/lib/openid/{htmltokenizer.rb → yadis/htmltokenizer.rb} +1 -54
- data/lib/openid/yadis/parsehtml.rb +36 -0
- data/lib/openid/yadis/services.rb +42 -0
- data/lib/openid/yadis/xrds.rb +171 -0
- data/lib/openid/yadis/xri.rb +90 -0
- data/lib/openid/yadis/xrires.rb +106 -0
- data/lib/openid.rb +1 -4
- data/test/data/accept.txt +124 -0
- data/test/data/dh.txt +29 -0
- data/test/data/example-xrds.xml +14 -0
- data/test/data/linkparse.txt +587 -0
- data/test/data/n2b64 +650 -0
- data/test/data/test1-discover.txt +137 -0
- data/test/data/test1-parsehtml.txt +128 -0
- data/test/data/test_discover/openid.html +11 -0
- data/test/data/test_discover/openid2.html +11 -0
- data/test/data/test_discover/openid2_xrds.xml +12 -0
- data/test/data/test_discover/openid2_xrds_no_local_id.xml +11 -0
- data/test/data/test_discover/openid_1_and_2.html +11 -0
- data/test/data/test_discover/openid_1_and_2_xrds.xml +16 -0
- data/test/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml +17 -0
- data/test/data/test_discover/openid_and_yadis.html +12 -0
- data/test/data/test_discover/openid_no_delegate.html +10 -0
- data/test/data/test_discover/yadis_0entries.xml +12 -0
- data/test/data/test_discover/yadis_2_bad_local_id.xml +15 -0
- data/test/data/test_discover/yadis_2entries_delegate.xml +22 -0
- data/test/data/test_discover/yadis_2entries_idp.xml +21 -0
- data/test/data/test_discover/yadis_another_delegate.xml +14 -0
- data/test/data/test_discover/yadis_idp.xml +12 -0
- data/test/data/test_discover/yadis_idp_delegate.xml +13 -0
- data/test/data/test_discover/yadis_no_delegate.xml +11 -0
- data/test/data/test_xrds/=j3h.2007.11.14.xrds +25 -0
- data/test/data/test_xrds/README +12 -0
- data/test/data/test_xrds/delegated-20060809-r1.xrds +34 -0
- data/test/data/test_xrds/delegated-20060809-r2.xrds +34 -0
- data/test/data/test_xrds/delegated-20060809.xrds +34 -0
- data/test/data/test_xrds/no-xrd.xml +7 -0
- data/test/data/test_xrds/not-xrds.xml +2 -0
- data/test/data/test_xrds/prefixsometimes.xrds +34 -0
- data/test/data/test_xrds/ref.xrds +109 -0
- data/test/data/test_xrds/sometimesprefix.xrds +34 -0
- data/test/data/test_xrds/spoof1.xrds +25 -0
- data/test/data/test_xrds/spoof2.xrds +25 -0
- data/test/data/test_xrds/spoof3.xrds +37 -0
- data/test/data/test_xrds/status222.xrds +9 -0
- data/test/data/test_xrds/valid-populated-xrds.xml +39 -0
- data/test/data/trustroot.txt +147 -0
- data/test/discoverdata.rb +131 -0
- data/test/test_accept.rb +170 -0
- data/test/test_association.rb +266 -0
- data/test/test_associationmanager.rb +899 -0
- data/test/test_ax.rb +587 -0
- data/test/test_checkid_request.rb +297 -0
- data/test/test_consumer.rb +257 -0
- data/test/test_cryptutil.rb +117 -0
- data/test/test_dh.rb +86 -0
- data/test/test_discover.rb +772 -0
- data/test/test_discovery_manager.rb +262 -0
- data/test/test_extras.rb +35 -0
- data/test/test_fetchers.rb +472 -0
- data/test/test_filters.rb +270 -0
- data/test/test_idres.rb +816 -0
- data/test/test_kvform.rb +165 -0
- data/test/test_kvpost.rb +65 -0
- data/test/test_linkparse.rb +101 -0
- data/test/test_message.rb +1058 -0
- data/test/test_nonce.rb +89 -0
- data/test/test_openid_yadis.rb +178 -0
- data/test/test_pape.rb +233 -0
- data/test/test_parsehtml.rb +80 -0
- data/test/test_responses.rb +63 -0
- data/test/test_server.rb +2270 -0
- data/test/test_sreg.rb +479 -0
- data/test/test_stores.rb +269 -0
- data/test/test_trustroot.rb +112 -0
- data/test/{urinorm.rb → test_urinorm.rb} +6 -3
- data/test/test_util.rb +144 -0
- data/test/test_xrds.rb +160 -0
- data/test/test_xri.rb +48 -0
- data/test/test_xrires.rb +63 -0
- data/test/test_yadis_discovery.rb +207 -0
- data/test/testutil.rb +116 -0
- data/test/util.rb +47 -50
- metadata +233 -143
- data/examples/consumer.rb +0 -290
- data/examples/rails_openid_login_generator/openid_login_generator-0.1.gem +0 -0
- data/examples/rails_server/app/controllers/server_controller.rb +0 -190
- data/examples/rails_server/app/views/server/decide.rhtml +0 -11
- data/examples/rails_server/public/images/rails.png +0 -0
- data/lib/hmac-md5.rb +0 -11
- data/lib/hmac-rmd160.rb +0 -11
- data/lib/openid/discovery.rb +0 -122
- data/lib/openid/filestore.rb +0 -315
- data/lib/openid/parse.rb +0 -23
- data/lib/openid/service.rb +0 -147
- data/lib/openid/stores.rb +0 -178
- data/test/assoc.rb +0 -38
- data/test/consumer.rb +0 -376
- data/test/data/brian.xrds +0 -16
- data/test/data/brianellin.mylid.xrds +0 -42
- data/test/dh.rb +0 -20
- data/test/extensions.rb +0 -30
- data/test/linkparse.rb +0 -305
- data/test/runtests.rb +0 -22
- data/test/server2.rb +0 -1053
- data/test/service.rb +0 -47
- data/test/storetestcase.rb +0 -172
- data/test/teststore.rb +0 -47
- 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>
|
|
File without changes
|
|
@@ -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
|
|
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>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -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 => '
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
data/lib/openid/association.rb
CHANGED
|
@@ -1,71 +1,57 @@
|
|
|
1
|
-
require
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
23
|
-
issued
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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
|
-
|
|
81
|
-
|
|
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
|
-
|
|
87
|
-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
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
|