sparkly-auth 1.0.0
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/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
|