diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb index f637b49..b91ad29 100644 --- a/app/controllers/my_controller.rb +++ b/app/controllers/my_controller.rb @@ -1,4 +1,4 @@ -# Redmine - project management software + # Redmine - project management software # Copyright (C) 2006-2009 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or @@ -84,10 +84,19 @@ class MyController < ApplicationController end if request.post? if @user.check_password?(params[:password]) - @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] - if @user.save - flash[:notice] = l(:notice_account_password_updated) - redirect_to :action => 'account' + if @user.isExternal? + if @user.changeExternalPassword(params[:password],params[:new_password], params[:new_password_confirmation]) + flash[:notice] = l(:notice_account_password_updated) + redirect_to :action => 'account' + else + flash[:error] = l(:notice_external_password_error) + end + else + @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] + if @user.save + flash[:notice] = l(:notice_account_password_updated) + redirect_to :action => 'account' + end end else flash[:error] = l(:notice_account_wrong_password) diff --git a/app/helpers/auth_sources_helper.rb b/app/helpers/auth_sources_helper.rb index d47e985..989d723 100644 --- a/app/helpers/auth_sources_helper.rb +++ b/app/helpers/auth_sources_helper.rb @@ -16,4 +16,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. module AuthSourcesHelper + + module Encryption + # Return an array of password encryptions + def self.encryptiontypes + ["MD5","SSHA","CLEAR"] + end + end end diff --git a/app/models/auth_source_ldap.rb b/app/models/auth_source_ldap.rb index d2a7e70..e56815e 100644 --- a/app/models/auth_source_ldap.rb +++ b/app/models/auth_source_ldap.rb @@ -17,6 +17,8 @@ require 'net/ldap' require 'iconv' +require 'digest' +require 'base64' class AuthSourceLdap < AuthSource validates_presence_of :host, :port, :attr_login @@ -24,11 +26,10 @@ class AuthSourceLdap < AuthSource validates_length_of :account, :base_dn, :maximum => 255, :allow_nil => true validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true validates_numericality_of :port, :only_integer => true - before_validation :strip_ldap_attributes def after_initialize - self.port = 389 if self.port == 0 + self.port = 389 if self.port == 0 end def authenticate(login, password) @@ -54,7 +55,51 @@ class AuthSourceLdap < AuthSource def auth_method_name "LDAP" end + + def allow_password_changes? + return self.enabled_passwd + end + + def encode_password(clear_password) + chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + salt = '' + 10.times { |i| salt << chars[rand(chars.size-1)] } + + if self.password_encryption == "MD5" + logger.debug "Encode as md5" + return "{MD5}"+Base64.encode64(Digest::MD5.digest(clear_password)).chomp! + end + if self.password_encryption == "SSHA" + logger.debug "Encode as ssha" + return "{SSHA}"+Base64.encode64(Digest::SHA1.digest(clear_password+salt)+salt).chomp! + end + + if self.password_encryption == "CLEAR" + logger.debug "Encode as cleartype" + return clear_password + end + end + # change password + def change_password(login,password,newPassword) + begin + attrs = get_user_dn(login) + if attrs + if self.account.blank? || self.account_password.blank? + logger.debug "Binding with user account" + ldap_con = initialize_ldap_con(attrs[:dn], password) + else + logger.debug "Binding with administrator account" + ldap_con = initialize_ldap_con(self.account, self.account_password) + end + return ldap_con.replace_attribute attrs[:dn], :userPassword, encode_password(newPassword) + end + rescue + return false + end + return false + end + private def strip_ldap_attributes diff --git a/app/models/user.rb b/app/models/user.rb index a38a091..eb3ba1b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -332,6 +332,19 @@ class User < Principal anonymous_user end + def isExternal? + return auth_source_id.present? + end + + def changeExternalPassword(password,newPassword,newPasswordConfirm) + return false if newPassword == "" || newPassword.length < 4 + return false if newPassword != newPasswordConfirm + if (self.isExternal?) + return self.auth_source.change_password(self.login,password,newPassword) + end + return false + end + protected def validate diff --git a/app/views/ldap_auth_sources/_form.rhtml b/app/views/ldap_auth_sources/_form.rhtml index 9ffffaf..e8f6df1 100644 --- a/app/views/ldap_auth_sources/_form.rhtml +++ b/app/views/ldap_auth_sources/_form.rhtml @@ -25,6 +25,8 @@

<%= check_box 'auth_source', 'onthefly_register' %>

+

+<%= check_box 'auth_source', 'enabled_passwd' %>

<%=l(:label_attribute_plural)%> @@ -39,6 +41,10 @@

<%= text_field 'auth_source', 'attr_mail', :size => 20 %>

+ +

+<%= select 'auth_source', 'password_encryption', AuthSourcesHelper::Encryption.encryptiontypes %> +

diff --git a/config/locales/de.yml b/config/locales/de.yml index 1337edd..d9a346f 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -150,13 +150,14 @@ de: general_pdf_encoding: ISO-8859-1 general_first_day_of_week: '1' + notice_external_password_error: Externes Konto konnte nicht aktualisiert werden. notice_account_updated: Konto wurde erfolgreich aktualisiert. notice_account_invalid_creditentials: Benutzer oder Kennwort ist ungültig. notice_account_password_updated: Kennwort wurde erfolgreich aktualisiert. notice_account_wrong_password: Falsches Kennwort. notice_account_register_done: Konto wurde erfolgreich angelegt. notice_account_unknown_email: Unbekannter Benutzer. - notice_can_t_change_password: Dieses Konto verwendet eine externe Authentifizierungs-Quelle. Unmöglich, das Kennwort zu ändern. + notice_can_t_change_password: Kennwort ändern ist gesperrt für diese externe Authentifizierungs-Quelle. notice_account_lost_email_sent: Eine E-Mail mit Anweisungen, ein neues Kennwort zu wählen, wurde Ihnen geschickt. notice_account_activated: Ihr Konto ist aktiviert. Sie können sich jetzt anmelden. notice_successful_create: Erfolgreich angelegt @@ -273,6 +274,8 @@ de: field_attr_lastname: Name-Attribut field_attr_mail: E-Mail-Attribut field_onthefly: On-the-fly-Benutzererstellung + field_password_encryption: Verschlüsselungsart + field_enabled_passwd: Password ändern erlauben field_start_date: Beginn field_done_ratio: % erledigt field_auth_source: Authentifizierungs-Modus diff --git a/config/locales/en.yml b/config/locales/en.yml index c3fc52e..816fe2f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -127,6 +127,7 @@ en: general_pdf_encoding: ISO-8859-1 general_first_day_of_week: '7' + notice_external_password_error: External password changing goes wrong notice_account_updated: Account was successfully updated. notice_account_invalid_creditentials: Invalid user or password notice_account_password_updated: Password was successfully updated. @@ -253,6 +254,8 @@ en: field_attr_lastname: Lastname attribute field_attr_mail: Email attribute field_onthefly: On-the-fly user creation + field_password_encryption: Encyrption + field_enabled_passwd: Enabled password changing field_start_date: Start field_done_ratio: % Done field_auth_source: Authentication mode diff --git a/db/migrate/20100609104539_ldap_password_change.rb b/db/migrate/20100609104539_ldap_password_change.rb new file mode 100644 index 0000000..52e231d --- /dev/null +++ b/db/migrate/20100609104539_ldap_password_change.rb @@ -0,0 +1,11 @@ +class LdapPasswordChange < ActiveRecord::Migration + def self.up + add_column :auth_sources, :password_encryption, :string, :default => "MD5", :null => false + add_column :auth_sources, :enabled_passwd, :boolean, :default => false, :null => false + end + + def self.down + remove_column :auth_sources, :password_encryption + remove_column :auth_sources, :enabled_passwd + end +end