##// END OF EJS Templates
LDAP: adds the ability to bind with user's account (#1913)....
Jean-Philippe Lang -
r9121:fdeb398c5e06
parent child
Show More
@@ -1,151 +1,157
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'iconv'
18 require 'iconv'
19 require 'net/ldap'
19 require 'net/ldap'
20 require 'net/ldap/dn'
20
21
21 class AuthSourceLdap < AuthSource
22 class AuthSourceLdap < AuthSource
22 validates_presence_of :host, :port, :attr_login
23 validates_presence_of :host, :port, :attr_login
23 validates_length_of :name, :host, :maximum => 60, :allow_nil => true
24 validates_length_of :name, :host, :maximum => 60, :allow_nil => true
24 validates_length_of :account, :account_password, :base_dn, :filter, :maximum => 255, :allow_blank => true
25 validates_length_of :account, :account_password, :base_dn, :filter, :maximum => 255, :allow_blank => true
25 validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
26 validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
26 validates_numericality_of :port, :only_integer => true
27 validates_numericality_of :port, :only_integer => true
27 validate :validate_filter
28 validate :validate_filter
28
29
29 before_validation :strip_ldap_attributes
30 before_validation :strip_ldap_attributes
30
31
31 def initialize(attributes=nil, *args)
32 def initialize(attributes=nil, *args)
32 super
33 super
33 self.port = 389 if self.port == 0
34 self.port = 389 if self.port == 0
34 end
35 end
35
36
36 def authenticate(login, password)
37 def authenticate(login, password)
37 return nil if login.blank? || password.blank?
38 return nil if login.blank? || password.blank?
38 attrs = get_user_dn(login)
39 attrs = get_user_dn(login, password)
39
40
40 if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password)
41 if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password)
41 logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
42 logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
42 return attrs.except(:dn)
43 return attrs.except(:dn)
43 end
44 end
44 rescue Net::LDAP::LdapError => e
45 rescue Net::LDAP::LdapError => e
45 raise AuthSourceException.new(e.message)
46 raise AuthSourceException.new(e.message)
46 end
47 end
47
48
48 # test the connection to the LDAP
49 # test the connection to the LDAP
49 def test_connection
50 def test_connection
50 ldap_con = initialize_ldap_con(self.account, self.account_password)
51 ldap_con = initialize_ldap_con(self.account, self.account_password)
51 ldap_con.open { }
52 ldap_con.open { }
52 rescue Net::LDAP::LdapError => e
53 rescue Net::LDAP::LdapError => e
53 raise "LdapError: " + e.message
54 raise "LdapError: " + e.message
54 end
55 end
55
56
56 def auth_method_name
57 def auth_method_name
57 "LDAP"
58 "LDAP"
58 end
59 end
59
60
60 private
61 private
61
62
62 def ldap_filter
63 def ldap_filter
63 if filter.present?
64 if filter.present?
64 Net::LDAP::Filter.construct(filter)
65 Net::LDAP::Filter.construct(filter)
65 end
66 end
66 rescue Net::LDAP::LdapError
67 rescue Net::LDAP::LdapError
67 nil
68 nil
68 end
69 end
69
70
70 def validate_filter
71 def validate_filter
71 if filter.present? && ldap_filter.nil?
72 if filter.present? && ldap_filter.nil?
72 errors.add(:filter, :invalid)
73 errors.add(:filter, :invalid)
73 end
74 end
74 end
75 end
75
76
76 def strip_ldap_attributes
77 def strip_ldap_attributes
77 [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr|
78 [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr|
78 write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil?
79 write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil?
79 end
80 end
80 end
81 end
81
82
82 def initialize_ldap_con(ldap_user, ldap_password)
83 def initialize_ldap_con(ldap_user, ldap_password)
83 options = { :host => self.host,
84 options = { :host => self.host,
84 :port => self.port,
85 :port => self.port,
85 :encryption => (self.tls ? :simple_tls : nil)
86 :encryption => (self.tls ? :simple_tls : nil)
86 }
87 }
87 options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank?
88 options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank?
88 Net::LDAP.new options
89 Net::LDAP.new options
89 end
90 end
90
91
91 def get_user_attributes_from_ldap_entry(entry)
92 def get_user_attributes_from_ldap_entry(entry)
92 {
93 {
93 :dn => entry.dn,
94 :dn => entry.dn,
94 :firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
95 :firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
95 :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
96 :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
96 :mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
97 :mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
97 :auth_source_id => self.id
98 :auth_source_id => self.id
98 }
99 }
99 end
100 end
100
101
101 # Return the attributes needed for the LDAP search. It will only
102 # Return the attributes needed for the LDAP search. It will only
102 # include the user attributes if on-the-fly registration is enabled
103 # include the user attributes if on-the-fly registration is enabled
103 def search_attributes
104 def search_attributes
104 if onthefly_register?
105 if onthefly_register?
105 ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]
106 ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]
106 else
107 else
107 ['dn']
108 ['dn']
108 end
109 end
109 end
110 end
110
111
111 # Check if a DN (user record) authenticates with the password
112 # Check if a DN (user record) authenticates with the password
112 def authenticate_dn(dn, password)
113 def authenticate_dn(dn, password)
113 if dn.present? && password.present?
114 if dn.present? && password.present?
114 initialize_ldap_con(dn, password).bind
115 initialize_ldap_con(dn, password).bind
115 end
116 end
116 end
117 end
117
118
118 # Get the user's dn and any attributes for them, given their login
119 # Get the user's dn and any attributes for them, given their login
119 def get_user_dn(login)
120 def get_user_dn(login, password)
121 ldap_con = nil
122 if self.account && self.account.include?("login")
123 ldap_con = initialize_ldap_con(self.account.sub("$login", Net::LDAP::DN.escape(login)), password)
124 else
120 ldap_con = initialize_ldap_con(self.account, self.account_password)
125 ldap_con = initialize_ldap_con(self.account, self.account_password)
126 end
121 login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
127 login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
122 object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
128 object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
123 attrs = {}
129 attrs = {}
124
130
125 search_filter = object_filter & login_filter
131 search_filter = object_filter & login_filter
126 if f = ldap_filter
132 if f = ldap_filter
127 search_filter = search_filter & f
133 search_filter = search_filter & f
128 end
134 end
129
135
130 ldap_con.search( :base => self.base_dn,
136 ldap_con.search( :base => self.base_dn,
131 :filter => search_filter,
137 :filter => search_filter,
132 :attributes=> search_attributes) do |entry|
138 :attributes=> search_attributes) do |entry|
133
139
134 if onthefly_register?
140 if onthefly_register?
135 attrs = get_user_attributes_from_ldap_entry(entry)
141 attrs = get_user_attributes_from_ldap_entry(entry)
136 else
142 else
137 attrs = {:dn => entry.dn}
143 attrs = {:dn => entry.dn}
138 end
144 end
139
145
140 logger.debug "DN found for #{login}: #{attrs[:dn]}" if logger && logger.debug?
146 logger.debug "DN found for #{login}: #{attrs[:dn]}" if logger && logger.debug?
141 end
147 end
142
148
143 attrs
149 attrs
144 end
150 end
145
151
146 def self.get_attr(entry, attr_name)
152 def self.get_attr(entry, attr_name)
147 if !attr_name.blank?
153 if !attr_name.blank?
148 entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
154 entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
149 end
155 end
150 end
156 end
151 end
157 end
@@ -1,884 +1,933
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class UserTest < ActiveSupport::TestCase
20 class UserTest < ActiveSupport::TestCase
21 fixtures :users, :members, :projects, :roles, :member_roles, :auth_sources,
21 fixtures :users, :members, :projects, :roles, :member_roles, :auth_sources,
22 :trackers, :issue_statuses,
22 :trackers, :issue_statuses,
23 :projects_trackers,
23 :projects_trackers,
24 :watchers,
24 :watchers,
25 :issue_categories, :enumerations, :issues,
25 :issue_categories, :enumerations, :issues,
26 :journals, :journal_details,
26 :journals, :journal_details,
27 :groups_users,
27 :groups_users,
28 :enabled_modules,
28 :enabled_modules,
29 :workflows
29 :workflows
30
30
31 def setup
31 def setup
32 @admin = User.find(1)
32 @admin = User.find(1)
33 @jsmith = User.find(2)
33 @jsmith = User.find(2)
34 @dlopper = User.find(3)
34 @dlopper = User.find(3)
35 end
35 end
36
36
37 test 'object_daddy creation' do
37 test 'object_daddy creation' do
38 User.generate_with_protected!(:firstname => 'Testing connection')
38 User.generate_with_protected!(:firstname => 'Testing connection')
39 User.generate_with_protected!(:firstname => 'Testing connection')
39 User.generate_with_protected!(:firstname => 'Testing connection')
40 assert_equal 2, User.count(:all, :conditions => {:firstname => 'Testing connection'})
40 assert_equal 2, User.count(:all, :conditions => {:firstname => 'Testing connection'})
41 end
41 end
42
42
43 def test_truth
43 def test_truth
44 assert_kind_of User, @jsmith
44 assert_kind_of User, @jsmith
45 end
45 end
46
46
47 def test_mail_should_be_stripped
47 def test_mail_should_be_stripped
48 u = User.new
48 u = User.new
49 u.mail = " foo@bar.com "
49 u.mail = " foo@bar.com "
50 assert_equal "foo@bar.com", u.mail
50 assert_equal "foo@bar.com", u.mail
51 end
51 end
52
52
53 def test_mail_validation
53 def test_mail_validation
54 u = User.new
54 u = User.new
55 u.mail = ''
55 u.mail = ''
56 assert !u.valid?
56 assert !u.valid?
57 assert_include I18n.translate('activerecord.errors.messages.blank'), u.errors[:mail]
57 assert_include I18n.translate('activerecord.errors.messages.blank'), u.errors[:mail]
58 end
58 end
59
59
60 def test_login_length_validation
60 def test_login_length_validation
61 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
61 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
62 user.login = "x" * (User::LOGIN_LENGTH_LIMIT+1)
62 user.login = "x" * (User::LOGIN_LENGTH_LIMIT+1)
63 assert !user.valid?
63 assert !user.valid?
64
64
65 user.login = "x" * (User::LOGIN_LENGTH_LIMIT)
65 user.login = "x" * (User::LOGIN_LENGTH_LIMIT)
66 assert user.valid?
66 assert user.valid?
67 assert user.save
67 assert user.save
68 end
68 end
69
69
70 def test_create
70 def test_create
71 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
71 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
72
72
73 user.login = "jsmith"
73 user.login = "jsmith"
74 user.password, user.password_confirmation = "password", "password"
74 user.password, user.password_confirmation = "password", "password"
75 # login uniqueness
75 # login uniqueness
76 assert !user.save
76 assert !user.save
77 assert_equal 1, user.errors.count
77 assert_equal 1, user.errors.count
78
78
79 user.login = "newuser"
79 user.login = "newuser"
80 user.password, user.password_confirmation = "passwd", "password"
80 user.password, user.password_confirmation = "passwd", "password"
81 # password confirmation
81 # password confirmation
82 assert !user.save
82 assert !user.save
83 assert_equal 1, user.errors.count
83 assert_equal 1, user.errors.count
84
84
85 user.password, user.password_confirmation = "password", "password"
85 user.password, user.password_confirmation = "password", "password"
86 assert user.save
86 assert user.save
87 end
87 end
88
88
89 context "User#before_create" do
89 context "User#before_create" do
90 should "set the mail_notification to the default Setting" do
90 should "set the mail_notification to the default Setting" do
91 @user1 = User.generate_with_protected!
91 @user1 = User.generate_with_protected!
92 assert_equal 'only_my_events', @user1.mail_notification
92 assert_equal 'only_my_events', @user1.mail_notification
93
93
94 with_settings :default_notification_option => 'all' do
94 with_settings :default_notification_option => 'all' do
95 @user2 = User.generate_with_protected!
95 @user2 = User.generate_with_protected!
96 assert_equal 'all', @user2.mail_notification
96 assert_equal 'all', @user2.mail_notification
97 end
97 end
98 end
98 end
99 end
99 end
100
100
101 context "User.login" do
101 context "User.login" do
102 should "be case-insensitive." do
102 should "be case-insensitive." do
103 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
103 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
104 u.login = 'newuser'
104 u.login = 'newuser'
105 u.password, u.password_confirmation = "password", "password"
105 u.password, u.password_confirmation = "password", "password"
106 assert u.save
106 assert u.save
107
107
108 u = User.new(:firstname => "Similar", :lastname => "User", :mail => "similaruser@somenet.foo")
108 u = User.new(:firstname => "Similar", :lastname => "User", :mail => "similaruser@somenet.foo")
109 u.login = 'NewUser'
109 u.login = 'NewUser'
110 u.password, u.password_confirmation = "password", "password"
110 u.password, u.password_confirmation = "password", "password"
111 assert !u.save
111 assert !u.save
112 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:login]
112 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:login]
113 end
113 end
114 end
114 end
115
115
116 def test_mail_uniqueness_should_not_be_case_sensitive
116 def test_mail_uniqueness_should_not_be_case_sensitive
117 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
117 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
118 u.login = 'newuser1'
118 u.login = 'newuser1'
119 u.password, u.password_confirmation = "password", "password"
119 u.password, u.password_confirmation = "password", "password"
120 assert u.save
120 assert u.save
121
121
122 u = User.new(:firstname => "new", :lastname => "user", :mail => "newUser@Somenet.foo")
122 u = User.new(:firstname => "new", :lastname => "user", :mail => "newUser@Somenet.foo")
123 u.login = 'newuser2'
123 u.login = 'newuser2'
124 u.password, u.password_confirmation = "password", "password"
124 u.password, u.password_confirmation = "password", "password"
125 assert !u.save
125 assert !u.save
126 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:mail]
126 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:mail]
127 end
127 end
128
128
129 def test_update
129 def test_update
130 assert_equal "admin", @admin.login
130 assert_equal "admin", @admin.login
131 @admin.login = "john"
131 @admin.login = "john"
132 assert @admin.save, @admin.errors.full_messages.join("; ")
132 assert @admin.save, @admin.errors.full_messages.join("; ")
133 @admin.reload
133 @admin.reload
134 assert_equal "john", @admin.login
134 assert_equal "john", @admin.login
135 end
135 end
136
136
137 def test_destroy_should_delete_members_and_roles
137 def test_destroy_should_delete_members_and_roles
138 members = Member.find_all_by_user_id(2)
138 members = Member.find_all_by_user_id(2)
139 ms = members.size
139 ms = members.size
140 rs = members.collect(&:roles).flatten.size
140 rs = members.collect(&:roles).flatten.size
141
141
142 assert_difference 'Member.count', - ms do
142 assert_difference 'Member.count', - ms do
143 assert_difference 'MemberRole.count', - rs do
143 assert_difference 'MemberRole.count', - rs do
144 User.find(2).destroy
144 User.find(2).destroy
145 end
145 end
146 end
146 end
147
147
148 assert_nil User.find_by_id(2)
148 assert_nil User.find_by_id(2)
149 assert Member.find_all_by_user_id(2).empty?
149 assert Member.find_all_by_user_id(2).empty?
150 end
150 end
151
151
152 def test_destroy_should_update_attachments
152 def test_destroy_should_update_attachments
153 attachment = Attachment.create!(:container => Project.find(1),
153 attachment = Attachment.create!(:container => Project.find(1),
154 :file => uploaded_test_file("testfile.txt", "text/plain"),
154 :file => uploaded_test_file("testfile.txt", "text/plain"),
155 :author_id => 2)
155 :author_id => 2)
156
156
157 User.find(2).destroy
157 User.find(2).destroy
158 assert_nil User.find_by_id(2)
158 assert_nil User.find_by_id(2)
159 assert_equal User.anonymous, attachment.reload.author
159 assert_equal User.anonymous, attachment.reload.author
160 end
160 end
161
161
162 def test_destroy_should_update_comments
162 def test_destroy_should_update_comments
163 comment = Comment.create!(
163 comment = Comment.create!(
164 :commented => News.create!(:project_id => 1, :author_id => 1, :title => 'foo', :description => 'foo'),
164 :commented => News.create!(:project_id => 1, :author_id => 1, :title => 'foo', :description => 'foo'),
165 :author => User.find(2),
165 :author => User.find(2),
166 :comments => 'foo'
166 :comments => 'foo'
167 )
167 )
168
168
169 User.find(2).destroy
169 User.find(2).destroy
170 assert_nil User.find_by_id(2)
170 assert_nil User.find_by_id(2)
171 assert_equal User.anonymous, comment.reload.author
171 assert_equal User.anonymous, comment.reload.author
172 end
172 end
173
173
174 def test_destroy_should_update_issues
174 def test_destroy_should_update_issues
175 issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
175 issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
176
176
177 User.find(2).destroy
177 User.find(2).destroy
178 assert_nil User.find_by_id(2)
178 assert_nil User.find_by_id(2)
179 assert_equal User.anonymous, issue.reload.author
179 assert_equal User.anonymous, issue.reload.author
180 end
180 end
181
181
182 def test_destroy_should_unassign_issues
182 def test_destroy_should_unassign_issues
183 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
183 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
184
184
185 User.find(2).destroy
185 User.find(2).destroy
186 assert_nil User.find_by_id(2)
186 assert_nil User.find_by_id(2)
187 assert_nil issue.reload.assigned_to
187 assert_nil issue.reload.assigned_to
188 end
188 end
189
189
190 def test_destroy_should_update_journals
190 def test_destroy_should_update_journals
191 issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
191 issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
192 issue.init_journal(User.find(2), "update")
192 issue.init_journal(User.find(2), "update")
193 issue.save!
193 issue.save!
194
194
195 User.find(2).destroy
195 User.find(2).destroy
196 assert_nil User.find_by_id(2)
196 assert_nil User.find_by_id(2)
197 assert_equal User.anonymous, issue.journals.first.reload.user
197 assert_equal User.anonymous, issue.journals.first.reload.user
198 end
198 end
199
199
200 def test_destroy_should_update_journal_details_old_value
200 def test_destroy_should_update_journal_details_old_value
201 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
201 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
202 issue.init_journal(User.find(1), "update")
202 issue.init_journal(User.find(1), "update")
203 issue.assigned_to_id = nil
203 issue.assigned_to_id = nil
204 assert_difference 'JournalDetail.count' do
204 assert_difference 'JournalDetail.count' do
205 issue.save!
205 issue.save!
206 end
206 end
207 journal_detail = JournalDetail.first(:order => 'id DESC')
207 journal_detail = JournalDetail.first(:order => 'id DESC')
208 assert_equal '2', journal_detail.old_value
208 assert_equal '2', journal_detail.old_value
209
209
210 User.find(2).destroy
210 User.find(2).destroy
211 assert_nil User.find_by_id(2)
211 assert_nil User.find_by_id(2)
212 assert_equal User.anonymous.id.to_s, journal_detail.reload.old_value
212 assert_equal User.anonymous.id.to_s, journal_detail.reload.old_value
213 end
213 end
214
214
215 def test_destroy_should_update_journal_details_value
215 def test_destroy_should_update_journal_details_value
216 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
216 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
217 issue.init_journal(User.find(1), "update")
217 issue.init_journal(User.find(1), "update")
218 issue.assigned_to_id = 2
218 issue.assigned_to_id = 2
219 assert_difference 'JournalDetail.count' do
219 assert_difference 'JournalDetail.count' do
220 issue.save!
220 issue.save!
221 end
221 end
222 journal_detail = JournalDetail.first(:order => 'id DESC')
222 journal_detail = JournalDetail.first(:order => 'id DESC')
223 assert_equal '2', journal_detail.value
223 assert_equal '2', journal_detail.value
224
224
225 User.find(2).destroy
225 User.find(2).destroy
226 assert_nil User.find_by_id(2)
226 assert_nil User.find_by_id(2)
227 assert_equal User.anonymous.id.to_s, journal_detail.reload.value
227 assert_equal User.anonymous.id.to_s, journal_detail.reload.value
228 end
228 end
229
229
230 def test_destroy_should_update_messages
230 def test_destroy_should_update_messages
231 board = Board.create!(:project_id => 1, :name => 'Board', :description => 'Board')
231 board = Board.create!(:project_id => 1, :name => 'Board', :description => 'Board')
232 message = Message.create!(:board_id => board.id, :author_id => 2, :subject => 'foo', :content => 'foo')
232 message = Message.create!(:board_id => board.id, :author_id => 2, :subject => 'foo', :content => 'foo')
233
233
234 User.find(2).destroy
234 User.find(2).destroy
235 assert_nil User.find_by_id(2)
235 assert_nil User.find_by_id(2)
236 assert_equal User.anonymous, message.reload.author
236 assert_equal User.anonymous, message.reload.author
237 end
237 end
238
238
239 def test_destroy_should_update_news
239 def test_destroy_should_update_news
240 news = News.create!(:project_id => 1, :author_id => 2, :title => 'foo', :description => 'foo')
240 news = News.create!(:project_id => 1, :author_id => 2, :title => 'foo', :description => 'foo')
241
241
242 User.find(2).destroy
242 User.find(2).destroy
243 assert_nil User.find_by_id(2)
243 assert_nil User.find_by_id(2)
244 assert_equal User.anonymous, news.reload.author
244 assert_equal User.anonymous, news.reload.author
245 end
245 end
246
246
247 def test_destroy_should_delete_private_queries
247 def test_destroy_should_delete_private_queries
248 query = Query.new(:name => 'foo', :is_public => false)
248 query = Query.new(:name => 'foo', :is_public => false)
249 query.project_id = 1
249 query.project_id = 1
250 query.user_id = 2
250 query.user_id = 2
251 query.save!
251 query.save!
252
252
253 User.find(2).destroy
253 User.find(2).destroy
254 assert_nil User.find_by_id(2)
254 assert_nil User.find_by_id(2)
255 assert_nil Query.find_by_id(query.id)
255 assert_nil Query.find_by_id(query.id)
256 end
256 end
257
257
258 def test_destroy_should_update_public_queries
258 def test_destroy_should_update_public_queries
259 query = Query.new(:name => 'foo', :is_public => true)
259 query = Query.new(:name => 'foo', :is_public => true)
260 query.project_id = 1
260 query.project_id = 1
261 query.user_id = 2
261 query.user_id = 2
262 query.save!
262 query.save!
263
263
264 User.find(2).destroy
264 User.find(2).destroy
265 assert_nil User.find_by_id(2)
265 assert_nil User.find_by_id(2)
266 assert_equal User.anonymous, query.reload.user
266 assert_equal User.anonymous, query.reload.user
267 end
267 end
268
268
269 def test_destroy_should_update_time_entries
269 def test_destroy_should_update_time_entries
270 entry = TimeEntry.new(:hours => '2', :spent_on => Date.today, :activity => TimeEntryActivity.create!(:name => 'foo'))
270 entry = TimeEntry.new(:hours => '2', :spent_on => Date.today, :activity => TimeEntryActivity.create!(:name => 'foo'))
271 entry.project_id = 1
271 entry.project_id = 1
272 entry.user_id = 2
272 entry.user_id = 2
273 entry.save!
273 entry.save!
274
274
275 User.find(2).destroy
275 User.find(2).destroy
276 assert_nil User.find_by_id(2)
276 assert_nil User.find_by_id(2)
277 assert_equal User.anonymous, entry.reload.user
277 assert_equal User.anonymous, entry.reload.user
278 end
278 end
279
279
280 def test_destroy_should_delete_tokens
280 def test_destroy_should_delete_tokens
281 token = Token.create!(:user_id => 2, :value => 'foo')
281 token = Token.create!(:user_id => 2, :value => 'foo')
282
282
283 User.find(2).destroy
283 User.find(2).destroy
284 assert_nil User.find_by_id(2)
284 assert_nil User.find_by_id(2)
285 assert_nil Token.find_by_id(token.id)
285 assert_nil Token.find_by_id(token.id)
286 end
286 end
287
287
288 def test_destroy_should_delete_watchers
288 def test_destroy_should_delete_watchers
289 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
289 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
290 watcher = Watcher.create!(:user_id => 2, :watchable => issue)
290 watcher = Watcher.create!(:user_id => 2, :watchable => issue)
291
291
292 User.find(2).destroy
292 User.find(2).destroy
293 assert_nil User.find_by_id(2)
293 assert_nil User.find_by_id(2)
294 assert_nil Watcher.find_by_id(watcher.id)
294 assert_nil Watcher.find_by_id(watcher.id)
295 end
295 end
296
296
297 def test_destroy_should_update_wiki_contents
297 def test_destroy_should_update_wiki_contents
298 wiki_content = WikiContent.create!(
298 wiki_content = WikiContent.create!(
299 :text => 'foo',
299 :text => 'foo',
300 :author_id => 2,
300 :author_id => 2,
301 :page => WikiPage.create!(:title => 'Foo', :wiki => Wiki.create!(:project_id => 1, :start_page => 'Start'))
301 :page => WikiPage.create!(:title => 'Foo', :wiki => Wiki.create!(:project_id => 1, :start_page => 'Start'))
302 )
302 )
303 wiki_content.text = 'bar'
303 wiki_content.text = 'bar'
304 assert_difference 'WikiContent::Version.count' do
304 assert_difference 'WikiContent::Version.count' do
305 wiki_content.save!
305 wiki_content.save!
306 end
306 end
307
307
308 User.find(2).destroy
308 User.find(2).destroy
309 assert_nil User.find_by_id(2)
309 assert_nil User.find_by_id(2)
310 assert_equal User.anonymous, wiki_content.reload.author
310 assert_equal User.anonymous, wiki_content.reload.author
311 wiki_content.versions.each do |version|
311 wiki_content.versions.each do |version|
312 assert_equal User.anonymous, version.reload.author
312 assert_equal User.anonymous, version.reload.author
313 end
313 end
314 end
314 end
315
315
316 def test_destroy_should_nullify_issue_categories
316 def test_destroy_should_nullify_issue_categories
317 category = IssueCategory.create!(:project_id => 1, :assigned_to_id => 2, :name => 'foo')
317 category = IssueCategory.create!(:project_id => 1, :assigned_to_id => 2, :name => 'foo')
318
318
319 User.find(2).destroy
319 User.find(2).destroy
320 assert_nil User.find_by_id(2)
320 assert_nil User.find_by_id(2)
321 assert_nil category.reload.assigned_to_id
321 assert_nil category.reload.assigned_to_id
322 end
322 end
323
323
324 def test_destroy_should_nullify_changesets
324 def test_destroy_should_nullify_changesets
325 changeset = Changeset.create!(
325 changeset = Changeset.create!(
326 :repository => Repository::Subversion.generate!(
326 :repository => Repository::Subversion.generate!(
327 :project_id => 1
327 :project_id => 1
328 ),
328 ),
329 :revision => '12',
329 :revision => '12',
330 :committed_on => Time.now,
330 :committed_on => Time.now,
331 :committer => 'jsmith'
331 :committer => 'jsmith'
332 )
332 )
333 assert_equal 2, changeset.user_id
333 assert_equal 2, changeset.user_id
334
334
335 User.find(2).destroy
335 User.find(2).destroy
336 assert_nil User.find_by_id(2)
336 assert_nil User.find_by_id(2)
337 assert_nil changeset.reload.user_id
337 assert_nil changeset.reload.user_id
338 end
338 end
339
339
340 def test_anonymous_user_should_not_be_destroyable
340 def test_anonymous_user_should_not_be_destroyable
341 assert_no_difference 'User.count' do
341 assert_no_difference 'User.count' do
342 assert_equal false, User.anonymous.destroy
342 assert_equal false, User.anonymous.destroy
343 end
343 end
344 end
344 end
345
345
346 def test_validate_login_presence
346 def test_validate_login_presence
347 @admin.login = ""
347 @admin.login = ""
348 assert !@admin.save
348 assert !@admin.save
349 assert_equal 1, @admin.errors.count
349 assert_equal 1, @admin.errors.count
350 end
350 end
351
351
352 def test_validate_mail_notification_inclusion
352 def test_validate_mail_notification_inclusion
353 u = User.new
353 u = User.new
354 u.mail_notification = 'foo'
354 u.mail_notification = 'foo'
355 u.save
355 u.save
356 assert_not_nil u.errors[:mail_notification]
356 assert_not_nil u.errors[:mail_notification]
357 end
357 end
358
358
359 context "User#try_to_login" do
359 context "User#try_to_login" do
360 should "fall-back to case-insensitive if user login is not found as-typed." do
360 should "fall-back to case-insensitive if user login is not found as-typed." do
361 user = User.try_to_login("AdMin", "admin")
361 user = User.try_to_login("AdMin", "admin")
362 assert_kind_of User, user
362 assert_kind_of User, user
363 assert_equal "admin", user.login
363 assert_equal "admin", user.login
364 end
364 end
365
365
366 should "select the exact matching user first" do
366 should "select the exact matching user first" do
367 case_sensitive_user = User.generate_with_protected!(
367 case_sensitive_user = User.generate_with_protected!(
368 :login => 'changed', :password => 'admin',
368 :login => 'changed', :password => 'admin',
369 :password_confirmation => 'admin')
369 :password_confirmation => 'admin')
370 # bypass validations to make it appear like existing data
370 # bypass validations to make it appear like existing data
371 case_sensitive_user.update_attribute(:login, 'ADMIN')
371 case_sensitive_user.update_attribute(:login, 'ADMIN')
372
372
373 user = User.try_to_login("ADMIN", "admin")
373 user = User.try_to_login("ADMIN", "admin")
374 assert_kind_of User, user
374 assert_kind_of User, user
375 assert_equal "ADMIN", user.login
375 assert_equal "ADMIN", user.login
376
376
377 end
377 end
378 end
378 end
379
379
380 def test_password
380 def test_password
381 user = User.try_to_login("admin", "admin")
381 user = User.try_to_login("admin", "admin")
382 assert_kind_of User, user
382 assert_kind_of User, user
383 assert_equal "admin", user.login
383 assert_equal "admin", user.login
384 user.password = "hello"
384 user.password = "hello"
385 assert user.save
385 assert user.save
386
386
387 user = User.try_to_login("admin", "hello")
387 user = User.try_to_login("admin", "hello")
388 assert_kind_of User, user
388 assert_kind_of User, user
389 assert_equal "admin", user.login
389 assert_equal "admin", user.login
390 end
390 end
391
391
392 def test_validate_password_length
392 def test_validate_password_length
393 with_settings :password_min_length => '100' do
393 with_settings :password_min_length => '100' do
394 user = User.new(:firstname => "new100", :lastname => "user100", :mail => "newuser100@somenet.foo")
394 user = User.new(:firstname => "new100", :lastname => "user100", :mail => "newuser100@somenet.foo")
395 user.login = "newuser100"
395 user.login = "newuser100"
396 user.password, user.password_confirmation = "password100", "password100"
396 user.password, user.password_confirmation = "password100", "password100"
397 assert !user.save
397 assert !user.save
398 assert_equal 1, user.errors.count
398 assert_equal 1, user.errors.count
399 end
399 end
400 end
400 end
401
401
402 def test_name_format
402 def test_name_format
403 assert_equal 'Smith, John', @jsmith.name(:lastname_coma_firstname)
403 assert_equal 'Smith, John', @jsmith.name(:lastname_coma_firstname)
404 with_settings :user_format => :firstname_lastname do
404 with_settings :user_format => :firstname_lastname do
405 assert_equal 'John Smith', @jsmith.reload.name
405 assert_equal 'John Smith', @jsmith.reload.name
406 end
406 end
407 with_settings :user_format => :username do
407 with_settings :user_format => :username do
408 assert_equal 'jsmith', @jsmith.reload.name
408 assert_equal 'jsmith', @jsmith.reload.name
409 end
409 end
410 end
410 end
411
411
412 def test_fields_for_order_statement_should_return_fields_according_user_format_setting
412 def test_fields_for_order_statement_should_return_fields_according_user_format_setting
413 with_settings :user_format => 'lastname_coma_firstname' do
413 with_settings :user_format => 'lastname_coma_firstname' do
414 assert_equal ['users.lastname', 'users.firstname', 'users.id'], User.fields_for_order_statement
414 assert_equal ['users.lastname', 'users.firstname', 'users.id'], User.fields_for_order_statement
415 end
415 end
416 end
416 end
417
417
418 def test_fields_for_order_statement_width_table_name_should_prepend_table_name
418 def test_fields_for_order_statement_width_table_name_should_prepend_table_name
419 with_settings :user_format => 'lastname_firstname' do
419 with_settings :user_format => 'lastname_firstname' do
420 assert_equal ['authors.lastname', 'authors.firstname', 'authors.id'], User.fields_for_order_statement('authors')
420 assert_equal ['authors.lastname', 'authors.firstname', 'authors.id'], User.fields_for_order_statement('authors')
421 end
421 end
422 end
422 end
423
423
424 def test_fields_for_order_statement_with_blank_format_should_return_default
424 def test_fields_for_order_statement_with_blank_format_should_return_default
425 with_settings :user_format => '' do
425 with_settings :user_format => '' do
426 assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
426 assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
427 end
427 end
428 end
428 end
429
429
430 def test_fields_for_order_statement_with_invalid_format_should_return_default
430 def test_fields_for_order_statement_with_invalid_format_should_return_default
431 with_settings :user_format => 'foo' do
431 with_settings :user_format => 'foo' do
432 assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
432 assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
433 end
433 end
434 end
434 end
435
435
436 def test_lock
436 def test_lock
437 user = User.try_to_login("jsmith", "jsmith")
437 user = User.try_to_login("jsmith", "jsmith")
438 assert_equal @jsmith, user
438 assert_equal @jsmith, user
439
439
440 @jsmith.status = User::STATUS_LOCKED
440 @jsmith.status = User::STATUS_LOCKED
441 assert @jsmith.save
441 assert @jsmith.save
442
442
443 user = User.try_to_login("jsmith", "jsmith")
443 user = User.try_to_login("jsmith", "jsmith")
444 assert_equal nil, user
444 assert_equal nil, user
445 end
445 end
446
446
447 context ".try_to_login" do
447 context ".try_to_login" do
448 context "with good credentials" do
448 context "with good credentials" do
449 should "return the user" do
449 should "return the user" do
450 user = User.try_to_login("admin", "admin")
450 user = User.try_to_login("admin", "admin")
451 assert_kind_of User, user
451 assert_kind_of User, user
452 assert_equal "admin", user.login
452 assert_equal "admin", user.login
453 end
453 end
454 end
454 end
455
455
456 context "with wrong credentials" do
456 context "with wrong credentials" do
457 should "return nil" do
457 should "return nil" do
458 assert_nil User.try_to_login("admin", "foo")
458 assert_nil User.try_to_login("admin", "foo")
459 end
459 end
460 end
460 end
461 end
461 end
462
462
463 if ldap_configured?
463 if ldap_configured?
464 context "#try_to_login using LDAP" do
464 context "#try_to_login using LDAP" do
465 context "with failed connection to the LDAP server" do
465 context "with failed connection to the LDAP server" do
466 should "return nil" do
466 should "return nil" do
467 @auth_source = AuthSourceLdap.find(1)
467 @auth_source = AuthSourceLdap.find(1)
468 AuthSource.any_instance.stubs(:initialize_ldap_con).raises(Net::LDAP::LdapError, 'Cannot connect')
468 AuthSource.any_instance.stubs(:initialize_ldap_con).raises(Net::LDAP::LdapError, 'Cannot connect')
469
469
470 assert_equal nil, User.try_to_login('edavis', 'wrong')
470 assert_equal nil, User.try_to_login('edavis', 'wrong')
471 end
471 end
472 end
472 end
473
473
474 context "with an unsuccessful authentication" do
474 context "with an unsuccessful authentication" do
475 should "return nil" do
475 should "return nil" do
476 assert_equal nil, User.try_to_login('edavis', 'wrong')
476 assert_equal nil, User.try_to_login('edavis', 'wrong')
477 end
477 end
478 end
478 end
479
479
480 context "binding with user's account" do
481 setup do
482 @auth_source = AuthSourceLdap.find(1)
483 @auth_source.account = "uid=$login,ou=Person,dc=redmine,dc=org"
484 @auth_source.account_password = ''
485 @auth_source.save!
486
487 @ldap_user = User.new(:mail => 'example1@redmine.org', :firstname => 'LDAP', :lastname => 'user', :auth_source_id => 1)
488 @ldap_user.login = 'example1'
489 @ldap_user.save!
490 end
491
492 context "with a successful authentication" do
493 should "return the user" do
494 assert_equal @ldap_user, User.try_to_login('example1', '123456')
495 end
496 end
497
498 context "with an unsuccessful authentication" do
499 should "return the user" do
500 assert_nil User.try_to_login('example1', '11111')
501 end
502 end
503 end
504
480 context "on the fly registration" do
505 context "on the fly registration" do
481 setup do
506 setup do
482 @auth_source = AuthSourceLdap.find(1)
507 @auth_source = AuthSourceLdap.find(1)
483 @auth_source.update_attribute :onthefly_register, true
508 @auth_source.update_attribute :onthefly_register, true
484 end
509 end
485
510
486 context "with a successful authentication" do
511 context "with a successful authentication" do
487 should "create a new user account if it doesn't exist" do
512 should "create a new user account if it doesn't exist" do
488 assert_difference('User.count') do
513 assert_difference('User.count') do
489 user = User.try_to_login('edavis', '123456')
514 user = User.try_to_login('edavis', '123456')
490 assert !user.admin?
515 assert !user.admin?
491 end
516 end
492 end
517 end
493
518
494 should "retrieve existing user" do
519 should "retrieve existing user" do
495 user = User.try_to_login('edavis', '123456')
520 user = User.try_to_login('edavis', '123456')
496 user.admin = true
521 user.admin = true
497 user.save!
522 user.save!
498
523
499 assert_no_difference('User.count') do
524 assert_no_difference('User.count') do
500 user = User.try_to_login('edavis', '123456')
525 user = User.try_to_login('edavis', '123456')
501 assert user.admin?
526 assert user.admin?
502 end
527 end
503 end
528 end
504 end
529 end
530
531 context "binding with user's account" do
532 setup do
533 @auth_source = AuthSourceLdap.find(1)
534 @auth_source.account = "uid=$login,ou=Person,dc=redmine,dc=org"
535 @auth_source.account_password = ''
536 @auth_source.save!
537 end
538
539 context "with a successful authentication" do
540 should "create a new user account if it doesn't exist" do
541 assert_difference('User.count') do
542 user = User.try_to_login('example1', '123456')
543 assert_kind_of User, user
544 end
545 end
546 end
547
548 context "with an unsuccessful authentication" do
549 should "return the user" do
550 assert_nil User.try_to_login('example1', '11111')
551 end
552 end
553 end
505 end
554 end
506 end
555 end
507
556
508 else
557 else
509 puts "Skipping LDAP tests."
558 puts "Skipping LDAP tests."
510 end
559 end
511
560
512 def test_create_anonymous
561 def test_create_anonymous
513 AnonymousUser.delete_all
562 AnonymousUser.delete_all
514 anon = User.anonymous
563 anon = User.anonymous
515 assert !anon.new_record?
564 assert !anon.new_record?
516 assert_kind_of AnonymousUser, anon
565 assert_kind_of AnonymousUser, anon
517 end
566 end
518
567
519 def test_ensure_single_anonymous_user
568 def test_ensure_single_anonymous_user
520 AnonymousUser.delete_all
569 AnonymousUser.delete_all
521 anon1 = User.anonymous
570 anon1 = User.anonymous
522 assert !anon1.new_record?
571 assert !anon1.new_record?
523 assert_kind_of AnonymousUser, anon1
572 assert_kind_of AnonymousUser, anon1
524 anon2 = AnonymousUser.create(
573 anon2 = AnonymousUser.create(
525 :lastname => 'Anonymous', :firstname => '',
574 :lastname => 'Anonymous', :firstname => '',
526 :mail => '', :login => '', :status => 0)
575 :mail => '', :login => '', :status => 0)
527 assert_equal 1, anon2.errors.count
576 assert_equal 1, anon2.errors.count
528 end
577 end
529
578
530 def test_rss_key
579 def test_rss_key
531 assert_nil @jsmith.rss_token
580 assert_nil @jsmith.rss_token
532 key = @jsmith.rss_key
581 key = @jsmith.rss_key
533 assert_equal 40, key.length
582 assert_equal 40, key.length
534
583
535 @jsmith.reload
584 @jsmith.reload
536 assert_equal key, @jsmith.rss_key
585 assert_equal key, @jsmith.rss_key
537 end
586 end
538
587
539 context "User#api_key" do
588 context "User#api_key" do
540 should "generate a new one if the user doesn't have one" do
589 should "generate a new one if the user doesn't have one" do
541 user = User.generate_with_protected!(:api_token => nil)
590 user = User.generate_with_protected!(:api_token => nil)
542 assert_nil user.api_token
591 assert_nil user.api_token
543
592
544 key = user.api_key
593 key = user.api_key
545 assert_equal 40, key.length
594 assert_equal 40, key.length
546 user.reload
595 user.reload
547 assert_equal key, user.api_key
596 assert_equal key, user.api_key
548 end
597 end
549
598
550 should "return the existing api token value" do
599 should "return the existing api token value" do
551 user = User.generate_with_protected!
600 user = User.generate_with_protected!
552 token = Token.generate!(:action => 'api')
601 token = Token.generate!(:action => 'api')
553 user.api_token = token
602 user.api_token = token
554 assert user.save
603 assert user.save
555
604
556 assert_equal token.value, user.api_key
605 assert_equal token.value, user.api_key
557 end
606 end
558 end
607 end
559
608
560 context "User#find_by_api_key" do
609 context "User#find_by_api_key" do
561 should "return nil if no matching key is found" do
610 should "return nil if no matching key is found" do
562 assert_nil User.find_by_api_key('zzzzzzzzz')
611 assert_nil User.find_by_api_key('zzzzzzzzz')
563 end
612 end
564
613
565 should "return nil if the key is found for an inactive user" do
614 should "return nil if the key is found for an inactive user" do
566 user = User.generate_with_protected!(:status => User::STATUS_LOCKED)
615 user = User.generate_with_protected!(:status => User::STATUS_LOCKED)
567 token = Token.generate!(:action => 'api')
616 token = Token.generate!(:action => 'api')
568 user.api_token = token
617 user.api_token = token
569 user.save
618 user.save
570
619
571 assert_nil User.find_by_api_key(token.value)
620 assert_nil User.find_by_api_key(token.value)
572 end
621 end
573
622
574 should "return the user if the key is found for an active user" do
623 should "return the user if the key is found for an active user" do
575 user = User.generate_with_protected!(:status => User::STATUS_ACTIVE)
624 user = User.generate_with_protected!(:status => User::STATUS_ACTIVE)
576 token = Token.generate!(:action => 'api')
625 token = Token.generate!(:action => 'api')
577 user.api_token = token
626 user.api_token = token
578 user.save
627 user.save
579
628
580 assert_equal user, User.find_by_api_key(token.value)
629 assert_equal user, User.find_by_api_key(token.value)
581 end
630 end
582 end
631 end
583
632
584 def test_roles_for_project
633 def test_roles_for_project
585 # user with a role
634 # user with a role
586 roles = @jsmith.roles_for_project(Project.find(1))
635 roles = @jsmith.roles_for_project(Project.find(1))
587 assert_kind_of Role, roles.first
636 assert_kind_of Role, roles.first
588 assert_equal "Manager", roles.first.name
637 assert_equal "Manager", roles.first.name
589
638
590 # user with no role
639 # user with no role
591 assert_nil @dlopper.roles_for_project(Project.find(2)).detect {|role| role.member?}
640 assert_nil @dlopper.roles_for_project(Project.find(2)).detect {|role| role.member?}
592 end
641 end
593
642
594 def test_projects_by_role_for_user_with_role
643 def test_projects_by_role_for_user_with_role
595 user = User.find(2)
644 user = User.find(2)
596 assert_kind_of Hash, user.projects_by_role
645 assert_kind_of Hash, user.projects_by_role
597 assert_equal 2, user.projects_by_role.size
646 assert_equal 2, user.projects_by_role.size
598 assert_equal [1,5], user.projects_by_role[Role.find(1)].collect(&:id).sort
647 assert_equal [1,5], user.projects_by_role[Role.find(1)].collect(&:id).sort
599 assert_equal [2], user.projects_by_role[Role.find(2)].collect(&:id).sort
648 assert_equal [2], user.projects_by_role[Role.find(2)].collect(&:id).sort
600 end
649 end
601
650
602 def test_projects_by_role_for_user_with_no_role
651 def test_projects_by_role_for_user_with_no_role
603 user = User.generate!
652 user = User.generate!
604 assert_equal({}, user.projects_by_role)
653 assert_equal({}, user.projects_by_role)
605 end
654 end
606
655
607 def test_projects_by_role_for_anonymous
656 def test_projects_by_role_for_anonymous
608 assert_equal({}, User.anonymous.projects_by_role)
657 assert_equal({}, User.anonymous.projects_by_role)
609 end
658 end
610
659
611 def test_valid_notification_options
660 def test_valid_notification_options
612 # without memberships
661 # without memberships
613 assert_equal 5, User.find(7).valid_notification_options.size
662 assert_equal 5, User.find(7).valid_notification_options.size
614 # with memberships
663 # with memberships
615 assert_equal 6, User.find(2).valid_notification_options.size
664 assert_equal 6, User.find(2).valid_notification_options.size
616 end
665 end
617
666
618 def test_valid_notification_options_class_method
667 def test_valid_notification_options_class_method
619 assert_equal 5, User.valid_notification_options.size
668 assert_equal 5, User.valid_notification_options.size
620 assert_equal 5, User.valid_notification_options(User.find(7)).size
669 assert_equal 5, User.valid_notification_options(User.find(7)).size
621 assert_equal 6, User.valid_notification_options(User.find(2)).size
670 assert_equal 6, User.valid_notification_options(User.find(2)).size
622 end
671 end
623
672
624 def test_mail_notification_all
673 def test_mail_notification_all
625 @jsmith.mail_notification = 'all'
674 @jsmith.mail_notification = 'all'
626 @jsmith.notified_project_ids = []
675 @jsmith.notified_project_ids = []
627 @jsmith.save
676 @jsmith.save
628 @jsmith.reload
677 @jsmith.reload
629 assert @jsmith.projects.first.recipients.include?(@jsmith.mail)
678 assert @jsmith.projects.first.recipients.include?(@jsmith.mail)
630 end
679 end
631
680
632 def test_mail_notification_selected
681 def test_mail_notification_selected
633 @jsmith.mail_notification = 'selected'
682 @jsmith.mail_notification = 'selected'
634 @jsmith.notified_project_ids = [1]
683 @jsmith.notified_project_ids = [1]
635 @jsmith.save
684 @jsmith.save
636 @jsmith.reload
685 @jsmith.reload
637 assert Project.find(1).recipients.include?(@jsmith.mail)
686 assert Project.find(1).recipients.include?(@jsmith.mail)
638 end
687 end
639
688
640 def test_mail_notification_only_my_events
689 def test_mail_notification_only_my_events
641 @jsmith.mail_notification = 'only_my_events'
690 @jsmith.mail_notification = 'only_my_events'
642 @jsmith.notified_project_ids = []
691 @jsmith.notified_project_ids = []
643 @jsmith.save
692 @jsmith.save
644 @jsmith.reload
693 @jsmith.reload
645 assert !@jsmith.projects.first.recipients.include?(@jsmith.mail)
694 assert !@jsmith.projects.first.recipients.include?(@jsmith.mail)
646 end
695 end
647
696
648 def test_comments_sorting_preference
697 def test_comments_sorting_preference
649 assert !@jsmith.wants_comments_in_reverse_order?
698 assert !@jsmith.wants_comments_in_reverse_order?
650 @jsmith.pref.comments_sorting = 'asc'
699 @jsmith.pref.comments_sorting = 'asc'
651 assert !@jsmith.wants_comments_in_reverse_order?
700 assert !@jsmith.wants_comments_in_reverse_order?
652 @jsmith.pref.comments_sorting = 'desc'
701 @jsmith.pref.comments_sorting = 'desc'
653 assert @jsmith.wants_comments_in_reverse_order?
702 assert @jsmith.wants_comments_in_reverse_order?
654 end
703 end
655
704
656 def test_find_by_mail_should_be_case_insensitive
705 def test_find_by_mail_should_be_case_insensitive
657 u = User.find_by_mail('JSmith@somenet.foo')
706 u = User.find_by_mail('JSmith@somenet.foo')
658 assert_not_nil u
707 assert_not_nil u
659 assert_equal 'jsmith@somenet.foo', u.mail
708 assert_equal 'jsmith@somenet.foo', u.mail
660 end
709 end
661
710
662 def test_random_password
711 def test_random_password
663 u = User.new
712 u = User.new
664 u.random_password
713 u.random_password
665 assert !u.password.blank?
714 assert !u.password.blank?
666 assert !u.password_confirmation.blank?
715 assert !u.password_confirmation.blank?
667 end
716 end
668
717
669 context "#change_password_allowed?" do
718 context "#change_password_allowed?" do
670 should "be allowed if no auth source is set" do
719 should "be allowed if no auth source is set" do
671 user = User.generate_with_protected!
720 user = User.generate_with_protected!
672 assert user.change_password_allowed?
721 assert user.change_password_allowed?
673 end
722 end
674
723
675 should "delegate to the auth source" do
724 should "delegate to the auth source" do
676 user = User.generate_with_protected!
725 user = User.generate_with_protected!
677
726
678 allowed_auth_source = AuthSource.generate!
727 allowed_auth_source = AuthSource.generate!
679 def allowed_auth_source.allow_password_changes?; true; end
728 def allowed_auth_source.allow_password_changes?; true; end
680
729
681 denied_auth_source = AuthSource.generate!
730 denied_auth_source = AuthSource.generate!
682 def denied_auth_source.allow_password_changes?; false; end
731 def denied_auth_source.allow_password_changes?; false; end
683
732
684 assert user.change_password_allowed?
733 assert user.change_password_allowed?
685
734
686 user.auth_source = allowed_auth_source
735 user.auth_source = allowed_auth_source
687 assert user.change_password_allowed?, "User not allowed to change password, though auth source does"
736 assert user.change_password_allowed?, "User not allowed to change password, though auth source does"
688
737
689 user.auth_source = denied_auth_source
738 user.auth_source = denied_auth_source
690 assert !user.change_password_allowed?, "User allowed to change password, though auth source does not"
739 assert !user.change_password_allowed?, "User allowed to change password, though auth source does not"
691 end
740 end
692
741
693 end
742 end
694
743
695 context "#allowed_to?" do
744 context "#allowed_to?" do
696 context "with a unique project" do
745 context "with a unique project" do
697 should "return false if project is archived" do
746 should "return false if project is archived" do
698 project = Project.find(1)
747 project = Project.find(1)
699 Project.any_instance.stubs(:status).returns(Project::STATUS_ARCHIVED)
748 Project.any_instance.stubs(:status).returns(Project::STATUS_ARCHIVED)
700 assert ! @admin.allowed_to?(:view_issues, Project.find(1))
749 assert ! @admin.allowed_to?(:view_issues, Project.find(1))
701 end
750 end
702
751
703 should "return false if related module is disabled" do
752 should "return false if related module is disabled" do
704 project = Project.find(1)
753 project = Project.find(1)
705 project.enabled_module_names = ["issue_tracking"]
754 project.enabled_module_names = ["issue_tracking"]
706 assert @admin.allowed_to?(:add_issues, project)
755 assert @admin.allowed_to?(:add_issues, project)
707 assert ! @admin.allowed_to?(:view_wiki_pages, project)
756 assert ! @admin.allowed_to?(:view_wiki_pages, project)
708 end
757 end
709
758
710 should "authorize nearly everything for admin users" do
759 should "authorize nearly everything for admin users" do
711 project = Project.find(1)
760 project = Project.find(1)
712 assert ! @admin.member_of?(project)
761 assert ! @admin.member_of?(project)
713 %w(edit_issues delete_issues manage_news manage_documents manage_wiki).each do |p|
762 %w(edit_issues delete_issues manage_news manage_documents manage_wiki).each do |p|
714 assert @admin.allowed_to?(p.to_sym, project)
763 assert @admin.allowed_to?(p.to_sym, project)
715 end
764 end
716 end
765 end
717
766
718 should "authorize normal users depending on their roles" do
767 should "authorize normal users depending on their roles" do
719 project = Project.find(1)
768 project = Project.find(1)
720 assert @jsmith.allowed_to?(:delete_messages, project) #Manager
769 assert @jsmith.allowed_to?(:delete_messages, project) #Manager
721 assert ! @dlopper.allowed_to?(:delete_messages, project) #Developper
770 assert ! @dlopper.allowed_to?(:delete_messages, project) #Developper
722 end
771 end
723 end
772 end
724
773
725 context "with multiple projects" do
774 context "with multiple projects" do
726 should "return false if array is empty" do
775 should "return false if array is empty" do
727 assert ! @admin.allowed_to?(:view_project, [])
776 assert ! @admin.allowed_to?(:view_project, [])
728 end
777 end
729
778
730 should "return true only if user has permission on all these projects" do
779 should "return true only if user has permission on all these projects" do
731 assert @admin.allowed_to?(:view_project, Project.all)
780 assert @admin.allowed_to?(:view_project, Project.all)
732 assert ! @dlopper.allowed_to?(:view_project, Project.all) #cannot see Project(2)
781 assert ! @dlopper.allowed_to?(:view_project, Project.all) #cannot see Project(2)
733 assert @jsmith.allowed_to?(:edit_issues, @jsmith.projects) #Manager or Developer everywhere
782 assert @jsmith.allowed_to?(:edit_issues, @jsmith.projects) #Manager or Developer everywhere
734 assert ! @jsmith.allowed_to?(:delete_issue_watchers, @jsmith.projects) #Dev cannot delete_issue_watchers
783 assert ! @jsmith.allowed_to?(:delete_issue_watchers, @jsmith.projects) #Dev cannot delete_issue_watchers
735 end
784 end
736
785
737 should "behave correctly with arrays of 1 project" do
786 should "behave correctly with arrays of 1 project" do
738 assert ! User.anonymous.allowed_to?(:delete_issues, [Project.first])
787 assert ! User.anonymous.allowed_to?(:delete_issues, [Project.first])
739 end
788 end
740 end
789 end
741
790
742 context "with options[:global]" do
791 context "with options[:global]" do
743 should "authorize if user has at least one role that has this permission" do
792 should "authorize if user has at least one role that has this permission" do
744 @dlopper2 = User.find(5) #only Developper on a project, not Manager anywhere
793 @dlopper2 = User.find(5) #only Developper on a project, not Manager anywhere
745 @anonymous = User.find(6)
794 @anonymous = User.find(6)
746 assert @jsmith.allowed_to?(:delete_issue_watchers, nil, :global => true)
795 assert @jsmith.allowed_to?(:delete_issue_watchers, nil, :global => true)
747 assert ! @dlopper2.allowed_to?(:delete_issue_watchers, nil, :global => true)
796 assert ! @dlopper2.allowed_to?(:delete_issue_watchers, nil, :global => true)
748 assert @dlopper2.allowed_to?(:add_issues, nil, :global => true)
797 assert @dlopper2.allowed_to?(:add_issues, nil, :global => true)
749 assert ! @anonymous.allowed_to?(:add_issues, nil, :global => true)
798 assert ! @anonymous.allowed_to?(:add_issues, nil, :global => true)
750 assert @anonymous.allowed_to?(:view_issues, nil, :global => true)
799 assert @anonymous.allowed_to?(:view_issues, nil, :global => true)
751 end
800 end
752 end
801 end
753 end
802 end
754
803
755 context "User#notify_about?" do
804 context "User#notify_about?" do
756 context "Issues" do
805 context "Issues" do
757 setup do
806 setup do
758 @project = Project.find(1)
807 @project = Project.find(1)
759 @author = User.generate_with_protected!
808 @author = User.generate_with_protected!
760 @assignee = User.generate_with_protected!
809 @assignee = User.generate_with_protected!
761 @issue = Issue.generate_for_project!(@project, :assigned_to => @assignee, :author => @author)
810 @issue = Issue.generate_for_project!(@project, :assigned_to => @assignee, :author => @author)
762 end
811 end
763
812
764 should "be true for a user with :all" do
813 should "be true for a user with :all" do
765 @author.update_attribute(:mail_notification, 'all')
814 @author.update_attribute(:mail_notification, 'all')
766 assert @author.notify_about?(@issue)
815 assert @author.notify_about?(@issue)
767 end
816 end
768
817
769 should "be false for a user with :none" do
818 should "be false for a user with :none" do
770 @author.update_attribute(:mail_notification, 'none')
819 @author.update_attribute(:mail_notification, 'none')
771 assert ! @author.notify_about?(@issue)
820 assert ! @author.notify_about?(@issue)
772 end
821 end
773
822
774 should "be false for a user with :only_my_events and isn't an author, creator, or assignee" do
823 should "be false for a user with :only_my_events and isn't an author, creator, or assignee" do
775 @user = User.generate_with_protected!(:mail_notification => 'only_my_events')
824 @user = User.generate_with_protected!(:mail_notification => 'only_my_events')
776 Member.create!(:user => @user, :project => @project, :role_ids => [1])
825 Member.create!(:user => @user, :project => @project, :role_ids => [1])
777 assert ! @user.notify_about?(@issue)
826 assert ! @user.notify_about?(@issue)
778 end
827 end
779
828
780 should "be true for a user with :only_my_events and is the author" do
829 should "be true for a user with :only_my_events and is the author" do
781 @author.update_attribute(:mail_notification, 'only_my_events')
830 @author.update_attribute(:mail_notification, 'only_my_events')
782 assert @author.notify_about?(@issue)
831 assert @author.notify_about?(@issue)
783 end
832 end
784
833
785 should "be true for a user with :only_my_events and is the assignee" do
834 should "be true for a user with :only_my_events and is the assignee" do
786 @assignee.update_attribute(:mail_notification, 'only_my_events')
835 @assignee.update_attribute(:mail_notification, 'only_my_events')
787 assert @assignee.notify_about?(@issue)
836 assert @assignee.notify_about?(@issue)
788 end
837 end
789
838
790 should "be true for a user with :only_assigned and is the assignee" do
839 should "be true for a user with :only_assigned and is the assignee" do
791 @assignee.update_attribute(:mail_notification, 'only_assigned')
840 @assignee.update_attribute(:mail_notification, 'only_assigned')
792 assert @assignee.notify_about?(@issue)
841 assert @assignee.notify_about?(@issue)
793 end
842 end
794
843
795 should "be false for a user with :only_assigned and is not the assignee" do
844 should "be false for a user with :only_assigned and is not the assignee" do
796 @author.update_attribute(:mail_notification, 'only_assigned')
845 @author.update_attribute(:mail_notification, 'only_assigned')
797 assert ! @author.notify_about?(@issue)
846 assert ! @author.notify_about?(@issue)
798 end
847 end
799
848
800 should "be true for a user with :only_owner and is the author" do
849 should "be true for a user with :only_owner and is the author" do
801 @author.update_attribute(:mail_notification, 'only_owner')
850 @author.update_attribute(:mail_notification, 'only_owner')
802 assert @author.notify_about?(@issue)
851 assert @author.notify_about?(@issue)
803 end
852 end
804
853
805 should "be false for a user with :only_owner and is not the author" do
854 should "be false for a user with :only_owner and is not the author" do
806 @assignee.update_attribute(:mail_notification, 'only_owner')
855 @assignee.update_attribute(:mail_notification, 'only_owner')
807 assert ! @assignee.notify_about?(@issue)
856 assert ! @assignee.notify_about?(@issue)
808 end
857 end
809
858
810 should "be true for a user with :selected and is the author" do
859 should "be true for a user with :selected and is the author" do
811 @author.update_attribute(:mail_notification, 'selected')
860 @author.update_attribute(:mail_notification, 'selected')
812 assert @author.notify_about?(@issue)
861 assert @author.notify_about?(@issue)
813 end
862 end
814
863
815 should "be true for a user with :selected and is the assignee" do
864 should "be true for a user with :selected and is the assignee" do
816 @assignee.update_attribute(:mail_notification, 'selected')
865 @assignee.update_attribute(:mail_notification, 'selected')
817 assert @assignee.notify_about?(@issue)
866 assert @assignee.notify_about?(@issue)
818 end
867 end
819
868
820 should "be false for a user with :selected and is not the author or assignee" do
869 should "be false for a user with :selected and is not the author or assignee" do
821 @user = User.generate_with_protected!(:mail_notification => 'selected')
870 @user = User.generate_with_protected!(:mail_notification => 'selected')
822 Member.create!(:user => @user, :project => @project, :role_ids => [1])
871 Member.create!(:user => @user, :project => @project, :role_ids => [1])
823 assert ! @user.notify_about?(@issue)
872 assert ! @user.notify_about?(@issue)
824 end
873 end
825 end
874 end
826
875
827 context "other events" do
876 context "other events" do
828 should 'be added and tested'
877 should 'be added and tested'
829 end
878 end
830 end
879 end
831
880
832 def test_salt_unsalted_passwords
881 def test_salt_unsalted_passwords
833 # Restore a user with an unsalted password
882 # Restore a user with an unsalted password
834 user = User.find(1)
883 user = User.find(1)
835 user.salt = nil
884 user.salt = nil
836 user.hashed_password = User.hash_password("unsalted")
885 user.hashed_password = User.hash_password("unsalted")
837 user.save!
886 user.save!
838
887
839 User.salt_unsalted_passwords!
888 User.salt_unsalted_passwords!
840
889
841 user.reload
890 user.reload
842 # Salt added
891 # Salt added
843 assert !user.salt.blank?
892 assert !user.salt.blank?
844 # Password still valid
893 # Password still valid
845 assert user.check_password?("unsalted")
894 assert user.check_password?("unsalted")
846 assert_equal user, User.try_to_login(user.login, "unsalted")
895 assert_equal user, User.try_to_login(user.login, "unsalted")
847 end
896 end
848
897
849 if Object.const_defined?(:OpenID)
898 if Object.const_defined?(:OpenID)
850
899
851 def test_setting_identity_url
900 def test_setting_identity_url
852 normalized_open_id_url = 'http://example.com/'
901 normalized_open_id_url = 'http://example.com/'
853 u = User.new( :identity_url => 'http://example.com/' )
902 u = User.new( :identity_url => 'http://example.com/' )
854 assert_equal normalized_open_id_url, u.identity_url
903 assert_equal normalized_open_id_url, u.identity_url
855 end
904 end
856
905
857 def test_setting_identity_url_without_trailing_slash
906 def test_setting_identity_url_without_trailing_slash
858 normalized_open_id_url = 'http://example.com/'
907 normalized_open_id_url = 'http://example.com/'
859 u = User.new( :identity_url => 'http://example.com' )
908 u = User.new( :identity_url => 'http://example.com' )
860 assert_equal normalized_open_id_url, u.identity_url
909 assert_equal normalized_open_id_url, u.identity_url
861 end
910 end
862
911
863 def test_setting_identity_url_without_protocol
912 def test_setting_identity_url_without_protocol
864 normalized_open_id_url = 'http://example.com/'
913 normalized_open_id_url = 'http://example.com/'
865 u = User.new( :identity_url => 'example.com' )
914 u = User.new( :identity_url => 'example.com' )
866 assert_equal normalized_open_id_url, u.identity_url
915 assert_equal normalized_open_id_url, u.identity_url
867 end
916 end
868
917
869 def test_setting_blank_identity_url
918 def test_setting_blank_identity_url
870 u = User.new( :identity_url => 'example.com' )
919 u = User.new( :identity_url => 'example.com' )
871 u.identity_url = ''
920 u.identity_url = ''
872 assert u.identity_url.blank?
921 assert u.identity_url.blank?
873 end
922 end
874
923
875 def test_setting_invalid_identity_url
924 def test_setting_invalid_identity_url
876 u = User.new( :identity_url => 'this is not an openid url' )
925 u = User.new( :identity_url => 'this is not an openid url' )
877 assert u.identity_url.blank?
926 assert u.identity_url.blank?
878 end
927 end
879
928
880 else
929 else
881 puts "Skipping openid tests."
930 puts "Skipping openid tests."
882 end
931 end
883
932
884 end
933 end
General Comments 0
You need to be logged in to leave comments. Login now