feat(authentik): add AuthentikUser and AuthentikConfig types
Introduce core types for the Authentik forward-auth integration: - AuthentikConfig with Issuer, ClientID, TrustedProxy, PublicPaths - AuthentikUser with Username, Email, Name, UID, Groups, Entitlements, JWT - HasGroup helper for group membership checks Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
17ae94530d
commit
6cd3b7e7e0
2 changed files with 130 additions and 0 deletions
42
authentik.go
Normal file
42
authentik.go
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package api
|
||||
|
||||
// AuthentikConfig holds settings for the Authentik forward-auth integration.
|
||||
type AuthentikConfig struct {
|
||||
// Issuer is the OIDC issuer URL (e.g. https://auth.example.com/application/o/my-app/).
|
||||
Issuer string
|
||||
|
||||
// ClientID is the OAuth2 client identifier.
|
||||
ClientID string
|
||||
|
||||
// TrustedProxy enables reading X-authentik-* headers set by a reverse proxy.
|
||||
// When false, headers are ignored to prevent spoofing from untrusted sources.
|
||||
TrustedProxy bool
|
||||
|
||||
// PublicPaths lists additional paths that do not require authentication.
|
||||
// /health and /swagger are always public.
|
||||
PublicPaths []string
|
||||
}
|
||||
|
||||
// AuthentikUser represents an authenticated user extracted from Authentik
|
||||
// forward-auth headers or a validated JWT.
|
||||
type AuthentikUser struct {
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
UID string `json:"uid"`
|
||||
Groups []string `json:"groups,omitempty"`
|
||||
Entitlements []string `json:"entitlements,omitempty"`
|
||||
JWT string `json:"-"`
|
||||
}
|
||||
|
||||
// HasGroup reports whether the user belongs to the named group.
|
||||
func (u *AuthentikUser) HasGroup(group string) bool {
|
||||
for _, g := range u.Groups {
|
||||
if g == group {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
88
authentik_test.go
Normal file
88
authentik_test.go
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package api_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "forge.lthn.ai/core/go-api"
|
||||
)
|
||||
|
||||
// ── AuthentikUser ──────────────────────────────────────────────────────
|
||||
|
||||
func TestAuthentikUser_Good(t *testing.T) {
|
||||
u := api.AuthentikUser{
|
||||
Username: "alice",
|
||||
Email: "alice@example.com",
|
||||
Name: "Alice Smith",
|
||||
UID: "abc-123",
|
||||
Groups: []string{"editors", "admins"},
|
||||
Entitlements: []string{"premium"},
|
||||
JWT: "tok.en.here",
|
||||
}
|
||||
|
||||
if u.Username != "alice" {
|
||||
t.Fatalf("expected Username=%q, got %q", "alice", u.Username)
|
||||
}
|
||||
if u.Email != "alice@example.com" {
|
||||
t.Fatalf("expected Email=%q, got %q", "alice@example.com", u.Email)
|
||||
}
|
||||
if u.Name != "Alice Smith" {
|
||||
t.Fatalf("expected Name=%q, got %q", "Alice Smith", u.Name)
|
||||
}
|
||||
if u.UID != "abc-123" {
|
||||
t.Fatalf("expected UID=%q, got %q", "abc-123", u.UID)
|
||||
}
|
||||
if len(u.Groups) != 2 || u.Groups[0] != "editors" {
|
||||
t.Fatalf("expected Groups=[editors admins], got %v", u.Groups)
|
||||
}
|
||||
if len(u.Entitlements) != 1 || u.Entitlements[0] != "premium" {
|
||||
t.Fatalf("expected Entitlements=[premium], got %v", u.Entitlements)
|
||||
}
|
||||
if u.JWT != "tok.en.here" {
|
||||
t.Fatalf("expected JWT=%q, got %q", "tok.en.here", u.JWT)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthentikUserHasGroup_Good(t *testing.T) {
|
||||
u := api.AuthentikUser{
|
||||
Groups: []string{"editors", "admins"},
|
||||
}
|
||||
|
||||
if !u.HasGroup("admins") {
|
||||
t.Fatal("expected HasGroup(admins) = true")
|
||||
}
|
||||
if !u.HasGroup("editors") {
|
||||
t.Fatal("expected HasGroup(editors) = true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthentikUserHasGroup_Bad_Empty(t *testing.T) {
|
||||
u := api.AuthentikUser{}
|
||||
|
||||
if u.HasGroup("admins") {
|
||||
t.Fatal("expected HasGroup(admins) = false for empty user")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthentikConfig_Good(t *testing.T) {
|
||||
cfg := api.AuthentikConfig{
|
||||
Issuer: "https://auth.example.com",
|
||||
ClientID: "my-client",
|
||||
TrustedProxy: true,
|
||||
PublicPaths: []string{"/public", "/docs"},
|
||||
}
|
||||
|
||||
if cfg.Issuer != "https://auth.example.com" {
|
||||
t.Fatalf("expected Issuer=%q, got %q", "https://auth.example.com", cfg.Issuer)
|
||||
}
|
||||
if cfg.ClientID != "my-client" {
|
||||
t.Fatalf("expected ClientID=%q, got %q", "my-client", cfg.ClientID)
|
||||
}
|
||||
if !cfg.TrustedProxy {
|
||||
t.Fatal("expected TrustedProxy=true")
|
||||
}
|
||||
if len(cfg.PublicPaths) != 2 {
|
||||
t.Fatalf("expected 2 public paths, got %d", len(cfg.PublicPaths))
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue