clearance 0.16.3 → 1.0.0.rc1

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

Potentially problematic release.


This version of clearance might be problematic. Click here for more details.

Files changed (85) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +0 -2
  3. data/Appraisals +2 -2
  4. data/CONTRIBUTING.md +10 -19
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +81 -82
  7. data/NEWS.md +17 -4
  8. data/README.md +176 -113
  9. data/app/controllers/clearance/passwords_controller.rb +44 -31
  10. data/app/controllers/clearance/sessions_controller.rb +11 -10
  11. data/app/controllers/clearance/users_controller.rb +8 -12
  12. data/app/mailers/clearance_mailer.rb +4 -5
  13. data/app/views/clearance_mailer/change_password.html.erb +2 -4
  14. data/app/views/layouts/application.html.erb +7 -5
  15. data/app/views/passwords/edit.html.erb +8 -7
  16. data/app/views/passwords/new.html.erb +6 -5
  17. data/app/views/sessions/_form.html.erb +7 -5
  18. data/app/views/sessions/new.html.erb +3 -2
  19. data/app/views/users/_form.html.erb +4 -3
  20. data/clearance.gemspec +29 -27
  21. data/config/routes.rb +10 -13
  22. data/db/migrate/20110111224543_create_clearance_users.rb +18 -0
  23. data/db/schema.rb +4 -5
  24. data/features/engine/visitor_resets_password.feature +0 -7
  25. data/features/engine/visitor_signs_in.feature +7 -0
  26. data/features/engine/visitor_signs_up.feature +2 -2
  27. data/features/integration.feature +0 -1
  28. data/features/integration_with_test_unit.feature +43 -0
  29. data/features/step_definitions/configuration_steps.rb +8 -15
  30. data/features/step_definitions/engine/clearance_steps.rb +38 -38
  31. data/features/support/clearance.rb +1 -1
  32. data/features/support/env.rb +4 -21
  33. data/gemfiles/{3.0.12.gemfile → 3.0.15.gemfile} +1 -1
  34. data/gemfiles/{3.0.12.gemfile.lock → 3.0.15.gemfile.lock} +75 -76
  35. data/gemfiles/{3.2.3.gemfile → 3.1.6.gemfile} +1 -1
  36. data/gemfiles/{3.1.4.gemfile.lock → 3.1.6.gemfile.lock} +79 -80
  37. data/gemfiles/{3.1.4.gemfile → 3.2.6.gemfile} +1 -1
  38. data/gemfiles/{3.2.3.gemfile.lock → 3.2.6.gemfile.lock} +80 -81
  39. data/lib/clearance.rb +1 -0
  40. data/lib/clearance/authentication.rb +37 -69
  41. data/lib/clearance/configuration.rb +3 -18
  42. data/lib/clearance/constraints.rb +2 -0
  43. data/lib/clearance/constraints/signed_in.rb +28 -0
  44. data/lib/clearance/constraints/signed_out.rb +9 -0
  45. data/lib/clearance/engine.rb +4 -4
  46. data/lib/clearance/password_strategies.rb +5 -1
  47. data/lib/clearance/password_strategies/bcrypt.rb +27 -0
  48. data/lib/clearance/password_strategies/bcrypt_migration_from_sha1.rb +52 -0
  49. data/lib/clearance/password_strategies/blowfish.rb +11 -15
  50. data/lib/clearance/password_strategies/fake.rb +23 -0
  51. data/lib/clearance/password_strategies/sha1.rb +15 -21
  52. data/lib/clearance/session.rb +28 -20
  53. data/lib/clearance/testing.rb +8 -3
  54. data/lib/clearance/testing/assertion_error.rb +2 -7
  55. data/lib/clearance/testing/deny_access_matcher.rb +27 -32
  56. data/lib/clearance/testing/helpers.rb +7 -8
  57. data/lib/clearance/user.rb +26 -92
  58. data/lib/clearance/version.rb +1 -1
  59. data/lib/generators/clearance/install/templates/db/migrate/upgrade_clearance_to_diesel.rb +24 -26
  60. data/spec/clearance/constraints/signed_in_spec.rb +51 -0
  61. data/spec/clearance/constraints/signed_out_spec.rb +15 -0
  62. data/spec/clearance/rack_session_spec.rb +8 -7
  63. data/spec/clearance/session_spec.rb +28 -27
  64. data/spec/configuration_spec.rb +7 -6
  65. data/spec/controllers/denies_controller_spec.rb +11 -10
  66. data/spec/controllers/flashes_controller_spec.rb +5 -5
  67. data/spec/controllers/forgeries_controller_spec.rb +9 -9
  68. data/spec/controllers/passwords_controller_spec.rb +42 -55
  69. data/spec/controllers/sessions_controller_spec.rb +26 -33
  70. data/spec/controllers/users_controller_spec.rb +16 -14
  71. data/spec/factories.rb +1 -3
  72. data/spec/mailers/clearance_mailer_spec.rb +4 -4
  73. data/spec/models/bcrypt_migration_from_sha1_spec.rb +71 -0
  74. data/spec/models/bcrypt_spec.rb +40 -0
  75. data/spec/models/blowfish_spec.rb +14 -13
  76. data/spec/models/{clearance_user_spec.rb → password_strategies_spec.rb} +5 -5
  77. data/spec/models/sha1_spec.rb +18 -13
  78. data/spec/models/user_spec.rb +58 -73
  79. data/spec/spec_helper.rb +5 -6
  80. data/spec/support/clearance.rb +0 -4
  81. data/spec/support/cookies.rb +25 -27
  82. data/spec/support/request_with_remember_token.rb +19 -0
  83. metadata +95 -90
  84. data/db/migrate/20110111224543_create_diesel_clearance_users.rb +0 -19
  85. data/init.rb +0 -1
@@ -3,41 +3,46 @@ require 'spec_helper'
3
3
  describe Clearance::PasswordStrategies::SHA1 do
4
4
  subject do
5
5
  Class.new do
6
- attr_accessor :salt, :password, :encrypted_password
6
+ attr_accessor :salt, :encrypted_password
7
7
  include Clearance::PasswordStrategies::SHA1
8
8
 
9
9
  def generate_random_code; "code"; end
10
10
  end.new
11
11
  end
12
12
 
13
- describe "#encrypt_password" do
14
- context "when the password is set" do
15
- let(:salt) { "salt" }
16
- let(:password) { "password" }
13
+ describe '#password=' do
14
+ context 'when the password is set' do
15
+ let(:salt) { 'salt' }
16
+ let(:password) { 'password' }
17
17
 
18
18
  before do
19
19
  subject.salt = salt
20
20
  subject.password = password
21
- subject.send(:encrypt_password)
22
21
  end
23
22
 
24
- it "should encrypt the password using SHA1 into encrypted_password" do
25
- expected = Digest::SHA1.hexdigest("--#{salt}--#{password}--")
23
+ it 'does not initialize the salt' do
24
+ subject.salt.should == salt
25
+ end
26
26
 
27
+ it 'encrypts the password using SHA1 and the existing salt' do
28
+ expected = Digest::SHA1.hexdigest("--#{salt}--#{password}--")
27
29
  subject.encrypted_password.should == expected
28
30
  end
29
31
  end
30
32
 
31
- context "when the salt is not set" do
33
+ context "when the password is not set" do
32
34
  before do
33
- subject.salt = nil
34
-
35
- subject.send(:encrypt_password)
35
+ subject.salt = nil
36
+ subject.password = ""
36
37
  end
37
38
 
38
- it "should initialize the salt" do
39
+ it "initializes the salt" do
39
40
  subject.salt.should_not be_nil
40
41
  end
42
+
43
+ it "doesn't encrpt the password" do
44
+ subject.encrypted_password.should be_nil
45
+ end
41
46
  end
42
47
  end
43
48
  end
@@ -4,129 +4,131 @@ describe User do
4
4
  it { should have_db_index(:email) }
5
5
  it { should have_db_index(:remember_token) }
6
6
 
7
- describe "When signing up" do
7
+ describe 'when signing up' do
8
8
  it { should validate_presence_of(:email) }
9
9
  it { should validate_presence_of(:password) }
10
- it { should allow_value("foo@example.co.uk").for(:email) }
11
- it { should allow_value("foo@example.com").for(:email) }
12
- it { should_not allow_value("foo@").for(:email) }
13
- it { should_not allow_value("foo@example..com").for(:email) }
14
- it { should_not allow_value("foo@.example.com").for(:email) }
15
- it { should_not allow_value("foo").for(:email) }
16
- it { should_not allow_value("example.com").for(:email) }
17
-
18
- it "should store email in down case" do
19
- user = create(:user, :email => "John.Doe@example.com")
20
- user.email.should == "john.doe@example.com"
10
+ it { should allow_value('foo@example.co.uk').for(:email) }
11
+ it { should allow_value('foo@example.com').for(:email) }
12
+ it { should_not allow_value('foo@').for(:email) }
13
+ it { should_not allow_value('foo@example..com').for(:email) }
14
+ it { should_not allow_value('foo@.example.com').for(:email) }
15
+ it { should_not allow_value('foo').for(:email) }
16
+ it { should_not allow_value('example.com').for(:email) }
17
+
18
+ it 'stores email in down case' do
19
+ user = create(:user, :email => 'John.Doe@example.com')
20
+ user.email.should == 'john.doe@example.com'
21
21
  end
22
22
  end
23
23
 
24
- describe "When multiple users have signed up" do
24
+ describe 'when multiple users have signed up' do
25
25
  before { create(:user) }
26
26
  it { should validate_uniqueness_of(:email) }
27
27
  end
28
28
 
29
- describe "A user" do
29
+ describe 'a user' do
30
30
  before do
31
- @user = create(:user)
31
+ @user = create(:user)
32
32
  @password = @user.password
33
33
  end
34
34
 
35
- it "is authenticated with correct email and password" do
36
- (Clearance.configuration.user_model.authenticate(@user.email, @password)).should be
35
+ it 'is authenticated with correct email and password' do
36
+ (Clearance.configuration.user_model.authenticate(@user.email, @password)).
37
+ should be
37
38
  @user.should be_authenticated(@password)
38
39
  end
39
40
 
40
- it "is authenticated with correct uppercased email and correct password" do
41
- (Clearance.configuration.user_model.authenticate(@user.email.upcase, @password)).should be
41
+ it 'is authenticated with correct uppercased email and correct password' do
42
+ (Clearance.configuration.user_model.authenticate(@user.email.upcase, @password)).
43
+ should be
42
44
  @user.should be_authenticated(@password)
43
45
  end
44
46
 
45
- it "is authenticated with incorrect credentials" do
46
- (Clearance.configuration.user_model.authenticate(@user.email, 'bad_password')).should_not be
47
+ it 'is authenticated with incorrect credentials' do
48
+ (Clearance.configuration.user_model.authenticate(@user.email, 'bad_password')).
49
+ should_not be
47
50
  @user.should_not be_authenticated('bad password')
48
51
  end
49
52
  end
50
53
 
51
- describe "When resetting authentication with reset_remember_token!" do
54
+ describe 'when resetting authentication with reset_remember_token!' do
52
55
  before do
53
56
  @user = create(:user)
54
- @user.remember_token = "old-token"
57
+ @user.remember_token = 'old-token'
55
58
  @user.reset_remember_token!
56
59
  end
57
60
 
58
- it "should change the remember token" do
59
- @user.remember_token.should_not == "old-token"
61
+ it 'changes the remember token' do
62
+ @user.remember_token.should_not == 'old-token'
60
63
  end
61
64
  end
62
65
 
63
- describe "An email confirmed user" do
66
+ describe 'an email confirmed user' do
64
67
  before do
65
68
  @user = create(:user)
66
69
  @old_encrypted_password = @user.encrypted_password
67
70
  end
68
71
 
69
- describe "who updates password" do
72
+ describe 'who updates password' do
70
73
  before do
71
- @user.update_password("new_password")
74
+ @user.update_password('new_password')
72
75
  end
73
76
 
74
- it "should change encrypted password" do
77
+ it 'changes encrypted password' do
75
78
  @user.encrypted_password.should_not == @old_encrypted_password
76
79
  end
77
80
  end
78
81
  end
79
82
 
80
- it "should not generate the same remember token for users with the same password at the same time" do
81
- Time.stubs(:now => Time.now)
82
- password = 'secret'
83
- first_user = create(:user, :password => password)
83
+ it 'does not generate same remember token for users with same password at same time' do
84
+ Time.stubs :now => Time.now
85
+ password = 'secret'
86
+ first_user = create(:user, :password => password)
84
87
  second_user = create(:user, :password => password)
85
-
86
88
  second_user.remember_token.should_not == first_user.remember_token
87
89
  end
88
90
 
89
- describe "An user" do
91
+ describe 'a user' do
90
92
  before do
91
93
  @user = create(:user)
92
94
  @old_encrypted_password = @user.encrypted_password
93
95
  end
94
96
 
95
- describe "who requests password reminder" do
97
+ describe 'who requests password reminder' do
96
98
  before do
97
99
  @user.confirmation_token.should be_nil
98
100
  @user.forgot_password!
99
101
  end
100
102
 
101
- it "should generate confirmation token" do
103
+ it 'generates confirmation token' do
102
104
  @user.confirmation_token.should_not be_nil
103
105
  end
104
106
 
105
- describe "and then updates password" do
107
+ describe 'and then updates password' do
106
108
  describe 'with password' do
107
109
  before do
108
- @user.update_password("new_password")
110
+ @user.update_password 'new_password'
109
111
  end
110
112
 
111
- it "should change encrypted password" do
113
+ it 'changes encrypted password' do
112
114
  @user.encrypted_password.should_not == @old_encrypted_password
113
115
  end
114
116
 
115
- it "should clear confirmation token" do
117
+ it 'clears confirmation token' do
116
118
  @user.confirmation_token.should be_nil
117
119
  end
118
120
  end
119
121
 
120
122
  describe 'with blank password' do
121
123
  before do
122
- @user.update_password("")
124
+ @user.update_password ''
123
125
  end
124
126
 
125
- it "does not change encrypted password" do
127
+ it 'does not change encrypted password' do
126
128
  @user.encrypted_password.should == @old_encrypted_password
127
129
  end
128
130
 
129
- it "does not clear confirmation token" do
131
+ it 'does not clear confirmation token' do
130
132
  @user.confirmation_token.should_not be_nil
131
133
  end
132
134
  end
@@ -134,7 +136,7 @@ describe User do
134
136
  end
135
137
  end
136
138
 
137
- describe "a user with an optional email" do
139
+ describe 'a user with an optional email' do
138
140
  before do
139
141
  @user = User.new
140
142
  class << @user
@@ -147,12 +149,13 @@ describe User do
147
149
  subject { @user }
148
150
 
149
151
  it { should allow_value(nil).for(:email) }
150
- it { should allow_value("").for(:email) }
152
+ it { should allow_value('').for(:email) }
151
153
  end
152
154
 
153
- describe "a user with an optional password" do
155
+ describe 'a user with an optional password' do
154
156
  before do
155
157
  @user = User.new
158
+
156
159
  class << @user
157
160
  def password_optional?
158
161
  true
@@ -163,42 +166,24 @@ describe User do
163
166
  subject { @user }
164
167
 
165
168
  it { should allow_value(nil).for(:password) }
166
- it { should allow_value("").for(:password) }
167
- end
168
-
169
- describe "user factory" do
170
- it "should create a valid user with just an overridden password" do
171
- build(:user, :password => "test").should be_valid
172
- end
169
+ it { should allow_value('').for(:password) }
173
170
  end
174
171
 
175
- describe "when user exists before Clearance was installed" do
176
- before do
177
- @user = create(:user)
178
- sql = "update users set salt = NULL, encrypted_password = NULL, remember_token = NULL where id = #{@user.id}"
179
- ActiveRecord::Base.connection.update(sql)
180
- @user.reload.salt.should be_nil
181
- @user.reload.encrypted_password.should be_nil
182
- @user.reload.remember_token.should be_nil
183
- end
184
-
185
- it "should initialize salt, generate remember token, and save encrypted password on update_password" do
186
- @user.update_password('password')
187
- @user.salt.should_not be_nil
188
- @user.encrypted_password.should_not be_nil
189
- @user.remember_token.should_not be_nil
172
+ describe 'user factory' do
173
+ it 'should create a valid user with just an overridden password' do
174
+ build(:user, :password => 'test').should be_valid
190
175
  end
191
176
  end
192
177
 
193
- describe "The password setter on a User" do
194
- let(:password) { "a-password" }
178
+ describe 'the password setter on a User' do
179
+ let(:password) { 'a-password' }
195
180
  before { subject.send(:password=, password) }
196
181
 
197
- it "sets password to the plain-text password" do
182
+ it 'sets password to the plain-text password' do
198
183
  subject.password.should == password
199
184
  end
200
185
 
201
- it "also sets encrypted_password" do
186
+ it 'also sets encrypted_password' do
202
187
  subject.encrypted_password.should_not be_nil
203
188
  end
204
189
  end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,7 @@
1
- ENV["RAILS_ENV"] ||= "test"
1
+ ENV['RAILS_ENV'] ||= 'test'
2
2
 
3
- PROJECT_ROOT = File.expand_path("../..", __FILE__)
4
- $LOAD_PATH << File.join(PROJECT_ROOT, "lib")
3
+ PROJECT_ROOT = File.expand_path('../..', __FILE__)
4
+ $LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
5
5
 
6
6
  require 'rails/all'
7
7
  require 'rails/test_help'
@@ -14,13 +14,12 @@ require 'bourne'
14
14
  require 'timecop'
15
15
  require 'factory_girl_rails'
16
16
  require 'shoulda-matchers'
17
-
18
17
  require 'clearance/testing'
19
18
 
20
- Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
19
+ Dir[Rails.root.join('spec/support/**/*.rb')].each {|f| require f}
21
20
 
22
21
  RSpec.configure do |config|
22
+ config.include FactoryGirl::Syntax::Methods
23
23
  config.mock_with :mocha
24
24
  config.use_transactional_fixtures = true
25
- config.include FactoryGirl::Syntax::Methods
26
25
  end
@@ -25,10 +25,6 @@ module Clearance
25
25
  def redirect_to_url_after_destroy
26
26
  redirect_to(@controller.send(:url_after_destroy))
27
27
  end
28
-
29
- def redirect_to_url_already_confirmed
30
- redirect_to(@controller.send(:url_already_confirmed))
31
- end
32
28
  end
33
29
  end
34
30
  end
@@ -1,21 +1,40 @@
1
1
  RSpec::Matchers.define :set_cookie do |name, expected_value, expected_expires_at|
2
+ failure_message_for_should do
3
+ "Expected #{expectation} got #{result}"
4
+ end
5
+
2
6
  match do |subject|
3
7
  @headers = subject
4
8
  @expected_name = name
5
9
  @expected_value = expected_value
6
10
  @expected_expires_at = expected_expires_at
7
-
8
11
  extract_cookies
9
12
  find_expected_cookie
10
13
  parse_expiration
11
14
  parse_value
12
15
  parse_path
13
-
14
16
  ensure_cookie_set
15
17
  ensure_expiration_correct
16
18
  ensure_path_is_correct
17
19
  end
18
20
 
21
+ def ensure_cookie_set
22
+ @value.should == @expected_value
23
+ end
24
+
25
+ def ensure_expiration_correct
26
+ @expires_at.should_not be_nil
27
+ @expires_at.should be_within(100).of(@expected_expires_at)
28
+ end
29
+
30
+ def ensure_path_is_correct
31
+ @path.should == "/"
32
+ end
33
+
34
+ def expectation
35
+ "a cookie named #{@expected_name} with value #{@expected_value.inspect} expiring at #{@expected_expires_at.inspect}"
36
+ end
37
+
19
38
  def extract_cookies
20
39
  @cookie_headers = @headers['Set-Cookie'] || []
21
40
  @cookie_headers = [@cookie_headers] if @cookie_headers.respond_to?(:to_str)
@@ -33,37 +52,16 @@ RSpec::Matchers.define :set_cookie do |name, expected_value, expected_expires_at
33
52
  end
34
53
  end
35
54
 
36
- def parse_value
37
- if @cookie && result = @cookie.match(/=(.*?)(?:;|$)/)
38
- @value = result[1]
39
- end
40
- end
41
-
42
55
  def parse_path
43
56
  if @cookie && result = @cookie.match(/; path=(.*?)(;|$)/)
44
57
  @path = result[1]
45
58
  end
46
59
  end
47
60
 
48
- def ensure_cookie_set
49
- @value.should == @expected_value
50
- end
51
-
52
- def ensure_expiration_correct
53
- @expires_at.should_not be_nil
54
- @expires_at.should be_within(100).of(@expected_expires_at)
55
- end
56
-
57
- def ensure_path_is_correct
58
- @path.should == "/"
59
- end
60
-
61
- failure_message_for_should do
62
- "Expected #{expectation} got #{result}"
63
- end
64
-
65
- def expectation
66
- "a cookie named #{@expected_name} with value #{@expected_value.inspect} expiring at #{@expected_expires_at.inspect}"
61
+ def parse_value
62
+ if @cookie && result = @cookie.match(/=(.*?)(?:;|$)/)
63
+ @value = result[1]
64
+ end
67
65
  end
68
66
 
69
67
  def result
@@ -0,0 +1,19 @@
1
+ module RememberTokenHelpers
2
+ def request_with_remember_token(remember_token)
3
+ cookies = {
4
+ 'action_dispatch.cookies' => {
5
+ Clearance::Session::REMEMBER_TOKEN_COOKIE => remember_token
6
+ }
7
+ }
8
+ env = { :clearance => Clearance::Session.new(cookies) }
9
+ Rack::Request.new env
10
+ end
11
+
12
+ def request_without_remember_token
13
+ request_with_remember_token nil
14
+ end
15
+ end
16
+
17
+ RSpec.configure do |config|
18
+ config.include RememberTokenHelpers
19
+ end