##// END OF EJS Templates
Improved on-the-fly account creation. If some attributes are missing (eg. not present in the LDAP) or are invalid, the registration form is displayed so that the user is able to fill or fix these attributes....
Jean-Philippe Lang -
r1661:eb1d969237a9
parent child
Show More
@@ -1,173 +1,191
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 class AccountController < ApplicationController
19 19 layout 'base'
20 20 helper :custom_fields
21 21 include CustomFieldsHelper
22 22
23 23 # prevents login action to be filtered by check_if_login_required application scope filter
24 24 skip_before_filter :check_if_login_required, :only => [:login, :lost_password, :register, :activate]
25 25
26 26 # Show user's account
27 27 def show
28 28 @user = User.find_active(params[:id])
29 29 @custom_values = @user.custom_values.find(:all, :include => :custom_field)
30 30
31 31 # show only public projects and private projects that the logged in user is also a member of
32 32 @memberships = @user.memberships.select do |membership|
33 33 membership.project.is_public? || (User.current.member_of?(membership.project))
34 34 end
35 35 rescue ActiveRecord::RecordNotFound
36 36 render_404
37 37 end
38 38
39 39 # Login request and validation
40 40 def login
41 41 if request.get?
42 42 # Logout user
43 43 self.logged_user = nil
44 44 else
45 45 # Authenticate user
46 46 user = User.try_to_login(params[:username], params[:password])
47 if user
47 if user.nil?
48 # Invalid credentials
49 flash.now[:error] = l(:notice_account_invalid_creditentials)
50 elsif user.new_record?
51 # Onthefly creation failed, display the registration form to fill/fix attributes
52 @user = user
53 session[:auth_source_registration] = {:login => user.login, :auth_source_id => user.auth_source_id }
54 render :action => 'register'
55 else
56 # Valid user
48 57 self.logged_user = user
49 58 # generate a key and set cookie if autologin
50 59 if params[:autologin] && Setting.autologin?
51 60 token = Token.create(:user => user, :action => 'autologin')
52 61 cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now }
53 62 end
54 63 redirect_back_or_default :controller => 'my', :action => 'page'
55 else
56 flash.now[:error] = l(:notice_account_invalid_creditentials)
57 64 end
58 65 end
59 rescue User::OnTheFlyCreationFailure
60 flash.now[:error] = 'Redmine could not retrieve the required information from the LDAP to create your account. Please, contact your Redmine administrator.'
61 66 end
62 67
63 68 # Log out current user and redirect to welcome page
64 69 def logout
65 70 cookies.delete :autologin
66 71 Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) if User.current.logged?
67 72 self.logged_user = nil
68 73 redirect_to home_url
69 74 end
70 75
71 76 # Enable user to choose a new password
72 77 def lost_password
73 78 redirect_to(home_url) && return unless Setting.lost_password?
74 79 if params[:token]
75 80 @token = Token.find_by_action_and_value("recovery", params[:token])
76 81 redirect_to(home_url) && return unless @token and !@token.expired?
77 82 @user = @token.user
78 83 if request.post?
79 84 @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
80 85 if @user.save
81 86 @token.destroy
82 87 flash[:notice] = l(:notice_account_password_updated)
83 88 redirect_to :action => 'login'
84 89 return
85 90 end
86 91 end
87 92 render :template => "account/password_recovery"
88 93 return
89 94 else
90 95 if request.post?
91 96 user = User.find_by_mail(params[:mail])
92 97 # user not found in db
93 98 flash.now[:error] = l(:notice_account_unknown_email) and return unless user
94 99 # user uses an external authentification
95 100 flash.now[:error] = l(:notice_can_t_change_password) and return if user.auth_source_id
96 101 # create a new token for password recovery
97 102 token = Token.new(:user => user, :action => "recovery")
98 103 if token.save
99 104 Mailer.deliver_lost_password(token)
100 105 flash[:notice] = l(:notice_account_lost_email_sent)
101 106 redirect_to :action => 'login'
102 107 return
103 108 end
104 109 end
105 110 end
106 111 end
107 112
108 113 # User self-registration
109 114 def register
110 redirect_to(home_url) && return unless Setting.self_registration?
115 redirect_to(home_url) && return unless Setting.self_registration? || session[:auth_source_registration]
111 116 if request.get?
117 session[:auth_source_registration] = nil
112 118 @user = User.new(:language => Setting.default_language)
113 119 else
114 120 @user = User.new(params[:user])
115 121 @user.admin = false
116 @user.login = params[:user][:login]
117 122 @user.status = User::STATUS_REGISTERED
118 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
119 case Setting.self_registration
120 when '1'
121 # Email activation
122 token = Token.new(:user => @user, :action => "register")
123 if @user.save and token.save
124 Mailer.deliver_register(token)
125 flash[:notice] = l(:notice_account_register_done)
126 redirect_to :action => 'login'
127 end
128 when '3'
129 # Automatic activation
123 if session[:auth_source_registration]
130 124 @user.status = User::STATUS_ACTIVE
125 @user.login = session[:auth_source_registration][:login]
126 @user.auth_source_id = session[:auth_source_registration][:auth_source_id]
131 127 if @user.save
128 session[:auth_source_registration] = nil
132 129 self.logged_user = @user
133 130 flash[:notice] = l(:notice_account_activated)
134 131 redirect_to :controller => 'my', :action => 'account'
135 132 end
136 133 else
137 # Manual activation by the administrator
138 if @user.save
139 # Sends an email to the administrators
140 Mailer.deliver_account_activation_request(@user)
141 flash[:notice] = l(:notice_account_pending)
142 redirect_to :action => 'login'
134 @user.login = params[:user][:login]
135 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
136 case Setting.self_registration
137 when '1'
138 # Email activation
139 token = Token.new(:user => @user, :action => "register")
140 if @user.save and token.save
141 Mailer.deliver_register(token)
142 flash[:notice] = l(:notice_account_register_done)
143 redirect_to :action => 'login'
144 end
145 when '3'
146 # Automatic activation
147 @user.status = User::STATUS_ACTIVE
148 if @user.save
149 self.logged_user = @user
150 flash[:notice] = l(:notice_account_activated)
151 redirect_to :controller => 'my', :action => 'account'
152 end
153 else
154 # Manual activation by the administrator
155 if @user.save
156 # Sends an email to the administrators
157 Mailer.deliver_account_activation_request(@user)
158 flash[:notice] = l(:notice_account_pending)
159 redirect_to :action => 'login'
160 end
143 161 end
144 162 end
145 163 end
146 164 end
147 165
148 166 # Token based account activation
149 167 def activate
150 168 redirect_to(home_url) && return unless Setting.self_registration? && params[:token]
151 169 token = Token.find_by_action_and_value('register', params[:token])
152 170 redirect_to(home_url) && return unless token and !token.expired?
153 171 user = token.user
154 172 redirect_to(home_url) && return unless user.status == User::STATUS_REGISTERED
155 173 user.status = User::STATUS_ACTIVE
156 174 if user.save
157 175 token.destroy
158 176 flash[:notice] = l(:notice_account_activated)
159 177 end
160 178 redirect_to :action => 'login'
161 179 end
162 180
163 181 private
164 182 def logged_user=(user)
165 183 if user && user.is_a?(User)
166 184 User.current = user
167 185 session[:user_id] = user.id
168 186 else
169 187 User.current = User.anonymous
170 188 session[:user_id] = nil
171 189 end
172 190 end
173 191 end
@@ -1,51 +1,48
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 class AuthSource < ActiveRecord::Base
19 19 has_many :users
20 20
21 21 validates_presence_of :name
22 22 validates_uniqueness_of :name
23 validates_length_of :name, :host, :maximum => 60
24 validates_length_of :account_password, :maximum => 60, :allow_nil => true
25 validates_length_of :account, :base_dn, :maximum => 255
26 validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30
23 validates_length_of :name, :maximum => 60
27 24
28 25 def authenticate(login, password)
29 26 end
30 27
31 28 def test_connection
32 29 end
33 30
34 31 def auth_method_name
35 32 "Abstract"
36 33 end
37 34
38 35 # Try to authenticate a user not yet registered against available sources
39 36 def self.authenticate(login, password)
40 37 AuthSource.find(:all, :conditions => ["onthefly_register=?", true]).each do |source|
41 38 begin
42 39 logger.debug "Authenticating '#{login}' against '#{source.name}'" if logger && logger.debug?
43 40 attrs = source.authenticate(login, password)
44 41 rescue
45 42 attrs = nil
46 43 end
47 44 return attrs if attrs
48 45 end
49 46 return nil
50 47 end
51 48 end
@@ -1,84 +1,87
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 validates_presence_of :attr_firstname, :attr_lastname, :attr_mail, :if => Proc.new { |a| a.onthefly_register? }
23 validates_length_of :name, :host, :account_password, :maximum => 60, :allow_nil => true
24 validates_length_of :account, :base_dn, :maximum => 255, :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
24 27
25 28 def after_initialize
26 29 self.port = 389 if self.port == 0
27 30 end
28 31
29 32 def authenticate(login, password)
30 33 return nil if login.blank? || password.blank?
31 34 attrs = []
32 35 # get user's DN
33 36 ldap_con = initialize_ldap_con(self.account, self.account_password)
34 37 login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
35 38 object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
36 39 dn = String.new
37 40 ldap_con.search( :base => self.base_dn,
38 41 :filter => object_filter & login_filter,
39 42 # only ask for the DN if on-the-fly registration is disabled
40 43 :attributes=> (onthefly_register? ? ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail] : ['dn'])) do |entry|
41 44 dn = entry.dn
42 45 attrs = [:firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
43 46 :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
44 47 :mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
45 48 :auth_source_id => self.id ] if onthefly_register?
46 49 end
47 50 return nil if dn.empty?
48 51 logger.debug "DN found for #{login}: #{dn}" if logger && logger.debug?
49 52 # authenticate user
50 53 ldap_con = initialize_ldap_con(dn, password)
51 54 return nil unless ldap_con.bind
52 55 # return user's attributes
53 56 logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
54 57 attrs
55 58 rescue Net::LDAP::LdapError => text
56 59 raise "LdapError: " + text
57 60 end
58 61
59 62 # test the connection to the LDAP
60 63 def test_connection
61 64 ldap_con = initialize_ldap_con(self.account, self.account_password)
62 65 ldap_con.open { }
63 66 rescue Net::LDAP::LdapError => text
64 67 raise "LdapError: " + text
65 68 end
66 69
67 70 def auth_method_name
68 71 "LDAP"
69 72 end
70 73
71 74 private
72 75 def initialize_ldap_con(ldap_user, ldap_password)
73 76 options = { :host => self.host,
74 77 :port => self.port,
75 78 :encryption => (self.tls ? :simple_tls : nil)
76 79 }
77 80 options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank?
78 81 Net::LDAP.new options
79 82 end
80 83
81 84 def self.get_attr(entry, attr_name)
82 85 entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
83 86 end
84 87 end
@@ -1,298 +1,295
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 "digest/sha1"
19 19
20 20 class User < ActiveRecord::Base
21 21
22 22 class OnTheFlyCreationFailure < Exception; end
23 23
24 24 # Account statuses
25 25 STATUS_ANONYMOUS = 0
26 26 STATUS_ACTIVE = 1
27 27 STATUS_REGISTERED = 2
28 28 STATUS_LOCKED = 3
29 29
30 30 USER_FORMATS = {
31 31 :firstname_lastname => '#{firstname} #{lastname}',
32 32 :firstname => '#{firstname}',
33 33 :lastname_firstname => '#{lastname} #{firstname}',
34 34 :lastname_coma_firstname => '#{lastname}, #{firstname}',
35 35 :username => '#{login}'
36 36 }
37 37
38 38 has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :conditions => "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}", :order => "#{Project.table_name}.name", :dependent => :delete_all
39 39 has_many :projects, :through => :memberships
40 40 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
41 41 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
42 42 has_one :rss_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='feeds'"
43 43 belongs_to :auth_source
44 44
45 45 acts_as_customizable
46 46
47 47 attr_accessor :password, :password_confirmation
48 48 attr_accessor :last_before_login_on
49 49 # Prevents unauthorized assignments
50 50 attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
51 51
52 52 validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
53 53 validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }
54 54 validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }
55 55 # Login must contain lettres, numbers, underscores only
56 56 validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
57 57 validates_length_of :login, :maximum => 30
58 58 validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-\.]*$/i
59 59 validates_length_of :firstname, :lastname, :maximum => 30
60 60 validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true
61 61 validates_length_of :mail, :maximum => 60, :allow_nil => true
62 62 validates_length_of :password, :minimum => 4, :allow_nil => true
63 63 validates_confirmation_of :password, :allow_nil => true
64 64
65 65 def before_create
66 66 self.mail_notification = false
67 67 true
68 68 end
69 69
70 70 def before_save
71 71 # update hashed_password if password was set
72 72 self.hashed_password = User.hash_password(self.password) if self.password
73 73 end
74 74
75 75 def self.active
76 76 with_scope :find => { :conditions => [ "status = ?", STATUS_ACTIVE ] } do
77 77 yield
78 78 end
79 79 end
80 80
81 81 def self.find_active(*args)
82 82 active do
83 83 find(*args)
84 84 end
85 85 end
86 86
87 87 # Returns the user that matches provided login and password, or nil
88 88 def self.try_to_login(login, password)
89 89 # Make sure no one can sign in with an empty password
90 90 return nil if password.to_s.empty?
91 91 user = find(:first, :conditions => ["login=?", login])
92 92 if user
93 93 # user is already in local database
94 94 return nil if !user.active?
95 95 if user.auth_source
96 96 # user has an external authentication method
97 97 return nil unless user.auth_source.authenticate(login, password)
98 98 else
99 99 # authentication with local password
100 100 return nil unless User.hash_password(password) == user.hashed_password
101 101 end
102 102 else
103 103 # user is not yet registered, try to authenticate with available sources
104 104 attrs = AuthSource.authenticate(login, password)
105 105 if attrs
106 onthefly = new(*attrs)
107 onthefly.login = login
108 onthefly.language = Setting.default_language
109 if onthefly.save
110 user = find(:first, :conditions => ["login=?", login])
106 user = new(*attrs)
107 user.login = login
108 user.language = Setting.default_language
109 if user.save
110 user.reload
111 111 logger.info("User '#{user.login}' created from the LDAP") if logger
112 else
113 logger.error("User '#{onthefly.login}' found in LDAP but could not be created (#{onthefly.errors.full_messages.join(', ')})") if logger
114 raise OnTheFlyCreationFailure.new
115 112 end
116 113 end
117 114 end
118 user.update_attribute(:last_login_on, Time.now) if user
115 user.update_attribute(:last_login_on, Time.now) if user && !user.new_record?
119 116 user
120 117 rescue => text
121 118 raise text
122 119 end
123 120
124 121 # Return user's full name for display
125 122 def name(formatter = nil)
126 123 f = USER_FORMATS[formatter || Setting.user_format] || USER_FORMATS[:firstname_lastname]
127 124 eval '"' + f + '"'
128 125 end
129 126
130 127 def active?
131 128 self.status == STATUS_ACTIVE
132 129 end
133 130
134 131 def registered?
135 132 self.status == STATUS_REGISTERED
136 133 end
137 134
138 135 def locked?
139 136 self.status == STATUS_LOCKED
140 137 end
141 138
142 139 def check_password?(clear_password)
143 140 User.hash_password(clear_password) == self.hashed_password
144 141 end
145 142
146 143 def pref
147 144 self.preference ||= UserPreference.new(:user => self)
148 145 end
149 146
150 147 def time_zone
151 148 self.pref.time_zone.nil? ? nil : TimeZone[self.pref.time_zone]
152 149 end
153 150
154 151 def wants_comments_in_reverse_order?
155 152 self.pref[:comments_sorting] == 'desc'
156 153 end
157 154
158 155 # Return user's RSS key (a 40 chars long string), used to access feeds
159 156 def rss_key
160 157 token = self.rss_token || Token.create(:user => self, :action => 'feeds')
161 158 token.value
162 159 end
163 160
164 161 # Return an array of project ids for which the user has explicitly turned mail notifications on
165 162 def notified_projects_ids
166 163 @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
167 164 end
168 165
169 166 def notified_project_ids=(ids)
170 167 Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
171 168 Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
172 169 @notified_projects_ids = nil
173 170 notified_projects_ids
174 171 end
175 172
176 173 def self.find_by_rss_key(key)
177 174 token = Token.find_by_value(key)
178 175 token && token.user.active? ? token.user : nil
179 176 end
180 177
181 178 def self.find_by_autologin_key(key)
182 179 token = Token.find_by_action_and_value('autologin', key)
183 180 token && (token.created_on > Setting.autologin.to_i.day.ago) && token.user.active? ? token.user : nil
184 181 end
185 182
186 183 def <=>(user)
187 184 if user.nil?
188 185 -1
189 186 elsif lastname.to_s.downcase == user.lastname.to_s.downcase
190 187 firstname.to_s.downcase <=> user.firstname.to_s.downcase
191 188 else
192 189 lastname.to_s.downcase <=> user.lastname.to_s.downcase
193 190 end
194 191 end
195 192
196 193 def to_s
197 194 name
198 195 end
199 196
200 197 def logged?
201 198 true
202 199 end
203 200
204 201 def anonymous?
205 202 !logged?
206 203 end
207 204
208 205 # Return user's role for project
209 206 def role_for_project(project)
210 207 # No role on archived projects
211 208 return nil unless project && project.active?
212 209 if logged?
213 210 # Find project membership
214 211 membership = memberships.detect {|m| m.project_id == project.id}
215 212 if membership
216 213 membership.role
217 214 else
218 215 @role_non_member ||= Role.non_member
219 216 end
220 217 else
221 218 @role_anonymous ||= Role.anonymous
222 219 end
223 220 end
224 221
225 222 # Return true if the user is a member of project
226 223 def member_of?(project)
227 224 role_for_project(project).member?
228 225 end
229 226
230 227 # Return true if the user is allowed to do the specified action on project
231 228 # action can be:
232 229 # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
233 230 # * a permission Symbol (eg. :edit_project)
234 231 def allowed_to?(action, project, options={})
235 232 if project
236 233 # No action allowed on archived projects
237 234 return false unless project.active?
238 235 # No action allowed on disabled modules
239 236 return false unless project.allows_to?(action)
240 237 # Admin users are authorized for anything else
241 238 return true if admin?
242 239
243 240 role = role_for_project(project)
244 241 return false unless role
245 242 role.allowed_to?(action) && (project.is_public? || role.member?)
246 243
247 244 elsif options[:global]
248 245 # authorize if user has at least one role that has this permission
249 246 roles = memberships.collect {|m| m.role}.uniq
250 247 roles.detect {|r| r.allowed_to?(action)}
251 248 else
252 249 false
253 250 end
254 251 end
255 252
256 253 def self.current=(user)
257 254 @current_user = user
258 255 end
259 256
260 257 def self.current
261 258 @current_user ||= User.anonymous
262 259 end
263 260
264 261 def self.anonymous
265 262 anonymous_user = AnonymousUser.find(:first)
266 263 if anonymous_user.nil?
267 264 anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
268 265 raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
269 266 end
270 267 anonymous_user
271 268 end
272 269
273 270 private
274 271 # Return password digest
275 272 def self.hash_password(clear_password)
276 273 Digest::SHA1.hexdigest(clear_password || "")
277 274 end
278 275 end
279 276
280 277 class AnonymousUser < User
281 278
282 279 def validate_on_create
283 280 # There should be only one AnonymousUser in the database
284 281 errors.add_to_base 'An anonymous user already exists.' if AnonymousUser.find(:first)
285 282 end
286 283
287 284 def available_custom_fields
288 285 []
289 286 end
290 287
291 288 # Overrides a few properties
292 289 def logged?; false end
293 290 def admin; false end
294 291 def name; 'Anonymous' end
295 292 def mail; nil end
296 293 def time_zone; nil end
297 294 def rss_key; nil end
298 295 end
@@ -1,37 +1,39
1 1 <h2><%=l(:label_register)%></h2>
2 2
3 3 <% form_tag({:action => 'register'}, :class => "tabular") do %>
4 4 <%= error_messages_for 'user' %>
5 5
6 6 <div class="box">
7 7 <!--[form:user]-->
8 <% if @user.auth_source_id.nil? %>
8 9 <p><label for="user_login"><%=l(:field_login)%> <span class="required">*</span></label>
9 <%= text_field 'user', 'login', :size => 25 %></p>
10 <%= text_field 'user', 'login', :size => 25 %></p>
10 11
11 12 <p><label for="password"><%=l(:field_password)%> <span class="required">*</span></label>
12 13 <%= password_field_tag 'password', nil, :size => 25 %><br />
13 14 <em><%= l(:text_caracters_minimum, 4) %></em></p>
14 15
15 16 <p><label for="password_confirmation"><%=l(:field_password_confirmation)%> <span class="required">*</span></label>
16 17 <%= password_field_tag 'password_confirmation', nil, :size => 25 %></p>
18 <% end %>
17 19
18 20 <p><label for="user_firstname"><%=l(:field_firstname)%> <span class="required">*</span></label>
19 21 <%= text_field 'user', 'firstname' %></p>
20 22
21 23 <p><label for="user_lastname"><%=l(:field_lastname)%> <span class="required">*</span></label>
22 24 <%= text_field 'user', 'lastname' %></p>
23 25
24 26 <p><label for="user_mail"><%=l(:field_mail)%> <span class="required">*</span></label>
25 27 <%= text_field 'user', 'mail' %></p>
26 28
27 29 <p><label for="user_language"><%=l(:field_language)%></label>
28 30 <%= select("user", "language", lang_options_for_select) %></p>
29 31
30 32 <% @user.custom_field_values.each do |value| %>
31 33 <p><%= custom_field_tag_with_label :user, value %></p>
32 34 <% end %>
33 35 <!--[eoform:user]-->
34 36 </div>
35 37
36 38 <%= submit_tag l(:button_submit) %>
37 39 <% end %>
@@ -1,48 +1,44
1 1 <%= error_messages_for 'auth_source' %>
2 2
3 3 <div class="box">
4 4 <!--[form:auth_source]-->
5 5 <p><label for="auth_source_name"><%=l(:field_name)%> <span class="required">*</span></label>
6 6 <%= text_field 'auth_source', 'name' %></p>
7 7
8 8 <p><label for="auth_source_host"><%=l(:field_host)%> <span class="required">*</span></label>
9 9 <%= text_field 'auth_source', 'host' %></p>
10 10
11 11 <p><label for="auth_source_port"><%=l(:field_port)%> <span class="required">*</span></label>
12 12 <%= text_field 'auth_source', 'port', :size => 6 %> <%= check_box 'auth_source', 'tls' %> LDAPS</p>
13 13
14 14 <p><label for="auth_source_account"><%=l(:field_account)%></label>
15 15 <%= text_field 'auth_source', 'account' %></p>
16 16
17 17 <p><label for="auth_source_account_password"><%=l(:field_password)%></label>
18 18 <%= password_field 'auth_source', 'account_password', :name => 'ignore',
19 19 :value => ((@auth_source.new_record? || @auth_source.account_password.blank?) ? '' : ('x'*15)),
20 20 :onfocus => "this.value=''; this.name='auth_source[account_password]';",
21 21 :onchange => "this.name='auth_source[account_password]';" %></p>
22 22
23 23 <p><label for="auth_source_base_dn"><%=l(:field_base_dn)%> <span class="required">*</span></label>
24 24 <%= text_field 'auth_source', 'base_dn', :size => 60 %></p>
25 </div>
26 25
27 <div class="box">
28 26 <p><label for="auth_source_onthefly_register"><%=l(:field_onthefly)%></label>
29 27 <%= check_box 'auth_source', 'onthefly_register' %></p>
28 </div>
30 29
31 <p>
32 <fieldset><legend><%=l(:label_attribute_plural)%></legend>
30 <fieldset class="box"><legend><%=l(:label_attribute_plural)%></legend>
33 31 <p><label for="auth_source_attr_login"><%=l(:field_login)%> <span class="required">*</span></label>
34 32 <%= text_field 'auth_source', 'attr_login', :size => 20 %></p>
35 33
36 34 <p><label for="auth_source_attr_firstname"><%=l(:field_firstname)%></label>
37 35 <%= text_field 'auth_source', 'attr_firstname', :size => 20 %></p>
38 36
39 37 <p><label for="auth_source_attr_lastname"><%=l(:field_lastname)%></label>
40 38 <%= text_field 'auth_source', 'attr_lastname', :size => 20 %></p>
41 39
42 40 <p><label for="auth_source_attr_mail"><%=l(:field_mail)%></label>
43 41 <%= text_field 'auth_source', 'attr_mail', :size => 20 %></p>
44 42 </fieldset>
45 </p>
46 </div>
47 43 <!--[eoform:auth_source]-->
48 44
@@ -1,105 +1,153
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 begin
21 require 'mocha'
22 rescue
23 # Won't run some tests
24 end
25
20 26 class AccountTest < ActionController::IntegrationTest
21 27 fixtures :users
22 28
23 29 # Replace this with your real tests.
24 30 def test_login
25 31 get "my/page"
26 32 assert_redirected_to "account/login"
27 33 log_user('jsmith', 'jsmith')
28 34
29 35 get "my/account"
30 36 assert_response :success
31 37 assert_template "my/account"
32 38 end
33 39
34 40 def test_lost_password
35 41 Token.delete_all
36 42
37 43 get "account/lost_password"
38 44 assert_response :success
39 45 assert_template "account/lost_password"
40 46
41 47 post "account/lost_password", :mail => 'jsmith@somenet.foo'
42 48 assert_redirected_to "account/login"
43 49
44 50 token = Token.find(:first)
45 51 assert_equal 'recovery', token.action
46 52 assert_equal 'jsmith@somenet.foo', token.user.mail
47 53 assert !token.expired?
48 54
49 55 get "account/lost_password", :token => token.value
50 56 assert_response :success
51 57 assert_template "account/password_recovery"
52 58
53 59 post "account/lost_password", :token => token.value, :new_password => 'newpass', :new_password_confirmation => 'newpass'
54 60 assert_redirected_to "account/login"
55 61 assert_equal 'Password was successfully updated.', flash[:notice]
56 62
57 63 log_user('jsmith', 'newpass')
58 64 assert_equal 0, Token.count
59 65 end
60 66
61 67 def test_register_with_automatic_activation
62 68 Setting.self_registration = '3'
63 69
64 70 get 'account/register'
65 71 assert_response :success
66 72 assert_template 'account/register'
67 73
68 74 post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"},
69 75 :password => "newpass", :password_confirmation => "newpass"
70 76 assert_redirected_to 'my/account'
71 77 follow_redirect!
72 78 assert_response :success
73 79 assert_template 'my/account'
74 80
75 81 assert User.find_by_login('newuser').active?
76 82 end
77 83
78 84 def test_register_with_manual_activation
79 85 Setting.self_registration = '2'
80 86
81 87 post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"},
82 88 :password => "newpass", :password_confirmation => "newpass"
83 89 assert_redirected_to 'account/login'
84 90 assert !User.find_by_login('newuser').active?
85 91 end
86 92
87 93 def test_register_with_email_activation
88 94 Setting.self_registration = '1'
89 95 Token.delete_all
90 96
91 97 post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"},
92 98 :password => "newpass", :password_confirmation => "newpass"
93 99 assert_redirected_to 'account/login'
94 100 assert !User.find_by_login('newuser').active?
95 101
96 102 token = Token.find(:first)
97 103 assert_equal 'register', token.action
98 104 assert_equal 'newuser@foo.bar', token.user.mail
99 105 assert !token.expired?
100 106
101 107 get 'account/activate', :token => token.value
102 108 assert_redirected_to 'account/login'
103 109 log_user('newuser', 'newpass')
104 110 end
111
112 if Object.const_defined?(:Mocha)
113
114 def test_onthefly_registration
115 # disable registration
116 Setting.self_registration = '0'
117 AuthSource.expects(:authenticate).returns([:login => 'foo', :firstname => 'Foo', :lastname => 'Smith', :mail => 'foo@bar.com', :auth_source_id => 66])
118
119 post 'account/login', :username => 'foo', :password => 'bar'
120 assert_redirected_to 'my/page'
121
122 user = User.find_by_login('foo')
123 assert user.is_a?(User)
124 assert_equal 66, user.auth_source_id
125 assert user.hashed_password.blank?
126 end
127
128 def test_onthefly_registration_with_invalid_attributes
129 # disable registration
130 Setting.self_registration = '0'
131 AuthSource.expects(:authenticate).returns([:login => 'foo', :lastname => 'Smith', :auth_source_id => 66])
132
133 post 'account/login', :username => 'foo', :password => 'bar'
134 assert_response :success
135 assert_template 'account/register'
136 assert_tag :input, :attributes => { :name => 'user[firstname]', :value => '' }
137 assert_tag :input, :attributes => { :name => 'user[lastname]', :value => 'Smith' }
138 assert_no_tag :input, :attributes => { :name => 'user[login]' }
139 assert_no_tag :input, :attributes => { :name => 'user[password]' }
140
141 post 'account/register', :user => {:firstname => 'Foo', :lastname => 'Smith', :mail => 'foo@bar.com'}
142 assert_redirected_to 'my/account'
143
144 user = User.find_by_login('foo')
145 assert user.is_a?(User)
146 assert_equal 66, user.auth_source_id
147 assert user.hashed_password.blank?
148 end
149
150 else
151 puts 'Mocha is missing. Skipping tests.'
152 end
105 153 end
General Comments 0
You need to be logged in to leave comments. Login now