##// END OF EJS Templates
Friendly response when the LDAP connection fails....
Jean-Philippe Lang -
r8791:3e3d7c8d4f4f
parent child
Show More
@@ -1,284 +1,287
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 class AccountController < ApplicationController
18 class AccountController < ApplicationController
19 helper :custom_fields
19 helper :custom_fields
20 include CustomFieldsHelper
20 include CustomFieldsHelper
21
21
22 # prevents login action to be filtered by check_if_login_required application scope filter
22 # prevents login action to be filtered by check_if_login_required application scope filter
23 skip_before_filter :check_if_login_required
23 skip_before_filter :check_if_login_required
24
24
25 # Login request and validation
25 # Login request and validation
26 def login
26 def login
27 if request.get?
27 if request.get?
28 logout_user
28 logout_user
29 else
29 else
30 authenticate_user
30 authenticate_user
31 end
31 end
32 rescue AuthSourceException => e
33 logger.error "An error occured when authenticating #{params[:username]}: #{e.message}"
34 render_error :message => e.message
32 end
35 end
33
36
34 # Log out current user and redirect to welcome page
37 # Log out current user and redirect to welcome page
35 def logout
38 def logout
36 logout_user
39 logout_user
37 redirect_to home_url
40 redirect_to home_url
38 end
41 end
39
42
40 # Enable user to choose a new password
43 # Enable user to choose a new password
41 def lost_password
44 def lost_password
42 redirect_to(home_url) && return unless Setting.lost_password?
45 redirect_to(home_url) && return unless Setting.lost_password?
43 if params[:token]
46 if params[:token]
44 @token = Token.find_by_action_and_value("recovery", params[:token])
47 @token = Token.find_by_action_and_value("recovery", params[:token])
45 redirect_to(home_url) && return unless @token and !@token.expired?
48 redirect_to(home_url) && return unless @token and !@token.expired?
46 @user = @token.user
49 @user = @token.user
47 if request.post?
50 if request.post?
48 @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
51 @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
49 if @user.save
52 if @user.save
50 @token.destroy
53 @token.destroy
51 flash[:notice] = l(:notice_account_password_updated)
54 flash[:notice] = l(:notice_account_password_updated)
52 redirect_to :action => 'login'
55 redirect_to :action => 'login'
53 return
56 return
54 end
57 end
55 end
58 end
56 render :template => "account/password_recovery"
59 render :template => "account/password_recovery"
57 return
60 return
58 else
61 else
59 if request.post?
62 if request.post?
60 user = User.find_by_mail(params[:mail])
63 user = User.find_by_mail(params[:mail])
61 # user not found in db
64 # user not found in db
62 (flash.now[:error] = l(:notice_account_unknown_email); return) unless user
65 (flash.now[:error] = l(:notice_account_unknown_email); return) unless user
63 # user uses an external authentification
66 # user uses an external authentification
64 (flash.now[:error] = l(:notice_can_t_change_password); return) if user.auth_source_id
67 (flash.now[:error] = l(:notice_can_t_change_password); return) if user.auth_source_id
65 # create a new token for password recovery
68 # create a new token for password recovery
66 token = Token.new(:user => user, :action => "recovery")
69 token = Token.new(:user => user, :action => "recovery")
67 if token.save
70 if token.save
68 Mailer.deliver_lost_password(token)
71 Mailer.deliver_lost_password(token)
69 flash[:notice] = l(:notice_account_lost_email_sent)
72 flash[:notice] = l(:notice_account_lost_email_sent)
70 redirect_to :action => 'login'
73 redirect_to :action => 'login'
71 return
74 return
72 end
75 end
73 end
76 end
74 end
77 end
75 end
78 end
76
79
77 # User self-registration
80 # User self-registration
78 def register
81 def register
79 redirect_to(home_url) && return unless Setting.self_registration? || session[:auth_source_registration]
82 redirect_to(home_url) && return unless Setting.self_registration? || session[:auth_source_registration]
80 if request.get?
83 if request.get?
81 session[:auth_source_registration] = nil
84 session[:auth_source_registration] = nil
82 @user = User.new(:language => Setting.default_language)
85 @user = User.new(:language => Setting.default_language)
83 else
86 else
84 @user = User.new
87 @user = User.new
85 @user.safe_attributes = params[:user]
88 @user.safe_attributes = params[:user]
86 @user.admin = false
89 @user.admin = false
87 @user.register
90 @user.register
88 if session[:auth_source_registration]
91 if session[:auth_source_registration]
89 @user.activate
92 @user.activate
90 @user.login = session[:auth_source_registration][:login]
93 @user.login = session[:auth_source_registration][:login]
91 @user.auth_source_id = session[:auth_source_registration][:auth_source_id]
94 @user.auth_source_id = session[:auth_source_registration][:auth_source_id]
92 if @user.save
95 if @user.save
93 session[:auth_source_registration] = nil
96 session[:auth_source_registration] = nil
94 self.logged_user = @user
97 self.logged_user = @user
95 flash[:notice] = l(:notice_account_activated)
98 flash[:notice] = l(:notice_account_activated)
96 redirect_to :controller => 'my', :action => 'account'
99 redirect_to :controller => 'my', :action => 'account'
97 end
100 end
98 else
101 else
99 @user.login = params[:user][:login]
102 @user.login = params[:user][:login]
100 @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation]
103 @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation]
101
104
102 case Setting.self_registration
105 case Setting.self_registration
103 when '1'
106 when '1'
104 register_by_email_activation(@user)
107 register_by_email_activation(@user)
105 when '3'
108 when '3'
106 register_automatically(@user)
109 register_automatically(@user)
107 else
110 else
108 register_manually_by_administrator(@user)
111 register_manually_by_administrator(@user)
109 end
112 end
110 end
113 end
111 end
114 end
112 end
115 end
113
116
114 # Token based account activation
117 # Token based account activation
115 def activate
118 def activate
116 redirect_to(home_url) && return unless Setting.self_registration? && params[:token]
119 redirect_to(home_url) && return unless Setting.self_registration? && params[:token]
117 token = Token.find_by_action_and_value('register', params[:token])
120 token = Token.find_by_action_and_value('register', params[:token])
118 redirect_to(home_url) && return unless token and !token.expired?
121 redirect_to(home_url) && return unless token and !token.expired?
119 user = token.user
122 user = token.user
120 redirect_to(home_url) && return unless user.registered?
123 redirect_to(home_url) && return unless user.registered?
121 user.activate
124 user.activate
122 if user.save
125 if user.save
123 token.destroy
126 token.destroy
124 flash[:notice] = l(:notice_account_activated)
127 flash[:notice] = l(:notice_account_activated)
125 end
128 end
126 redirect_to :action => 'login'
129 redirect_to :action => 'login'
127 end
130 end
128
131
129 private
132 private
130
133
131 def logout_user
134 def logout_user
132 if User.current.logged?
135 if User.current.logged?
133 cookies.delete :autologin
136 cookies.delete :autologin
134 Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin'])
137 Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin'])
135 self.logged_user = nil
138 self.logged_user = nil
136 end
139 end
137 end
140 end
138
141
139 def authenticate_user
142 def authenticate_user
140 if Setting.openid? && using_open_id?
143 if Setting.openid? && using_open_id?
141 open_id_authenticate(params[:openid_url])
144 open_id_authenticate(params[:openid_url])
142 else
145 else
143 password_authentication
146 password_authentication
144 end
147 end
145 end
148 end
146
149
147 def password_authentication
150 def password_authentication
148 user = User.try_to_login(params[:username], params[:password])
151 user = User.try_to_login(params[:username], params[:password])
149
152
150 if user.nil?
153 if user.nil?
151 invalid_credentials
154 invalid_credentials
152 elsif user.new_record?
155 elsif user.new_record?
153 onthefly_creation_failed(user, {:login => user.login, :auth_source_id => user.auth_source_id })
156 onthefly_creation_failed(user, {:login => user.login, :auth_source_id => user.auth_source_id })
154 else
157 else
155 # Valid user
158 # Valid user
156 successful_authentication(user)
159 successful_authentication(user)
157 end
160 end
158 end
161 end
159
162
160 def open_id_authenticate(openid_url)
163 def open_id_authenticate(openid_url)
161 authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration|
164 authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration|
162 if result.successful?
165 if result.successful?
163 user = User.find_or_initialize_by_identity_url(identity_url)
166 user = User.find_or_initialize_by_identity_url(identity_url)
164 if user.new_record?
167 if user.new_record?
165 # Self-registration off
168 # Self-registration off
166 redirect_to(home_url) && return unless Setting.self_registration?
169 redirect_to(home_url) && return unless Setting.self_registration?
167
170
168 # Create on the fly
171 # Create on the fly
169 user.login = registration['nickname'] unless registration['nickname'].nil?
172 user.login = registration['nickname'] unless registration['nickname'].nil?
170 user.mail = registration['email'] unless registration['email'].nil?
173 user.mail = registration['email'] unless registration['email'].nil?
171 user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil?
174 user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil?
172 user.random_password
175 user.random_password
173 user.register
176 user.register
174
177
175 case Setting.self_registration
178 case Setting.self_registration
176 when '1'
179 when '1'
177 register_by_email_activation(user) do
180 register_by_email_activation(user) do
178 onthefly_creation_failed(user)
181 onthefly_creation_failed(user)
179 end
182 end
180 when '3'
183 when '3'
181 register_automatically(user) do
184 register_automatically(user) do
182 onthefly_creation_failed(user)
185 onthefly_creation_failed(user)
183 end
186 end
184 else
187 else
185 register_manually_by_administrator(user) do
188 register_manually_by_administrator(user) do
186 onthefly_creation_failed(user)
189 onthefly_creation_failed(user)
187 end
190 end
188 end
191 end
189 else
192 else
190 # Existing record
193 # Existing record
191 if user.active?
194 if user.active?
192 successful_authentication(user)
195 successful_authentication(user)
193 else
196 else
194 account_pending
197 account_pending
195 end
198 end
196 end
199 end
197 end
200 end
198 end
201 end
199 end
202 end
200
203
201 def successful_authentication(user)
204 def successful_authentication(user)
202 # Valid user
205 # Valid user
203 self.logged_user = user
206 self.logged_user = user
204 # generate a key and set cookie if autologin
207 # generate a key and set cookie if autologin
205 if params[:autologin] && Setting.autologin?
208 if params[:autologin] && Setting.autologin?
206 set_autologin_cookie(user)
209 set_autologin_cookie(user)
207 end
210 end
208 call_hook(:controller_account_success_authentication_after, {:user => user })
211 call_hook(:controller_account_success_authentication_after, {:user => user })
209 redirect_back_or_default :controller => 'my', :action => 'page'
212 redirect_back_or_default :controller => 'my', :action => 'page'
210 end
213 end
211
214
212 def set_autologin_cookie(user)
215 def set_autologin_cookie(user)
213 token = Token.create(:user => user, :action => 'autologin')
216 token = Token.create(:user => user, :action => 'autologin')
214 cookie_name = Redmine::Configuration['autologin_cookie_name'] || 'autologin'
217 cookie_name = Redmine::Configuration['autologin_cookie_name'] || 'autologin'
215 cookie_options = {
218 cookie_options = {
216 :value => token.value,
219 :value => token.value,
217 :expires => 1.year.from_now,
220 :expires => 1.year.from_now,
218 :path => (Redmine::Configuration['autologin_cookie_path'] || '/'),
221 :path => (Redmine::Configuration['autologin_cookie_path'] || '/'),
219 :secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false),
222 :secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false),
220 :httponly => true
223 :httponly => true
221 }
224 }
222 cookies[cookie_name] = cookie_options
225 cookies[cookie_name] = cookie_options
223 end
226 end
224
227
225 # Onthefly creation failed, display the registration form to fill/fix attributes
228 # Onthefly creation failed, display the registration form to fill/fix attributes
226 def onthefly_creation_failed(user, auth_source_options = { })
229 def onthefly_creation_failed(user, auth_source_options = { })
227 @user = user
230 @user = user
228 session[:auth_source_registration] = auth_source_options unless auth_source_options.empty?
231 session[:auth_source_registration] = auth_source_options unless auth_source_options.empty?
229 render :action => 'register'
232 render :action => 'register'
230 end
233 end
231
234
232 def invalid_credentials
235 def invalid_credentials
233 logger.warn "Failed login for '#{params[:username]}' from #{request.remote_ip} at #{Time.now.utc}"
236 logger.warn "Failed login for '#{params[:username]}' from #{request.remote_ip} at #{Time.now.utc}"
234 flash.now[:error] = l(:notice_account_invalid_creditentials)
237 flash.now[:error] = l(:notice_account_invalid_creditentials)
235 end
238 end
236
239
237 # Register a user for email activation.
240 # Register a user for email activation.
238 #
241 #
239 # Pass a block for behavior when a user fails to save
242 # Pass a block for behavior when a user fails to save
240 def register_by_email_activation(user, &block)
243 def register_by_email_activation(user, &block)
241 token = Token.new(:user => user, :action => "register")
244 token = Token.new(:user => user, :action => "register")
242 if user.save and token.save
245 if user.save and token.save
243 Mailer.deliver_register(token)
246 Mailer.deliver_register(token)
244 flash[:notice] = l(:notice_account_register_done)
247 flash[:notice] = l(:notice_account_register_done)
245 redirect_to :action => 'login'
248 redirect_to :action => 'login'
246 else
249 else
247 yield if block_given?
250 yield if block_given?
248 end
251 end
249 end
252 end
250
253
251 # Automatically register a user
254 # Automatically register a user
252 #
255 #
253 # Pass a block for behavior when a user fails to save
256 # Pass a block for behavior when a user fails to save
254 def register_automatically(user, &block)
257 def register_automatically(user, &block)
255 # Automatic activation
258 # Automatic activation
256 user.activate
259 user.activate
257 user.last_login_on = Time.now
260 user.last_login_on = Time.now
258 if user.save
261 if user.save
259 self.logged_user = user
262 self.logged_user = user
260 flash[:notice] = l(:notice_account_activated)
263 flash[:notice] = l(:notice_account_activated)
261 redirect_to :controller => 'my', :action => 'account'
264 redirect_to :controller => 'my', :action => 'account'
262 else
265 else
263 yield if block_given?
266 yield if block_given?
264 end
267 end
265 end
268 end
266
269
267 # Manual activation by the administrator
270 # Manual activation by the administrator
268 #
271 #
269 # Pass a block for behavior when a user fails to save
272 # Pass a block for behavior when a user fails to save
270 def register_manually_by_administrator(user, &block)
273 def register_manually_by_administrator(user, &block)
271 if user.save
274 if user.save
272 # Sends an email to the administrators
275 # Sends an email to the administrators
273 Mailer.deliver_account_activation_request(user)
276 Mailer.deliver_account_activation_request(user)
274 account_pending
277 account_pending
275 else
278 else
276 yield if block_given?
279 yield if block_given?
277 end
280 end
278 end
281 end
279
282
280 def account_pending
283 def account_pending
281 flash[:notice] = l(:notice_account_pending)
284 flash[:notice] = l(:notice_account_pending)
282 redirect_to :action => 'login'
285 redirect_to :action => 'login'
283 end
286 end
284 end
287 end
@@ -1,68 +1,72
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 # Generic exception for when the AuthSource can not be reached
19 # (eg. can not connect to the LDAP)
20 class AuthSourceException < Exception; end
21
18 class AuthSource < ActiveRecord::Base
22 class AuthSource < ActiveRecord::Base
19 include Redmine::Ciphering
23 include Redmine::Ciphering
20
24
21 has_many :users
25 has_many :users
22
26
23 validates_presence_of :name
27 validates_presence_of :name
24 validates_uniqueness_of :name
28 validates_uniqueness_of :name
25 validates_length_of :name, :maximum => 60
29 validates_length_of :name, :maximum => 60
26
30
27 def authenticate(login, password)
31 def authenticate(login, password)
28 end
32 end
29
33
30 def test_connection
34 def test_connection
31 end
35 end
32
36
33 def auth_method_name
37 def auth_method_name
34 "Abstract"
38 "Abstract"
35 end
39 end
36
40
37 def account_password
41 def account_password
38 read_ciphered_attribute(:account_password)
42 read_ciphered_attribute(:account_password)
39 end
43 end
40
44
41 def account_password=(arg)
45 def account_password=(arg)
42 write_ciphered_attribute(:account_password, arg)
46 write_ciphered_attribute(:account_password, arg)
43 end
47 end
44
48
45 def allow_password_changes?
49 def allow_password_changes?
46 self.class.allow_password_changes?
50 self.class.allow_password_changes?
47 end
51 end
48
52
49 # Does this auth source backend allow password changes?
53 # Does this auth source backend allow password changes?
50 def self.allow_password_changes?
54 def self.allow_password_changes?
51 false
55 false
52 end
56 end
53
57
54 # Try to authenticate a user not yet registered against available sources
58 # Try to authenticate a user not yet registered against available sources
55 def self.authenticate(login, password)
59 def self.authenticate(login, password)
56 AuthSource.find(:all, :conditions => ["onthefly_register=?", true]).each do |source|
60 AuthSource.find(:all, :conditions => ["onthefly_register=?", true]).each do |source|
57 begin
61 begin
58 logger.debug "Authenticating '#{login}' against '#{source.name}'" if logger && logger.debug?
62 logger.debug "Authenticating '#{login}' against '#{source.name}'" if logger && logger.debug?
59 attrs = source.authenticate(login, password)
63 attrs = source.authenticate(login, password)
60 rescue => e
64 rescue => e
61 logger.error "Error during authentication: #{e.message}"
65 logger.error "Error during authentication: #{e.message}"
62 attrs = nil
66 attrs = nil
63 end
67 end
64 return attrs if attrs
68 return attrs if attrs
65 end
69 end
66 return nil
70 return nil
67 end
71 end
68 end
72 end
@@ -1,131 +1,131
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
20
21 class AuthSourceLdap < AuthSource
21 class AuthSourceLdap < AuthSource
22 validates_presence_of :host, :port, :attr_login
22 validates_presence_of :host, :port, :attr_login
23 validates_length_of :name, :host, :maximum => 60, :allow_nil => true
23 validates_length_of :name, :host, :maximum => 60, :allow_nil => true
24 validates_length_of :account, :account_password, :base_dn, :maximum => 255, :allow_nil => true
24 validates_length_of :account, :account_password, :base_dn, :maximum => 255, :allow_nil => true
25 validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
25 validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
26 validates_numericality_of :port, :only_integer => true
26 validates_numericality_of :port, :only_integer => true
27
27
28 before_validation :strip_ldap_attributes
28 before_validation :strip_ldap_attributes
29
29
30 def initialize(attributes=nil, *args)
30 def initialize(attributes=nil, *args)
31 super
31 super
32 self.port = 389 if self.port == 0
32 self.port = 389 if self.port == 0
33 end
33 end
34
34
35 def authenticate(login, password)
35 def authenticate(login, password)
36 return nil if login.blank? || password.blank?
36 return nil if login.blank? || password.blank?
37 attrs = get_user_dn(login)
37 attrs = get_user_dn(login)
38
38
39 if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password)
39 if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password)
40 logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
40 logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
41 return attrs.except(:dn)
41 return attrs.except(:dn)
42 end
42 end
43 rescue Net::LDAP::LdapError => text
43 rescue Net::LDAP::LdapError => e
44 raise "LdapError: " + text
44 raise AuthSourceException.new(e.message)
45 end
45 end
46
46
47 # test the connection to the LDAP
47 # test the connection to the LDAP
48 def test_connection
48 def test_connection
49 ldap_con = initialize_ldap_con(self.account, self.account_password)
49 ldap_con = initialize_ldap_con(self.account, self.account_password)
50 ldap_con.open { }
50 ldap_con.open { }
51 rescue Net::LDAP::LdapError => text
51 rescue Net::LDAP::LdapError => text
52 raise "LdapError: " + text
52 raise "LdapError: " + text
53 end
53 end
54
54
55 def auth_method_name
55 def auth_method_name
56 "LDAP"
56 "LDAP"
57 end
57 end
58
58
59 private
59 private
60
60
61 def strip_ldap_attributes
61 def strip_ldap_attributes
62 [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr|
62 [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr|
63 write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil?
63 write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil?
64 end
64 end
65 end
65 end
66
66
67 def initialize_ldap_con(ldap_user, ldap_password)
67 def initialize_ldap_con(ldap_user, ldap_password)
68 options = { :host => self.host,
68 options = { :host => self.host,
69 :port => self.port,
69 :port => self.port,
70 :encryption => (self.tls ? :simple_tls : nil)
70 :encryption => (self.tls ? :simple_tls : nil)
71 }
71 }
72 options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank?
72 options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank?
73 Net::LDAP.new options
73 Net::LDAP.new options
74 end
74 end
75
75
76 def get_user_attributes_from_ldap_entry(entry)
76 def get_user_attributes_from_ldap_entry(entry)
77 {
77 {
78 :dn => entry.dn,
78 :dn => entry.dn,
79 :firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
79 :firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
80 :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
80 :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
81 :mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
81 :mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
82 :auth_source_id => self.id
82 :auth_source_id => self.id
83 }
83 }
84 end
84 end
85
85
86 # Return the attributes needed for the LDAP search. It will only
86 # Return the attributes needed for the LDAP search. It will only
87 # include the user attributes if on-the-fly registration is enabled
87 # include the user attributes if on-the-fly registration is enabled
88 def search_attributes
88 def search_attributes
89 if onthefly_register?
89 if onthefly_register?
90 ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]
90 ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]
91 else
91 else
92 ['dn']
92 ['dn']
93 end
93 end
94 end
94 end
95
95
96 # Check if a DN (user record) authenticates with the password
96 # Check if a DN (user record) authenticates with the password
97 def authenticate_dn(dn, password)
97 def authenticate_dn(dn, password)
98 if dn.present? && password.present?
98 if dn.present? && password.present?
99 initialize_ldap_con(dn, password).bind
99 initialize_ldap_con(dn, password).bind
100 end
100 end
101 end
101 end
102
102
103 # Get the user's dn and any attributes for them, given their login
103 # Get the user's dn and any attributes for them, given their login
104 def get_user_dn(login)
104 def get_user_dn(login)
105 ldap_con = initialize_ldap_con(self.account, self.account_password)
105 ldap_con = initialize_ldap_con(self.account, self.account_password)
106 login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
106 login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
107 object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
107 object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
108 attrs = {}
108 attrs = {}
109
109
110 ldap_con.search( :base => self.base_dn,
110 ldap_con.search( :base => self.base_dn,
111 :filter => object_filter & login_filter,
111 :filter => object_filter & login_filter,
112 :attributes=> search_attributes) do |entry|
112 :attributes=> search_attributes) do |entry|
113
113
114 if onthefly_register?
114 if onthefly_register?
115 attrs = get_user_attributes_from_ldap_entry(entry)
115 attrs = get_user_attributes_from_ldap_entry(entry)
116 else
116 else
117 attrs = {:dn => entry.dn}
117 attrs = {:dn => entry.dn}
118 end
118 end
119
119
120 logger.debug "DN found for #{login}: #{attrs[:dn]}" if logger && logger.debug?
120 logger.debug "DN found for #{login}: #{attrs[:dn]}" if logger && logger.debug?
121 end
121 end
122
122
123 attrs
123 attrs
124 end
124 end
125
125
126 def self.get_attr(entry, attr_name)
126 def self.get_attr(entry, attr_name)
127 if !attr_name.blank?
127 if !attr_name.blank?
128 entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
128 entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
129 end
129 end
130 end
130 end
131 end
131 end
@@ -1,222 +1,232
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 require 'account_controller'
19 require 'account_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class AccountController; def rescue_action(e) raise e end; end
22 class AccountController; def rescue_action(e) raise e end; end
23
23
24 class AccountControllerTest < ActionController::TestCase
24 class AccountControllerTest < ActionController::TestCase
25 fixtures :users, :roles
25 fixtures :users, :roles
26
26
27 def setup
27 def setup
28 @controller = AccountController.new
28 @controller = AccountController.new
29 @request = ActionController::TestRequest.new
29 @request = ActionController::TestRequest.new
30 @response = ActionController::TestResponse.new
30 @response = ActionController::TestResponse.new
31 User.current = nil
31 User.current = nil
32 end
32 end
33
33
34 def test_login_should_redirect_to_back_url_param
34 def test_login_should_redirect_to_back_url_param
35 # request.uri is "test.host" in test environment
35 # request.uri is "test.host" in test environment
36 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http%3A%2F%2Ftest.host%2Fissues%2Fshow%2F1'
36 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http%3A%2F%2Ftest.host%2Fissues%2Fshow%2F1'
37 assert_redirected_to '/issues/show/1'
37 assert_redirected_to '/issues/show/1'
38 end
38 end
39
39
40 def test_login_should_not_redirect_to_another_host
40 def test_login_should_not_redirect_to_another_host
41 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http%3A%2F%2Ftest.foo%2Ffake'
41 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http%3A%2F%2Ftest.foo%2Ffake'
42 assert_redirected_to '/my/page'
42 assert_redirected_to '/my/page'
43 end
43 end
44
44
45 def test_login_with_wrong_password
45 def test_login_with_wrong_password
46 post :login, :username => 'admin', :password => 'bad'
46 post :login, :username => 'admin', :password => 'bad'
47 assert_response :success
47 assert_response :success
48 assert_template 'login'
48 assert_template 'login'
49 assert_tag 'div',
49 assert_tag 'div',
50 :attributes => { :class => "flash error" },
50 :attributes => { :class => "flash error" },
51 :content => /Invalid user or password/
51 :content => /Invalid user or password/
52 end
52 end
53
53
54 def test_login_should_rescue_auth_source_exception
55 source = AuthSource.create!(:name => 'Test')
56 User.find(2).update_attribute :auth_source_id, source.id
57 AuthSource.any_instance.stubs(:authenticate).raises(AuthSourceException.new("Something wrong"))
58
59 post :login, :username => 'jsmith', :password => 'jsmith'
60 assert_response 500
61 assert_error_tag :content => /Something wrong/
62 end
63
54 if Object.const_defined?(:OpenID)
64 if Object.const_defined?(:OpenID)
55
65
56 def test_login_with_openid_for_existing_user
66 def test_login_with_openid_for_existing_user
57 Setting.self_registration = '3'
67 Setting.self_registration = '3'
58 Setting.openid = '1'
68 Setting.openid = '1'
59 existing_user = User.new(:firstname => 'Cool',
69 existing_user = User.new(:firstname => 'Cool',
60 :lastname => 'User',
70 :lastname => 'User',
61 :mail => 'user@somedomain.com',
71 :mail => 'user@somedomain.com',
62 :identity_url => 'http://openid.example.com/good_user')
72 :identity_url => 'http://openid.example.com/good_user')
63 existing_user.login = 'cool_user'
73 existing_user.login = 'cool_user'
64 assert existing_user.save!
74 assert existing_user.save!
65
75
66 post :login, :openid_url => existing_user.identity_url
76 post :login, :openid_url => existing_user.identity_url
67 assert_redirected_to '/my/page'
77 assert_redirected_to '/my/page'
68 end
78 end
69
79
70 def test_login_with_invalid_openid_provider
80 def test_login_with_invalid_openid_provider
71 Setting.self_registration = '0'
81 Setting.self_registration = '0'
72 Setting.openid = '1'
82 Setting.openid = '1'
73 post :login, :openid_url => 'http;//openid.example.com/good_user'
83 post :login, :openid_url => 'http;//openid.example.com/good_user'
74 assert_redirected_to home_url
84 assert_redirected_to home_url
75 end
85 end
76
86
77 def test_login_with_openid_for_existing_non_active_user
87 def test_login_with_openid_for_existing_non_active_user
78 Setting.self_registration = '2'
88 Setting.self_registration = '2'
79 Setting.openid = '1'
89 Setting.openid = '1'
80 existing_user = User.new(:firstname => 'Cool',
90 existing_user = User.new(:firstname => 'Cool',
81 :lastname => 'User',
91 :lastname => 'User',
82 :mail => 'user@somedomain.com',
92 :mail => 'user@somedomain.com',
83 :identity_url => 'http://openid.example.com/good_user',
93 :identity_url => 'http://openid.example.com/good_user',
84 :status => User::STATUS_REGISTERED)
94 :status => User::STATUS_REGISTERED)
85 existing_user.login = 'cool_user'
95 existing_user.login = 'cool_user'
86 assert existing_user.save!
96 assert existing_user.save!
87
97
88 post :login, :openid_url => existing_user.identity_url
98 post :login, :openid_url => existing_user.identity_url
89 assert_redirected_to '/login'
99 assert_redirected_to '/login'
90 end
100 end
91
101
92 def test_login_with_openid_with_new_user_created
102 def test_login_with_openid_with_new_user_created
93 Setting.self_registration = '3'
103 Setting.self_registration = '3'
94 Setting.openid = '1'
104 Setting.openid = '1'
95 post :login, :openid_url => 'http://openid.example.com/good_user'
105 post :login, :openid_url => 'http://openid.example.com/good_user'
96 assert_redirected_to '/my/account'
106 assert_redirected_to '/my/account'
97 user = User.find_by_login('cool_user')
107 user = User.find_by_login('cool_user')
98 assert user
108 assert user
99 assert_equal 'Cool', user.firstname
109 assert_equal 'Cool', user.firstname
100 assert_equal 'User', user.lastname
110 assert_equal 'User', user.lastname
101 end
111 end
102
112
103 def test_login_with_openid_with_new_user_and_self_registration_off
113 def test_login_with_openid_with_new_user_and_self_registration_off
104 Setting.self_registration = '0'
114 Setting.self_registration = '0'
105 Setting.openid = '1'
115 Setting.openid = '1'
106 post :login, :openid_url => 'http://openid.example.com/good_user'
116 post :login, :openid_url => 'http://openid.example.com/good_user'
107 assert_redirected_to home_url
117 assert_redirected_to home_url
108 user = User.find_by_login('cool_user')
118 user = User.find_by_login('cool_user')
109 assert ! user
119 assert ! user
110 end
120 end
111
121
112 def test_login_with_openid_with_new_user_created_with_email_activation_should_have_a_token
122 def test_login_with_openid_with_new_user_created_with_email_activation_should_have_a_token
113 Setting.self_registration = '1'
123 Setting.self_registration = '1'
114 Setting.openid = '1'
124 Setting.openid = '1'
115 post :login, :openid_url => 'http://openid.example.com/good_user'
125 post :login, :openid_url => 'http://openid.example.com/good_user'
116 assert_redirected_to '/login'
126 assert_redirected_to '/login'
117 user = User.find_by_login('cool_user')
127 user = User.find_by_login('cool_user')
118 assert user
128 assert user
119
129
120 token = Token.find_by_user_id_and_action(user.id, 'register')
130 token = Token.find_by_user_id_and_action(user.id, 'register')
121 assert token
131 assert token
122 end
132 end
123
133
124 def test_login_with_openid_with_new_user_created_with_manual_activation
134 def test_login_with_openid_with_new_user_created_with_manual_activation
125 Setting.self_registration = '2'
135 Setting.self_registration = '2'
126 Setting.openid = '1'
136 Setting.openid = '1'
127 post :login, :openid_url => 'http://openid.example.com/good_user'
137 post :login, :openid_url => 'http://openid.example.com/good_user'
128 assert_redirected_to '/login'
138 assert_redirected_to '/login'
129 user = User.find_by_login('cool_user')
139 user = User.find_by_login('cool_user')
130 assert user
140 assert user
131 assert_equal User::STATUS_REGISTERED, user.status
141 assert_equal User::STATUS_REGISTERED, user.status
132 end
142 end
133
143
134 def test_login_with_openid_with_new_user_with_conflict_should_register
144 def test_login_with_openid_with_new_user_with_conflict_should_register
135 Setting.self_registration = '3'
145 Setting.self_registration = '3'
136 Setting.openid = '1'
146 Setting.openid = '1'
137 existing_user = User.new(:firstname => 'Cool', :lastname => 'User', :mail => 'user@somedomain.com')
147 existing_user = User.new(:firstname => 'Cool', :lastname => 'User', :mail => 'user@somedomain.com')
138 existing_user.login = 'cool_user'
148 existing_user.login = 'cool_user'
139 assert existing_user.save!
149 assert existing_user.save!
140
150
141 post :login, :openid_url => 'http://openid.example.com/good_user'
151 post :login, :openid_url => 'http://openid.example.com/good_user'
142 assert_response :success
152 assert_response :success
143 assert_template 'register'
153 assert_template 'register'
144 assert assigns(:user)
154 assert assigns(:user)
145 assert_equal 'http://openid.example.com/good_user', assigns(:user)[:identity_url]
155 assert_equal 'http://openid.example.com/good_user', assigns(:user)[:identity_url]
146 end
156 end
147
157
148 def test_setting_openid_should_return_true_when_set_to_true
158 def test_setting_openid_should_return_true_when_set_to_true
149 Setting.openid = '1'
159 Setting.openid = '1'
150 assert_equal true, Setting.openid?
160 assert_equal true, Setting.openid?
151 end
161 end
152
162
153 else
163 else
154 puts "Skipping openid tests."
164 puts "Skipping openid tests."
155 end
165 end
156
166
157 def test_logout
167 def test_logout
158 @request.session[:user_id] = 2
168 @request.session[:user_id] = 2
159 get :logout
169 get :logout
160 assert_redirected_to '/'
170 assert_redirected_to '/'
161 assert_nil @request.session[:user_id]
171 assert_nil @request.session[:user_id]
162 end
172 end
163
173
164 def test_get_register_with_registration_on
174 def test_get_register_with_registration_on
165 with_settings :self_registration => '3' do
175 with_settings :self_registration => '3' do
166 get :register
176 get :register
167 assert_response :success
177 assert_response :success
168 assert_template 'register'
178 assert_template 'register'
169 assert_not_nil assigns(:user)
179 assert_not_nil assigns(:user)
170
180
171 assert_tag 'input', :attributes => {:name => 'user[password]'}
181 assert_tag 'input', :attributes => {:name => 'user[password]'}
172 assert_tag 'input', :attributes => {:name => 'user[password_confirmation]'}
182 assert_tag 'input', :attributes => {:name => 'user[password_confirmation]'}
173 end
183 end
174 end
184 end
175
185
176 def test_get_register_with_registration_off_should_redirect
186 def test_get_register_with_registration_off_should_redirect
177 with_settings :self_registration => '0' do
187 with_settings :self_registration => '0' do
178 get :register
188 get :register
179 assert_redirected_to '/'
189 assert_redirected_to '/'
180 end
190 end
181 end
191 end
182
192
183 # See integration/account_test.rb for the full test
193 # See integration/account_test.rb for the full test
184 def test_post_register_with_registration_on
194 def test_post_register_with_registration_on
185 with_settings :self_registration => '3' do
195 with_settings :self_registration => '3' do
186 assert_difference 'User.count' do
196 assert_difference 'User.count' do
187 post :register, :user => {
197 post :register, :user => {
188 :login => 'register',
198 :login => 'register',
189 :password => 'test',
199 :password => 'test',
190 :password_confirmation => 'test',
200 :password_confirmation => 'test',
191 :firstname => 'John',
201 :firstname => 'John',
192 :lastname => 'Doe',
202 :lastname => 'Doe',
193 :mail => 'register@example.com'
203 :mail => 'register@example.com'
194 }
204 }
195 assert_redirected_to '/my/account'
205 assert_redirected_to '/my/account'
196 end
206 end
197 user = User.first(:order => 'id DESC')
207 user = User.first(:order => 'id DESC')
198 assert_equal 'register', user.login
208 assert_equal 'register', user.login
199 assert_equal 'John', user.firstname
209 assert_equal 'John', user.firstname
200 assert_equal 'Doe', user.lastname
210 assert_equal 'Doe', user.lastname
201 assert_equal 'register@example.com', user.mail
211 assert_equal 'register@example.com', user.mail
202 assert user.check_password?('test')
212 assert user.check_password?('test')
203 assert user.active?
213 assert user.active?
204 end
214 end
205 end
215 end
206
216
207 def test_post_register_with_registration_off_should_redirect
217 def test_post_register_with_registration_off_should_redirect
208 with_settings :self_registration => '0' do
218 with_settings :self_registration => '0' do
209 assert_no_difference 'User.count' do
219 assert_no_difference 'User.count' do
210 post :register, :user => {
220 post :register, :user => {
211 :login => 'register',
221 :login => 'register',
212 :password => 'test',
222 :password => 'test',
213 :password_confirmation => 'test',
223 :password_confirmation => 'test',
214 :firstname => 'John',
224 :firstname => 'John',
215 :lastname => 'Doe',
225 :lastname => 'Doe',
216 :mail => 'register@example.com'
226 :mail => 'register@example.com'
217 }
227 }
218 assert_redirected_to '/'
228 assert_redirected_to '/'
219 end
229 end
220 end
230 end
221 end
231 end
222 end
232 end
General Comments 0
You need to be logged in to leave comments. Login now