diff --git a/src/internal/adapters/lldap/adapter.go b/src/internal/adapters/lldap/adapter.go index 038ec93..6121cca 100644 --- a/src/internal/adapters/lldap/adapter.go +++ b/src/internal/adapters/lldap/adapter.go @@ -316,8 +316,11 @@ func mapEntryToUser(entry *ldap.Entry) domain.User { func identityEnvelopeFromGroups(groups []string) (string, []string) { tenants := make(map[string]bool) admins := make(map[string]bool) + platformOperator := false for _, group := range groups { switch { + case group == "net-kingdom-admins": + platformOperator = true case strings.HasPrefix(group, "tenant:") && strings.HasSuffix(group, ":users"): tenants[strings.TrimSuffix(group, ":users")] = true case strings.HasPrefix(group, "tenant:") && strings.HasSuffix(group, ":admins"): @@ -326,6 +329,12 @@ func identityEnvelopeFromGroups(groups []string) (string, []string) { admins[tenant] = true } } + // Preserve the established bootstrap/platform-root group as an explicit + // platform control-plane identity. Tenant envelopes must never narrow or + // ambiguously reinterpret platform authority. + if platformOperator { + return "tenant:platform", []string{"user", "platform-operator"} + } if len(tenants) != 1 { return "", []string{} } diff --git a/src/internal/adapters/lldap/adapter_test.go b/src/internal/adapters/lldap/adapter_test.go index dce1571..d94bd5f 100644 --- a/src/internal/adapters/lldap/adapter_test.go +++ b/src/internal/adapters/lldap/adapter_test.go @@ -167,6 +167,31 @@ func TestLookupUser_IgnoresAmbiguousTenantGroups(t *testing.T) { } } +func TestLookupUser_MapsEstablishedPlatformAdminGroup(t *testing.T) { + conn := &mockConn{ + searchFn: func(req *ldap.SearchRequest) (*ldap.SearchResult, error) { + return singleEntryResult( + "uid=platform-root,ou=people,dc=test,dc=local", + "platform-root", "Platform", "Root", "root@example.test", + []string{ + "cn=net-kingdom-admins,ou=groups,dc=test,dc=local", + "cn=net-kingdom-users,ou=groups,dc=test,dc=local", + }, + ), nil + }, + } + user, err := makeAdapter(testConfig(), conn).LookupUser(context.Background(), "platform-root") + if err != nil { + t.Fatal(err) + } + if user.Tenant != "tenant:platform" { + t.Fatalf("tenant = %q", user.Tenant) + } + if len(user.Roles) != 2 || user.Roles[1] != "platform-operator" { + t.Fatalf("roles = %v", user.Roles) + } +} + func TestLookupUser_DisplayName_FallsBackToSN(t *testing.T) { dn := "uid=bob,ou=users,dc=netkingdom,dc=local" conn := &mockConn{