##// END OF EJS Templates
Makes AuthSource.authenticate return a hash instead of an array....
Jean-Philippe Lang -
r3378:d6f9e576e88d
parent child
Show More
@@ -1,130 +1,130
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'net/ldap'
19 19 require 'iconv'
20 20
21 21 class AuthSourceLdap < AuthSource
22 22 validates_presence_of :host, :port, :attr_login
23 23 validates_length_of :name, :host, :account_password, :maximum => 60, :allow_nil => true
24 24 validates_length_of :account, :base_dn, :maximum => 255, :allow_nil => true
25 25 validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
26 26 validates_numericality_of :port, :only_integer => true
27 27
28 28 before_validation :strip_ldap_attributes
29 29
30 30 def after_initialize
31 31 self.port = 389 if self.port == 0
32 32 end
33 33
34 34 def authenticate(login, password)
35 35 return nil if login.blank? || password.blank?
36 36 attrs = get_user_dn(login)
37 37
38 if attrs.first && attrs.first[:dn] && authenticate_dn(attrs.first[:dn], password)
38 if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password)
39 39 logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
40 return [] << attrs.first.except(:dn)
40 return attrs.except(:dn)
41 41 end
42 42 rescue Net::LDAP::LdapError => text
43 43 raise "LdapError: " + text
44 44 end
45 45
46 46 # test the connection to the LDAP
47 47 def test_connection
48 48 ldap_con = initialize_ldap_con(self.account, self.account_password)
49 49 ldap_con.open { }
50 50 rescue Net::LDAP::LdapError => text
51 51 raise "LdapError: " + text
52 52 end
53 53
54 54 def auth_method_name
55 55 "LDAP"
56 56 end
57 57
58 58 private
59 59
60 60 def strip_ldap_attributes
61 61 [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr|
62 62 write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil?
63 63 end
64 64 end
65 65
66 66 def initialize_ldap_con(ldap_user, ldap_password)
67 67 options = { :host => self.host,
68 68 :port => self.port,
69 69 :encryption => (self.tls ? :simple_tls : nil)
70 70 }
71 71 options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank?
72 72 Net::LDAP.new options
73 73 end
74 74
75 75 def get_user_attributes_from_ldap_entry(entry)
76 [
76 {
77 77 :dn => entry.dn,
78 78 :firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
79 79 :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
80 80 :mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
81 81 :auth_source_id => self.id
82 ]
82 }
83 83 end
84 84
85 85 # Return the attributes needed for the LDAP search. It will only
86 86 # include the user attributes if on-the-fly registration is enabled
87 87 def search_attributes
88 88 if onthefly_register?
89 89 ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]
90 90 else
91 91 ['dn']
92 92 end
93 93 end
94 94
95 95 # Check if a DN (user record) authenticates with the password
96 96 def authenticate_dn(dn, password)
97 97 if dn.present? && password.present?
98 98 initialize_ldap_con(dn, password).bind
99 99 end
100 100 end
101 101
102 102 # Get the user's dn and any attributes for them, given their login
103 103 def get_user_dn(login)
104 104 ldap_con = initialize_ldap_con(self.account, self.account_password)
105 105 login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
106 106 object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
107 attrs = []
107 attrs = {}
108 108
109 109 ldap_con.search( :base => self.base_dn,
110 110 :filter => object_filter & login_filter,
111 111 :attributes=> search_attributes) do |entry|
112 112
113 113 if onthefly_register?
114 114 attrs = get_user_attributes_from_ldap_entry(entry)
115 115 else
116 attrs = [:dn => entry.dn]
116 attrs = {:dn => entry.dn}
117 117 end
118 118
119 logger.debug "DN found for #{login}: #{attrs.first[:dn]}" if logger && logger.debug?
119 logger.debug "DN found for #{login}: #{attrs[:dn]}" if logger && logger.debug?
120 120 end
121 121
122 122 attrs
123 123 end
124 124
125 125 def self.get_attr(entry, attr_name)
126 126 if !attr_name.blank?
127 127 entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
128 128 end
129 129 end
130 130 end
@@ -1,360 +1,360
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2009 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require "digest/sha1"
19 19
20 20 class User < Principal
21 21
22 22 # Account statuses
23 23 STATUS_ANONYMOUS = 0
24 24 STATUS_ACTIVE = 1
25 25 STATUS_REGISTERED = 2
26 26 STATUS_LOCKED = 3
27 27
28 28 USER_FORMATS = {
29 29 :firstname_lastname => '#{firstname} #{lastname}',
30 30 :firstname => '#{firstname}',
31 31 :lastname_firstname => '#{lastname} #{firstname}',
32 32 :lastname_coma_firstname => '#{lastname}, #{firstname}',
33 33 :username => '#{login}'
34 34 }
35 35
36 36 has_and_belongs_to_many :groups, :after_add => Proc.new {|user, group| group.user_added(user)},
37 37 :after_remove => Proc.new {|user, group| group.user_removed(user)}
38 38 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
39 39 has_many :changesets, :dependent => :nullify
40 40 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
41 41 has_one :rss_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='feeds'"
42 42 has_one :api_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='api'"
43 43 belongs_to :auth_source
44 44
45 45 # Active non-anonymous users scope
46 46 named_scope :active, :conditions => "#{User.table_name}.status = #{STATUS_ACTIVE}"
47 47
48 48 acts_as_customizable
49 49
50 50 attr_accessor :password, :password_confirmation
51 51 attr_accessor :last_before_login_on
52 52 # Prevents unauthorized assignments
53 53 attr_protected :login, :admin, :password, :password_confirmation, :hashed_password, :group_ids
54 54
55 55 validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
56 56 validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }
57 57 validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false
58 58 # Login must contain lettres, numbers, underscores only
59 59 validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
60 60 validates_length_of :login, :maximum => 30
61 61 validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-\.]*$/i
62 62 validates_length_of :firstname, :lastname, :maximum => 30
63 63 validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true
64 64 validates_length_of :mail, :maximum => 60, :allow_nil => true
65 65 validates_confirmation_of :password, :allow_nil => true
66 66
67 67 def before_create
68 68 self.mail_notification = false
69 69 true
70 70 end
71 71
72 72 def before_save
73 73 # update hashed_password if password was set
74 74 self.hashed_password = User.hash_password(self.password) if self.password
75 75 end
76 76
77 77 def reload(*args)
78 78 @name = nil
79 79 super
80 80 end
81 81
82 82 def identity_url=(url)
83 83 if url.blank?
84 84 write_attribute(:identity_url, '')
85 85 else
86 86 begin
87 87 write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))
88 88 rescue OpenIdAuthentication::InvalidOpenId
89 89 # Invlaid url, don't save
90 90 end
91 91 end
92 92 self.read_attribute(:identity_url)
93 93 end
94 94
95 95 # Returns the user that matches provided login and password, or nil
96 96 def self.try_to_login(login, password)
97 97 # Make sure no one can sign in with an empty password
98 98 return nil if password.to_s.empty?
99 99 user = find(:first, :conditions => ["login=?", login])
100 100 if user
101 101 # user is already in local database
102 102 return nil if !user.active?
103 103 if user.auth_source
104 104 # user has an external authentication method
105 105 return nil unless user.auth_source.authenticate(login, password)
106 106 else
107 107 # authentication with local password
108 108 return nil unless User.hash_password(password) == user.hashed_password
109 109 end
110 110 else
111 111 # user is not yet registered, try to authenticate with available sources
112 112 attrs = AuthSource.authenticate(login, password)
113 113 if attrs
114 user = new(*attrs)
114 user = new(attrs)
115 115 user.login = login
116 116 user.language = Setting.default_language
117 117 if user.save
118 118 user.reload
119 119 logger.info("User '#{user.login}' created from the LDAP") if logger
120 120 end
121 121 end
122 122 end
123 123 user.update_attribute(:last_login_on, Time.now) if user && !user.new_record?
124 124 user
125 125 rescue => text
126 126 raise text
127 127 end
128 128
129 129 # Returns the user who matches the given autologin +key+ or nil
130 130 def self.try_to_autologin(key)
131 131 tokens = Token.find_all_by_action_and_value('autologin', key)
132 132 # Make sure there's only 1 token that matches the key
133 133 if tokens.size == 1
134 134 token = tokens.first
135 135 if (token.created_on > Setting.autologin.to_i.day.ago) && token.user && token.user.active?
136 136 token.user.update_attribute(:last_login_on, Time.now)
137 137 token.user
138 138 end
139 139 end
140 140 end
141 141
142 142 # Return user's full name for display
143 143 def name(formatter = nil)
144 144 if formatter
145 145 eval('"' + (USER_FORMATS[formatter] || USER_FORMATS[:firstname_lastname]) + '"')
146 146 else
147 147 @name ||= eval('"' + (USER_FORMATS[Setting.user_format] || USER_FORMATS[:firstname_lastname]) + '"')
148 148 end
149 149 end
150 150
151 151 def active?
152 152 self.status == STATUS_ACTIVE
153 153 end
154 154
155 155 def registered?
156 156 self.status == STATUS_REGISTERED
157 157 end
158 158
159 159 def locked?
160 160 self.status == STATUS_LOCKED
161 161 end
162 162
163 163 def check_password?(clear_password)
164 164 User.hash_password(clear_password) == self.hashed_password
165 165 end
166 166
167 167 # Generate and set a random password. Useful for automated user creation
168 168 # Based on Token#generate_token_value
169 169 #
170 170 def random_password
171 171 chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
172 172 password = ''
173 173 40.times { |i| password << chars[rand(chars.size-1)] }
174 174 self.password = password
175 175 self.password_confirmation = password
176 176 self
177 177 end
178 178
179 179 def pref
180 180 self.preference ||= UserPreference.new(:user => self)
181 181 end
182 182
183 183 def time_zone
184 184 @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone])
185 185 end
186 186
187 187 def wants_comments_in_reverse_order?
188 188 self.pref[:comments_sorting] == 'desc'
189 189 end
190 190
191 191 # Return user's RSS key (a 40 chars long string), used to access feeds
192 192 def rss_key
193 193 token = self.rss_token || Token.create(:user => self, :action => 'feeds')
194 194 token.value
195 195 end
196 196
197 197 # Return user's API key (a 40 chars long string), used to access the API
198 198 def api_key
199 199 token = self.api_token || self.create_api_token(:action => 'api')
200 200 token.value
201 201 end
202 202
203 203 # Return an array of project ids for which the user has explicitly turned mail notifications on
204 204 def notified_projects_ids
205 205 @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
206 206 end
207 207
208 208 def notified_project_ids=(ids)
209 209 Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
210 210 Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
211 211 @notified_projects_ids = nil
212 212 notified_projects_ids
213 213 end
214 214
215 215 def self.find_by_rss_key(key)
216 216 token = Token.find_by_value(key)
217 217 token && token.user.active? ? token.user : nil
218 218 end
219 219
220 220 def self.find_by_api_key(key)
221 221 token = Token.find_by_action_and_value('api', key)
222 222 token && token.user.active? ? token.user : nil
223 223 end
224 224
225 225 # Makes find_by_mail case-insensitive
226 226 def self.find_by_mail(mail)
227 227 find(:first, :conditions => ["LOWER(mail) = ?", mail.to_s.downcase])
228 228 end
229 229
230 230 def to_s
231 231 name
232 232 end
233 233
234 234 # Returns the current day according to user's time zone
235 235 def today
236 236 if time_zone.nil?
237 237 Date.today
238 238 else
239 239 Time.now.in_time_zone(time_zone).to_date
240 240 end
241 241 end
242 242
243 243 def logged?
244 244 true
245 245 end
246 246
247 247 def anonymous?
248 248 !logged?
249 249 end
250 250
251 251 # Return user's roles for project
252 252 def roles_for_project(project)
253 253 roles = []
254 254 # No role on archived projects
255 255 return roles unless project && project.active?
256 256 if logged?
257 257 # Find project membership
258 258 membership = memberships.detect {|m| m.project_id == project.id}
259 259 if membership
260 260 roles = membership.roles
261 261 else
262 262 @role_non_member ||= Role.non_member
263 263 roles << @role_non_member
264 264 end
265 265 else
266 266 @role_anonymous ||= Role.anonymous
267 267 roles << @role_anonymous
268 268 end
269 269 roles
270 270 end
271 271
272 272 # Return true if the user is a member of project
273 273 def member_of?(project)
274 274 !roles_for_project(project).detect {|role| role.member?}.nil?
275 275 end
276 276
277 277 # Return true if the user is allowed to do the specified action on project
278 278 # action can be:
279 279 # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
280 280 # * a permission Symbol (eg. :edit_project)
281 281 def allowed_to?(action, project, options={})
282 282 if project
283 283 # No action allowed on archived projects
284 284 return false unless project.active?
285 285 # No action allowed on disabled modules
286 286 return false unless project.allows_to?(action)
287 287 # Admin users are authorized for anything else
288 288 return true if admin?
289 289
290 290 roles = roles_for_project(project)
291 291 return false unless roles
292 292 roles.detect {|role| (project.is_public? || role.member?) && role.allowed_to?(action)}
293 293
294 294 elsif options[:global]
295 295 # Admin users are always authorized
296 296 return true if admin?
297 297
298 298 # authorize if user has at least one role that has this permission
299 299 roles = memberships.collect {|m| m.roles}.flatten.uniq
300 300 roles.detect {|r| r.allowed_to?(action)} || (self.logged? ? Role.non_member.allowed_to?(action) : Role.anonymous.allowed_to?(action))
301 301 else
302 302 false
303 303 end
304 304 end
305 305
306 306 def self.current=(user)
307 307 @current_user = user
308 308 end
309 309
310 310 def self.current
311 311 @current_user ||= User.anonymous
312 312 end
313 313
314 314 # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only
315 315 # one anonymous user per database.
316 316 def self.anonymous
317 317 anonymous_user = AnonymousUser.find(:first)
318 318 if anonymous_user.nil?
319 319 anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
320 320 raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
321 321 end
322 322 anonymous_user
323 323 end
324 324
325 325 protected
326 326
327 327 def validate
328 328 # Password length validation based on setting
329 329 if !password.nil? && password.size < Setting.password_min_length.to_i
330 330 errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
331 331 end
332 332 end
333 333
334 334 private
335 335
336 336 # Return password digest
337 337 def self.hash_password(clear_password)
338 338 Digest::SHA1.hexdigest(clear_password || "")
339 339 end
340 340 end
341 341
342 342 class AnonymousUser < User
343 343
344 344 def validate_on_create
345 345 # There should be only one AnonymousUser in the database
346 346 errors.add_to_base 'An anonymous user already exists.' if AnonymousUser.find(:first)
347 347 end
348 348
349 349 def available_custom_fields
350 350 []
351 351 end
352 352
353 353 # Overrides a few properties
354 354 def logged?; false end
355 355 def admin; false end
356 356 def name(*args); I18n.t(:label_user_anonymous) end
357 357 def mail; nil end
358 358 def time_zone; nil end
359 359 def rss_key; nil end
360 360 end
@@ -1,206 +1,206
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require "#{File.dirname(__FILE__)}/../test_helper"
19 19
20 20 begin
21 21 require 'mocha'
22 22 rescue
23 23 # Won't run some tests
24 24 end
25 25
26 26 class AccountTest < ActionController::IntegrationTest
27 27 fixtures :users, :roles
28 28
29 29 # Replace this with your real tests.
30 30 def test_login
31 31 get "my/page"
32 32 assert_redirected_to "/login?back_url=http%3A%2F%2Fwww.example.com%2Fmy%2Fpage"
33 33 log_user('jsmith', 'jsmith')
34 34
35 35 get "my/account"
36 36 assert_response :success
37 37 assert_template "my/account"
38 38 end
39 39
40 40 def test_autologin
41 41 user = User.find(1)
42 42 Setting.autologin = "7"
43 43 Token.delete_all
44 44
45 45 # User logs in with 'autologin' checked
46 46 post '/login', :username => user.login, :password => 'admin', :autologin => 1
47 47 assert_redirected_to 'my/page'
48 48 token = Token.find :first
49 49 assert_not_nil token
50 50 assert_equal user, token.user
51 51 assert_equal 'autologin', token.action
52 52 assert_equal user.id, session[:user_id]
53 53 assert_equal token.value, cookies['autologin']
54 54
55 55 # Session is cleared
56 56 reset!
57 57 User.current = nil
58 58 # Clears user's last login timestamp
59 59 user.update_attribute :last_login_on, nil
60 60 assert_nil user.reload.last_login_on
61 61
62 62 # User comes back with his autologin cookie
63 63 cookies[:autologin] = token.value
64 64 get '/my/page'
65 65 assert_response :success
66 66 assert_template 'my/page'
67 67 assert_equal user.id, session[:user_id]
68 68 assert_not_nil user.reload.last_login_on
69 69 assert user.last_login_on.utc > 10.second.ago.utc
70 70 end
71 71
72 72 def test_lost_password
73 73 Token.delete_all
74 74
75 75 get "account/lost_password"
76 76 assert_response :success
77 77 assert_template "account/lost_password"
78 78
79 79 post "account/lost_password", :mail => 'jSmith@somenet.foo'
80 80 assert_redirected_to "/login"
81 81
82 82 token = Token.find(:first)
83 83 assert_equal 'recovery', token.action
84 84 assert_equal 'jsmith@somenet.foo', token.user.mail
85 85 assert !token.expired?
86 86
87 87 get "account/lost_password", :token => token.value
88 88 assert_response :success
89 89 assert_template "account/password_recovery"
90 90
91 91 post "account/lost_password", :token => token.value, :new_password => 'newpass', :new_password_confirmation => 'newpass'
92 92 assert_redirected_to "/login"
93 93 assert_equal 'Password was successfully updated.', flash[:notice]
94 94
95 95 log_user('jsmith', 'newpass')
96 96 assert_equal 0, Token.count
97 97 end
98 98
99 99 def test_register_with_automatic_activation
100 100 Setting.self_registration = '3'
101 101
102 102 get 'account/register'
103 103 assert_response :success
104 104 assert_template 'account/register'
105 105
106 106 post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"},
107 107 :password => "newpass", :password_confirmation => "newpass"
108 108 assert_redirected_to 'my/account'
109 109 follow_redirect!
110 110 assert_response :success
111 111 assert_template 'my/account'
112 112
113 113 user = User.find_by_login('newuser')
114 114 assert_not_nil user
115 115 assert user.active?
116 116 assert_not_nil user.last_login_on
117 117 end
118 118
119 119 def test_register_with_manual_activation
120 120 Setting.self_registration = '2'
121 121
122 122 post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"},
123 123 :password => "newpass", :password_confirmation => "newpass"
124 124 assert_redirected_to '/login'
125 125 assert !User.find_by_login('newuser').active?
126 126 end
127 127
128 128 def test_register_with_email_activation
129 129 Setting.self_registration = '1'
130 130 Token.delete_all
131 131
132 132 post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"},
133 133 :password => "newpass", :password_confirmation => "newpass"
134 134 assert_redirected_to '/login'
135 135 assert !User.find_by_login('newuser').active?
136 136
137 137 token = Token.find(:first)
138 138 assert_equal 'register', token.action
139 139 assert_equal 'newuser@foo.bar', token.user.mail
140 140 assert !token.expired?
141 141
142 142 get 'account/activate', :token => token.value
143 143 assert_redirected_to '/login'
144 144 log_user('newuser', 'newpass')
145 145 end
146 146
147 147 if Object.const_defined?(:Mocha)
148 148
149 149 def test_onthefly_registration
150 150 # disable registration
151 151 Setting.self_registration = '0'
152 AuthSource.expects(:authenticate).returns([:login => 'foo', :firstname => 'Foo', :lastname => 'Smith', :mail => 'foo@bar.com', :auth_source_id => 66])
152 AuthSource.expects(:authenticate).returns({:login => 'foo', :firstname => 'Foo', :lastname => 'Smith', :mail => 'foo@bar.com', :auth_source_id => 66})
153 153
154 154 post 'account/login', :username => 'foo', :password => 'bar'
155 155 assert_redirected_to 'my/page'
156 156
157 157 user = User.find_by_login('foo')
158 158 assert user.is_a?(User)
159 159 assert_equal 66, user.auth_source_id
160 160 assert user.hashed_password.blank?
161 161 end
162 162
163 163 def test_onthefly_registration_with_invalid_attributes
164 164 # disable registration
165 165 Setting.self_registration = '0'
166 AuthSource.expects(:authenticate).returns([:login => 'foo', :lastname => 'Smith', :auth_source_id => 66])
166 AuthSource.expects(:authenticate).returns({:login => 'foo', :lastname => 'Smith', :auth_source_id => 66})
167 167
168 168 post 'account/login', :username => 'foo', :password => 'bar'
169 169 assert_response :success
170 170 assert_template 'account/register'
171 171 assert_tag :input, :attributes => { :name => 'user[firstname]', :value => '' }
172 172 assert_tag :input, :attributes => { :name => 'user[lastname]', :value => 'Smith' }
173 173 assert_no_tag :input, :attributes => { :name => 'user[login]' }
174 174 assert_no_tag :input, :attributes => { :name => 'user[password]' }
175 175
176 176 post 'account/register', :user => {:firstname => 'Foo', :lastname => 'Smith', :mail => 'foo@bar.com'}
177 177 assert_redirected_to '/my/account'
178 178
179 179 user = User.find_by_login('foo')
180 180 assert user.is_a?(User)
181 181 assert_equal 66, user.auth_source_id
182 182 assert user.hashed_password.blank?
183 183 end
184 184
185 185 def test_login_and_logout_should_clear_session
186 186 get '/login'
187 187 sid = session[:session_id]
188 188
189 189 post '/login', :username => 'admin', :password => 'admin'
190 190 assert_redirected_to 'my/page'
191 191 assert_not_equal sid, session[:session_id], "login should reset session"
192 192 assert_equal 1, session[:user_id]
193 193 sid = session[:session_id]
194 194
195 195 get '/'
196 196 assert_equal sid, session[:session_id]
197 197
198 198 get '/logout'
199 199 assert_not_equal sid, session[:session_id], "logout should reset session"
200 200 assert_nil session[:user_id]
201 201 end
202 202
203 203 else
204 204 puts 'Mocha is missing. Skipping tests.'
205 205 end
206 206 end
@@ -1,82 +1,80
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2008 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.dirname(__FILE__) + '/../test_helper'
19 19
20 20 class AuthSourceLdapTest < ActiveSupport::TestCase
21 21 fixtures :auth_sources
22 22
23 23 def setup
24 24 end
25 25
26 26 def test_create
27 27 a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName')
28 28 assert a.save
29 29 end
30 30
31 31 def test_should_strip_ldap_attributes
32 32 a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName',
33 33 :attr_firstname => 'givenName ')
34 34 assert a.save
35 35 assert_equal 'givenName', a.reload.attr_firstname
36 36 end
37 37
38 38 if ldap_configured?
39 39 context '#authenticate' do
40 40 setup do
41 41 @auth = AuthSourceLdap.find(1)
42 42 end
43 43
44 44 context 'with a valid LDAP user' do
45 45 should 'return the user attributes' do
46 response = @auth.authenticate('example1','123456')
47 assert response.is_a?(Array), "An array was not returned"
48 assert response.first.present?, "No user data returned"
49 attributes = response.first
46 attributes = @auth.authenticate('example1','123456')
47 assert attributes.is_a?(Hash), "An hash was not returned"
50 48 assert_equal 'Example', attributes[:firstname]
51 49 assert_equal 'One', attributes[:lastname]
52 50 assert_equal 'example1@redmine.org', attributes[:mail]
53 51 assert_equal @auth.id, attributes[:auth_source_id]
54 52 attributes.keys.each do |attribute|
55 53 assert User.new.respond_to?("#{attribute}="), "Unexpected :#{attribute} attribute returned"
56 54 end
57 55 end
58 56 end
59 57
60 58 context 'with an invalid LDAP user' do
61 59 should 'return nil' do
62 60 assert_equal nil, @auth.authenticate('nouser','123456')
63 61 end
64 62 end
65 63
66 64 context 'without a login' do
67 65 should 'return nil' do
68 66 assert_equal nil, @auth.authenticate('','123456')
69 67 end
70 68 end
71 69
72 70 context 'without a password' do
73 71 should 'return nil' do
74 72 assert_equal nil, @auth.authenticate('edavis','')
75 73 end
76 74 end
77 75
78 76 end
79 77 else
80 78 puts '(Test LDAP server not configured)'
81 79 end
82 80 end
General Comments 0
You need to be logged in to leave comments. Login now