Project

General

Profile

Patch #5690 » redmine_ldap_passwd_patch_issue_5690.patch

Andrey Ivanov, 2024-01-08 08:30

View differences:

app/controllers/account_controller.rb (working copy)
83 83
      if request.post?
84 84
        if @user.must_change_passwd? && @user.check_password?(params[:new_password])
85 85
          flash.now[:error] = l(:notice_new_password_must_be_different)
86
        elsif @user.isExternal?
87
          if @user.newExternalPassword(params[:new_password], params[:new_password_confirmation])
88
            @token.destroy
89
            flash[:notice] = l(:notice_account_password_updated)
90
            redirect_to signin_path
91
            return
92
          else
93
            flash[:error] = l(:error_changing_external_password)
94
          end
86 95
        else
87 96
          @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
88 97
          @user.must_change_passwd = false
app/controllers/my_controller.rb (working copy)
103 103
        flash.now[:error] = l(:notice_account_wrong_password)
104 104
      elsif params[:password] == params[:new_password]
105 105
        flash.now[:error] = l(:notice_new_password_must_be_different)
106
      elsif @user.isExternal?
107
        if @user.changeExternalPassword(params[:password], params[:new_password], params[:new_password_confirmation])
108
          session[:tk] = @user.generate_session_token
109
          flash[:notice] = l(:notice_account_password_updated)
110
          redirect_to my_account_path
111
        else
112
          flash[:error] = l(:error_changing_external_password)
113
        end
106 114
      else
107 115
        @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
108 116
        @user.must_change_passwd = false
app/models/auth_source_ldap.rb (working copy)
20 20
require 'net/ldap'
21 21
require 'net/ldap/dn'
22 22
require 'timeout'
23
require 'digest'
24
require 'base64'
23 25

  
24 26
class AuthSourceLdap < AuthSource
25 27
  NETWORK_EXCEPTIONS = [
......
84 86
    "LDAP"
85 87
  end
86 88

  
89
  def allow_password_changes?
90
    true
91
  end
92
  
93
  def password_encryption
94
    "MD5"
95
  end
96

  
97
  def encode_password(clear_password)
98
    salt = User.generate_salt
99

  
100
    if self.password_encryption == "MD5"
101
      logger.debug "Encode as md5"
102
      return "{MD5}"+Base64.encode64(Digest::MD5.digest(clear_password)).chomp!
103
    end
104
    if self.password_encryption == "SSHA"
105
      logger.debug "Encode as ssha"
106
      return "{SSHA}"+Base64.encode64(Digest::SHA1.digest(clear_password+salt)+salt).chomp!
107
    end
108

  
109
    if self.password_encryption == "CLEAR"
110
      logger.debug "Encode as cleartype"
111
      return clear_password
112
    end
113
    #
114
  end
115

  
116
  # change password
117
  def change_password(login,password,newPassword)
118
    begin
119
      attrs = get_user_dn(login, password)
120
      if attrs
121
        logger.debug "Binding with user account"
122
        ldap_con = initialize_ldap_con(attrs[:dn], password)
123
        ops = [
124
          [:delete, :userPassword, password],
125
          [:add, :userPassword, newPassword]
126
        ]
127
        #return ldap_con.modify :dn => attrs[:dn], :operations => ops
128
        # This is another password change method, probably more common
129
        newPassword = encode_password(newPassword)
130
        # logger.info("NEW PASSWORD #{newPassword}")
131
        if newPassword.blank?
132
          logger.debug "Invaild password"
133
          return false
134
        else
135
          logger.debug "Try to change password"
136
          return ldap_con.replace_attribute attrs[:dn], :userPassword, newPassword
137
        end
138
      end
139
    rescue Exception => ex
140
      logger.error "LDAP: #{ex.message}"
141
      return false
142
    end
143
    return false
144
  end
145

  
146
  def lost_password(login,newPassword)
147
    begin
148
      attrs = get_user_dn_nopass(login)
149
      if attrs
150
        ldap_con = initialize_ldap_con(self.account, self.account_password)
151
         return ldap_con.replace_attribute attrs[:dn], :userPassword, encode_password(newPassword)
152
      end
153
    rescue
154
      return false
155
    end
156
    return false
157
  end
158

  
159
  def get_user_dn_nopass(login)
160
    ldap_con = nil
161
    ldap_con = initialize_ldap_con(self.account, self.account_password)
162
    attrs = {}
163
    search_filter = base_filter & Net::LDAP::Filter.eq(self.attr_login, login)
164
    ldap_con.search(:base => self.base_dn,
165
                    :filter => search_filter,
166
                    :attributes=> search_attributes) do |entry|
167
                              if onthefly_register?
168
                                attrs = get_user_attributes_from_ldap_entry(entry)
169
                              else
170
                                attrs = {:dn => entry.dn}
171
                              end
172
                              logger.debug "DN found for #{login}: #{attrs[:dn]}" if logger && logger.debug?
173
                              end
174
    attrs
175
  end
176

  
87 177
  # Returns true if this source can be searched for users
88 178
  def searchable?
89 179
    !account.to_s.include?("$login") && %w(login firstname lastname mail).all? {|a| send(:"attr_#{a}?")}
app/models/user.rb (working copy)
903 903
    User.where("created_on < ? AND status = ?", Time.now - age, STATUS_REGISTERED).destroy_all
904 904
  end
905 905

  
906
  def isExternal?
907
    return auth_source_id.present?
908
  end
909

  
910
  def changeExternalPassword(password,newPassword,newPasswordConfirm)
911
    return false if newPassword == "" || newPassword.length < Setting.password_min_length.to_i
912
    return false if newPassword != newPasswordConfirm
913
    if (self.isExternal?)
914
      return self.auth_source.change_password(self.login,password,newPassword)
915
    end
916
    return false
917
  end
918

  
919
  def newExternalPassword(newPassword,newPasswordConfirm)
920
    return false if newPassword == "" || newPassword.length < 4
921
    return false if newPassword != newPasswordConfirm
922
    if (self.isExternal?)
923
      return self.auth_source.lost_password(self.login,newPassword)
924
    end
925
    return false
926
  end
927

  
906 928
  protected
907 929

  
908 930
  def validate_password_length
config/locales/en.yml (working copy)
226 226
  error_no_data_in_file: "The file does not contain any data"
227 227
  error_attachment_extension_not_allowed: "Attachment extension %{extension} is not allowed"
228 228
  error_ldap_bind_credentials: "Invalid LDAP Account/Password"
229
  error_changing_external_password: "Error changing external password"
229 230
  error_no_tracker_allowed_for_new_issue_in_project: "The project doesn't have any trackers for which you can create an issue"
230 231
  error_no_projects_with_tracker_allowed_for_new_issue: "There are no projects with trackers for which you can create an issue"
231 232
  error_move_of_child_not_possible: "Subtask %{child} could not be moved to the new project: %{errors}"
(7-7/7)