Skip to content

validate identity provider form fields before save - #2816

Merged
AlexSanchez-bit merged 7 commits into
release/v12.0.0from
backlog/identity-provider-form-field-validation
Oct 6, 2026
Merged

AlexSanchez-bit merged 7 commits into
release/v12.0.0from
backlog/identity-provider-form-field-validation

Conversation

@AndresTK89

Copy link
Copy Markdown

feat(v12): validate identity provider form fields before save

The IdP create/edit form only checked presence and the backend only
checked format at login, so a mistyped URL, PEM or port reached a
signing user instead of the admin who typed it.

Add src/features/settings/lib/idp-form-validation.ts (pure, no React)
that returns one i18n key per bad field, and wire it into the
UpsertDialog: per-field red border + aria-invalid + message, and the
save button gated on it.

Rules per protocol:

  • name: required, <=64, no spaces (create only; the edit input is
    disabled, so its format must not lock the form out of saving
    anything else)
  • saml: metadataUrl + spAcsUrl are http(s); spEntityId is a URI
    (http/https/urn) on create; certificate and private key must carry
    PEM armour; secret required on create, optional on edit
  • oidc: issuer is https (discovery runs against it); redirectUrl is
    https or an http loopback per RFC 8252 section 7.3; client secret
    required on create
  • ldap: host is a hostname/IP without scheme; port is an integer
    1-65535 (0 is the 389 default, not a mistype); userFilter must
    contain %s and have balanced parentheses; bind password required
    on create

Fix the LDAP port input: it stored Number(e.target.value), so a float
like 389.5 400'd on unmarshal to int. Now Math.trunc(...).

Sources cross-checked: OpenID Connect Core 1.0, RFC 8252 section 7.3,
SAML vendor guides (Cisco IPR, OneStream, Vendasta), and the backend's
own service-bind -> search -> user-bind flow in modules/iam/usecase/idp.go.

41 unit tests in idp-form-validation.test.ts, one per rule.
i18n keys under idp.form.errors.* in en/es/fr/de/it/pt/ru.

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

🛑 AI review — Sensitive area, extra care recommended

This PR touches critical paths or introduces changes the model cannot judge with sufficient confidence. Review carefully before merging.

🛑 architecture (silas-1.7-pro) — high/critical — please review

Summary: IDP save validation adds auth/secret checks and may reject previously valid persisted settings; frontend/backend rules duplicate and can drift.

  • high backend/modules/iam/usecase/idp.go:93 — Strict format validation runs on every save, so editing an existing IDP with legacy invalid settings can fail; gate on changed fields or provide compatibility/rollout.
  • medium backend/modules/iam/usecase/idp_validation.go:19 — Auth/secret format rules are now enforced in the usecase; ensure OIDC https/loopback and PEM checks do not weaken or unexpectedly block existing IdP configurations.
  • medium frontend/src/features/settings/lib/idp-form-validation.ts:1 — Frontend duplicates backend validation rules and documents an IPv6 divergence; keep parity tests or derive from a shared contract to avoid drift.
  • low frontend/src/features/settings/pages/IdentityProvidersPage.tsx:387 — Form validation is coupled to backend error semantics via i18n keys; acceptable, but add contract tests if backend rules change.

🛑 bugs (silas-1.7-pro) — high/critical — please review

Summary: New IDP validation has whitespace normalization gaps, frontend/backend name and IPv6 mismatches, port truncation, and stale docs.

  • high backend/modules/iam/usecase/idp_validation.go:51 — idpIsHTTPURL and related validators trim before checking, but prepareSettings marshals the original settings. A value like ' https://idp.example.com/metadata ' passes and is stored with whitespace, likely failing at login. Normalize fields before saving or validate raw values.
  • medium frontend/src/features/settings/lib/idp-form-validation.ts:143 — commonErrors validates name after trim, but backend build validates req.Name raw with idpNameRe and len. A name with leading or trailing spaces passes the form but is rejected by the backend. Validate the raw name or trim before submit.
  • low frontend/src/features/settings/lib/idp-form-validation.ts:26 — HOST_RE bracketed IPv6 alternative accepts any hex/colon string in brackets, e.g. [1234], but backend validateLDAPFormat requires net.ParseIP. Such values pass the form and fail on save. Use a stricter IPv6 check or align with backend.
  • low frontend/src/features/settings/pages/IdentityProvidersPage.tsx:555 — Port onChange uses Math.trunc(Number(e.target.value) || 0), so fractional input like 389.5 is silently stored as 389 and 0.5 as 0 (default 389). Reject non-integer input instead of truncating.
  • low frontend/src/features/settings/lib/idp-form-validation.md:114 — Doc says backend does not accept bracketed IPv6 hosts, but new validateLDAPFormat accepts [::1] via idpBracketedIPv6Re and net.ParseIP. Update the divergence note.
  • low frontend/src/features/settings/lib/idp-form-validation.md:124 — Doc references validateIDPSettingsFormat in idp_validation.go, but no such function exists in the added file; only validateSAMLFormat, validateOIDCFormat, and validateLDAPFormat are defined. Remove or correct the note.
  • low backend/modules/iam/usecase/idp_validation.go:23 — validateSAMLFormat only checks that BEGIN and END CERTIFICATE markers are present, so a reversed or malformed PEM containing both markers passes. Use a regex requiring BEGIN before END like the frontend CERT_PEM_RE.

🛑 security (silas-1.7-pro) — high/critical — please review

Summary: IDP validation changes touch auth/secret paths; low-risk SAML http allowance found, no information disclosure.

  • low backend/modules/iam/usecase/idp_validation.go:21 — validateSAMLFormat accepts http for MetadataURL and SpACSURL, allowing interception or tampering of SAML metadata/assertions. Require https unless an explicit local test exception is needed.

🔴 go-deps — pending updates

🔍 Discovered 30 Go projects

📦 Dependencies with updates available:

  📁 ./plugins/gcp:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/aws:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/alerts:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/events:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/stats:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/rule-flood-guard:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/o365:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/playground:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/soc-ai:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/sophos:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/azure:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/crowdstrike:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/bitdefender:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/feeds:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/geolocation:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./plugins/soar:
     - github.com/threatwinds/go-sdk: v1.1.37-0.20261001164002-a596631a84c5 → v1.1.37

  📁 ./backend:
     - github.com/threatwinds/go-sdk: v1.1.27-0.20260819160318-c56c250bc585 → v1.1.37

  📁 ./tools/rulecheck:
     - github.com/threatwinds/go-sdk: v1.1.31 → v1.1.37

  📁 ./agent-manager:
     - github.com/threatwinds/go-sdk: v1.1.31 → v1.1.37

  📁 ./log-input:
     - github.com/threatwinds/go-sdk: v1.1.31 → v1.1.37

  📁 ./agent:
     - github.com/threatwinds/go-sdk: v1.1.28 → v1.1.37

  📁 ./collectors/utmstack:
     - github.com/threatwinds/go-sdk: v1.1.31 → v1.1.37

  📁 ./collectors/forwarder:
     - github.com/threatwinds/go-sdk: v1.1.31 → v1.1.37

  📁 ./collectors/as400:
     - github.com/threatwinds/go-sdk: v1.1.31 → v1.1.37

❌ Please update dependencies before merging.

@AlexSanchez-bit AlexSanchez-bit linked an issue Oct 1, 2026 that may be closed by this pull request
2 of 3 tasks
AlexSanchez-bit and others added 6 commits October 2, 2026 10:43
…ad ?? on paren check, port message 0..65535

- HOST_RE now allows [::1] alongside bare hostnames (the form no longer
  blocks IPv6 LDAP hosts; backend parity + the dial gap are documented in
  idp-form-validation.md under "Paridad con el backend").
- userFilter paren balance: each side resolves to a number with its own
  ?? 0. The right-hand ?? in the old one-liner was dead code (!== binds
  before ??), which read as if it guarded a zero-paren filter.
- 7 locales: port error says "between 0 and 65535" to match the validator
  and the backend, where 0 is the default (dialled as 389).
- 4 regression tests: bracketed IPv6 accepted, unbracketed rejected,
  single unclosed paren flagged, zero-paren filter accepted.
@AlexSanchez-bit
AlexSanchez-bit merged commit 31d8d0d into release/v12.0.0 Oct 6, 2026
1 check passed
@AlexSanchez-bit
AlexSanchez-bit deleted the backlog/identity-provider-form-field-validation branch October 6, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

identity providers form lacks of validation of fields

2 participants