Files
signoz/pkg/modules/authdomain/implauthdomain/module.go
Pandey 5b3b2865d1 fix(authtypes): restructure auth domain payload into a kind/spec envelope (#12472)
#### Description

- Moves the endpoints to `/api/v2/auth_domains` and removes the
`/api/v1/domains` routes — the request/response shapes changed, so they
live behind new paths instead of breaking v1 in place.
- Restructures the auth domain payload: `config` is now a `{kind, spec}`
discriminated envelope (same pattern as `RuleThresholdData` /
`EvaluationEnvelope`), replacing the old `ssoType` discriminator with
`samlConfig` / `googleAuthConfig` / `oidcConfig` sibling fields;
`ssoEnabled` and `roleMapping` move to the root as `enabled` and
`roleMapping`.
- Renames the provider kind `google_auth` → `google`, and the SAML keys
to metadata-consistent ones: `samlEntity` → `entityId`, `samlIdp` →
`location`, `samlCert` → `certificate`.
- Migrates the persisted documents too: a new sqlmigration rewrites
`auth_domain.data` into `{enabled, config: {kind, spec}, roleMapping}`,
so all legacy-shape code (storable twins, `google_auth` translation,
per-kind conversion switches) is deleted; the remaining per-kind wiring
lives in a single variant registry that `UnmarshalJSON`,
`JSONSchemaOneOf` and the discriminator mapping derive from.
- `AuthDomain` exposes the domain shape (`Enabled()`, `Kind()`,
`Config()`, `RoleMapping()`, typed spec accessors) instead of the
persisted document; `config` presence is enforced explicitly on
Postable/Updatable (the old PUT path never enforced it and could poison
a row).
- Secret fields (`clientSecret`, `serviceAccountJson`) are `format:
password` in the schema, and `GoogleConfig` loses the unused
`redirectURI` (the migration strips it from persisted documents).
- Frontend: regenerated client is a clean discriminated union; both
directions of the envelope↔form translation live in
`CreateEdit.utils.ts` with an explicit kind→provider mapping (no
cross-enum casts).
- The generated OpenAPI spec carries a real `discriminator`; the
kind/spec envelope pattern itself is documented generically in #12494,
and this PR only keeps the auth domain worked example in `types.md` in
step with the refactored types.
- Updates the google authn integration tests (#12486) to the new API,
and adds parametrized POST→GET roundtrip cases pinning the response
contract per kind (server-side defaulting, role-name normalization, null
maps) plus enforcement-toggle update coverage.

#### Issues closed by this PR

Closes SigNoz/platform-pod#2268

#### Additional Information

- Breaking change: `/api/v1/domains` is gone; the resource is now
`/api/v2/auth_domains` with the new shape. Login and SSO callback flows
are behaviorally unchanged, and existing rows are migrated in place at
startup.
- The `AuthNProvider` rename also surfaces in `/api/v2/sessions/context`
responses (`provider: "google"`) — the login page only consumes the
callback `url` — and in the reported stats key, which changes from
`authdomain.google_auth.count` to `authdomain.google.count`.
- Verified: `make go-test`, Go lint, frontend jest suites for
AuthDomain, `pnpm build`, `pnpm tsgo --noEmit`, and the full
`callbackauthn` domain suites (17 tests: roundtrip pins, the enforcement
toggle, and the google E2E flows) against a container rebuilt from this
branch — including a live run of the data migration over legacy-format
rows.
2026-08-13 16:39:27 +00:00

97 lines
2.8 KiB
Go

package implauthdomain
import (
"context"
"github.com/SigNoz/signoz/pkg/authn"
"github.com/SigNoz/signoz/pkg/authz"
"github.com/SigNoz/signoz/pkg/modules/authdomain"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/SigNoz/signoz/pkg/valuer"
)
type module struct {
store authtypes.AuthDomainStore
authNs map[authtypes.AuthNProvider]authn.AuthN
authz authz.AuthZ
}
func NewModule(store authtypes.AuthDomainStore, authNs map[authtypes.AuthNProvider]authn.AuthN, authz authz.AuthZ) authdomain.Module {
return &module{store: store, authNs: authNs, authz: authz}
}
func (module *module) Create(ctx context.Context, domain *authtypes.AuthDomain) error {
if err := module.validateRoleMapping(ctx, domain); err != nil {
return err
}
return module.store.Create(ctx, domain)
}
func (module *module) Get(ctx context.Context, id valuer.UUID) (*authtypes.AuthDomain, error) {
return module.store.Get(ctx, id)
}
func (module *module) GetAuthNProviderInfo(ctx context.Context, domain *authtypes.AuthDomain) *authtypes.AuthNProviderInfo {
if callbackAuthN, ok := module.authNs[domain.Kind()].(authn.CallbackAuthN); ok {
return callbackAuthN.ProviderInfo(ctx, domain)
}
return &authtypes.AuthNProviderInfo{}
}
func (module *module) GetByOrgIDAndID(ctx context.Context, orgID valuer.UUID, id valuer.UUID) (*authtypes.AuthDomain, error) {
return module.store.GetByOrgIDAndID(ctx, orgID, id)
}
func (module *module) GetByNameAndOrgID(ctx context.Context, name string, orgID valuer.UUID) (*authtypes.AuthDomain, error) {
return module.store.GetByNameAndOrgID(ctx, name, orgID)
}
func (module *module) Delete(ctx context.Context, orgID valuer.UUID, id valuer.UUID) error {
return module.store.Delete(ctx, orgID, id)
}
func (module *module) ListByOrgID(ctx context.Context, orgID valuer.UUID) ([]*authtypes.AuthDomain, error) {
return module.store.ListByOrgID(ctx, orgID)
}
func (module *module) Update(ctx context.Context, domain *authtypes.AuthDomain) error {
if err := module.validateRoleMapping(ctx, domain); err != nil {
return err
}
return module.store.Update(ctx, domain)
}
func (module *module) Collect(ctx context.Context, orgID valuer.UUID) (map[string]any, error) {
domains, err := module.store.ListByOrgID(ctx, orgID)
if err != nil {
return nil, err
}
stats := make(map[string]any)
for _, domain := range domains {
key := "authdomain." + domain.Kind().StringValue() + ".count"
if value, ok := stats[key]; ok {
stats[key] = value.(int64) + 1
} else {
stats[key] = int64(1)
}
}
stats["authdomain.count"] = len(domains)
return stats, nil
}
func (module *module) validateRoleMapping(ctx context.Context, domain *authtypes.AuthDomain) error {
roleNames := domain.RoleMapping().RoleNames()
if len(roleNames) == 0 {
return nil
}
_, err := module.authz.ListByOrgIDAndNames(ctx, domain.StorableAuthDomain().OrgID, roleNames)
return err
}