diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb index 9fdc143..37cdbd1 100644 --- a/app/controllers/my_controller.rb +++ b/app/controllers/my_controller.rb @@ -100,13 +100,24 @@ class MyController < ApplicationController elsif params[:password] == params[:new_password] flash.now[:error] = l(:notice_new_password_must_be_different) else - @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] - @user.must_change_passwd = false - if @user.save - # The session token was destroyed by the password change, generate a new one - session[:tk] = @user.generate_session_token - flash[:notice] = l(:notice_account_password_updated) - redirect_to my_account_path + if @user.isExternal? + if @user.changeExternalPassword(params[:password],params[:new_password], params[:new_password_confirmation]) + session[:ctime] = Time.now.change(:usec => 0).utc.to_i + flash[:notice] = l(:notice_account_password_updated) + redirect_to my_account_path + else + flash[:error] = l(:notice_external_password_error) + end + else + @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] + @user.must_change_passwd = false + if @user.save + # Reset the session creation time to not log out this session on next + # request due to ApplicationController#force_logout_if_password_changed + session[:ctime] = User.current.passwd_changed_on.utc.to_i + flash[:notice] = l(:notice_account_password_updated) + redirect_to my_account_path + end end end end diff --git a/app/helpers/auth_sources_helper.rb b/app/helpers/auth_sources_helper.rb index 8364d64..0be27db 100644 --- a/app/helpers/auth_sources_helper.rb +++ b/app/helpers/auth_sources_helper.rb @@ -21,4 +21,11 @@ module AuthSourcesHelper def auth_source_partial_name(auth_source) "form_#{auth_source.class.name.underscore}" end + + 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 d5a8550..f10a20c 100644 --- a/app/models/auth_source_ldap.rb +++ b/app/models/auth_source_ldap.rb @@ -18,6 +18,8 @@ require 'net/ldap' require 'net/ldap/dn' require 'timeout' +require 'digest' +require 'base64' class AuthSourceLdap < AuthSource NETWORK_EXCEPTIONS = [ @@ -70,6 +72,65 @@ class AuthSourceLdap < AuthSource "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, password) + 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 + + ops = [ + [:delete, :userPassword, password], + [:add, :userPassword, newPassword] + ] + #return ldap_con.modify :dn => attrs[:dn], :operations => ops + # This is another password change method, probably more common + newPassword = encode_password(newPassword) + if newPassword.blank? + logger.debug "Invaild password" + return false + else + logger.debug "Try to change password" + return ldap_con.replace_attribute attrs[:dn], :userPassword, newPassword + end + end + rescue + return false + end + return false + end + # Returns true if this source can be searched for users def searchable? !account.to_s.include?("$login") && %w(login firstname lastname mail).all? {|a| send("attr_#{a}?")} diff --git a/app/models/user.rb b/app/models/user.rb index 4a6109f..1f07322 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -756,6 +756,19 @@ class User < Principal end end + def isExternal? + return auth_source_id.present? + end + + def changeExternalPassword(password,newPassword,newPasswordConfirm) + return false if newPassword == "" || newPassword.length < Setting.password_min_length.to_i + 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_password_length diff --git a/app/views/auth_sources/_form_auth_source_ldap.html.erb b/app/views/auth_sources/_form_auth_source_ldap.html.erb index d52e979..acd8063 100644 --- a/app/views/auth_sources/_form_auth_source_ldap.html.erb +++ b/app/views/auth_sources/_form_auth_source_ldap.html.erb @@ -14,6 +14,7 @@

<%= f.text_area :filter, :size => 60, :label => :field_auth_source_ldap_filter %>

<%= f.text_field :timeout, :size => 4 %>

<%= f.check_box :onthefly_register, :label => :field_onthefly %>

+

<%= f.check_box :enabled_passwd, :label => :field_enabled_passwd %>

<%=l(:label_attribute_plural)%> @@ -21,4 +22,5 @@

<%= f.text_field :attr_firstname, :size => 20 %>

<%= f.text_field :attr_lastname, :size => 20 %>

<%= f.text_field :attr_mail, :size => 20 %>

+

<%= f.select :password_encryption, AuthSourcesHelper::Encryption.encryptiontypes %>

diff --git a/config/locales/en.yml b/config/locales/en.yml index 24d5fe7..3a1d45f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1168,3 +1168,6 @@ en: description_date_from: Enter start date description_date_to: Enter end date text_repository_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed.
Once saved, the identifier cannot be changed.' + notice_external_password_error: Error changing external password. + field_password_encryption: Encryption + field_enabled_passwd: Enabled password changing diff --git a/db/migrate/20151209092800_add_auth_source_external_password.rb b/db/migrate/20151209092800_add_auth_source_external_password.rb new file mode 100644 index 0000000..d950363 --- /dev/null +++ b/db/migrate/20151209092800_add_auth_source_external_password.rb @@ -0,0 +1,11 @@ +class AddAuthSourceExternalPassword < ActiveRecord::Migration + def self.up + add_column :auth_sources, :enabled_passwd, :boolean, :default => false, :null => false + add_column :auth_sources, :password_encryption, :string, :limit => 30 + end + + def self.down + remove_column :auth_sources, :enabled_passwd + remove_column :auth_sources, :password_encryption + end +end