forked from Nixius/authelia
1
0
Fork 0
ATLAS/docker/ss-atlas/internal/ldap/graphql.go

115 lines
2.6 KiB
Go

package ldap
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"sync"
"time"
)
type gqlClient struct {
baseURL string
username string
password string
token string
mu sync.Mutex
client *http.Client
}
type gqlRequest struct {
Query string `json:"query"`
Variables map[string]any `json:"variables,omitempty"`
}
type gqlResponse struct {
Data json.RawMessage `json:"data"`
Errors []struct {
Message string `json:"message"`
} `json:"errors"`
}
func newGQLClient(baseURL, username, password string) *gqlClient {
return &gqlClient{
baseURL: baseURL,
username: username,
password: password,
client: &http.Client{Timeout: 10 * time.Second},
}
}
func (g *gqlClient) authenticate() error {
body, _ := json.Marshal(map[string]string{
"username": g.username,
"password": g.password,
})
resp, err := g.client.Post(g.baseURL+"/auth/simple/login", "application/json", bytes.NewReader(body))
if err != nil {
return fmt.Errorf("lldap auth: %w", err)
}
defer resp.Body.Close()
var result struct {
Token string `json:"token"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return fmt.Errorf("lldap auth decode: %w", err)
}
if result.Token == "" {
return fmt.Errorf("lldap auth: empty token")
}
g.token = result.Token
return nil
}
func (g *gqlClient) exec(query string, variables map[string]any) (json.RawMessage, error) {
g.mu.Lock()
defer g.mu.Unlock()
if g.token == "" {
if err := g.authenticate(); err != nil {
return nil, err
}
}
data, err := g.doRequest(query, variables)
if err != nil {
if err := g.authenticate(); err != nil {
return nil, err
}
data, err = g.doRequest(query, variables)
if err != nil {
return nil, err
}
}
return data, nil
}
func (g *gqlClient) doRequest(query string, variables map[string]any) (json.RawMessage, error) {
reqBody, _ := json.Marshal(gqlRequest{Query: query, Variables: variables})
req, err := http.NewRequest("POST", g.baseURL+"/api/graphql", bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+g.token)
resp, err := g.client.Do(req)
if err != nil {
return nil, fmt.Errorf("lldap graphql: %w", err)
}
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
var gqlResp gqlResponse
if err := json.Unmarshal(respBody, &gqlResp); err != nil {
return nil, fmt.Errorf("lldap graphql decode: %w", err)
}
if len(gqlResp.Errors) > 0 {
return nil, fmt.Errorf("lldap graphql: %s", gqlResp.Errors[0].Message)
}
return gqlResp.Data, nil
}