pasaporte 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,53 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestEditProfile < Pasaporte::WebTest
4
+ test 'should require login' do
5
+ get '/julik/edit'
6
+ assert_response :redirect
7
+ assert_redirected_to '/julik/signon'
8
+ end
9
+
10
+ test 'should preload profile' do
11
+ prelogin 'julik'
12
+ get '/julik/edit'
13
+ assert_response :success
14
+ assert_kind_of Profile, @assigns.profile
15
+ deny @assigns.profile.new_record?, "This is a presaved profile"
16
+ assert_match_body /Your profile/
17
+ end
18
+
19
+ test 'should show message and not save when posting faulty data' do
20
+ prelogin 'julik'
21
+ post '/julik/edit', :profile => {:openid_server => 'xyz'}
22
+
23
+ assert_response :success
24
+ assert_not_nil @assigns.err, "An error message should be assigned"
25
+
26
+ prof = @assigns.profile
27
+ prof.reload
28
+ assert_nil prof.openid_server, "Nothing should have been assigned"
29
+ end
30
+
31
+ test 'should redirect with success message when changing the profile succeeds' do
32
+ prelogin 'julik'
33
+ post '/julik/edit', :profile => {:email => 'trof@groff.com'}
34
+ assert_response :redirect
35
+ assert_not_nil @state.msg
36
+ assert_match /Changed/i, @state.msg
37
+ end
38
+
39
+ test 'default country should be selected when loading the profile page for the first time' do
40
+ prelogin 'joe-boss'
41
+
42
+ begin
43
+ c = Pasaporte::DEFAULT_COUNTRY
44
+ silence_warnings { Pasaporte.const_set(:DEFAULT_COUNTRY, 'us')}
45
+ get '/joe-boss/edit'
46
+ assert_response :success
47
+ assert_select 'option[value="us"][selected]', true
48
+ ensure
49
+ silence_warnings { Pasaporte.const_set(:DEFAULT_COUNTRY, c) }
50
+ end
51
+ end
52
+
53
+ end
@@ -1,16 +1,9 @@
1
- $:.reject! { |e| e.include? 'TextMate' }
2
1
  require File.dirname(__FILE__) + '/helper'
3
2
  require 'fileutils'
4
3
  require File.dirname(__FILE__) + '/testable_openid_fetcher'
5
4
  require 'openid/store/memory'
6
5
  require 'openid/extensions/sreg'
7
6
 
8
- class Object
9
- def own_methods
10
- raise (methods - Object.instance_methods).inspect
11
- end
12
- end
13
-
14
7
  class TestOpenid < Pasaporte::WebTest
15
8
  # We have to open up because it's the Fecther that's going
16
9
  # to make requests
@@ -50,12 +43,12 @@ class TestOpenid < Pasaporte::WebTest
50
43
  assert_select 'link[rel=openid.server]', true do | s |
51
44
  s = s.pop
52
45
  assert_equal "http://test.host/pasaporte/monsieur-hulot/openid", s.attributes["href"],
53
- "Should contain the delegate address for Monsieur Hulot"
46
+ "Should contain the endpoint address for Monsieur Hulot"
54
47
  end
55
48
  assert_select 'link[rel=openid.delegate]', true do | s |
56
49
  s = s.pop
57
- assert_equal "http://test.host/pasaporte/monsieur-hulot/openid", s.attributes["href"],
58
- "Should contain the endpoint address for Monsieur Hulot"
50
+ assert_equal "http://test.host/pasaporte/monsieur-hulot", s.attributes["href"],
51
+ "Should refer to itself"
59
52
  end
60
53
  end
61
54
 
@@ -82,7 +75,7 @@ class TestOpenid < Pasaporte::WebTest
82
75
  assert_match(/#{Regexp.escape(@return_to + '?openid1_claimed_id=')}(.+)#{Regexp.escape('&rp_nonce=')}(.+)/,
83
76
  response_params["openid.return_to"],
84
77
  "The return_to should be the one of the signup with a nonce")
85
- assert_equal "http://test.host/pasaporte/monsieur-hulot/openid",
78
+ assert_equal "http://test.host/pasaporte/monsieur-hulot",
86
79
  response_params["openid.identity"], "The identity is the server URL in this case"
87
80
  assert_equal "checkid_setup", response_params['openid.mode'],
88
81
  "The current mode is checkid_setup"
@@ -315,10 +308,24 @@ class TestOpenid < Pasaporte::WebTest
315
308
  assert_equal "Monsieur Hulot", sreg_response['fullname']
316
309
  end
317
310
 
311
+ def test_in_which_julik_wants_to_login_but_monsieur_hulot_is_logged_in_already
312
+ prelogin! "monsieur-hulot"
313
+
314
+ req = @consumer.begin("http://test.host/pasaporte/julik")
315
+ assert_kind_of OpenID::Consumer::CheckIDRequest, req
316
+ assert_nothing_raised { get_with_verbatim_url req.redirect_url(@trust_root, @return_to) }
317
+ assert_response :redirect
318
+ assert_redirected_to '/julik/signon'
319
+ assert_not_nil @state.pending_openid, "A pending OpenID request should have been "+
320
+ "placed in the session"
321
+ assert_nil @state.nickname, "The nickname should have been removed from the session"
322
+ assert_kind_of OpenID::Server::CheckIDRequest, @state.pending_openid
323
+ end
324
+
318
325
  private
319
326
  # Prelogins Monsieur Hulot into Pasaporte
320
- def prelogin!
321
- post '/monsieur-hulot/signon', :pass => 'monsieur-hulot'.reverse
327
+ def prelogin!(name = 'monsieur-hulot')
328
+ post('/%s/signon' % name, :pass => name.reverse)
322
329
  end
323
330
 
324
331
  # Preapproves tativille.fr as a site Monsieur Hulot trusts
@@ -1,7 +1,4 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
- require File.dirname(__FILE__) + '/testable_openid_fetcher'
3
-
4
- require 'flexmock'
5
2
 
6
3
  class TestProfilePage < Pasaporte::WebTest
7
4
  fixtures :pasaporte_profiles
@@ -126,28 +123,6 @@ class TestSignon < Pasaporte::WebTest
126
123
  end
127
124
  end
128
125
 
129
- class TestSignout < Pasaporte::WebTest
130
- def test_signout_should_silently_redirect_unless_signed_in
131
- get '/somebody/signout'
132
- assert_response :redirect
133
- assert_redirected_to '/somebody/signon'
134
- end
135
-
136
- def test_signout_should_erase_session_and_redirect
137
- flexmock(Pasaporte::AUTH).
138
- should_receive(:call).with("gemanges", "tairn", "test.host").once.and_return(true)
139
- post '/gemanges/signon', :pass => 'tairn'
140
- assert_response :redirect
141
- assert_equal 'gemanges', @state.nickname
142
-
143
- get '/gemanges/signout'
144
- assert_response :redirect
145
- assert_redirected_to '/gemanges/signon'
146
- assert_kind_of Camping::H, @state, "State should be reset with Camping::H"
147
- assert_equal %w( msg ), @state.keys, "State should only contain the message"
148
- end
149
- end
150
-
151
126
  class TestApprovalsPage < Pasaporte::WebTest
152
127
  fixtures :pasaporte_profiles, :pasaporte_approvals
153
128
  def test_approvals_page_requires_login
@@ -210,58 +185,6 @@ class TestAssets < Pasaporte::WebTest
210
185
  end
211
186
  end
212
187
 
213
- class TestProfileEditor < Pasaporte::WebTest
214
- test 'should require login' do
215
- get '/julik/edit'
216
- assert_response :redirect
217
- assert_redirected_to '/julik/signon'
218
- end
219
-
220
- test 'should preload profile' do
221
- prelogin 'julik'
222
- get '/julik/edit'
223
- assert_response :success
224
- assert_kind_of Profile, @assigns.profile
225
- deny @assigns.profile.new_record?, "This is a presaved profile"
226
- assert_match_body /Your profile/
227
- end
228
-
229
- test 'should show message and not save when posting faulty data' do
230
- prelogin 'julik'
231
- post '/julik/edit', :profile => {:openid_server => 'xyz'}
232
-
233
- assert_response :success
234
- assert_not_nil @assigns.err, "An error message should be assigned"
235
- assert_match /Cannot save/, @assigns.err, "The error message should describe the problem"
236
-
237
- prof = @assigns.profile
238
- prof.reload
239
- assert_nil prof.openid_server, "Nothing should have been assigned"
240
- end
241
-
242
- test 'should redirect with success message when changing the profile succeeds' do
243
- prelogin 'julik'
244
- post '/julik/edit', :profile => {:email => 'trof@groff.com'}
245
- assert_response :redirect
246
- assert_not_nil @state.msg
247
- assert_match /Changed/i, @state.msg
248
- end
249
-
250
- test 'default country should be selected when loading the profile page for the first time' do
251
- prelogin 'joe-boss'
252
-
253
- begin
254
- c = Pasaporte::DEFAULT_COUNTRY
255
- silence_warnings { Pasaporte.const_set(:DEFAULT_COUNTRY, 'us')}
256
- get '/joe-boss/edit'
257
- assert_response :success
258
- assert_select 'option[value="us"][selected]', true
259
- ensure
260
- silence_warnings { Pasaporte.const_set(:DEFAULT_COUNTRY, c) }
261
- end
262
- end
263
-
264
- end
265
188
 
266
189
  # class TestYadis < Pasaporte::WebTest
267
190
  # attr_reader :request, :response
@@ -291,32 +214,6 @@ end
291
214
  # end
292
215
  # end
293
216
 
294
- class TestPublicSignon < Pasaporte::WebTest
295
- fixtures :pasaporte_profiles
296
- test 'should present a login screen without predefined nickname' do
297
- get
298
- assert_response :success
299
- assert_select 'input[name="login"]', true
300
-
301
- flexmock(Pasaporte::AUTH).should_receive(:call).with("schtwo", "foo", "test.host").and_return(false)
302
-
303
- post '/', :login => 'schtwo', :pass => 'foo'
304
- assert_response :success
305
- assert_nil @state.nickname
306
- assert_select 'input[type="hidden"]', true
307
- "The response should include a hidden field now instead of a text field"
308
- end
309
-
310
- test 'should redirect to profile page for new users' do
311
- flexmock(Pasaporte::AUTH).should_receive(:call).with("unknown", "pfew", "test.host").and_return(true)
312
- post '/', :login => "unknown", :pass => "pfew"
313
- assert_response :redirect
314
- assert_not_nil Profile.find_by_nickname('unknown'), "A profile should have been created during login"
315
- assert_redirected_to '/unknown/prefs'
316
- end
317
-
318
- end
319
-
320
217
  # A littol auditte
321
218
  at_exit do
322
219
  missing = Pasaporte::Controllers.constants.reject do |c|
@@ -95,12 +95,13 @@ class TestProfile < Camping::ModelTest
95
95
  deny p.delegates_openid?, "Delegation is now turned off because we sent a bool switch of false"
96
96
  end
97
97
 
98
+ # This is how the new OpenID lib normalizes URIs, has to do with the variance in "what" can be an OpenID URL
98
99
  def test_normalizes_both_delegate_urls
99
100
  p = create('julik', DOMAIN,
100
101
  :openid_server => 'xxx.com', :openid_delegate => 'xyz.org/x')
101
- assert_equal 'http://xxx.com/', p.openid_server,
102
+ assert_equal 'xxx.com', p.openid_server,
102
103
  "The URL should be normalized with HTTP scheme and trailing slash"
103
- assert_equal 'http://xyz.org/x', p.openid_delegate,
104
+ assert_equal 'xyz.org/x', p.openid_delegate,
104
105
  "The URL should be normalized with HTTP scheme"
105
106
  end
106
107
 
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestPublicSignon < Pasaporte::WebTest
4
+ fixtures :pasaporte_profiles
5
+ test 'should present a login screen without predefined nickname' do
6
+ get
7
+ assert_response :success
8
+ assert_select 'input[name="login"]', true
9
+
10
+ flexmock(Pasaporte::AUTH).should_receive(:call).with("schtwo", "foo", "test.host").and_return(false)
11
+
12
+ post '/', :login => 'schtwo', :pass => 'foo'
13
+ assert_response :success
14
+ assert_nil @state.nickname
15
+ assert_select 'input[value="schtwo"]', true
16
+ end
17
+
18
+ test 'should redirect to profile page for new users' do
19
+ flexmock(Pasaporte::AUTH).should_receive(:call).with("unknown", "pfew", "test.host").and_return(true)
20
+ post '/', :login => "unknown", :pass => "pfew"
21
+ assert_response :redirect
22
+ assert_not_nil Profile.find_by_nickname('unknown'), "A profile should have been created during login"
23
+ assert_redirected_to '/unknown/prefs'
24
+ end
25
+
26
+ end
@@ -6,8 +6,7 @@ class TestSettings < Camping::Test
6
6
  def test_application
7
7
  emit :throttle_for => 45.minutes
8
8
  assert_nothing_raised { Pasaporte.apply_config! }
9
- assert_equal 45.minutes, Pasaporte::THROTTLE_FOR, "The setting should have " +
10
- "been applied"
9
+ assert_equal 45.minutes, Pasaporte::THROTTLE_FOR, "The setting should have been applied"
11
10
  end
12
11
 
13
12
  def test_bail_on_unknowns
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestSignout < Pasaporte::WebTest
4
+ def test_signout_should_silently_redirect_unless_signed_in
5
+ get '/somebody/signout'
6
+ assert_response :redirect
7
+ assert_redirected_to '/somebody/signon'
8
+ end
9
+
10
+ def test_signout_should_erase_session_and_redirect
11
+ flexmock(Pasaporte::AUTH).
12
+ should_receive(:call).with("gemanges", "tairn", "test.host").once.and_return(true)
13
+ post '/gemanges/signon', :pass => 'tairn'
14
+ assert_response :redirect
15
+ assert_equal 'gemanges', @state.nickname
16
+
17
+ get '/gemanges/signout'
18
+ assert_response :redirect
19
+ assert_redirected_to '/gemanges/signon'
20
+ assert_kind_of Camping::H, @state, "State should be reset with Camping::H"
21
+ # TODO: why err is still here??
22
+ assert_equal %w( msg err ), @state.keys, "State should only contain the message and error"
23
+ end
24
+ end
@@ -0,0 +1,54 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestTokenBox < Test::Unit::TestCase
4
+ def test_init
5
+ assert_nothing_raised { TokenBox.new }
6
+ end
7
+
8
+ def test_procurement
9
+ box = TokenBox.new
10
+ tok = box.procure!("abc")
11
+ assert_kind_of String, tok
12
+ assert_equal TokenBox::TOKEN_SIZE, tok.length
13
+ tokens = (0...30).map { box.procure!("abc") }.uniq
14
+ assert_equal 30, tokens.uniq.length, "All generated tokens should differ"
15
+ tokens.each do | tok |
16
+ assert_equal TokenBox::TOKEN_SIZE, tok.length
17
+ end
18
+ end
19
+
20
+ def test_validation_should_happen_once
21
+ box = TokenBox.new
22
+ tok = box.procure!("a")
23
+ assert_nothing_raised { box.validate!("a", tok) }
24
+ assert_raise(TokenBox::Invalid) { box.validate!("a", tok) }
25
+ end
26
+
27
+ def test_validation_should_work_for_the_request_only
28
+ box = TokenBox.new
29
+ tok = box.procure!("a")
30
+ assert_raise(TokenBox::Invalid) { box.validate!("b", tok) }
31
+ assert_nothing_raised { box.validate!("a", tok) }
32
+ end
33
+
34
+ def test_tokens_should_be_discarded
35
+ box = TokenBox.new
36
+ first = box.procure!("a")
37
+ TokenBox::MAX_TOKENS.times { box.procure!("a") }
38
+ assert_raise(TokenBox::Invalid) { box.validate!("a", first)}
39
+ end
40
+
41
+ def test_token_should_expire
42
+ box = TokenBox.new
43
+ begin
44
+ old, $VERBOSE, w = TokenBox::WINDOW, nil, $VERBOSE
45
+ TokenBox.const_set(:WINDOW, 2)
46
+ tok = box.procure!("a")
47
+ sleep(2.3)
48
+ assert_raise(TokenBox::Invalid) { box.validate!("a", tok)}
49
+ ensure
50
+ TokenBox.const_set(:WINDOW, old)
51
+ $VERBOSE = w
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,99 @@
1
+ $:.reject! { |e| e.include? 'TextMate' }
2
+ require File.dirname(__FILE__) + '/helper'
3
+ require 'fileutils'
4
+ require File.dirname(__FILE__) + '/testable_openid_fetcher'
5
+ require 'openid/store/memory'
6
+ require 'openid/extensions/sreg'
7
+
8
+ class TestWithPartialSSL < Pasaporte::WebTest
9
+ # We have to open up because it's the Fecther that's going
10
+ # to make requests
11
+ attr_reader :request, :response
12
+ fixtures :pasaporte_profiles
13
+
14
+ def setup
15
+ super
16
+ @fetcher = TestableOpenidFetcher.new(self)
17
+
18
+ OpenID.fetcher = @fetcher
19
+ OpenID::Util.logger = Pasaporte::LOGGER
20
+
21
+ @store = OpenID::Store::Memory.new
22
+ @openid_session = {}
23
+ init_consumer
24
+
25
+ @request.domain = 'test.host'
26
+
27
+ @trust_root = 'http://tativille.fr/wiki'
28
+ @return_to = 'http://tativille.fr/wiki/signup'
29
+ @hulot = Profile.find(1)
30
+ silence_warnings { Pasaporte.const_set(:PARTIAL_SSL, true) }
31
+ end
32
+
33
+ def teardown
34
+ # Delete all the associations created during the test case
35
+ JulikState::State.delete_all; Association.delete_all; Approval.delete_all; Throttle.delete_all
36
+ # Delete the store
37
+ FileUtils.rm_rf('openid-consumer-store')
38
+ # Call super for flexmock a.o.
39
+ silence_warnings { Pasaporte.const_set(:PARTIAL_SSL, false) }
40
+ super
41
+ end
42
+
43
+ def test_in_which_monsieur_hulot_is_not_logged_in_and_asked_for_login_after_setup_and_gets_bounced_to_ssl_page
44
+ req = @consumer.begin("http://test.host/pasaporte/monsieur-hulot")
45
+ assert_kind_of OpenID::Consumer::CheckIDRequest, req
46
+ assert_nothing_raised { get_with_verbatim_url req.redirect_url(@trust_root, @return_to) }
47
+ assert_response :redirect
48
+
49
+ redirection = @response.headers['Location']
50
+ assert_redirected_to '/monsieur-hulot/signon'
51
+ follow_redirect
52
+
53
+ assert_response :redirect
54
+ assert_match /^https/, @response.headers['Location'].to_s, "Signon should redirect to itself over HTTPS"
55
+
56
+ assert_not_nil @state.pending_openid, "A pending OpenID request should have been "+
57
+ "placed in the session"
58
+
59
+ # TODO: Verify that the cookie indeed gets transferred along to the SSL domain
60
+ assert_kind_of OpenID::Server::CheckIDRequest, @state.pending_openid
61
+ end
62
+
63
+ private
64
+
65
+ def init_consumer
66
+ @consumer = OpenID::Consumer.new(@openid_session, @store)
67
+ end
68
+ def decode_qs(qs)
69
+ qs.to_s.split(/\&/).inject({}) do | params, segment |
70
+ k, v = segment.split(/\=/).map{|s| Camping.un(s)}
71
+ params[k] = v; params
72
+ end
73
+ end
74
+ def response_to_hash
75
+ Hash[*@response.body.split(/\n/).map{|p| p.split(/\:/)}.flatten].with_indifferent_access
76
+ end
77
+ def redirect_path_and_params(t = nil)
78
+ # Camping conveniently places a URI object in the location header
79
+ uri = (t ? URI.parse(t) : @response.headers["Location"])
80
+ [uri.path, decode_qs(uri.query)]
81
+ end
82
+
83
+ def redirect_url_path_and_params(t = nil)
84
+ # Camping conveniently places a URI object in the location header
85
+ uri = (t ? URI.parse(t) : @response.headers["Location"])
86
+ uri_with_scheme, qry = uri.to_s.split(/\?/)
87
+
88
+ [uri_with_scheme, uri.path, decode_qs(qry)]
89
+ end
90
+
91
+ def get_with_verbatim_url(url)
92
+ get(*recompose(url))
93
+ end
94
+
95
+ def recompose(url)
96
+ u = URI.parse(url)
97
+ [u.path.gsub(/^\/pasaporte/, ''), decode_qs(u.query)]
98
+ end
99
+ end