From 1c7861559700992dc627ea306326d4d585995972 Mon Sep 17 00:00:00 2001 From: valentinkolb Date: Sat, 11 May 2024 13:29:56 +0200 Subject: [PATCH] feat(ldapSync): changed ldap-groups and ldap-users id field 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 --- ldapSync/db.go | 58 +++++++++++++++++++++++++++++++++++--------- ldapSync/ldapSync.go | 12 +++++---- ldapSync/models.go | 16 ++++++------ ldapSync/tables.go | 20 +++++++++++++-- 4 files changed, 78 insertions(+), 28 deletions(-) diff --git a/ldapSync/db.go b/ldapSync/db.go index 1fd7fdf..488fe8c 100644 --- a/ldapSync/db.go +++ b/ldapSync/db.go @@ -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 +} diff --git a/ldapSync/ldapSync.go b/ldapSync/ldapSync.go index 3602490..78dba3c 100644 --- a/ldapSync/ldapSync.go +++ b/ldapSync/ldapSync.go @@ -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"), diff --git a/ldapSync/models.go b/ldapSync/models.go index 77c5d55..4623fa6 100644 --- a/ldapSync/models.go +++ b/ldapSync/models.go @@ -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 diff --git a/ldapSync/tables.go b/ldapSync/tables.go index 675f84b..9207660 100644 --- a/ldapSync/tables.go +++ b/ldapSync/tables.go @@ -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()