feat: implement T09, T15, T21 — userinfo endpoint, LLDAP export, negative tests

- T09: /userinfo with RS256 JWT validation, scope-filtered claims
- T15: LLDAP→canonical export tool with validation, migration_event telemetry
- T21: Negative test suite (Scenario D) — all 7 unsupported features verified

All go tests passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 02:08:03 +01:00
parent 4097a7de8b
commit 3ee8090a98
9 changed files with 1156 additions and 2 deletions

View File

@@ -170,6 +170,49 @@ func (a *LDAPAdapter) LookupGroups(ctx context.Context, userDN string) ([]domain
return groups, nil
}
// ListUsers returns all user records from the LLDAP directory.
// It performs an LDAP search with filter (objectClass=inetOrgPerson) to list every user,
// then validates each against the canonical LDAP schema.
func (a *LDAPAdapter) ListUsers(ctx context.Context) ([]domain.User, error) {
conn, err := a.dial()
if err != nil {
return nil, err
}
defer conn.Close()
req := ldap.NewSearchRequest(
a.cfg.userBaseDN(),
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0, 0, false,
"(objectClass=inetOrgPerson)",
[]string{"dn", "uid", "cn", "sn", "mail", "memberOf"},
nil,
)
result, err := conn.Search(req)
if err != nil {
return nil, fmt.Errorf("lldap: list users search: %w", err)
}
users := make([]domain.User, 0, len(result.Entries))
for _, entry := range result.Entries {
user := mapEntryToUser(entry)
snap := validator.Snapshot{Users: []domain.User{user}}
report := validator.Validate(snap, validator.ModeProvisioning)
if !report.Passed {
// Non-fatal: return the user with a warning embedded in LDAPAttributes.
if user.LDAPAttributes == nil {
user.LDAPAttributes = make(map[string]string)
}
user.LDAPAttributes["_validation_warning"] = validationSummary(report)
}
users = append(users, user)
}
return users, nil
}
// ValidatePassword returns true when the username and password are valid.
// It opens a second connection and attempts a user bind. Bind failure (wrong
// credentials) returns false, nil. Infrastructure errors return false, err.