stuve-it-backend/ldapSync/db.go

160 lines
4.5 KiB
Go

package ldapSync
/*
this file contains functions to sync ldap users and groups to the database
*/
import (
"fmt"
"git.stuve.uni-ulm.de/StuVe-IT/stuve-it-backend/logger"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/forms"
"github.com/pocketbase/pocketbase/models"
)
// 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,
"id = {:id}",
dbx.Params{"id": ldapGroup.id},
); 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{
"id": ldapGroup.id,
"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,
"id = {:id}",
dbx.Params{"id": ldapUser.id},
); 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("id", ldapUser.id)
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
}