feat: enhance LDAP integration with new configuration options and browsing capabilities

This commit is contained in:
Björn Blomberg
2026-04-14 16:07:52 +02:00
parent d6fd50e511
commit 61f33d350a
6 changed files with 631 additions and 163 deletions

View File

@@ -51,8 +51,36 @@ func (d *DB) init() error {
username TEXT NOT NULL UNIQUE,
pass_hash TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'user',
is_ldap BOOLEAN NOT NULL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
);
CREATE TABLE IF NOT EXISTS groups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
is_ldap BOOLEAN NOT NULL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS user_groups (
user_id INTEGER NOT NULL,
group_id INTEGER NOT NULL,
PRIMARY KEY(user_id, group_id),
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY(group_id) REFERENCES groups(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS acl (
id INTEGER PRIMARY KEY AUTOINCREMENT,
path TEXT NOT NULL,
subject_type TEXT NOT NULL CHECK(subject_type IN ('user', 'group')),
subject_id INTEGER NOT NULL,
can_search BOOLEAN NOT NULL DEFAULT 0,
can_view BOOLEAN NOT NULL DEFAULT 0,
can_read BOOLEAN NOT NULL DEFAULT 0,
can_edit BOOLEAN NOT NULL DEFAULT 0,
can_create BOOLEAN NOT NULL DEFAULT 0,
can_delete BOOLEAN NOT NULL DEFAULT 0,
can_move BOOLEAN NOT NULL DEFAULT 0,
UNIQUE(path, subject_type, subject_id)
);
`)
return err
}
@@ -153,3 +181,96 @@ func (d *DB) UserCount() (int, error) {
err := d.sql.QueryRow(`SELECT COUNT(*) FROM users`).Scan(&n)
return n, err
}
// --- LDAP & Roles ---
// CreateOrUpdateLDAPUser inserts or updates an LDAP user (without password, role='user').
func (d *DB) CreateOrUpdateLDAPUser(username string) error {
_, err := d.sql.Exec(`
INSERT INTO users (username, pass_hash, role, is_ldap)
VALUES (?, '', 'user', 1)
ON CONFLICT(username) DO UPDATE SET is_ldap=1;
`, username)
return err
}
// CreateOrUpdateGroup inserts or updates a group (local or LDAP).
func (d *DB) CreateOrUpdateGroup(name string, isLdap bool) error {
ldVal := 0
if isLdap {
ldVal = 1
}
_, err := d.sql.Exec(`
INSERT INTO groups (name, is_ldap)
VALUES (?, ?)
ON CONFLICT(name) DO UPDATE SET is_ldap=excluded.is_ldap;
`, name, ldVal)
return err
}
// --- ACL Methods ---
type ACLEntry struct {
ID int64
Path string
SubjectType string
SubjectID int64
CanSearch bool
CanView bool
CanRead bool
CanEdit bool
CanCreate bool
CanDelete bool
CanMove bool
}
// SetACL inserts or replaces an ACL entry.
func (d *DB) SetACL(entry ACLEntry) error {
_, err := d.sql.Exec(`
INSERT INTO acl (path, subject_type, subject_id, can_search, can_view, can_read, can_edit, can_create, can_delete, can_move)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(path, subject_type, subject_id) DO UPDATE SET
can_search = excluded.can_search,
can_view = excluded.can_view,
can_read = excluded.can_read,
can_edit = excluded.can_edit,
can_create = excluded.can_create,
can_delete = excluded.can_delete,
can_move = excluded.can_move;
`, entry.Path, entry.SubjectType, entry.SubjectID,
entry.CanSearch, entry.CanView, entry.CanRead, entry.CanEdit,
entry.CanCreate, entry.CanDelete, entry.CanMove)
return err
}
// RemoveACL deletes an ACL entry by ID.
func (d *DB) RemoveACL(id int64) error {
_, err := d.sql.Exec(`DELETE FROM acl WHERE id = ?`, id)
return err
}
// GetACLsForPath retrieves all ACL definitions for a specific document or folder.
func (d *DB) GetACLsForPath(path string) ([]ACLEntry, error) {
rows, err := d.sql.Query(`
SELECT id, path, subject_type, subject_id, can_search, can_view, can_read, can_edit, can_create, can_delete, can_move
FROM acl WHERE path = ?
`, path)
if err != nil {
return nil, err
}
defer rows.Close()
var entries []ACLEntry
for rows.Next() {
var e ACLEntry
if err := rows.Scan(
&e.ID, &e.Path, &e.SubjectType, &e.SubjectID,
&e.CanSearch, &e.CanView, &e.CanRead, &e.CanEdit,
&e.CanCreate, &e.CanDelete, &e.CanMove,
); err != nil {
return nil, err
}
entries = append(entries, e)
}
return entries, nil
}