feat(ldapSync): changed ldap-groups and ldap-users id field
Build and Push Docker image / build-and-push (push) Successful in 3m30s Details

In the past the objectGUID of the groups and users where used to set the id of the record.
This led to bugs for filter queries, so from now on the the id is autogenerated from pocketbase and the objectGUID is stored in a seperate columns (with unique index)

BREAKING CHANGE: The ID's of all users and groups changed
This commit is contained in:
Valentin Kolb 2024-05-11 13:29:56 +02:00
parent d3658f58f2
commit 1c78615597
4 changed files with 78 additions and 28 deletions

View File

@ -27,8 +27,8 @@ func upsertLDAPGroup(app *pocketbase.PocketBase, ldapGroup *LDAPGroup) error {
// if record exists, update it
if res, _ := app.Dao().FindFirstRecordByFilter(
ldapGroupsTableName,
"id = {:id}",
dbx.Params{"id": ldapGroup.id},
"objectGUID = {:objectGUID}",
dbx.Params{"objectGUID": ldapGroup.objectGUID},
); res != nil {
record = res
} else { // if record does not exist, create it
@ -37,13 +37,13 @@ func upsertLDAPGroup(app *pocketbase.PocketBase, ldapGroup *LDAPGroup) error {
form := forms.NewRecordUpsert(app, record)
var groups []string
var memberOfGroupIds []string
// get group ids from group dns
for _, groupDn := range ldapGroup.memberOf {
group, err := GetLdapGroupByDN(app, groupDn)
if err == nil {
groups = append(groups, group.Id)
memberOfGroupIds = append(memberOfGroupIds, group.Id)
} else {
logger.LogErrorF("unable to find %s.memberOf: %s", ldapGroup.cn, groupDn)
}
@ -51,11 +51,11 @@ func upsertLDAPGroup(app *pocketbase.PocketBase, ldapGroup *LDAPGroup) error {
// load data
err = form.LoadData(map[string]any{
"id": ldapGroup.id,
"objectGUID": ldapGroup.objectGUID,
"cn": ldapGroup.cn,
"dn": ldapGroup.dn,
"description": ldapGroup.description,
"memberOf": groups,
"memberOf": memberOfGroupIds,
})
if err != nil {
return err
@ -83,8 +83,8 @@ func upsertLDAPUser(app *pocketbase.PocketBase, ldapUser *LDAPUser) error {
// if record exists, update it
if res, _ := app.Dao().FindFirstRecordByFilter(
ldapUsersTableName,
"id = {:id}",
dbx.Params{"id": ldapUser.id},
"objectGUID = {:objectGUID}",
dbx.Params{"objectGUID": ldapUser.objectGUID},
); res != nil {
record = res
} else { // if record does not exist, create it
@ -99,19 +99,19 @@ func upsertLDAPUser(app *pocketbase.PocketBase, ldapUser *LDAPUser) error {
accountExpires, _ := ldapTimeToUnixTime(ldapUser.accountExpires)
var groups []string
var memberOfGroupIds []string
// get group ids from group dns
for _, groupDn := range ldapUser.memberOf {
group, err := GetLdapGroupByDN(app, groupDn)
if err == nil {
groups = append(groups, group.Id)
memberOfGroupIds = append(memberOfGroupIds, group.Id)
} else {
logger.LogErrorF("unable to find %s.memberOf: %s", ldapUser.cn, groupDn)
}
}
record.Set("id", ldapUser.id)
record.Set("objectGUID", ldapUser.objectGUID)
record.Set("givenName", ldapUser.givenName)
record.Set("sn", ldapUser.sn)
record.Set("username", ldapUser.cn)
@ -121,7 +121,7 @@ func upsertLDAPUser(app *pocketbase.PocketBase, ldapUser *LDAPUser) error {
record.Set("verified", true)
record.Set("dn", ldapUser.dn)
record.Set("cn", ldapUser.cn)
record.Set("memberOf", groups)
record.Set("memberOf", memberOfGroupIds)
if err := app.Dao().SaveRecord(record); err != nil {
return fmt.Errorf("failed to upsert user with dn: %s - %w", ldapUser.dn, err)
@ -157,3 +157,37 @@ func GetLdapUserByCN(app *pocketbase.PocketBase, cn string) (*models.Record, err
}
return record, nil
}
// GetLdapGroupByObjectGUID This function returns a record from the ldap groups table by objectGUID.
// It also expands the memberOf field.
func GetLdapGroupByObjectGUID(app *pocketbase.PocketBase, objectGUID string) (*models.Record, error) {
record, err := app.Dao().FindFirstRecordByFilter(
ldapGroupsTableName,
"objectGUID = {:objectGUID}",
dbx.Params{"objectGUID": objectGUID},
)
if err != nil {
return nil, err
}
if errs := app.Dao().ExpandRecord(record, []string{"memberOf"}, nil); len(errs) > 0 {
return nil, fmt.Errorf("ldap group - failed to expand: %v", errs)
}
return record, nil
}
// GetLdapUserByObjectGUID This function returns a record from the ldap users table by objectGUID.
// It also expands the memberOf field.
func GetLdapUserByObjectGUID(app *pocketbase.PocketBase, objectGUID string) (*models.Record, error) {
record, err := app.Dao().FindFirstRecordByFilter(
ldapUsersTableName,
"objectGUID = {:objectGUID}",
dbx.Params{"objectGUID": objectGUID},
)
if err != nil {
return nil, err
}
if errs := app.Dao().ExpandRecord(record, []string{"memberOf"}, nil); len(errs) > 0 {
return nil, fmt.Errorf("ldap user - failed to expand: %v", errs)
}
return record, nil
}

View File

@ -33,7 +33,9 @@ func getObjectGUID(entry *ldap.Entry) (string, error) {
if err != nil {
return "", err
}
return u.String()[:15], nil // only use the first 15 characters of the uuid
// only use the first 15 characters of the uuid and remove all slashes
return u.String(), nil
}
// upsertLDAPGroup This function creates / updates a record in the ldap groups table
@ -63,14 +65,14 @@ func syncLdapGroups(app *pocketbase.PocketBase, ldapClient *ldap.Conn) SyncResul
for _, entry := range groupsFoundInLdap.Entries {
var id, e = getObjectGUID(entry)
var objectGUID, e = getObjectGUID(entry)
if e != nil {
errors = append(errors, fmt.Errorf("unable to get objectGUID for group with dn: %s - %s", entry.DN, e))
}
err := upsertLDAPGroup(app, &LDAPGroup{
id: id,
objectGUID: objectGUID,
description: entry.GetAttributeValue("description"),
dn: entry.DN,
cn: entry.GetAttributeValue("cn"),
@ -151,7 +153,7 @@ func syncLdapUsers(app *pocketbase.PocketBase, ldapClient *ldap.Conn) SyncResult
for _, entry := range usersFoundInLdap.Entries {
var id, e = getObjectGUID(entry)
var objectGUID, e = getObjectGUID(entry)
if e != nil {
errors = append(errors, fmt.Errorf("unable to get objectGUID for user with dn: %s - %s", entry.DN, e))
@ -161,7 +163,7 @@ func syncLdapUsers(app *pocketbase.PocketBase, ldapClient *ldap.Conn) SyncResult
givenName: entry.GetAttributeValue("givenName"),
sn: entry.GetAttributeValue("sn"),
accountExpires: entry.GetAttributeValue("accountExpires"),
id: id,
objectGUID: objectGUID,
mail: entry.GetAttributeValue("mail"),
dn: entry.DN,
cn: entry.GetAttributeValue("cn"),

View File

@ -1,12 +1,11 @@
package ldapSync
type LDAPUser struct {
id string
givenName string
sn string
accountExpires string
mail string
objectGUID string
givenName string
sn string
accountExpires string
mail string
dn string
cn string
msSFU30NisDomain string // must be STUVE
@ -14,9 +13,8 @@ type LDAPUser struct {
}
type LDAPGroup struct {
id string
description string
objectGUID string
description string
dn string
cn string
msSFU30NisDomain string

View File

@ -55,9 +55,17 @@ func createLDAPGroupsTable(app *pocketbase.PocketBase) error {
Required: true,
})
// add objectGUID field
form.Schema.AddField(&schema.SchemaField{
Name: "objectGUID",
Type: schema.FieldTypeText,
Required: true,
})
// create index on cn
form.Indexes = types.JsonArray[string]{
"CREATE UNIQUE INDEX idx_ldapGroups ON " + ldapGroupsTableName + " (cn, dn)",
"CREATE UNIQUE INDEX idx_ldapGroups_cn ON " + ldapGroupsTableName + " (cn)",
"CREATE UNIQUE INDEX idx_ldapGroups_objectGUID ON " + ldapSyncLogsTableName + " (objectGUID)",
}
// validate and submit (internally it calls app.Dao().SaveCollection(collection) in a transaction)
@ -130,6 +138,13 @@ func createLDAPUsersTable(app *pocketbase.PocketBase) error {
Presentable: true,
})
// add objectGUID field
form.Schema.AddField(&schema.SchemaField{
Name: "objectGUID",
Type: schema.FieldTypeText,
Required: true,
})
// add distinguished name field
form.Schema.AddField(&schema.SchemaField{
Name: "dn",
@ -171,7 +186,8 @@ func createLDAPUsersTable(app *pocketbase.PocketBase) error {
// create index on username
form.Indexes = types.JsonArray[string]{
"CREATE UNIQUE INDEX idx_ldapUsers ON " + ldapGroupsTableName + " (cn, dn)",
"CREATE UNIQUE INDEX idx_ldapUsers_cn ON " + ldapGroupsTableName + " (cn)",
"CREATE UNIQUE INDEX idx_ldapUsers_objectGUID ON " + ldapSyncLogsTableName + " (objectGUID)",
}
return form.Submit()