ruby-openid 1.0.2 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ruby-openid might be problematic. Click here for more details.

Files changed (54) hide show
  1. data/examples/cacert.pem +7815 -0
  2. data/examples/consumer.rb +2 -2
  3. data/examples/consumerd.rb +290 -0
  4. data/examples/openid-store/associations/http-localhost_3A3000_2Fserver-LQl7HUNueJIJcpPoAGiHEHNdJMc +6 -0
  5. data/examples/openid-store/associations/http-www.myopenid.com_2Fserver-ZFp96P4qV1FjqgGt2rtZBvRJWic +6 -0
  6. data/examples/openid-store/auth_key +1 -0
  7. data/examples/openid-store/nonces/PNiw86rQ +0 -0
  8. data/examples/openid-store/nonces/hdZo7WC9 +0 -0
  9. data/examples/openid-store/nonces/uHhMdi1i +0 -0
  10. data/examples/rails_openid_login_generator/templates/controller.rb +1 -1
  11. data/examples/rails_server/app/controllers/login_controller.rb~ +35 -0
  12. data/examples/rails_server/app/controllers/server_controller.rb~ +190 -0
  13. data/examples/rails_server/db/openid-store/associations/http-localhost_2F_7Cnormal-YU.tkND1J4fEZhnuAoT5Zc0yCA0 +6 -0
  14. data/examples/rails_server/db/openid-store/associations/http-localhost_2F_7Cnormal-jRS20gc5OzJ5pkpjy9BjqvTj3B0 +6 -0
  15. data/examples/rails_server/log/development.log +6459 -0
  16. data/examples/rails_server/log/production.log +0 -0
  17. data/examples/rails_server/log/server.log +0 -0
  18. data/examples/rails_server/log/test.log +0 -0
  19. data/examples/rails_server/tmp/sessions/ruby_sess.1b2e9635e0f69c0d +0 -0
  20. data/examples/rails_server/tmp/sessions/ruby_sess.1b3584d2b3784c97 +0 -0
  21. data/examples/rails_server/tmp/sessions/ruby_sess.20ed70e0e63d7e31 +0 -0
  22. data/examples/rails_server/tmp/sessions/ruby_sess.30cf5b98539677d5 +0 -0
  23. data/examples/rails_server/tmp/sessions/ruby_sess.3910508c0c857695 +0 -0
  24. data/examples/rails_server/tmp/sessions/ruby_sess.472170ef38098672 +0 -0
  25. data/examples/rails_server/tmp/sessions/ruby_sess.5406e21ba5b1c7bb +0 -0
  26. data/examples/rails_server/tmp/sessions/ruby_sess.5d2bd2b7086f12d5 +0 -0
  27. data/examples/rails_server/tmp/sessions/ruby_sess.968757c6d12af322 +0 -0
  28. data/examples/rails_server/tmp/sessions/ruby_sess.a87a5045744b3abf +0 -0
  29. data/examples/rails_server/tmp/sessions/ruby_sess.ca9f0a416be0be57 +0 -0
  30. data/examples/rails_server/tmp/sessions/ruby_sess.cd269e6040645b5b +0 -0
  31. data/examples/rails_server/tmp/sessions/ruby_sess.cf2acf62b93dbc88 +0 -0
  32. data/examples/rails_server/tmp/sessions/ruby_sess.d2ef8fe29591ef9b +0 -0
  33. data/examples/rails_server/tmp/sessions/ruby_sess.e23240e097e2c83d +0 -0
  34. data/examples/rails_server/tmp/sessions/ruby_sess.fb154d2f7c286aba +0 -0
  35. data/lib/openid/consumer.rb +40 -71
  36. data/lib/openid/discovery.rb +34 -1
  37. data/lib/openid/discovery.rb~ +122 -0
  38. data/lib/openid/fetchers.rb +41 -0
  39. data/lib/openid/server.rb +1 -1
  40. data/lib/openid/service.rb +9 -2
  41. data/lib/openid/stores.rb~ +178 -0
  42. data/lib/openid/trustroot.rb +23 -10
  43. data/lib/openid/urinorm.rb +72 -0
  44. data/lib/openid/util.rb +3 -3
  45. data/test/consumer.rb +0 -8
  46. data/test/data/urinorm.txt +79 -0
  47. data/test/runtests.rb +1 -0
  48. data/test/service.rb +18 -1
  49. data/test/teststore.rb~ +47 -0
  50. data/test/trustroot.rb +5 -1
  51. data/test/urinorm.rb +32 -0
  52. metadata +93 -41
  53. data/examples/rails_openid_login_generator/templates/controller.rb~ +0 -111
  54. data/test/runtests.rb~ +0 -21
data/examples/consumer.rb CHANGED
@@ -3,7 +3,6 @@ require "cgi"
3
3
  require "uri"
4
4
  require "pathname"
5
5
 
6
-
7
6
  require "webrick"
8
7
  include WEBrick
9
8
 
@@ -69,6 +68,7 @@ class SimpleServlet < HTTPServlet::AbstractServlet
69
68
  def do_begin
70
69
  # First make sure the user entered something
71
70
  openid_url = @req.query.fetch("openid_url", "")
71
+
72
72
  if openid_url.empty?
73
73
  self.render("Enter an identity URL to verify",
74
74
  css_class="error", form_contents=openid_url)
@@ -116,7 +116,7 @@ class SimpleServlet < HTTPServlet::AbstractServlet
116
116
 
117
117
  # build the redirect
118
118
  redirect_url = request.redirect_url($trust_root, return_to)
119
-
119
+
120
120
  # send redirect to the server
121
121
  self.redirect(redirect_url)
122
122
  else
@@ -0,0 +1,290 @@
1
+ #!/usr/bin/env ruby
2
+ require "cgi"
3
+ require "uri"
4
+ require "pathname"
5
+
6
+ require "webrick"
7
+ include WEBrick
8
+
9
+ # load the openid library, first trying rubygems
10
+ begin
11
+ require "openid"
12
+ rescue LoadError
13
+ require "rubygems"
14
+ require_gem "ruby-openid", ">= 1.0"
15
+ end
16
+
17
+ ################ start config ##########################
18
+ # use your desired store implementation here
19
+ #store_dir = Pathname.new(Dir.pwd).join("openid-store")
20
+ #store = OpenID::FilesystemStore.new(store_dir)
21
+ store = OpenID::DumbStore.new('areg')
22
+
23
+ $host = "localhost"
24
+ $port = 2000
25
+ ################ end config ############################
26
+
27
+ if $port.nil?
28
+ $base_url = "http://#{$host}/"
29
+ else
30
+ $base_url = "http://#{$host}:#{$port}/"
31
+ end
32
+
33
+ # NOTE: Please note that a Hash is not a valid session storage type, it is just
34
+ # used here to get something that works. In a production environment this
35
+ # should be an object representing the CURRENT USER's session, NOT a global
36
+ # hash. Every user visiting this running consumer.rb will write into this
37
+ # same hash.
38
+ $session = {}
39
+
40
+ $trust_root = $base_url
41
+ $consumer = OpenID::Consumer.new($session, store)
42
+
43
+ server = HTTPServer.new(:Port=>$port)
44
+ class SimpleServlet < HTTPServlet::AbstractServlet
45
+
46
+ def do_GET(req, res)
47
+ @req = req
48
+ @res = res
49
+
50
+ begin
51
+ case req.path
52
+ when "", "/", "/start"
53
+ self.render
54
+ when "/begin"
55
+ self.do_begin
56
+ when "/complete"
57
+ self.do_complete
58
+ when '/policy'
59
+ self.do_policy
60
+ else
61
+ self.redirect(self.build_url("/"))
62
+ end
63
+ ensure
64
+ @req = nil
65
+ @res = nil
66
+ end
67
+ end
68
+
69
+ def do_begin
70
+ # First make sure the user entered something
71
+ openid_url = @req.query.fetch("openid_url", "")
72
+ if openid_url.empty?
73
+ self.render("Enter an identity URL to verify",
74
+ css_class="error", form_contents=openid_url)
75
+ return HTTPStatus::Success
76
+ end
77
+
78
+ # Then ask the openid library to begin the authorization
79
+ request = $consumer.begin(openid_url)
80
+
81
+ # If the URL was unusable (either because of network conditions,
82
+ # a server error, or that the response returned was not an OpenID
83
+ # identity page), the library will return HTTP_FAILURE or PARSE_ERROR.
84
+ # Let the user know that the URL is unusable.
85
+ case request.status
86
+ when OpenID::FAILURE
87
+ self.render("Unable to find openid server for <q>#{openid_url}</q>",
88
+ css_class="error", form_contents=openid_url)
89
+ return HTTPStatus::Success
90
+
91
+ when OpenID::SUCCESS
92
+ # The URL was a valid identity URL. Now we just need to send a redirect
93
+ # to the server using the redirect_url the library created for us.
94
+
95
+ # check to see if we want to make an SREG request. Generally this will
96
+ # not take the form of a checkbox, but will be part of your site policy.
97
+ # For example, you may perform an sreg request if the user appears
98
+ # to be new to the site. The checkbox is here for convenience of
99
+ # testing.
100
+ do_sreg = @req.query.fetch('sreg', nil)
101
+
102
+ if do_sreg and request.uses_extension?('http://openid.net/sreg/1.0')
103
+ policy_url = self.build_url('/policy')
104
+ request.add_extension_arg('sreg','policy_url', policy_url)
105
+ request.add_extension_arg('sreg','required','email,nickname')
106
+ request.add_extension_arg('sreg','optional','fullname,dob,gender,postcode,country')
107
+ end
108
+
109
+ if do_sreg
110
+ extra = {'did_sreg' => 'true'}
111
+ else
112
+ extra = {}
113
+ end
114
+
115
+ return_to = self.build_url("/complete", extra)
116
+
117
+ # build the redirect
118
+ redirect_url = request.redirect_url($trust_root, return_to)
119
+
120
+ # send redirect to the server
121
+ self.redirect(redirect_url)
122
+ else
123
+ # Should never get here
124
+ raise "Not Reached"
125
+ end
126
+ end
127
+
128
+ # handle the redirect from the OpenID server
129
+ def do_complete
130
+ # Ask the library to check the response that the server sent
131
+ # us. Status is a code indicating the response type. info is
132
+ # either nil or a string containing more information about
133
+ # the return type.
134
+ response = $consumer.complete(@req.query)
135
+
136
+ css_class = "error"
137
+
138
+ did_sreg = @req.query.fetch('did_sreg', nil)
139
+ sreg_checked = did_sreg ? 'checked="checked"' : ''
140
+
141
+ if response.status == OpenID::FAILURE
142
+ # In the case of failure, if info is non-nil, it is the
143
+ # URL that we were verifying. We include it in the error
144
+ # message to help the user figure out what happened.
145
+ if response.identity_url
146
+ message = "Verification of #{response.identity_url} failed"
147
+ else
148
+ message = 'Verification failed.'
149
+ end
150
+
151
+ # add on the failure message for a little debug info
152
+ message += ' '+response.msg.to_s
153
+
154
+ elsif response.status == OpenID::SUCCESS
155
+ # Success means that the transaction completed without
156
+ # error. If info is nil, it means that the user cancelled
157
+ # the verification.
158
+ css_class = "alert"
159
+
160
+ message = "You have successfully verified #{response.identity_url} as your identity."
161
+
162
+ # get the signed extension sreg arguments
163
+ sreg = response.extension_response('sreg')
164
+ if sreg.length > 0
165
+ message += "<hr/> With simple registration fields:<br/>"
166
+ sreg.keys.sort.each {|k| message += "<br/><b>#{k}</b>: #{sreg[k]}"}
167
+ elsif did_sreg
168
+ message += "<hr/> But the server does not support simple registration."
169
+ end
170
+
171
+ elsif response.status == OpenID::CANCEL
172
+ message = "Verification cancelled."
173
+
174
+ else
175
+ message = "Unknown response status: #{response.status}"
176
+
177
+ end
178
+ self.render(message, css_class, response.identity_url, sreg_checked)
179
+ end
180
+
181
+ def do_policy
182
+ @res.body = <<END
183
+ <html>
184
+ <head></head>
185
+ <body>
186
+ <h3>Ruby Consumer Simple Registration Policy</h3>
187
+ <p>This consumer makes a simple registration request for the following fields:<br/><br/>
188
+ <b>Required:</b> email, nickname<br/>
189
+ <b>Optional:</b> fullname, dob, gender, postcode, country<br/><br/>
190
+ Nothing is actually done with the data provided, it simply exists to illustrate the simple registration protocol.
191
+ </p>
192
+ </body>
193
+ </html>
194
+
195
+ END
196
+ end
197
+
198
+ # build a URL relative to the server base URL, with the given query
199
+ # parameters added.
200
+ def build_url(action, query=nil)
201
+ url = URI.parse($base_url).merge(action).to_s
202
+ url = OpenID::Util.append_args(url, query) unless query.nil?
203
+ return url
204
+ end
205
+
206
+ def redirect(url)
207
+ @res.set_redirect(HTTPStatus::TemporaryRedirect, url)
208
+ end
209
+
210
+ def render(message=nil, css_class="alert", form_contents="", checked="")
211
+ @res.body = self.page_header
212
+ unless message.nil?
213
+ @res.body << "<div class=\"#{css_class}\">#{message}</div>"
214
+ end
215
+ @res.body << self.page_footer(form_contents, checked)
216
+ end
217
+
218
+ def page_header(title="Ruby OpenID WEBrick example")
219
+ header = <<END_OF_STRING
220
+ <html>
221
+ <head><title>#{title}</title></head>
222
+ <style type="text/css">
223
+ * {
224
+ font-family: verdana,sans-serif;
225
+ }
226
+ body {
227
+ width: 50em;
228
+ margin: 1em;
229
+ }
230
+ div {
231
+ padding: .5em;
232
+ }
233
+ table {
234
+ margin: none;
235
+ padding: none;
236
+ }
237
+ .alert {
238
+ border: 1px solid #e7dc2b;
239
+ background: #fff888;
240
+ }
241
+ .error {
242
+ border: 1px solid #ff0000;
243
+ background: #ffaaaa;
244
+ }
245
+ #verify-form {
246
+ border: 1px solid #777777;
247
+ background: #dddddd;
248
+ margin-top: 1em;
249
+ padding-bottom: 0em;
250
+ }
251
+ </style>
252
+ <body>
253
+ <h1>#{title}</h1>
254
+ <p>
255
+ This example consumer uses the <a href="http://openidenabled.com/openid/libraries/ruby">Ruby OpenID</a> library
256
+ on a WEBrick platform. The example just verifies that the URL that
257
+ you enter is your identity URL.
258
+ </p>
259
+ END_OF_STRING
260
+ end
261
+
262
+
263
+ def page_footer(form_contents="", checked="")
264
+ form_contents = "" if form_contents == "/"
265
+ footer = <<END_OF_STRING
266
+ <div id="verify-form">
267
+ <form method="get" action="#{self.build_url("/begin")}">
268
+ Identity&nbsp;URL:
269
+ <input type="text" name="openid_url" value="#{form_contents}" />
270
+ <input type="submit" value="Verify" />
271
+ <input type="checkbox" id="sregbox" name="sreg" #{checked} />
272
+ <label for="sregbox">with simple registration</label>
273
+ <a href="http://www.openidenabled.com/openid/simple-registration-extension" target="_blank">?</a>
274
+ </form>
275
+ </div>
276
+ </body>
277
+ </html>
278
+ END_OF_STRING
279
+ end
280
+
281
+
282
+
283
+ end
284
+
285
+ # Bootstrap the example
286
+ server.mount("/", SimpleServlet)
287
+ trap("INT") {server.shutdown}
288
+ print "\nVisit http://#{$host}:#{$port}/ in your browser.\n\n"
289
+ server.start
290
+
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ handle: {HMAC-SHA1}{4471fc64}{p5qlgA==}
3
+ secret: wDw+/+4MFdm9Y86/MKfxpyn6Ato=
4
+ issued: 1148320868
5
+ lifetime: 120960
6
+ assoc_type: HMAC-SHA1
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ handle: {HMAC-SHA1}{44637c57}{YcwFSQ==}
3
+ secret: N2o4OrdrEhtke+lcpAOwOQaffGU=
4
+ issued: 1147370327
5
+ lifetime: 1209599
6
+ assoc_type: HMAC-SHA1
@@ -0,0 +1 @@
1
+ _eK��2�X,�|RG+
File without changes
File without changes
File without changes
@@ -62,7 +62,7 @@ class <%= class_name %>Controller < ApplicationController
62
62
 
63
63
  flash[:notice] = "Logged in as #{CGI::escape(response.identity_url)}"
64
64
 
65
- redirect_to :action => "welcome"
65
+ redirect_back_or_default :action => "welcome"
66
66
  return
67
67
 
68
68
  when OpenID::FAILURE
@@ -0,0 +1,35 @@
1
+ # Controller for handling the login, logout process for "users" of our
2
+ # little server. Users have no password. This is just an example.
3
+
4
+ class LoginController < ApplicationController
5
+
6
+ layout 'server'
7
+
8
+ def index
9
+ # just show the login page
10
+ end
11
+
12
+ def submit
13
+ user = @params[:username]
14
+
15
+ # if we get a user, log them in by putting their username in
16
+ # the session hash.
17
+ unless user.nil?
18
+ session[:username] = user unless user.nil?
19
+ session[:approvals] = []
20
+ flash[:notice] = "Your OpenID URL is <b>http://localhost:3000/user/#{user}</b><br/><br/>Proceed to step 2 below."
21
+ else
22
+ flash[:error] = "Sorry, couldn't log you in. Try again."
23
+ end
24
+
25
+ redirect_to :action => 'index'
26
+ end
27
+
28
+ def logout
29
+ # delete the username from the session hash
30
+ session[:username] = nil
31
+ session[:approvals] = nil
32
+ redirect_to :action => 'index'
33
+ end
34
+
35
+ end
@@ -0,0 +1,190 @@
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
+ end
10
+
11
+ class ServerController < ApplicationController
12
+
13
+ include ServerHelper
14
+ include OpenID::Server
15
+ layout nil
16
+
17
+ def index
18
+ begin
19
+ request = server.decode_request(@params)
20
+ rescue ProtocolError => e
21
+ # invalid openid request, so just display a page with an error message
22
+ render_text e.to_s
23
+ return
24
+ end
25
+
26
+ # no openid.mode was given
27
+ unless request
28
+ render_text "This is an OpenID server endpoint."
29
+ return
30
+ end
31
+
32
+ if request.kind_of?(CheckIDRequest)
33
+
34
+ if self.is_authorized(request.identity_url, request.trust_root)
35
+ response = request.answer(true)
36
+
37
+ # add the sreg response if requested
38
+ self.add_sreg(request, response)
39
+
40
+ elsif request.immediate
41
+ server_url = url_for :action => 'index'
42
+ response = request.answer(false, server_url)
43
+
44
+ else
45
+ @session[:last_request] = request
46
+ @request = request
47
+ flash[:notice] = "Do you trust this site with your identity?"
48
+ render :template => 'server/decide', :layout => 'server'
49
+ return
50
+ end
51
+
52
+ else
53
+ response = server.handle_request(request)
54
+ end
55
+
56
+ self.render_response(response)
57
+ end
58
+
59
+ def user_page
60
+ # Yadis content-negotiation: we want to return the xrds if asked for.
61
+ accept = request.env['HTTP_ACCEPT']
62
+
63
+ # This is not technically correct, and should eventually be updated
64
+ # to do real Accept header parsing and logic. Though I expect it will work
65
+ # 99% of the time.
66
+ if accept and accept.include?('application/xrds+xml')
67
+ render_xrds
68
+ return
69
+ end
70
+
71
+ # content negotiation failed, so just render the user page
72
+ xrds_url = url_for(:controller=>'user',:action=>@params[:username])+'/xrds'
73
+ identity_page = <<EOS
74
+ <html><head>
75
+ <meta http-equiv="X-XRDS-Location" content="#{xrds_url}" />
76
+ <link rel="openid.server" href="#{url_for :action => 'index'}" />
77
+ </head><body><p>OpenID identity page for #{@params[:username]}</p>
78
+ </body></html>
79
+ EOS
80
+
81
+ # Also add the Yadis location header, so that they don't have
82
+ # to parse the html unless absolutely necessary.
83
+ response.headers['X-XRDS-Location'] = xrds_url
84
+ render_text identity_page
85
+ end
86
+
87
+ def xrds
88
+ render_xrds
89
+ end
90
+
91
+ def decision
92
+ request = @session[:last_request]
93
+ @session[:last_request] = nil
94
+
95
+ if @params[:yes].nil?
96
+ redirect_to request.cancel_url
97
+ return
98
+ else
99
+ session[:approvals] << request.trust_root
100
+ response = request.answer(true)
101
+ self.add_sreg(request, response)
102
+ return self.render_response(response)
103
+ end
104
+ end
105
+
106
+ protected
107
+
108
+ def server
109
+ if @server.nil?
110
+ dir = Pathname.new(RAILS_ROOT).join('db').join('openid-store')
111
+ store = OpenID::FilesystemStore.new(dir)
112
+ @server = Server.new(store)
113
+ end
114
+ return @server
115
+ end
116
+
117
+ def approved(trust_root)
118
+ return false if session[:approvals].nil?
119
+ return session[:approvals].member?(trust_root)
120
+ end
121
+
122
+ def is_authorized(identity_url, trust_root)
123
+ return (session[:username] and (identity_url == url_for_user) and self.approved(trust_root))
124
+ end
125
+
126
+ def render_xrds
127
+ yadis = <<EOS
128
+ <?xml version="1.0" encoding="UTF-8"?>
129
+ <xrds:XRDS
130
+ xmlns:xrds="xri://$xrds"
131
+ xmlns:openid="http://openid.net/xmlns/1.0"
132
+ xmlns="xri://$xrd*($v*2.0)">
133
+ <XRD>
134
+ <Service priority="1">
135
+ <Type>http://openid.net/signon/1.0</Type>
136
+ <Type>http://openid.net/sreg/1.0</Type>
137
+ <URI>#{url_for(:controller => 'server')}</URI>
138
+ </Service>
139
+ </XRD>
140
+ </xrds:XRDS>
141
+ EOS
142
+
143
+ response.headers['content-type'] = 'application/xrds+xml'
144
+ render_text yadis
145
+ end
146
+
147
+ def add_sreg(request, response)
148
+ # Your code should examine request.query
149
+ # for openid.sreg.required, openid.sreg.optional, and
150
+ # openid.sreg.policy_url, and generate add fields to your response
151
+ # accordingly. For this example, we'll just see if there are any
152
+ # sreg args and add some sreg data to the response. Take note,
153
+ # that this does not actually respect the sreg query, it just sends
154
+ # back some fake sreg data. Your implemetation should be better! :)
155
+
156
+ required = request.query['openid.sreg.required']
157
+ optional = request.query['openid.sreg.optional']
158
+ policy_url = request.query['openid.sreg.policy_url']
159
+
160
+ if required or optional or policy_url
161
+ # this should be taken out of the user's profile,
162
+ # but since we don't have one lets just make up some data.
163
+ # Also, the user should be able to approve the transfer
164
+ # and modify each field if she likes.
165
+ sreg_fields = {
166
+ 'email' => 'mayor@example.com',
167
+ 'nickname' => 'Mayor McCheese'
168
+ }
169
+ response.add_fields('sreg', sreg_fields)
170
+ end
171
+
172
+ end
173
+
174
+ def render_response(response)
175
+ web_response = server.encode_response(response)
176
+
177
+ case web_response.code
178
+ when HTTP_OK
179
+ render_text web_response.body, :status => 200
180
+
181
+ when HTTP_REDIRECT
182
+ redirect_to web_response.redirect_url
183
+
184
+ else
185
+ render_text web_response.body, :status => 400
186
+ end
187
+ end
188
+
189
+
190
+ end