rails3-restful-authentication 3.0.1
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/CHANGELOG +70 -0
- data/README.textile +176 -0
- data/Rakefile +32 -0
- data/TODO +15 -0
- data/init.rb +3 -0
- data/lib/authentication.rb +40 -0
- data/lib/authentication/by_cookie_token.rb +73 -0
- data/lib/authentication/by_password.rb +64 -0
- data/lib/authorization.rb +14 -0
- data/lib/authorization/aasm_roles.rb +63 -0
- data/lib/authorization/stateful_roles.rb +62 -0
- data/lib/generators/authenticated/USAGE +1 -0
- data/lib/generators/authenticated/authenticated_generator.rb +524 -0
- data/lib/generators/authenticated/templates/_model_partial.html.erb +8 -0
- data/lib/generators/authenticated/templates/activation.erb +3 -0
- data/lib/generators/authenticated/templates/authenticated_system.rb +189 -0
- data/lib/generators/authenticated/templates/authenticated_test_helper.rb +22 -0
- data/lib/generators/authenticated/templates/controller.rb +41 -0
- data/lib/generators/authenticated/templates/features/accounts.feature +109 -0
- data/lib/generators/authenticated/templates/features/sessions.feature +134 -0
- data/lib/generators/authenticated/templates/features/step_definitions/ra_env.rb +9 -0
- data/lib/generators/authenticated/templates/features/step_definitions/ra_navigation_steps.rb +48 -0
- data/lib/generators/authenticated/templates/features/step_definitions/ra_resource_steps.rb +178 -0
- data/lib/generators/authenticated/templates/features/step_definitions/ra_response_steps.rb +169 -0
- data/lib/generators/authenticated/templates/features/step_definitions/rest_auth_features_helper.rb +81 -0
- data/lib/generators/authenticated/templates/features/step_definitions/user_steps.rb +131 -0
- data/lib/generators/authenticated/templates/helper.rb +2 -0
- data/lib/generators/authenticated/templates/login.html.erb +16 -0
- data/lib/generators/authenticated/templates/mailer.rb +26 -0
- data/lib/generators/authenticated/templates/migration.rb +26 -0
- data/lib/generators/authenticated/templates/model.rb +87 -0
- data/lib/generators/authenticated/templates/model_controller.rb +83 -0
- data/lib/generators/authenticated/templates/model_helper.rb +93 -0
- data/lib/generators/authenticated/templates/model_helper_spec.rb +158 -0
- data/lib/generators/authenticated/templates/observer.rb +11 -0
- data/lib/generators/authenticated/templates/signup.html.erb +19 -0
- data/lib/generators/authenticated/templates/signup_notification.erb +8 -0
- data/lib/generators/authenticated/templates/site_keys.rb +38 -0
- data/lib/generators/authenticated/templates/spec/controllers/access_control_spec.rb +101 -0
- data/lib/generators/authenticated/templates/spec/controllers/authenticated_system_spec.rb +102 -0
- data/lib/generators/authenticated/templates/spec/controllers/sessions_controller_spec.rb +127 -0
- data/lib/generators/authenticated/templates/spec/controllers/users_controller_spec.rb +131 -0
- data/lib/generators/authenticated/templates/spec/fixtures/users.yml +60 -0
- data/lib/generators/authenticated/templates/spec/helpers/users_helper_spec.rb +141 -0
- data/lib/generators/authenticated/templates/spec/models/user_spec.rb +227 -0
- data/lib/generators/authenticated/templates/test/functional_test.rb +82 -0
- data/lib/generators/authenticated/templates/test/mailer_test.rb +32 -0
- data/lib/generators/authenticated/templates/test/model_functional_test.rb +93 -0
- data/lib/generators/authenticated/templates/test/unit_test.rb +164 -0
- data/lib/restful_authentication.rb +3 -0
- data/lib/tasks/auth.rake +33 -0
- data/lib/trustification.rb +14 -0
- data/lib/trustification/email_validation.rb +20 -0
- metadata +130 -0
@@ -0,0 +1,131 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
# Be sure to include AuthenticatedTestHelper in spec/spec_helper.rb instead
|
4
|
+
# Then, you can remove it from this and the units test.
|
5
|
+
include AuthenticatedTestHelper
|
6
|
+
|
7
|
+
describe UsersController do
|
8
|
+
fixtures :users
|
9
|
+
|
10
|
+
it 'allows signup' do
|
11
|
+
lambda do
|
12
|
+
create_user
|
13
|
+
response.should be_redirect
|
14
|
+
end.should change(User, :count).by(1)
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
it 'requires login on signup' do
|
21
|
+
lambda do
|
22
|
+
create_user(:login => nil)
|
23
|
+
assigns[:user].errors.get(:login).should_not be_nil
|
24
|
+
response.should be_success
|
25
|
+
end.should_not change(User, :count)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'requires password on signup' do
|
29
|
+
lambda do
|
30
|
+
create_user(:password => nil)
|
31
|
+
assigns[:user].errors.get(:password).should_not be_nil
|
32
|
+
response.should be_success
|
33
|
+
end.should_not change(User, :count)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'requires password confirmation on signup' do
|
37
|
+
lambda do
|
38
|
+
create_user(:password_confirmation => nil)
|
39
|
+
assigns[:user].errors.get(:password_confirmation).should_not be_nil
|
40
|
+
response.should be_success
|
41
|
+
end.should_not change(User, :count)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'requires email on signup' do
|
45
|
+
lambda do
|
46
|
+
create_user(:email => nil)
|
47
|
+
assigns[:user].errors.get(:email).should_not be_nil
|
48
|
+
response.should be_success
|
49
|
+
end.should_not change(User, :count)
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
def create_user(options = {})
|
55
|
+
post :create, :user => { :login => 'quire', :email => 'quire@example.com',
|
56
|
+
:password => 'quire69', :password_confirmation => 'quire69' }.merge(options)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe UsersController do
|
61
|
+
describe "route recognition and generation" do
|
62
|
+
it "should generate params for users's index action from GET /users" do
|
63
|
+
{:get => '/users'}.should route_to(:controller => 'users', :action => 'index')
|
64
|
+
{:get => '/users.xml'}.should route_to(:controller => 'users', :action => 'index', :format => 'xml')
|
65
|
+
{:get => '/users.json'}.should route_to(:controller => 'users', :action => 'index', :format => 'json')
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should generate params for users's new action from GET /users" do
|
69
|
+
{:get => '/users/new'}.should route_to(:controller => 'users', :action => 'new')
|
70
|
+
{:get => '/users/new.xml'}.should route_to(:controller => 'users', :action => 'new', :format => 'xml')
|
71
|
+
{:get => '/users/new.json'}.should route_to(:controller => 'users', :action => 'new', :format => 'json')
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should generate params for users's create action from POST /users" do
|
75
|
+
{:post => '/users'}.should route_to(:controller => 'users', :action => 'create')
|
76
|
+
{:post => '/users.xml'}.should route_to(:controller => 'users', :action => 'create', :format => 'xml')
|
77
|
+
{:post => '/users.json'}.should route_to(:controller => 'users', :action => 'create', :format => 'json')
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should generate params for users's show action from GET /users/1" do
|
81
|
+
{:get => '/users/1'}.should route_to(:controller => 'users', :action => 'show', :id => '1')
|
82
|
+
{:get => '/users/1.xml'}.should route_to(:controller => 'users', :action => 'show', :id => '1', :format => 'xml')
|
83
|
+
{:get => '/users/1.json'}.should route_to(:controller => 'users', :action => 'show', :id => '1', :format => 'json')
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should generate params for users's edit action from GET /users/1/edit" do
|
87
|
+
{:get => '/users/1/edit'}.should route_to(:controller => 'users', :action => 'edit', :id => '1')
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should generate params {:controller => 'users', :action => update', :id => '1'} from PUT /users/1" do
|
91
|
+
{:put => '/users/1'}.should route_to(:controller => 'users', :action => 'update', :id => '1')
|
92
|
+
{:put => '/users/1.xml'}.should route_to(:controller => 'users', :action => 'update', :id => '1', :format => 'xml')
|
93
|
+
{:put => '/users/1.json'}.should route_to(:controller => 'users', :action => 'update', :id => '1', :format => 'json')
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should generate params for users's destroy action from DELETE /users/1" do
|
97
|
+
{:delete => '/users/1'}.should route_to(:controller => 'users', :action => 'destroy', :id => '1')
|
98
|
+
{:delete => '/users/1.xml'}.should route_to(:controller => 'users', :action => 'destroy', :id => '1', :format => 'xml')
|
99
|
+
{:delete => '/users/1.json'}.should route_to(:controller => 'users', :action => 'destroy', :id => '1', :format => 'json')
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "named routing" do
|
104
|
+
before(:each) do
|
105
|
+
get :new
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should route users_path() to /users" do
|
109
|
+
users_path().should == "/users"
|
110
|
+
controller.users_path(:format => 'xml').should == "/users.xml"
|
111
|
+
controller.users_path(:format => 'json').should == "/users.json"
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should route new_user_path() to /users/new" do
|
115
|
+
new_user_path().should == "/users/new"
|
116
|
+
controller.new_user_path(:format => 'xml').should == "/users/new.xml"
|
117
|
+
controller.new_user_path(:format => 'json').should == "/users/new.json"
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should route user_(:id => '1') to /users/1" do
|
121
|
+
user_path(:id => '1').should == "/users/1"
|
122
|
+
controller.user_path(:id => '1', :format => 'xml').should == "/users/1.xml"
|
123
|
+
controller.user_path(:id => '1', :format => 'json').should == "/users/1.json"
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should route edit_user_path(:id => '1') to /users/1/edit" do
|
127
|
+
controller.edit_user_path(:id => '1').should == "/users/1/edit"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
<%
|
2
|
+
## this code must match that in templates/model.rb
|
3
|
+
require 'digest/sha1'
|
4
|
+
def make_fake_token
|
5
|
+
@fake_token_counter ||= 0
|
6
|
+
@fake_token_counter += 1
|
7
|
+
Digest::SHA1.hexdigest(@fake_token_counter.to_s)
|
8
|
+
end
|
9
|
+
salts = (1..2).map{ make_fake_token }
|
10
|
+
passwds = salts.map{ |salt| password_digest('monkey', salt) }
|
11
|
+
-%>
|
12
|
+
|
13
|
+
quentin:
|
14
|
+
id: 1
|
15
|
+
login: quentin
|
16
|
+
email: quentin@example.com
|
17
|
+
salt: <%= salts[0] %> # SHA1('0')
|
18
|
+
crypted_password: <%= passwds[0] %> # 'monkey'
|
19
|
+
created_at: <%%= 5.days.ago.to_s :db %>
|
20
|
+
remember_token_expires_at: <%%= 1.days.from_now.to_s %>
|
21
|
+
remember_token: <%= make_fake_token %>
|
22
|
+
<% if options[:include_activation] -%>
|
23
|
+
activation_code:
|
24
|
+
activated_at: <%%= 5.days.ago.to_s :db %>
|
25
|
+
<% end -%>
|
26
|
+
<% if options[:stateful] -%>
|
27
|
+
state: active
|
28
|
+
<% end -%>
|
29
|
+
|
30
|
+
aaron:
|
31
|
+
id: 2
|
32
|
+
login: aaron
|
33
|
+
email: aaron@example.com
|
34
|
+
salt: <%= salts[1] %> # SHA1('1')
|
35
|
+
crypted_password: <%= passwds[1] %> # 'monkey'
|
36
|
+
created_at: <%%= 1.days.ago.to_s :db %>
|
37
|
+
remember_token_expires_at:
|
38
|
+
remember_token:
|
39
|
+
<% if options[:include_activation] -%>
|
40
|
+
activation_code: <%= make_fake_token %>
|
41
|
+
activated_at:
|
42
|
+
<% end -%>
|
43
|
+
<% if options[:stateful] %>
|
44
|
+
state: pending
|
45
|
+
<% end -%>
|
46
|
+
|
47
|
+
|
48
|
+
old_password_holder:
|
49
|
+
id: 3
|
50
|
+
login: old_password_holder
|
51
|
+
email: salty_dog@example.com
|
52
|
+
salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
|
53
|
+
crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
|
54
|
+
created_at: <%%= 1.days.ago.to_s :db %>
|
55
|
+
<% if options[:include_activation] %>
|
56
|
+
activation_code:
|
57
|
+
activated_at: <%%= 5.days.ago.to_s :db %>
|
58
|
+
<% end %>
|
59
|
+
<% if options[:stateful] %>
|
60
|
+
state: active<% end %>
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
include ApplicationHelper
|
3
|
+
include UsersHelper
|
4
|
+
include AuthenticatedTestHelper
|
5
|
+
|
6
|
+
describe UsersHelper do
|
7
|
+
before do
|
8
|
+
@user = mock_user
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "if_authorized" do
|
12
|
+
it "yields if authorized" do
|
13
|
+
helper.should_receive(:authorized?).with('a','r').and_return(true)
|
14
|
+
helper.if_authorized?('a','r'){|action,resource| [action,resource,'hi'] }.should == ['a','r','hi']
|
15
|
+
end
|
16
|
+
it "does nothing if not authorized" do
|
17
|
+
helper.should_receive(:authorized?).with('a','r').and_return(false)
|
18
|
+
helper.if_authorized?('a','r'){ 'hi' }.should be_nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "link_to_user" do
|
23
|
+
it "should give an error on a nil user" do
|
24
|
+
lambda { helper.link_to_user(nil) }.should raise_error('Invalid user')
|
25
|
+
end
|
26
|
+
it "should link to the given user" do
|
27
|
+
helper.should_receive(:user_path).at_least(:once).and_return('/users/1')
|
28
|
+
helper.link_to_user(@user).should have_tag("a[href='/users/1']")
|
29
|
+
end
|
30
|
+
it "should use given link text if :content_text is specified" do
|
31
|
+
helper.link_to_user(@user, :content_text => 'Hello there!').should have_tag("a", :text => 'Hello there!')
|
32
|
+
end
|
33
|
+
it "should use the login as link text with no :content_method specified" do
|
34
|
+
helper.link_to_user(@user).should have_tag("a", :text => 'user_name')
|
35
|
+
end
|
36
|
+
it "should use the name as link text with :content_method => :name" do
|
37
|
+
helper.link_to_user(@user, :content_method => :name).should have_tag("a", :text => 'U. Surname')
|
38
|
+
end
|
39
|
+
it "should use the login as title with no :title_method specified" do
|
40
|
+
helper.link_to_user(@user).should have_tag("a[title='user_name']")
|
41
|
+
end
|
42
|
+
it "should use the name as link title with :content_method => :name" do
|
43
|
+
helper.link_to_user(@user, :title_method => :name).should have_tag("a[title='U. Surname']")
|
44
|
+
end
|
45
|
+
it "should have nickname as a class by default" do
|
46
|
+
helper.link_to_user(@user).should have_tag("a.nickname")
|
47
|
+
end
|
48
|
+
it "should take other classes and no longer have the nickname class" do
|
49
|
+
result = helper.link_to_user(@user, :class => 'foo bar')
|
50
|
+
result.should have_tag("a.foo")
|
51
|
+
result.should have_tag("a.bar")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "link_to_login_with_IP" do
|
56
|
+
it "should link to the login_path" do
|
57
|
+
helper.link_to_login_with_IP().should have_tag("a[href='/login']")
|
58
|
+
end
|
59
|
+
it "should use given link text if :content_text is specified" do
|
60
|
+
helper.link_to_login_with_IP('Hello there!').should have_tag("a", :text => 'Hello there!')
|
61
|
+
end
|
62
|
+
it "should use the login as link text with no :content_method specified" do
|
63
|
+
helper.link_to_login_with_IP().should have_tag("a", :text => '0.0.0.0')
|
64
|
+
end
|
65
|
+
it "should use the ip address as title" do
|
66
|
+
helper.link_to_login_with_IP().should have_tag("a[title='0.0.0.0']")
|
67
|
+
end
|
68
|
+
it "should by default be like school in summer and have no class" do
|
69
|
+
helper.link_to_login_with_IP().should_not have_tag("a.nickname")
|
70
|
+
end
|
71
|
+
it "should have some class if you tell it to" do
|
72
|
+
result = helper.link_to_login_with_IP(nil, :class => 'foo bar')
|
73
|
+
result.should have_tag("a.foo")
|
74
|
+
result.should have_tag("a.bar")
|
75
|
+
end
|
76
|
+
it "should have some class if you tell it to" do
|
77
|
+
result = helper.link_to_login_with_IP(nil, :tag => 'abbr')
|
78
|
+
result.should have_tag("abbr[title='0.0.0.0']")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "link_to_current_user, When logged in" do
|
83
|
+
before do
|
84
|
+
helper.current_user = @user
|
85
|
+
end
|
86
|
+
it "should link to the given user" do
|
87
|
+
helper.should_receive(:user_path).at_least(:once).and_return('/users/1')
|
88
|
+
helper.link_to_current_user().should have_tag("a[href='/users/1']")
|
89
|
+
end
|
90
|
+
it "should use given link text if :content_text is specified" do
|
91
|
+
helper.link_to_current_user(:content_text => 'Hello there!').should have_tag("a", :text => 'Hello there!')
|
92
|
+
end
|
93
|
+
it "should use the login as link text with no :content_method specified" do
|
94
|
+
helper.link_to_current_user().should have_tag("a", :text => 'user_name')
|
95
|
+
end
|
96
|
+
it "should use the name as link text with :content_method => :name" do
|
97
|
+
helper.link_to_current_user(:content_method => :name).should have_tag("a", :text => 'U. Surname')
|
98
|
+
end
|
99
|
+
it "should use the login as title with no :title_method specified" do
|
100
|
+
helper.link_to_current_user().should have_tag("a[title='user_name']")
|
101
|
+
end
|
102
|
+
it "should use the name as link title with :content_method => :name" do
|
103
|
+
helper.link_to_current_user(:title_method => :name).should have_tag("a[title='U. Surname']")
|
104
|
+
end
|
105
|
+
it "should have nickname as a class" do
|
106
|
+
helper.link_to_current_user().should have_tag("a.nickname")
|
107
|
+
end
|
108
|
+
it "should take other classes and no longer have the nickname class" do
|
109
|
+
result = helper.link_to_current_user(:class => 'foo bar')
|
110
|
+
result.should have_tag("a.foo")
|
111
|
+
result.should have_tag("a.bar")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "link_to_current_user, When logged out" do
|
116
|
+
before do
|
117
|
+
helper.current_user = nil
|
118
|
+
end
|
119
|
+
it "should link to the login_path" do
|
120
|
+
helper.link_to_current_user().should have_tag("a[href='/login']")
|
121
|
+
end
|
122
|
+
it "should use given link text if :content_text is specified" do
|
123
|
+
helper.link_to_current_user(:content_text => 'Hello there!').should have_tag("a", :text => 'Hello there!')
|
124
|
+
end
|
125
|
+
it "should use 'not signed in' as link text with no :content_method specified" do
|
126
|
+
helper.link_to_current_user().should have_tag("a", :text => 'not signed in')
|
127
|
+
end
|
128
|
+
it "should use the ip address as title" do
|
129
|
+
helper.link_to_current_user().should have_tag("a[title='0.0.0.0']")
|
130
|
+
end
|
131
|
+
it "should by default be like school in summer and have no class" do
|
132
|
+
helper.link_to_current_user().should_not have_tag("a.nickname")
|
133
|
+
end
|
134
|
+
it "should have some class if you tell it to" do
|
135
|
+
result = helper.link_to_current_user(:class => 'foo bar')
|
136
|
+
result.should have_tag("a.foo")
|
137
|
+
result.should have_tag("a.bar")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
@@ -0,0 +1,227 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
3
|
+
|
4
|
+
# Be sure to include AuthenticatedTestHelper in spec/spec_helper.rb instead.
|
5
|
+
# Then, you can remove it from this and the functional test.
|
6
|
+
include AuthenticatedTestHelper
|
7
|
+
|
8
|
+
describe User do
|
9
|
+
fixtures :users
|
10
|
+
|
11
|
+
describe 'being created' do
|
12
|
+
before do
|
13
|
+
@user = nil
|
14
|
+
@creating_user = lambda do
|
15
|
+
@user = create_user
|
16
|
+
violated "#{@user.errors.full_messages.to_sentence}" if @user.new_record?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'increments User#count' do
|
21
|
+
@creating_user.should change(User, :count).by(1)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Validations
|
27
|
+
#
|
28
|
+
|
29
|
+
it 'requires login' do
|
30
|
+
lambda do
|
31
|
+
u = create_user(:login => nil)
|
32
|
+
u.errors.get(:login).should_not be_nil
|
33
|
+
end.should_not change(User, :count)
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'allows legitimate logins:' do
|
37
|
+
['123', '1234567890_234567890_234567890_234567890',
|
38
|
+
'hello.-_there@funnychar.com'].each do |login_str|
|
39
|
+
it "'#{login_str}'" do
|
40
|
+
lambda do
|
41
|
+
u = create_user(:login => login_str)
|
42
|
+
u.errors.get(:login).should be_nil
|
43
|
+
end.should change(User, :count).by(1)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
describe 'disallows illegitimate logins:' do
|
48
|
+
['12', '1234567890_234567890_234567890_234567890_', "tab\t", "newline\n",
|
49
|
+
"Iñtërnâtiônàlizætiøn hasn't happened to ruby 1.8 yet",
|
50
|
+
'semicolon;', 'quote"', 'tick\'', 'backtick`', 'percent%', 'plus+', 'space '].each do |login_str|
|
51
|
+
it "'#{login_str}'" do
|
52
|
+
lambda do
|
53
|
+
u = create_user(:login => login_str)
|
54
|
+
u.errors.get(:login).should_not be_nil
|
55
|
+
end.should_not change(User, :count)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'requires password' do
|
61
|
+
lambda do
|
62
|
+
u = create_user(:password => nil)
|
63
|
+
u.errors.get(:password).should_not be_nil
|
64
|
+
end.should_not change(User, :count)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'requires password confirmation' do
|
68
|
+
lambda do
|
69
|
+
u = create_user(:password_confirmation => nil)
|
70
|
+
u.errors.get(:password_confirmation).should_not be_nil
|
71
|
+
end.should_not change(User, :count)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'requires email' do
|
75
|
+
lambda do
|
76
|
+
u = create_user(:email => nil)
|
77
|
+
u.errors.get(:email).should_not be_nil
|
78
|
+
end.should_not change(User, :count)
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'allows legitimate emails:' do
|
82
|
+
['foo@bar.com', 'foo@newskool-tld.museum', 'foo@twoletter-tld.de', 'foo@nonexistant-tld.qq',
|
83
|
+
'r@a.wk', '1234567890-234567890-234567890-234567890-234567890-234567890-234567890-234567890-234567890@gmail.com',
|
84
|
+
'hello.-_there@funnychar.com', 'uucp%addr@gmail.com', 'hello+routing-str@gmail.com',
|
85
|
+
'domain@can.haz.many.sub.doma.in', 'student.name@university.edu'
|
86
|
+
].each do |email_str|
|
87
|
+
it "'#{email_str}'" do
|
88
|
+
lambda do
|
89
|
+
u = create_user(:email => email_str)
|
90
|
+
u.errors.get(:email).should be_nil
|
91
|
+
end.should change(User, :count).by(1)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
describe 'disallows illegitimate emails' do
|
96
|
+
['!!@nobadchars.com', 'foo@no-rep-dots..com', 'foo@badtld.xxx', 'foo@toolongtld.abcdefg',
|
97
|
+
'Iñtërnâtiônàlizætiøn@hasnt.happened.to.email', 'need.domain.and.tld@de', "tab\t", "newline\n",
|
98
|
+
'r@.wk', '1234567890-234567890-234567890-234567890-234567890-234567890-234567890-234567890-234567890@gmail2.com',
|
99
|
+
# these are technically allowed but not seen in practice:
|
100
|
+
'uucp!addr@gmail.com', 'semicolon;@gmail.com', 'quote"@gmail.com', 'tick\'@gmail.com', 'backtick`@gmail.com', 'space @gmail.com', 'bracket<@gmail.com', 'bracket>@gmail.com'
|
101
|
+
].each do |email_str|
|
102
|
+
it "'#{email_str}'" do
|
103
|
+
lambda do
|
104
|
+
u = create_user(:email => email_str)
|
105
|
+
u.errors.get(:email).should_not be_nil
|
106
|
+
end.should_not change(User, :count)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'allows legitimate names:' do
|
112
|
+
['Andre The Giant (7\'4", 520 lb.) -- has a posse',
|
113
|
+
'', '1234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890',
|
114
|
+
].each do |name_str|
|
115
|
+
it "'#{name_str}'" do
|
116
|
+
lambda do
|
117
|
+
u = create_user(:name => name_str)
|
118
|
+
u.errors.get(:name).should be_nil
|
119
|
+
end.should change(User, :count).by(1)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
describe "disallows illegitimate names" do
|
124
|
+
["tab\t", "newline\n",
|
125
|
+
'1234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_',
|
126
|
+
].each do |name_str|
|
127
|
+
it "'#{name_str}'" do
|
128
|
+
lambda do
|
129
|
+
u = create_user(:name => name_str)
|
130
|
+
u.errors.get(:name).should_not be_nil
|
131
|
+
end.should_not change(User, :count)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'resets password' do
|
137
|
+
users(:quentin).update_attributes(:password => 'new password', :password_confirmation => 'new password')
|
138
|
+
User.authenticate('quentin', 'new password').should == users(:quentin)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'does not rehash password' do
|
142
|
+
users(:quentin).update_attributes(:login => 'quentin2')
|
143
|
+
User.authenticate('quentin2', 'monkey').should == users(:quentin)
|
144
|
+
end
|
145
|
+
|
146
|
+
#
|
147
|
+
# Authentication
|
148
|
+
#
|
149
|
+
|
150
|
+
it 'authenticates user' do
|
151
|
+
User.authenticate('quentin', 'monkey').should == users(:quentin)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "doesn't authenticate user with bad password" do
|
155
|
+
User.authenticate('quentin', 'invalid_password').should be_nil
|
156
|
+
end
|
157
|
+
|
158
|
+
if REST_AUTH_SITE_KEY.blank?
|
159
|
+
# old-school passwords
|
160
|
+
it "authenticates a user against a hard-coded old-style password" do
|
161
|
+
User.authenticate('old_password_holder', 'test').should == users(:old_password_holder)
|
162
|
+
end
|
163
|
+
else
|
164
|
+
it "doesn't authenticate a user against a hard-coded old-style password" do
|
165
|
+
User.authenticate('old_password_holder', 'test').should be_nil
|
166
|
+
end
|
167
|
+
|
168
|
+
# New installs should bump this up and set REST_AUTH_DIGEST_STRETCHES to give a 10ms encrypt time or so
|
169
|
+
desired_encryption_expensiveness_ms = 0.1
|
170
|
+
it "takes longer than #{desired_encryption_expensiveness_ms}ms to encrypt a password" do
|
171
|
+
test_reps = 100
|
172
|
+
start_time = Time.now; test_reps.times{ User.authenticate('quentin', 'monkey'+rand.to_s) }; end_time = Time.now
|
173
|
+
auth_time_ms = 1000 * (end_time - start_time)/test_reps
|
174
|
+
auth_time_ms.should > desired_encryption_expensiveness_ms
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
#
|
179
|
+
# Authentication
|
180
|
+
#
|
181
|
+
|
182
|
+
it 'sets remember token' do
|
183
|
+
users(:quentin).remember_me
|
184
|
+
users(:quentin).remember_token.should_not be_nil
|
185
|
+
users(:quentin).remember_token_expires_at.should_not be_nil
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'unsets remember token' do
|
189
|
+
users(:quentin).remember_me
|
190
|
+
users(:quentin).remember_token.should_not be_nil
|
191
|
+
users(:quentin).forget_me
|
192
|
+
users(:quentin).remember_token.should be_nil
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'remembers me for one week' do
|
196
|
+
before = 1.week.from_now.utc
|
197
|
+
users(:quentin).remember_me_for 1.week
|
198
|
+
after = 1.week.from_now.utc
|
199
|
+
users(:quentin).remember_token.should_not be_nil
|
200
|
+
users(:quentin).remember_token_expires_at.should_not be_nil
|
201
|
+
users(:quentin).remember_token_expires_at.between?(before, after).should be_true
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'remembers me until one week' do
|
205
|
+
time = 1.week.from_now.utc
|
206
|
+
users(:quentin).remember_me_until time
|
207
|
+
users(:quentin).remember_token.should_not be_nil
|
208
|
+
users(:quentin).remember_token_expires_at.should_not be_nil
|
209
|
+
users(:quentin).remember_token_expires_at.should == time
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'remembers me default two weeks' do
|
213
|
+
before = 2.weeks.from_now.utc
|
214
|
+
users(:quentin).remember_me
|
215
|
+
after = 2.weeks.from_now.utc
|
216
|
+
users(:quentin).remember_token.should_not be_nil
|
217
|
+
users(:quentin).remember_token_expires_at.should_not be_nil
|
218
|
+
users(:quentin).remember_token_expires_at.between?(before, after).should be_true
|
219
|
+
end
|
220
|
+
|
221
|
+
protected
|
222
|
+
def create_user(options = {})
|
223
|
+
record = User.new({ :login => 'quire', :email => 'quire@example.com', :password => 'quire69', :password_confirmation => 'quire69' }.merge(options))
|
224
|
+
record.save
|
225
|
+
record
|
226
|
+
end
|
227
|
+
end
|