feat: compatible different uid of LDAP server (#1860)

* feat: compatible different uid of LDAP server

* Update organization.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
This commit is contained in:
Yaodong Yu
2023-05-19 02:34:25 +08:00
committed by GitHub
parent 6455734807
commit 65dcbd2236
8 changed files with 76 additions and 88 deletions

View File

@@ -126,7 +126,7 @@ func (c *ApiController) Signup() {
username = id username = id
} }
initScore, err := getInitScore(organization) initScore, err := organization.GetInitScore()
if err != nil { if err != nil {
c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error()) c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error())
return return

View File

@@ -454,7 +454,7 @@ func (c *ApiController) Login() {
properties := map[string]string{} properties := map[string]string{}
properties["no"] = strconv.Itoa(object.GetUserCount(application.Organization, "", "") + 2) properties["no"] = strconv.Itoa(object.GetUserCount(application.Organization, "", "") + 2)
initScore, err := getInitScore(organization) initScore, err := organization.GetInitScore()
if err != nil { if err != nil {
c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error()) c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error())
return return

View File

@@ -23,7 +23,8 @@ import (
type LdapResp struct { type LdapResp struct {
// Groups []LdapRespGroup `json:"groups"` // Groups []LdapRespGroup `json:"groups"`
Users []object.LdapRespUser `json:"users"` Users []object.LdapUser `json:"users"`
ExistUuids []string `json:"existUuids"`
} }
//type LdapRespGroup struct { //type LdapRespGroup struct {
@@ -32,8 +33,8 @@ type LdapResp struct {
//} //}
type LdapSyncResp struct { type LdapSyncResp struct {
Exist []object.LdapRespUser `json:"exist"` Exist []object.LdapUser `json:"exist"`
Failed []object.LdapRespUser `json:"failed"` Failed []object.LdapUser `json:"failed"`
} }
// GetLdapUsers // GetLdapUsers
@@ -71,30 +72,17 @@ func (c *ApiController) GetLdapUsers() {
return return
} }
var resp LdapResp
uuids := make([]string, len(users)) uuids := make([]string, len(users))
for _, user := range users { for i, user := range users {
resp.Users = append(resp.Users, object.LdapRespUser{ uuids[i] = user.GetLdapUuid()
UidNumber: user.UidNumber,
Uid: user.Uid,
Cn: user.Cn,
GroupId: user.GidNumber,
// GroupName: groupsMap[user.GidNumber].Cn,
Uuid: user.Uuid,
DisplayName: user.DisplayName,
Email: util.GetMaxLenStr(user.Mail, user.Email, user.EmailAddress),
Phone: util.GetMaxLenStr(user.TelephoneNumber, user.Mobile, user.MobileTelephoneNumber),
Address: util.GetMaxLenStr(user.RegisteredAddress, user.PostalAddress),
})
if user.Uuid != "" {
uuids = append(uuids, user.Uuid)
}
} }
existUuids := object.GetExistUuids(ldapServer.Owner, uuids) existUuids := object.GetExistUuids(ldapServer.Owner, uuids)
c.ResponseOk(resp, existUuids) resp := LdapResp{
Users: object.AutoAdjustLdapUser(users),
ExistUuids: existUuids,
}
c.ResponseOk(resp)
} }
// GetLdaps // GetLdaps
@@ -209,7 +197,7 @@ func (c *ApiController) DeleteLdap() {
func (c *ApiController) SyncLdapUsers() { func (c *ApiController) SyncLdapUsers() {
owner := c.Input().Get("owner") owner := c.Input().Get("owner")
ldapId := c.Input().Get("ldapId") ldapId := c.Input().Get("ldapId")
var users []object.LdapRespUser var users []object.LdapUser
err := json.Unmarshal(c.Ctx.Input.RequestBody, &users) err := json.Unmarshal(c.Ctx.Input.RequestBody, &users)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())

View File

@@ -16,7 +16,6 @@ package controllers
import ( import (
"fmt" "fmt"
"strconv"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
@@ -115,14 +114,6 @@ func (c *ApiController) RequireAdmin() (string, bool) {
return user.Owner, true return user.Owner, true
} }
func getInitScore(organization *object.Organization) (int, error) {
if organization != nil {
return organization.InitScore, nil
} else {
return strconv.Atoi(conf.GetConfigString("initScore"))
}
}
func (c *ApiController) GetProviderFromContext(category string) (*object.Provider, *object.User, bool) { func (c *ApiController) GetProviderFromContext(category string) (*object.Provider, *object.User, bool) {
providerName := c.Input().Get("provider") providerName := c.Input().Get("provider")
if providerName != "" { if providerName != "" {

View File

@@ -88,7 +88,7 @@ func (l *LdapAutoSynchronizer) syncRoutine(ldap *Ldap, stopChan chan struct{}) {
continue continue
} }
existed, failed, err := SyncLdapUsers(ldap.Owner, LdapUsersToLdapRespUsers(users), ldap.Id) existed, failed, err := SyncLdapUsers(ldap.Owner, AutoAdjustLdapUser(users), ldap.Id)
if len(failed) != 0 { if len(failed) != 0 {
logs.Warning(fmt.Sprintf("ldap autosync,%d new users,but %d user failed during :", len(users)-len(existed)-len(failed), len(failed)), failed) logs.Warning(fmt.Sprintf("ldap autosync,%d new users,but %d user failed during :", len(users)-len(existed)-len(failed), len(failed)), failed)
logs.Warning(err.Error()) logs.Warning(err.Error())

View File

@@ -19,7 +19,6 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/beego/beego"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
goldap "github.com/go-ldap/ldap/v3" goldap "github.com/go-ldap/ldap/v3"
"github.com/thanhpk/randstr" "github.com/thanhpk/randstr"
@@ -35,35 +34,26 @@ type LdapConn struct {
// Cn string // Cn string
//} //}
type ldapUser struct { type LdapUser struct {
UidNumber string UidNumber string `json:"uidNumber"`
Uid string Uid string `json:"uid"`
Cn string Cn string `json:"cn"`
GidNumber string GidNumber string `json:"gidNumber"`
// Gcn string // Gcn string
Uuid string Uuid string `json:"uuid"`
DisplayName string DisplayName string `json:"displayName"`
Mail string Mail string
Email string Email string `json:"email"`
EmailAddress string EmailAddress string
TelephoneNumber string TelephoneNumber string
Mobile string Mobile string
MobileTelephoneNumber string MobileTelephoneNumber string
RegisteredAddress string RegisteredAddress string
PostalAddress string PostalAddress string
}
type LdapRespUser struct { GroupId string `json:"groupId"`
UidNumber string `json:"uidNumber"` Phone string `json:"phone"`
Uid string `json:"uid"` Address string `json:"address"`
Cn string `json:"cn"`
GroupId string `json:"groupId"`
// GroupName string `json:"groupName"`
Uuid string `json:"uuid"`
DisplayName string `json:"displayName"`
Email string `json:"email"`
Phone string `json:"phone"`
Address string `json:"address"`
} }
func (ldap *Ldap) GetLdapConn() (c *LdapConn, err error) { func (ldap *Ldap) GetLdapConn() (c *LdapConn, err error) {
@@ -136,7 +126,7 @@ func isMicrosoftAD(Conn *goldap.Conn) (bool, error) {
return isMicrosoft, err return isMicrosoft, err
} }
func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]ldapUser, error) { func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]LdapUser, error) {
SearchAttributes := []string{ SearchAttributes := []string{
"uidNumber", "cn", "sn", "gidNumber", "entryUUID", "displayName", "mail", "email", "uidNumber", "cn", "sn", "gidNumber", "entryUUID", "displayName", "mail", "email",
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress", "emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress",
@@ -159,9 +149,9 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]ldapUser, error) {
return nil, errors.New("no result") return nil, errors.New("no result")
} }
var ldapUsers []ldapUser var ldapUsers []LdapUser
for _, entry := range searchResult.Entries { for _, entry := range searchResult.Entries {
var user ldapUser var user LdapUser
for _, attribute := range entry.Attributes { for _, attribute := range entry.Attributes {
switch attribute.Name { switch attribute.Name {
case "uidNumber": case "uidNumber":
@@ -241,27 +231,26 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]ldapUser, error) {
// return groupMap, nil // return groupMap, nil
// } // }
func LdapUsersToLdapRespUsers(users []ldapUser) []LdapRespUser { func AutoAdjustLdapUser(users []LdapUser) []LdapUser {
res := make([]LdapRespUser, 0) res := make([]LdapUser, len(users))
for _, user := range users { for i, user := range users {
res = append(res, LdapRespUser{ res[i] = LdapUser{
UidNumber: user.UidNumber, UidNumber: user.UidNumber,
Uid: user.Uid, Uid: user.Uid,
Cn: user.Cn, Cn: user.Cn,
GroupId: user.GidNumber, GroupId: user.GidNumber,
Uuid: user.Uuid, Uuid: user.GetLdapUuid(),
DisplayName: user.DisplayName, DisplayName: user.DisplayName,
Email: util.ReturnAnyNotEmpty(user.Email, user.EmailAddress, user.Mail), Email: util.ReturnAnyNotEmpty(user.Email, user.EmailAddress, user.Mail),
Phone: util.ReturnAnyNotEmpty(user.Mobile, user.MobileTelephoneNumber, user.TelephoneNumber), Mobile: util.ReturnAnyNotEmpty(user.Mobile, user.MobileTelephoneNumber, user.TelephoneNumber),
Address: util.ReturnAnyNotEmpty(user.PostalAddress, user.RegisteredAddress), RegisteredAddress: util.ReturnAnyNotEmpty(user.PostalAddress, user.RegisteredAddress),
}) }
} }
return res return res
} }
func SyncLdapUsers(owner string, syncUsers []LdapRespUser, ldapId string) (existUsers []LdapRespUser, failedUsers []LdapRespUser, err error) { func SyncLdapUsers(owner string, syncUsers []LdapUser, ldapId string) (existUsers []LdapUser, failedUsers []LdapUser, err error) {
var uuids []string var uuids []string
for _, user := range syncUsers { for _, user := range syncUsers {
uuids = append(uuids, user.Uuid) uuids = append(uuids, user.Uuid)
} }
@@ -286,12 +275,6 @@ func SyncLdapUsers(owner string, syncUsers []LdapRespUser, ldapId string) (exist
tag := strings.Join(ou, ".") tag := strings.Join(ou, ".")
for _, syncUser := range syncUsers { for _, syncUser := range syncUsers {
if syncUser.Uuid == "" {
failedUsers = append(failedUsers, syncUser)
err = errors.New("uuid of user being synced is empty")
continue
}
existUuids := GetExistUuids(owner, uuids) existUuids := GetExistUuids(owner, uuids)
found := false found := false
if len(existUuids) > 0 { if len(existUuids) > 0 {
@@ -304,6 +287,7 @@ func SyncLdapUsers(owner string, syncUsers []LdapRespUser, ldapId string) (exist
} }
if !found { if !found {
score, _ := organization.GetInitScore()
newUser := &User{ newUser := &User{
Owner: owner, Owner: owner,
Name: syncUser.buildLdapUserName(), Name: syncUser.buildLdapUserName(),
@@ -315,7 +299,7 @@ func SyncLdapUsers(owner string, syncUsers []LdapRespUser, ldapId string) (exist
Address: []string{syncUser.Address}, Address: []string{syncUser.Address},
Affiliation: affiliation, Affiliation: affiliation,
Tag: tag, Tag: tag,
Score: beego.AppConfig.DefaultInt("initScore", 2000), Score: score,
Ldap: syncUser.Uuid, Ldap: syncUser.Uuid,
} }
@@ -342,7 +326,7 @@ func GetExistUuids(owner string, uuids []string) []string {
return existUuids return existUuids
} }
func (ldapUser *LdapRespUser) buildLdapUserName() string { func (ldapUser *LdapUser) buildLdapUserName() string {
user := User{} user := User{}
uidWithNumber := fmt.Sprintf("%s_%s", ldapUser.Uid, ldapUser.UidNumber) uidWithNumber := fmt.Sprintf("%s_%s", ldapUser.Uid, ldapUser.UidNumber)
has, err := adapter.Engine.Where("name = ? or name = ?", ldapUser.Uid, uidWithNumber).Get(&user) has, err := adapter.Engine.Where("name = ? or name = ?", ldapUser.Uid, uidWithNumber).Get(&user)
@@ -357,10 +341,14 @@ func (ldapUser *LdapRespUser) buildLdapUserName() string {
return fmt.Sprintf("%s_%s", uidWithNumber, randstr.Hex(6)) return fmt.Sprintf("%s_%s", uidWithNumber, randstr.Hex(6))
} }
return ldapUser.Uid if ldapUser.Uid != "" {
return ldapUser.Uid
}
return ldapUser.Cn
} }
func (ldapUser *LdapRespUser) buildLdapDisplayName() string { func (ldapUser *LdapUser) buildLdapDisplayName() string {
if ldapUser.DisplayName != "" { if ldapUser.DisplayName != "" {
return ldapUser.DisplayName return ldapUser.DisplayName
} }
@@ -368,6 +356,17 @@ func (ldapUser *LdapRespUser) buildLdapDisplayName() string {
return ldapUser.Cn return ldapUser.Cn
} }
func (ldapUser *LdapUser) GetLdapUuid() string {
if ldapUser.Uuid != "" {
return ldapUser.Uuid
}
if ldapUser.Uid != "" {
return ldapUser.Uid
}
return ldapUser.Cn
}
func (ldap *Ldap) buildFilterString(user *User) string { func (ldap *Ldap) buildFilterString(user *User) string {
if len(ldap.FilterFields) == 0 { if len(ldap.FilterFields) == 0 {
return fmt.Sprintf("(&%s(uid=%s))", ldap.Filter, user.Name) return fmt.Sprintf("(&%s(uid=%s))", ldap.Filter, user.Name)

View File

@@ -16,7 +16,9 @@ package object
import ( import (
"fmt" "fmt"
"strconv"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/cred" "github.com/casdoor/casdoor/cred"
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
@@ -423,3 +425,11 @@ func (org *Organization) HasRequiredMfa() bool {
} }
return false return false
} }
func (org *Organization) GetInitScore() (int, error) {
if org != nil {
return org.InitScore, nil
} else {
return strconv.Atoi(conf.GetConfigString("initScore"))
}
}

View File

@@ -94,7 +94,7 @@ class LdapSyncPage extends React.Component {
if (res.status === "ok") { if (res.status === "ok") {
this.setState((prevState) => { this.setState((prevState) => {
prevState.users = res.data.users; prevState.users = res.data.users;
prevState.existUuids = res.data2?.length > 0 ? res.data2.filter(uuid => uuid !== "") : []; prevState.existUuids = res.data.existUuids?.length > 0 ? res.data.existUuids.filter(uuid => uuid !== "") : [];
return prevState; return prevState;
}); });
} else { } else {
@@ -210,7 +210,7 @@ class LdapSyncPage extends React.Component {
}); });
}, },
getCheckboxProps: record => ({ getCheckboxProps: record => ({
disabled: this.state.existUuids.indexOf(record.uuid) !== -1 || record.uidNumber === "", disabled: this.state.existUuids.indexOf(record.uuid) !== -1,
}), }),
}; };