forked from Nixius/authelia
123 lines
3.5 KiB
Go
123 lines
3.5 KiB
Go
package ldap
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
)
|
|
|
|
func (c *Client) getGroupID(groupName string) (int, error) {
|
|
query := `query { groups { id displayName } }`
|
|
data, err := c.gql.exec(query, nil)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
var result struct {
|
|
Groups []struct {
|
|
ID int `json:"id"`
|
|
DisplayName string `json:"displayName"`
|
|
} `json:"groups"`
|
|
}
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
for _, g := range result.Groups {
|
|
if g.DisplayName == groupName {
|
|
return g.ID, nil
|
|
}
|
|
}
|
|
return 0, fmt.Errorf("group %s not found", groupName)
|
|
}
|
|
|
|
// EnsureGroup creates the group in LLDAP if it does not exist (e.g. "customers").
|
|
// Idempotent: no-op if group already exists.
|
|
func (c *Client) EnsureGroup(displayName string) error {
|
|
_, err := c.getGroupID(displayName)
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
// Group missing: try to create via GraphQL (LLDAP mutation uses "name").
|
|
query := `mutation($name: String!) { createGroup(name: $name) { id } }`
|
|
data, err := c.gql.exec(query, map[string]any{"name": displayName})
|
|
if err != nil {
|
|
log.Printf("lldap createGroup %q failed: %v (create group manually in LLDAP admin if needed)", displayName, err)
|
|
return err
|
|
}
|
|
var out struct {
|
|
CreateGroup struct {
|
|
ID int `json:"id"`
|
|
} `json:"createGroup"`
|
|
}
|
|
if err := json.Unmarshal(data, &out); err != nil {
|
|
log.Printf("lldap createGroup %q response unmarshal: %v", displayName, err)
|
|
return err
|
|
}
|
|
if out.CreateGroup.ID == 0 {
|
|
log.Printf("lldap createGroup %q returned no id", displayName)
|
|
return fmt.Errorf("createGroup %s: no id in response", displayName)
|
|
}
|
|
log.Printf("lldap created group %q (id=%d)", displayName, out.CreateGroup.ID)
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) AddToGroup(username, groupName string) error {
|
|
if err := c.EnsureGroup(groupName); err != nil {
|
|
return fmt.Errorf("ensure group %s: %w", groupName, err)
|
|
}
|
|
groupID, err := c.getGroupID(groupName)
|
|
if err != nil {
|
|
return fmt.Errorf("resolve group %s: %w", groupName, err)
|
|
}
|
|
|
|
query := `mutation($userId: String!, $groupId: Int!) { addUserToGroup(userId: $userId, groupId: $groupId) { ok } }`
|
|
_, err = c.gql.exec(query, map[string]any{"userId": username, "groupId": groupID})
|
|
if err != nil {
|
|
return fmt.Errorf("add %s to group %s: %w", username, groupName, err)
|
|
}
|
|
log.Printf("added %s to group %s", username, groupName)
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) RemoveFromGroup(username, groupName string) error {
|
|
groupID, err := c.getGroupID(groupName)
|
|
if err != nil {
|
|
return fmt.Errorf("resolve group %s: %w", groupName, err)
|
|
}
|
|
|
|
query := `mutation($userId: String!, $groupId: Int!) { removeUserFromGroup(userId: $userId, groupId: $groupId) { ok } }`
|
|
_, err = c.gql.exec(query, map[string]any{"userId": username, "groupId": groupID})
|
|
if err != nil {
|
|
return fmt.Errorf("remove %s from group %s: %w", username, groupName, err)
|
|
}
|
|
log.Printf("removed %s from group %s", username, groupName)
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) IsInGroup(username, groupName string) (bool, error) {
|
|
query := `query($userId: String!) { user(userId: $userId) { groups { displayName } } }`
|
|
data, err := c.gql.exec(query, map[string]any{"userId": username})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
var result struct {
|
|
User struct {
|
|
Groups []struct {
|
|
DisplayName string `json:"displayName"`
|
|
} `json:"groups"`
|
|
} `json:"user"`
|
|
}
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
return false, err
|
|
}
|
|
|
|
for _, g := range result.User.Groups {
|
|
if g.DisplayName == groupName {
|
|
return true, nil
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|