diff --git a/controllers/user.go b/controllers/user.go index 46a4343e..128d6ca6 100644 --- a/controllers/user.go +++ b/controllers/user.go @@ -475,6 +475,16 @@ func (c *ApiController) SetPassword() { userId := util.GetId(userOwner, userName) + user, err := object.GetUser(userId) + if err != nil { + c.ResponseError(err.Error()) + return + } + if user == nil { + c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId)) + return + } + requestUserId := c.GetSessionUsername() if requestUserId == "" && code == "" { c.ResponseError(c.T("general:Please login first"), "Please login first") @@ -518,7 +528,11 @@ func (c *ApiController) SetPassword() { } } } else if code == "" { - err = object.CheckPassword(targetUser, oldPassword, c.GetAcceptLanguage()) + if user.Ldap == "" { + err = object.CheckPassword(targetUser, oldPassword, c.GetAcceptLanguage()) + } else { + err = object.CheckLdapUserPassword(targetUser, oldPassword, c.GetAcceptLanguage()) + } if err != nil { c.ResponseError(err.Error()) return @@ -563,7 +577,12 @@ func (c *ApiController) SetPassword() { targetUser.NeedUpdatePassword = false targetUser.LastChangePasswordTime = util.GetCurrentTime() - _, err = object.UpdateUser(userId, targetUser, []string{"password", "need_update_password", "password_type", "last_change_password_time"}, false) + if user.Ldap == "" { + _, err = object.UpdateUser(userId, targetUser, []string{"password", "need_update_password", "password_type", "last_change_password_time"}, false) + } else { + err = object.ResetLdapPassword(targetUser, newPassword, c.GetAcceptLanguage()) + } + if err != nil { c.ResponseError(err.Error()) return diff --git a/go.mod b/go.mod index a2477815..6193a22e 100644 --- a/go.mod +++ b/go.mod @@ -63,6 +63,7 @@ require ( golang.org/x/crypto v0.21.0 golang.org/x/net v0.21.0 golang.org/x/oauth2 v0.17.0 + golang.org/x/text v0.14.0 google.golang.org/api v0.150.0 gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 diff --git a/object/check.go b/object/check.go index 6bf4ebd8..66867d3f 100644 --- a/object/check.go +++ b/object/check.go @@ -273,7 +273,7 @@ func CheckPasswordComplexity(user *User, password string) string { return CheckPasswordComplexityByOrg(organization, password) } -func checkLdapUserPassword(user *User, password string, lang string) error { +func CheckLdapUserPassword(user *User, password string, lang string) error { ldaps, err := GetLdaps(user.Owner) if err != nil { return err @@ -368,7 +368,7 @@ func CheckUserPassword(organization string, username string, password string, la } // only for LDAP users - err = checkLdapUserPassword(user, password, lang) + err = CheckLdapUserPassword(user, password, lang) if err != nil { if err.Error() == "user not exist" { return nil, fmt.Errorf(i18n.Translate(lang, "check:The user: %s doesn't exist in LDAP server"), username) diff --git a/object/ldap_conn.go b/object/ldap_conn.go index 47fc94e4..f9cf497c 100644 --- a/object/ldap_conn.go +++ b/object/ldap_conn.go @@ -20,9 +20,11 @@ import ( "strings" "github.com/casdoor/casdoor/conf" + "github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/util" goldap "github.com/go-ldap/ldap/v3" "github.com/thanhpk/randstr" + "golang.org/x/text/encoding/unicode" ) type LdapConn struct { @@ -371,6 +373,64 @@ func GetExistUuids(owner string, uuids []string) ([]string, error) { return existUuids, nil } +func ResetLdapPassword(user *User, newPassword string, lang string) error { + ldaps, err := GetLdaps(user.Owner) + if err != nil { + return err + } + + for _, ldapServer := range ldaps { + conn, err := ldapServer.GetLdapConn() + if err != nil { + continue + } + + searchReq := goldap.NewSearchRequest(ldapServer.BaseDn, goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, + 0, 0, false, ldapServer.buildAuthFilterString(user), []string{}, nil) + + searchResult, err := conn.Conn.Search(searchReq) + if err != nil { + conn.Close() + return err + } + + if len(searchResult.Entries) == 0 { + conn.Close() + continue + } + if len(searchResult.Entries) > 1 { + conn.Close() + return fmt.Errorf(i18n.Translate(lang, "check:Multiple accounts with same uid, please check your ldap server")) + } + + userDn := searchResult.Entries[0].DN + + var pwdEncoded string + modifyPasswordRequest := goldap.NewModifyRequest(userDn, nil) + if conn.IsAD { + utf16 := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM) + pwdEncoded, err := utf16.NewEncoder().String("\"" + newPassword + "\"") + if err != nil { + conn.Close() + return err + } + modifyPasswordRequest.Replace("unicodePwd", []string{pwdEncoded}) + modifyPasswordRequest.Replace("userAccountControl", []string{"512"}) + } else { + pwdEncoded = newPassword + modifyPasswordRequest.Replace("userPassword", []string{pwdEncoded}) + } + + err = conn.Conn.Modify(modifyPasswordRequest) + if err != nil { + conn.Close() + return err + } + conn.Close() + } + return nil +} + func (ldapUser *LdapUser) buildLdapUserName(owner string) (string, error) { user := User{} uidWithNumber := fmt.Sprintf("%s_%s", ldapUser.Uid, ldapUser.UidNumber) diff --git a/object/token_oauth.go b/object/token_oauth.go index 590ab5c9..5db0bb4e 100644 --- a/object/token_oauth.go +++ b/object/token_oauth.go @@ -504,7 +504,7 @@ func GetPasswordToken(application *Application, username string, password string } if user.Ldap != "" { - err = checkLdapUserPassword(user, password, "en") + err = CheckLdapUserPassword(user, password, "en") } else { err = CheckPassword(user, password, "en") }