generated from coulomb/repo-seed
152 lines
5.0 KiB
Go
152 lines
5.0 KiB
Go
package directory_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/netkingdom/flex-auth/internal/adapters/directory"
|
|
"github.com/netkingdom/flex-auth/pkg/api"
|
|
)
|
|
|
|
func TestGraphResolverDetectsTokenOverage(t *testing.T) {
|
|
now := time.Date(2026, 5, 17, 5, 0, 0, 0, time.UTC)
|
|
resolver := directory.GraphResolver{
|
|
Client: graphClient{groups: []directory.ExternalGroup{{ID: "group:platform", DisplayName: "Platform"}}},
|
|
OrganizationRelation: api.OrganizationRelationCustomer,
|
|
MaxAge: time.Hour,
|
|
}
|
|
|
|
got, err := resolver.ResolveGroups(context.Background(), directory.ResolveRequest{
|
|
Subject: api.SubjectRef{ID: "user:alice"},
|
|
Claims: map[string]any{
|
|
"_claim_names": map[string]any{"groups": "src1"},
|
|
},
|
|
Now: now,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("ResolveGroups: %v", err)
|
|
}
|
|
if !got.Overage.Detected || got.Overage.Claim != "_claim_names.groups" {
|
|
t.Fatalf("overage = %+v", got.Overage)
|
|
}
|
|
if len(got.Groups) != 1 || got.Groups[0].Source != directory.SourceGraph {
|
|
t.Fatalf("groups = %+v", got.Groups)
|
|
}
|
|
if got.Freshness.ExpiresAt != now.Add(time.Hour) {
|
|
t.Fatalf("freshness = %+v", got.Freshness)
|
|
}
|
|
}
|
|
|
|
func TestSCIMResolverCarriesDescriptorProvenance(t *testing.T) {
|
|
descriptor := caringDescriptor()
|
|
resolver := directory.SCIMResolver{
|
|
Client: scimClient{groups: []directory.ExternalGroup{{ID: "group:customers", Descriptor: descriptor}}},
|
|
OrganizationRelation: api.OrganizationRelationCustomer,
|
|
}
|
|
|
|
got, err := resolver.ResolveGroups(context.Background(), directory.ResolveRequest{Subject: api.SubjectRef{ID: "user:alice"}})
|
|
if err != nil {
|
|
t.Fatalf("ResolveGroups: %v", err)
|
|
}
|
|
if got.Groups[0].Descriptor == nil || got.Groups[0].Descriptor.CanonicalRole != api.CanonicalRoleDoer {
|
|
t.Fatalf("descriptor = %+v", got.Groups[0].Descriptor)
|
|
}
|
|
if got.Groups[0].Claim != "groups" {
|
|
t.Fatalf("claim = %q", got.Groups[0].Claim)
|
|
}
|
|
}
|
|
|
|
func TestLDAPResolverUsesDistinguishedNameClaim(t *testing.T) {
|
|
client := ldapClient{groups: []directory.ExternalGroup{{ID: "cn=platform,ou=groups,dc=example,dc=test"}}}
|
|
resolver := directory.LDAPResolver{Client: client}
|
|
|
|
_, err := resolver.ResolveGroups(context.Background(), directory.ResolveRequest{
|
|
Subject: api.SubjectRef{ID: "user:alice"},
|
|
Claims: map[string]any{"distinguished_name": "cn=alice,ou=users,dc=example,dc=test"},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("ResolveGroups: %v", err)
|
|
}
|
|
if client.lastDN != "" {
|
|
t.Fatal("value receiver should not update original client")
|
|
}
|
|
}
|
|
|
|
func TestMergeResultsAndApplyToSubject(t *testing.T) {
|
|
subject := api.SubjectRef{ID: "user:alice"}
|
|
enrichment := directory.MergeResults(subject,
|
|
directory.ResolveResult{
|
|
Source: directory.SourceGraph,
|
|
Groups: []directory.GroupGrant{
|
|
{ID: "group:b", Source: directory.SourceGraph},
|
|
{ID: "group:a", Source: directory.SourceGraph, Descriptor: caringDescriptor()},
|
|
},
|
|
Overage: directory.OverageMetadata{Detected: true, Claim: "_claim_names.groups"},
|
|
},
|
|
directory.ResolveResult{
|
|
Source: directory.SourceKeycloak,
|
|
Groups: []directory.GroupGrant{
|
|
{ID: "group:a", Source: directory.SourceKeycloak},
|
|
},
|
|
Roles: []directory.RoleGrant{
|
|
{Role: api.CanonicalRoleDoer, Source: directory.SourceKeycloak},
|
|
},
|
|
},
|
|
)
|
|
|
|
if len(enrichment.Groups) != 2 || enrichment.Groups[0] != "group:a" || enrichment.Groups[1] != "group:b" {
|
|
t.Fatalf("groups = %+v", enrichment.Groups)
|
|
}
|
|
if len(enrichment.Roles) != 1 || enrichment.Roles[0] != api.CanonicalRoleDoer {
|
|
t.Fatalf("roles = %+v", enrichment.Roles)
|
|
}
|
|
if len(enrichment.Descriptors) != 1 || len(enrichment.Overage) != 1 {
|
|
t.Fatalf("enrichment = %+v", enrichment)
|
|
}
|
|
|
|
applied := directory.ApplyToSubject(api.Subject{ID: "user:alice", Groups: []string{"group:existing"}}, enrichment)
|
|
if len(applied.Groups) != 3 || applied.Metadata["directory_overage"] == nil {
|
|
t.Fatalf("applied subject = %+v", applied)
|
|
}
|
|
}
|
|
|
|
func caringDescriptor() *api.CaringAccessDescriptor {
|
|
return &api.CaringAccessDescriptor{
|
|
ID: "descriptor:directory",
|
|
Profile: api.CaringProfileCaring040RC2,
|
|
SubjectType: api.SubjectTypeGroup,
|
|
OrganizationRelation: api.OrganizationRelationCustomer,
|
|
CanonicalRole: api.CanonicalRoleDoer,
|
|
Scope: api.CaringScope{Level: api.ScopeLevelTenant, ID: "tenant:alpha"},
|
|
Planes: []api.Plane{api.PlaneIdentity},
|
|
Capabilities: []api.Capability{api.CapabilityUse},
|
|
}
|
|
}
|
|
|
|
type graphClient struct {
|
|
groups []directory.ExternalGroup
|
|
}
|
|
|
|
func (c graphClient) GetMemberGroups(context.Context, string) ([]directory.ExternalGroup, directory.OverageMetadata, error) {
|
|
return c.groups, directory.OverageMetadata{Total: len(c.groups)}, nil
|
|
}
|
|
|
|
type scimClient struct {
|
|
groups []directory.ExternalGroup
|
|
}
|
|
|
|
func (c scimClient) GroupsForUser(context.Context, string) ([]directory.ExternalGroup, error) {
|
|
return c.groups, nil
|
|
}
|
|
|
|
type ldapClient struct {
|
|
groups []directory.ExternalGroup
|
|
lastDN string
|
|
}
|
|
|
|
func (c ldapClient) GroupsForDN(_ context.Context, dn string) ([]directory.ExternalGroup, error) {
|
|
c.lastDN = dn
|
|
return c.groups, nil
|
|
}
|