Skip to content

feat(auth): add Microsoft Azure Service Principal and Entra ID SSO credential templates - #207

Open
JLCode-tech wants to merge 10 commits into
stagingfrom
feat/azure-auth-templates
Open

feat(auth): add Microsoft Azure Service Principal and Entra ID SSO credential templates#207
JLCode-tech wants to merge 10 commits into
stagingfrom
feat/azure-auth-templates

Conversation

@JLCode-tech

@JLCode-tech JLCode-tech commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds support for Microsoft Azure Service Principal credentials and Entra ID SSO credential templates, including OAuth token refresh lifecycle management and region auto-discovery.

Key Changes

  • Database & Models: Added Alembic migration (v2_156_add_azure_credential_template_fields.py) and updated SystemCredentialTemplate models.
  • Backend Services:
    • Added AzureAuthService, which performs token acquisition and validation via raw OAuth2 requests to login.microsoftonline.com (using the requests library — no msal dependency).
    • Updated CredentialTemplateService and CredentialRefreshService to handle Azure Service Principal and Entra ID secrets/certificates.
    • Added test coverage in test_azure_auth_service.py and test_credential_template_service.py.
  • Frontend UI:
    • Added Azure provider option in CredentialTemplates.tsx, SSOAuthDialog.tsx, and resolveCredStatus.ts.
    • Added Azure region support in CloudRegionSelector.tsx.

https://claude.ai/code/session_01UCsZXDxBsWV2s4kT47DwDW

@JLCode-tech
JLCode-tech changed the base branch from main to staging September 7, 2026 02:24
…O routes, doc SSO/terraform split

F1: normalize naive azure_sso_token_expiry to UTC before comparing in
_test_azure_template — matches get_sso_status / credential_refresh_service
guards; fixes TypeError on SQLite/dev naive round-trip. Adds SQLite
regression test (mutation-verified: fails with the exact TypeError without
the guard).

F2: remove the unwired standalone Azure SSO routes (/azure/sso/initiate,
/azure/sso/poll, /azure/subscriptions), their request models, and the
unused client methods (initiateAzureSSO/pollAzureSSO/listAzureSubscriptions).
The frontend uses the server-side template flow (authenticate-sso/poll-sso,
returns only has_credentials); these paths leaked long-lived access/refresh
tokens in the response body. Regenerated openapi.json + api-generated.ts.

F4: document at the terraform credential-injection site that SSO Azure
templates deliberately inject no credential (SSO is validation/console;
terraform provisioning uses the service-principal secret).

Claude-Session: https://claude.ai/code/session_01UCsZXDxBsWV2s4kT47DwDW
@jgruberf5

Copy link
Copy Markdown
Collaborator

Self-review (cold, adversarial) + fixes applied

Independent cold audit, executed. No blockers — secret-at-rest is correct (azure_client_secret_encrypted, response exposes only has_azure_client_secret), SSO tokens never serialized, migration is single-head/reversible/backfill-safe, authZ holds, and (unlike #199's original) the provider model_validator does not echo the request body. Findings, all now fixed:

F1 (MEDIUM — tz-naive datetime crash) — FIXED. _test_azure_template (credential_template_service.py:132) compared datetime.now(UTC) against a possibly-naive azure_sso_token_expiry — the one of three expiry checks missing the guard its siblings (get_sso_status, credential_refresh_service) have. Reproduced on SQLite: the "Test" button on an SSO template with a naive expiry → TypeError: can't compare offset-naive and offset-aware. Added the identical tzinfo-normalization guard + a SQLite test asserting a clean expired result. Mutation-verified (revert → exact TypeError).

F2 (LOW — token-leaking unused routes) — FIXED (removed). POST /azure/sso/poll returned access_token+refresh_token in the body and POST /azure/subscriptions accepted a bearer token — but grep confirmed the client methods (initiateAzureSSO/pollAzureSSO/listAzureSubscriptions) are wired into no component (the UI uses the server-side authenticate-sso/poll-sso flow that returns only has_credentials). Removed the 3 routes + request models + unwired client methods; regenerated openapi.json (534 paths) + api-generated.ts (--check passes, FE regen is a no-op). The AzureAuthService methods stay (still covered).

F3 (description) — FIXED: corrected the "MSAL" claim (it's raw OAuth2 requests, no msal dep). F4 (INFO) — documented: added a comment that SSO templates deliberately inject no terraform credential (SSO = validation/console; terraform uses the SP secret).

Verified: 74 passed, ruff clean, contract fresh. Note for merge coordination: #206/#208 also touch credentials_service.py — kept mutually mergeable. Ready for review.

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.

3 participants