sparkly-auth 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/app/controllers/sparkly_accounts_controller.rb +59 -0
- data/app/controllers/sparkly_controller.rb +47 -0
- data/app/controllers/sparkly_sessions_controller.rb +52 -0
- data/app/models/password.rb +3 -0
- data/app/models/remembrance_token.rb +50 -0
- data/app/views/sparkly_accounts/edit.html.erb +24 -0
- data/app/views/sparkly_accounts/new.html.erb +24 -0
- data/app/views/sparkly_accounts/show.html.erb +0 -0
- data/app/views/sparkly_sessions/new.html.erb +22 -0
- data/dependencies.rb +1 -0
- data/generators/sparkly/USAGE +27 -0
- data/generators/sparkly/sparkly_generator.rb +76 -0
- data/generators/sparkly/templates/accounts_controller.rb +65 -0
- data/generators/sparkly/templates/accounts_helper.rb +2 -0
- data/generators/sparkly/templates/help_file.txt +56 -0
- data/generators/sparkly/templates/initializer.rb +30 -0
- data/generators/sparkly/templates/migrations/add_confirmed_to_sparkly_passwords.rb +9 -0
- data/generators/sparkly/templates/migrations/create_sparkly_passwords.rb +19 -0
- data/generators/sparkly/templates/migrations/create_sparkly_remembered_tokens.rb +15 -0
- data/generators/sparkly/templates/sessions_controller.rb +45 -0
- data/generators/sparkly/templates/sessions_helper.rb +2 -0
- data/generators/sparkly/templates/tasks/migrations.rb +1 -0
- data/generators/sparkly/templates/views/sparkly_accounts/edit.html.erb +24 -0
- data/generators/sparkly/templates/views/sparkly_accounts/new.html.erb +24 -0
- data/generators/sparkly/templates/views/sparkly_accounts/show.html.erb +0 -0
- data/generators/sparkly/templates/views/sparkly_sessions/new.html.erb +22 -0
- data/init.rb +44 -0
- data/lib/auth.rb +52 -0
- data/lib/auth/behavior/base.rb +64 -0
- data/lib/auth/behavior/core.rb +87 -0
- data/lib/auth/behavior/core/authenticated_model_methods.rb +52 -0
- data/lib/auth/behavior/core/controller_extensions.rb +52 -0
- data/lib/auth/behavior/core/controller_extensions/class_methods.rb +24 -0
- data/lib/auth/behavior/core/controller_extensions/current_user.rb +54 -0
- data/lib/auth/behavior/core/password_methods.rb +65 -0
- data/lib/auth/behavior/remember_me.rb +17 -0
- data/lib/auth/behavior/remember_me/configuration.rb +21 -0
- data/lib/auth/behavior/remember_me/controller_extensions.rb +66 -0
- data/lib/auth/behavior_lookup.rb +10 -0
- data/lib/auth/configuration.rb +328 -0
- data/lib/auth/encryptors/sha512.rb +20 -0
- data/lib/auth/generators/configuration_generator.rb +20 -0
- data/lib/auth/generators/controllers_generator.rb +34 -0
- data/lib/auth/generators/migration_generator.rb +32 -0
- data/lib/auth/generators/route_generator.rb +19 -0
- data/lib/auth/generators/views_generator.rb +26 -0
- data/lib/auth/model.rb +94 -0
- data/lib/auth/observer.rb +21 -0
- data/lib/auth/target_list.rb +5 -0
- data/lib/auth/tasks/migrations.rb +71 -0
- data/lib/auth/token.rb +10 -0
- data/lib/sparkly-auth.rb +1 -0
- data/rails/init.rb +17 -0
- data/rails/routes.rb +19 -0
- data/sparkly-auth.gemspec +143 -0
- data/spec/controllers/application_controller_spec.rb +13 -0
- data/spec/generators/sparkly_spec.rb +64 -0
- data/spec/lib/auth/behavior/core_spec.rb +184 -0
- data/spec/lib/auth/behavior/remember_me_spec.rb +127 -0
- data/spec/lib/auth/extensions/controller_spec.rb +32 -0
- data/spec/lib/auth/model_spec.rb +57 -0
- data/spec/lib/auth_spec.rb +32 -0
- data/spec/mocks/models/user.rb +3 -0
- data/spec/routes_spec.rb +24 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/views_spec.rb +18 -0
- metadata +210 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe :sparkly do
|
4
|
+
before(:each) do
|
5
|
+
Auth.configure do |config|
|
6
|
+
config.authenticate :user
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
context "with :remember_me behavior" do
|
11
|
+
before(:each) { Auth.configure { |c| c.behaviors << :remember_me } }
|
12
|
+
|
13
|
+
with_args :migrations do
|
14
|
+
it "should generate a remembered_tokens migration" do
|
15
|
+
subject.should generate("db/migrate/002_create_sparkly_remembered_tokens.rb")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
with_args :migrations do
|
22
|
+
it "should generate db/migrate" do
|
23
|
+
subject.should generate("db/migrate")
|
24
|
+
subject.should generate("db/migrate/001_create_sparkly_passwords.rb")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
with_args :config do
|
29
|
+
it "should generate the sparkly initializers" do
|
30
|
+
subject.should generate('lib/tasks/sparkly_migration.rb')
|
31
|
+
subject.should generate('config/initializers/sparkly_authentication.rb')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
with_args :controllers do
|
36
|
+
it "should generate the sparkly controllers" do
|
37
|
+
Auth.configuration.authenticate(:user, :accounts_controller => 'users', :sessions_controller => 'user_sessions')
|
38
|
+
Auth.kick!
|
39
|
+
|
40
|
+
subject.should generate("app/controllers/users_controller.rb")
|
41
|
+
subject.should generate("app/controllers/user_sessions_controller.rb")
|
42
|
+
subject.should generate("app/helpers/users_helper.rb")
|
43
|
+
subject.should generate("app/helpers/user_sessions_helper.rb")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
with_args :views do
|
48
|
+
it "should generate the sparkly views with /users if given the users controller" do
|
49
|
+
Auth.configuration.authenticate(:user, :accounts_controller => 'users', :sessions_controller => 'user_sessions')
|
50
|
+
Auth.kick!
|
51
|
+
|
52
|
+
subject.should generate("app/views/users/edit.html.erb")
|
53
|
+
subject.should generate("app/views/users/new.html.erb")
|
54
|
+
subject.should generate("app/views/users/show.html.erb")
|
55
|
+
subject.should generate("app/views/user_sessions/new.html.erb")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
with_args :help do
|
60
|
+
it "should generate the sparkly help" do
|
61
|
+
subject.should generate('doc/sparkly_authentication.txt')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Behavior: Core" do
|
4
|
+
subject { Auth::Model.new(:user, :behaviors => [:core], :password_update_frequency => 30.days) }
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
subject.apply_options!
|
8
|
+
end
|
9
|
+
|
10
|
+
context "user" do
|
11
|
+
it "should not be able to reuse a previous password" do
|
12
|
+
u = User.new(:email => "generic1@example.com")
|
13
|
+
u.password = u.password_confirmation = "Generic12"
|
14
|
+
u.save!
|
15
|
+
u.password = u.password_confirmation = "Generic13"
|
16
|
+
u.save!
|
17
|
+
u.password = u.password_confirmation = "Generic12"
|
18
|
+
|
19
|
+
proc { u.save! }.should raise_error(ActiveRecord::RecordInvalid)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should produce multiple password models" do
|
23
|
+
u = User.new(:email => "generic2@example.com")
|
24
|
+
u.password = u.password_confirmation = "Generic12"
|
25
|
+
u.save!
|
26
|
+
u.password = u.password_confirmation = "Generic13"
|
27
|
+
u.save!
|
28
|
+
|
29
|
+
u.passwords.length.should == 2
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should not store more than 4 passwords" do
|
33
|
+
User.destroy_all
|
34
|
+
u = User.new(:email => "generic3@example.com")
|
35
|
+
%w(Generic12 Generic13 Generic14 Generic15 Generic16 Generic17 Generic18).each do |pw|
|
36
|
+
u.password = u.password_confirmation = pw
|
37
|
+
u.save!
|
38
|
+
end
|
39
|
+
|
40
|
+
u.passwords.length.should == 4
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should not be valid if password and confirmation are skipped" do
|
44
|
+
u = User.new(:email => "generic@example.com")
|
45
|
+
u.should_not be_valid
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should create a user that can have a password validated against it" do
|
49
|
+
email = "generic@example.com"
|
50
|
+
password = "Ab12345"
|
51
|
+
|
52
|
+
User.destroy_all
|
53
|
+
returning(User.new(:email => email)) { |user|
|
54
|
+
user.password = password
|
55
|
+
user.password_confirmation = password
|
56
|
+
user.save!
|
57
|
+
}
|
58
|
+
|
59
|
+
User.find_by_email(email).password_matches?(password).should == true
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should not produce error messages that contain 'secret' or are duplicates" do
|
63
|
+
u = User.new(:email => "generic@example.com")
|
64
|
+
u.password = u.password_confirmation = nil
|
65
|
+
u.valid?
|
66
|
+
u.errors.to_a.should == u.errors.to_a.uniq
|
67
|
+
u.errors.to_a.collect { |ar| ar.first }.should_not include('secret')
|
68
|
+
u.errors.to_a.collect { |ar| ar.first }.should_not include('secret_confirmation')
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should create #password" do
|
72
|
+
u = User.new
|
73
|
+
u.password.should be_blank
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should create #password=" do
|
77
|
+
u = User.new
|
78
|
+
u.password = "hi there"
|
79
|
+
u.password.should_not be_blank
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should encrypt password assignments" do
|
83
|
+
u = User.new
|
84
|
+
u.password = "hi there"
|
85
|
+
u.password.should_not == "hi there"
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should create #password_confirmation" do
|
89
|
+
u = User.new
|
90
|
+
u.password_confirmation.should be_blank
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should create #password_confirmation=" do
|
94
|
+
u = User.new
|
95
|
+
u.password_confirmation = "hi there"
|
96
|
+
u.password_confirmation.should_not be_blank
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should encrypt password confirmation assignments" do
|
100
|
+
u = User.new
|
101
|
+
u.password_confirmation = "hi there"
|
102
|
+
u.password_confirmation.should_not == "hi there"
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should delegate persistence token to password model" do
|
106
|
+
u = User.new
|
107
|
+
u.password = "hi there"
|
108
|
+
u.persistence_token.should_not be_blank
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should reset the persistence token when password is assigned" do
|
113
|
+
pw = Password.new
|
114
|
+
pw.secret = "Hello12"
|
115
|
+
pw.persistence_token.should_not be_blank
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should encrypt the :secret and :secret_confirmation upon assignment in Password" do
|
119
|
+
u = User.new
|
120
|
+
pw = u.passwords.build
|
121
|
+
pw.secret = "Hello12"
|
122
|
+
pw.secret_confirmation = "Hello12"
|
123
|
+
|
124
|
+
pw.secret.should_not == "Hello12" # ...but we don't know what it actually should equal, 'cause that's randomized.
|
125
|
+
pw.secret_confirmation.should_not == "Hello12"
|
126
|
+
pw.secret.should == pw.secret_confirmation
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should force confirmation of the :secret on Password" do
|
130
|
+
u = User.new
|
131
|
+
pw = u.passwords.build
|
132
|
+
pw.secret = "Hello12"
|
133
|
+
pw.valid?
|
134
|
+
pw.errors.to_a.should_not be_empty
|
135
|
+
|
136
|
+
pw.secret_confirmation = "Hello1"
|
137
|
+
pw.valid?
|
138
|
+
pw.errors.on(:secret).should == "doesn't match confirmation"
|
139
|
+
|
140
|
+
pw.secret_confirmation = "Hello12"
|
141
|
+
pw.should be_valid
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should validate presence of :secret on Password' do
|
145
|
+
error_on(Password, :secret).should == "can't be blank"
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'should validate password length >= 7' do
|
149
|
+
error_on(Password, :secret, "123456").should include("must be at least 7 characters")
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'should validate password complexity' do
|
153
|
+
error_on(Password, :secret, "Ab12345").should == nil
|
154
|
+
error_on(Password, :secret, "1234567").should ==
|
155
|
+
"must contain at least 1 uppercase, 1 lowercase and 1 number"
|
156
|
+
error_on(Password, :secret, "abcdefg").should ==
|
157
|
+
"must contain at least 1 uppercase, 1 lowercase and 1 number"
|
158
|
+
error_on(Password, :secret, "ABCDEFG").should ==
|
159
|
+
"must contain at least 1 uppercase, 1 lowercase and 1 number"
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should add has_many :passwords to User' do
|
163
|
+
User.new.should respond_to(:passwords)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should expire passwords after 30 days or if no password is available" do
|
167
|
+
(u = User.new).password_expired?.should be_true
|
168
|
+
p = u.passwords.build(:created_at => 1.month.ago)
|
169
|
+
p.authenticatable = u # need to build the reverse relationship cause it's not saved yet... i hate that.
|
170
|
+
p.should be_expired
|
171
|
+
end
|
172
|
+
|
173
|
+
context "with password update frequency 90 days" do
|
174
|
+
subject { Auth::Model.new(:user, :behaviors => [:core], :password_update_frequency => 90.days) }
|
175
|
+
|
176
|
+
it "should expire passwords after 90 days or if no password is available" do
|
177
|
+
(u = User.new).password_expired?.should be_true # because there're no passwords yet
|
178
|
+
|
179
|
+
p = u.passwords.build(:created_at => 1.month.ago)
|
180
|
+
p.authenticatable = u # need to build the reverse relationship cause it's not saved yet... i hate that.
|
181
|
+
p.should_not be_expired
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spec/rails'
|
3
|
+
|
4
|
+
describe "Behavior: Remember Me", :type => :controller do
|
5
|
+
controller_name :sparkly_sessions
|
6
|
+
|
7
|
+
def cookies
|
8
|
+
controller.send(:cookies)
|
9
|
+
end
|
10
|
+
|
11
|
+
def reset_auth!
|
12
|
+
# the lack of a current user will trigger authentication of various flavors, making these tests possible.
|
13
|
+
controller.instance_variable_set("@current_user", nil)
|
14
|
+
end
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
Auth.configure do |c|
|
18
|
+
c.authenticate :user
|
19
|
+
c.behaviors = :core, :remember_me
|
20
|
+
c.remember_me.duration = 6.months
|
21
|
+
end
|
22
|
+
|
23
|
+
Auth.kick!
|
24
|
+
u = User.new(:email => "generic12@example.com")
|
25
|
+
u.password = u.password_confirmation = "Generic12"
|
26
|
+
u.save!
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should set an auth token cookie upon successful login" do
|
30
|
+
post :create, { :model => "User", :user => { :email => "generic12@example.com", :password => "Generic12", :remember_me => true } }
|
31
|
+
|
32
|
+
session[:session_token].should_not be_blank
|
33
|
+
|
34
|
+
# There should be a token in the remebered_tokens table. We can use that data to decide
|
35
|
+
# what should be in the cookie.
|
36
|
+
RemembranceToken.count.should == 1
|
37
|
+
|
38
|
+
# We're looking for a string containing password model ID, series token, and auth token.
|
39
|
+
token = RemembranceToken.first
|
40
|
+
|
41
|
+
cookies[:remembrance_token].should == token.value
|
42
|
+
end
|
43
|
+
|
44
|
+
context "a user with a remember token" do
|
45
|
+
before(:each) do
|
46
|
+
post :create, { :model => "User", :user => { :email => "generic12@example.com", :password => "Generic12", :remember_me => true } }
|
47
|
+
end
|
48
|
+
|
49
|
+
shared_examples_for "an expired or missing session" do
|
50
|
+
it "should authenticate with the auth token cookie" do
|
51
|
+
controller.current_user.should_not be_nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should generate a new auth token cookie" do
|
55
|
+
token = cookies[:remembrance_token]
|
56
|
+
controller.current_user
|
57
|
+
cookies[:remembrance_token].should_not == token
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should not change the series identifier" do
|
61
|
+
controller.current_user
|
62
|
+
controller.current_user.remembrance_tokens.first.series_token == @series_identifier
|
63
|
+
end
|
64
|
+
|
65
|
+
context "and an invalid token id but valid series id" do
|
66
|
+
before(:each) do
|
67
|
+
cookies[:remembrance_token] = { :value => cookies[:remembrance_token]+"1", :expires => 6.months.from_now }
|
68
|
+
reset_auth!
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should be considered a theft" do
|
72
|
+
# because the token is changed every time - if the wrong token is used it is due either to tampering or to
|
73
|
+
# using an expired token, indicating that someone has stolen and used the one-use token.
|
74
|
+
controller.current_user
|
75
|
+
flash[:error].should == Auth.remember_me.token_theft_message
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should delete all remembrance tokens" do
|
79
|
+
controller.current_user.remembrance_tokens.count.should == 0
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "and token data is not present" do
|
84
|
+
before(:each) do
|
85
|
+
cookies[:remembrance_token] = { :value => "", :expires => 6.months.from_now }
|
86
|
+
reset_auth!
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should not authenticate the user" do
|
90
|
+
controller.current_user.should == false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "and token is missing" do
|
95
|
+
before(:each) do
|
96
|
+
cookies.delete(:remembrance_token)
|
97
|
+
#cookies[:remembrance_token] = nil
|
98
|
+
reset_auth!
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should not authenticate the user" do
|
102
|
+
controller.current_user.should == false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "and an expired session" do
|
108
|
+
before(:each) do
|
109
|
+
@series_identifier = controller.current_user.remembrance_tokens.first.series_token
|
110
|
+
session[:active_at] = 30.days.ago # i'm pretty sure this is past the session duration.
|
111
|
+
reset_auth!
|
112
|
+
end
|
113
|
+
|
114
|
+
it_should_behave_like "an expired or missing session"
|
115
|
+
end
|
116
|
+
|
117
|
+
context "and a missing session" do
|
118
|
+
before(:each) do
|
119
|
+
@series_identifier = controller.current_user.remembrance_tokens.first.series_token
|
120
|
+
session.clear
|
121
|
+
reset_auth!
|
122
|
+
end
|
123
|
+
|
124
|
+
it_should_behave_like "an expired or missing session"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Auth::Behavior::Core::ControllerExtensions do
|
4
|
+
#subject { ApplicationController.new }
|
5
|
+
subject { ApplicationController.call(Rack::MockRequest.env_for("/").merge('REQUEST_URI' => '')).template.controller }
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
Auth.configure do |config|
|
9
|
+
config.session_duration = nil
|
10
|
+
config.authenticate :user
|
11
|
+
end
|
12
|
+
|
13
|
+
Auth.kick!
|
14
|
+
|
15
|
+
unless User.count == 1
|
16
|
+
u = User.new(:email => "generic4@example.com")
|
17
|
+
u.password = u.password_confirmation = "Generic12"
|
18
|
+
u.save!
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should let users authenticate with single access token" do
|
23
|
+
subject.params = { :single_access_token => User.first.single_access_token }
|
24
|
+
subject.current_user.should be_kind_of(User)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should not raise nil errors when Auth.session_duration is nil" do
|
28
|
+
subject.session = { :session_token => User.first.persistence_token }
|
29
|
+
|
30
|
+
subject.current_user.should be_kind_of(User)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Auth::Model do
|
4
|
+
context "given nonexisting model name" do
|
5
|
+
subject { Auth::Model.new(:nonexisting_user) }
|
6
|
+
|
7
|
+
it "should fail silently during initialization because it might not have been generated yet" do
|
8
|
+
proc { subject }.should_not raise_error
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "with default options" do
|
13
|
+
subject { Auth::Model.new(:user) }
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
Dispatcher.cleanup_application
|
17
|
+
Dispatcher.reload_application
|
18
|
+
subject.apply_options!
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should validate presence of :email on User" do
|
22
|
+
error_on(User, :email).should == "can't be blank"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should use :core behavior" do
|
26
|
+
subject.behaviors.should include(:core)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "with an empty :behaviors option" do
|
31
|
+
subject { Auth::Model.new(:user, :behaviors => []) }
|
32
|
+
before(:each) do
|
33
|
+
Dispatcher.cleanup_application
|
34
|
+
Dispatcher.reload_application
|
35
|
+
subject.apply_options!
|
36
|
+
end
|
37
|
+
it "should have no behaviors" do subject.behaviors.should be_empty end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "with a hash for :with option" do
|
41
|
+
subject { Auth::Model.new(:user, :with => {
|
42
|
+
:secret => :passwd,
|
43
|
+
:format => /^.{8}$/,
|
44
|
+
:message => "must be exactly 8 characters"
|
45
|
+
})}
|
46
|
+
|
47
|
+
before(:each) do
|
48
|
+
Dispatcher.cleanup_application
|
49
|
+
Dispatcher.reload_application
|
50
|
+
subject.apply_options!
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should validate presence of :email on User" do
|
54
|
+
error_on(User, :email).should == "can't be blank"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|