package ldapSync /* this file contains functions to sync ldap users and groups to the database */ import ( "fmt" "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/forms" "github.com/pocketbase/pocketbase/models" "gitlab.uni-ulm.de/stuve-it/it-tools/backend/logger" ) // upsertLDAPGroup This function creates / updates a record in the ldap groups table func upsertLDAPGroup(app *pocketbase.PocketBase, ldapGroup *LDAPGroup) error { // find ldapGroups table collection, err := app.Dao().FindCollectionByNameOrId(ldapGroupsTableName) if err != nil { return err } var record *models.Record // if record exists, update it if res, _ := app.Dao().FindFirstRecordByFilter( ldapGroupsTableName, "gidNumber = {:gidNumber}", dbx.Params{"gidNumber": ldapGroup.gidNumber}, ); res != nil { record = res } else { // if record does not exist, create it record = models.NewRecord(collection) } form := forms.NewRecordUpsert(app, record) var groups []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) } else { logger.LogErrorF("unable to find %s.memberOf: %s", ldapGroup.cn, groupDn) } } // load data err = form.LoadData(map[string]any{ "gidNumber": ldapGroup.gidNumber, "cn": ldapGroup.cn, "dn": ldapGroup.dn, "description": ldapGroup.description, "memberOf": groups, }) if err != nil { return err } // validate and submit (internally it calls app.Dao().SaveRecord(record) in a transaction) if err := form.Submit(); err != nil { return fmt.Errorf("failed to upsert group with dn: %s - %w", ldapGroup.dn, err) } return nil } // upsertLDAPUser This function creates / updates a record in the ldap users table func upsertLDAPUser(app *pocketbase.PocketBase, ldapUser *LDAPUser) error { // find ldapUsers table collection, err := app.Dao().FindCollectionByNameOrId(ldapUsersTableName) if err != nil { return err } var record *models.Record // if record exists, update it if res, _ := app.Dao().FindFirstRecordByFilter( ldapUsersTableName, "uidNumber = {:uidNumber}", dbx.Params{"uidNumber": ldapUser.uidNumber}, ); res != nil { record = res } else { // if record does not exist, create it record = models.NewRecord(collection) // refresh token key only if new record is created // if record is updated, the token key should not be changed because it is used to authenticate the user // if the token key is changed, the user will be logged out if err := record.RefreshTokenKey(); err != nil { return err } } accountExpires, _ := ldapTimeToUnixTime(ldapUser.accountExpires) var groups []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) } else { logger.LogErrorF("unable to find %s.memberOf: %s", ldapUser.cn, groupDn) } } record.Set("uidNumber", ldapUser.uidNumber) record.Set("givenName", ldapUser.givenName) record.Set("sn", ldapUser.sn) record.Set("username", ldapUser.cn) record.Set("accountExpires", accountExpires) record.Set("email", ldapUser.mail) record.Set("emailVisibility", false) record.Set("verified", true) record.Set("dn", ldapUser.dn) record.Set("cn", ldapUser.cn) record.Set("memberOf", groups) if err := app.Dao().SaveRecord(record); err != nil { return fmt.Errorf("failed to upsert user with dn: %s - %w", ldapUser.dn, err) } return nil } // GetLdapGroupByDN This function returns a record from the ldap groups table by dn. It also expands the memberOf field. func GetLdapGroupByDN(app *pocketbase.PocketBase, dn string) (*models.Record, error) { record, err := app.Dao().FindFirstRecordByFilter( ldapGroupsTableName, "dn = {:dn}", dbx.Params{"dn": dn}, ) 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 } // GetLdapUserByCN This function returns a record from the ldap users table by cn. It also expands the memberOf field. func GetLdapUserByCN(app *pocketbase.PocketBase, cn string) (*models.Record, error) { record, err := app.Dao().FindAuthRecordByUsername(ldapUsersTableName, cn) 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 }