Skip to content

Commit 1ed2fde

Browse files
committed
feat(auth): add ADFS SSO authorization provider
Add ADFS (Active Directory Federation Services) as a new SSO provider, enabling enterprise SSO login for organizations using on-prem or federated ADFS deployments. Core changes: - ADFS provider config (sso_adfs_*), bootstrap, and ID token-based user info extraction (ADFS doesn't support GET on userinfo endpoint) - UPN normalization for DOMAIN\user, plain username, and email formats - OAuth error callback handling with RFC 6749 error code mapping - Email validation in admin privilege evaluation to prevent bypass - Auto-disable feature flag for unconfigured SSO providers - ADFS tutorial documentation and comprehensive test coverage Co-authored-by: Santhana Krishnan <a.santhana.k@gmail.com> Closes #3532 Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
1 parent 6c567f7 commit 1ed2fde

16 files changed

Lines changed: 2464 additions & 78 deletions

File tree

.env.example

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,18 @@ OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
11161116
# SSO_ENTRA_CLIENT_SECRET=your-entra-client-secret-value
11171117
# SSO_ENTRA_TENANT_ID=your-entra-tenant-id
11181118

1119+
# ADFS Configuration
1120+
# SSO_ADFS_ENABLED=false
1121+
# SSO_ADFS_DISPLAY_NAME=your-value
1122+
# SSO_ADFS_CLIENT_ID=your-adfs-client-id
1123+
# SSO_ADFS_CLIENT_SECRET=your-adfs-client-secret # pragma: allowlist secret
1124+
# SSO_ADFS_AUTHORIZATION_URL=https://adfs.ds.example.net/adfs/oauth2/authorize
1125+
# SSO_ADFS_TOKEN_URL=https://adfs.ds.example.net/adfs/oauth2/token
1126+
# SSO_ADFS_ISSUER=https://adfs.ds.example.net/adfs
1127+
# SSO_ADFS_SCOPE=openid profile email
1128+
# Fallback: Default email domain for ADFS when UPN is plain username (e.g., converts 'user123' to 'user123@company.com')
1129+
# SSO_ADFS_DEFAULT_EMAIL_DOMAIN=company.com
1130+
11191131
# ─────────────────────────────────────────────────────────────────────────────
11201132
# EntraID Role Mapping Configuration
11211133
# ─────────────────────────────────────────────────────────────────────────────
@@ -1177,6 +1189,16 @@ OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
11771189
# Keep local admin authentication when SSO is enabled
11781190
# SSO_PRESERVE_ADMIN_AUTH=true
11791191

1192+
# Bootstrap Behavior: Auto-disable providers not in environment config
1193+
# When true: Providers configured in database but missing from SSO_*_ENABLED
1194+
# environment variables will be automatically disabled during bootstrap.
1195+
# This enforces environment config as the single source of truth.
1196+
# When false: Manually configured providers in database are preserved (default).
1197+
# IMPORTANT: Enabling this may be a breaking change for existing deployments
1198+
# with manually configured SSO providers.
1199+
# Default: false (backward compatible)
1200+
# SSO_AUTO_DISABLE_UNCONFIGURED_PROVIDERS=false
1201+
11801202
# SSO Issuers Configuration
11811203
# Optional JSON array of issuer URLs for SSO providers
11821204
# Example: ["https://idp1.example.com", "https://idp2.example.com"]

.secrets.baseline

Lines changed: 22 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"files": "^.secrets.baseline$",
44
"lines": null
55
},
6-
"generated_at": "2026-04-01T19:01:30Z",
6+
"generated_at": "2026-04-02T01:14:31Z",
77
"plugins_used": [
88
{
99
"name": "AWSKeyDetector"
@@ -172,7 +172,7 @@
172172
"hashed_secret": "910fbf00f58e9bcb095ea26a75cc1d9a3355e671",
173173
"is_secret": false,
174174
"is_verified": false,
175-
"line_number": 1165,
175+
"line_number": 1177,
176176
"type": "Secret Keyword",
177177
"verified_result": null
178178
}
@@ -788,63 +788,63 @@
788788
"hashed_secret": "25ab86bed149ca6ca9c1c0d5db7c9a91388ddeab",
789789
"is_secret": false,
790790
"is_verified": false,
791-
"line_number": 955,
791+
"line_number": 956,
792792
"type": "Basic Auth Credentials",
793793
"verified_result": null
794794
},
795795
{
796796
"hashed_secret": "d08f88df745fa7950b104e4a707a31cfce7b5841",
797797
"is_secret": false,
798798
"is_verified": false,
799-
"line_number": 1055,
799+
"line_number": 1056,
800800
"type": "Secret Keyword",
801801
"verified_result": null
802802
},
803803
{
804804
"hashed_secret": "7288edd0fc3ffcbe93a0cf06e3568e28521687bc",
805805
"is_secret": false,
806806
"is_verified": false,
807-
"line_number": 1058,
807+
"line_number": 1059,
808808
"type": "Secret Keyword",
809809
"verified_result": null
810810
},
811811
{
812812
"hashed_secret": "8674c9b302d20800e4ab3808f139704d8641a6e3",
813813
"is_secret": false,
814814
"is_verified": false,
815-
"line_number": 1224,
815+
"line_number": 1225,
816816
"type": "Secret Keyword",
817817
"verified_result": null
818818
},
819819
{
820820
"hashed_secret": "cff0d14e4337fa8bdb68dfa906f04b0df6fad72f",
821821
"is_secret": false,
822822
"is_verified": false,
823-
"line_number": 1263,
823+
"line_number": 1264,
824824
"type": "Secret Keyword",
825825
"verified_result": null
826826
},
827827
{
828828
"hashed_secret": "f865b53623b121fd34ee5426c792e5c33af8c227",
829829
"is_secret": false,
830830
"is_verified": false,
831-
"line_number": 1311,
831+
"line_number": 1312,
832832
"type": "Secret Keyword",
833833
"verified_result": null
834834
},
835835
{
836836
"hashed_secret": "acde39840735314af1300688b6c2324ea89770a3",
837837
"is_secret": false,
838838
"is_verified": false,
839-
"line_number": 1406,
839+
"line_number": 1407,
840840
"type": "Secret Keyword",
841841
"verified_result": null
842842
},
843843
{
844844
"hashed_secret": "fa9beb99e4029ad5a6615399e7bbae21356086b3",
845845
"is_secret": false,
846846
"is_verified": false,
847-
"line_number": 1754,
847+
"line_number": 1755,
848848
"type": "Secret Keyword",
849849
"verified_result": null
850850
}
@@ -2884,22 +2884,6 @@
28842884
}
28852885
],
28862886
"docs/docs/manage/sso-github-tutorial.md": [
2887-
{
2888-
"hashed_secret": "15a1549fd810c90cbb12e8e007eb6c7b18627261",
2889-
"is_secret": false,
2890-
"is_verified": false,
2891-
"line_number": 74,
2892-
"type": "Secret Keyword",
2893-
"verified_result": null
2894-
},
2895-
{
2896-
"hashed_secret": "e175c6f5f2a92e8623bd9a4820edb4e8c1b0fd10",
2897-
"is_secret": false,
2898-
"is_verified": false,
2899-
"line_number": 74,
2900-
"type": "GitHub Token",
2901-
"verified_result": null
2902-
},
29032887
{
29042888
"hashed_secret": "d7d24cbbbbaaacb8e213f754cd8f783eb747b56c",
29052889
"is_secret": false,
@@ -9174,7 +9158,7 @@
91749158
"hashed_secret": "ff37a98a9963d347e9749a5c1b3936a4a245a6ff",
91759159
"is_secret": false,
91769160
"is_verified": false,
9177-
"line_number": 2075,
9161+
"line_number": 2098,
91789162
"type": "Secret Keyword",
91799163
"verified_result": null
91809164
}
@@ -9506,7 +9490,7 @@
95069490
"hashed_secret": "920a25ef686c4f7ca6ad23dd109d3ad653161832",
95079491
"is_secret": false,
95089492
"is_verified": false,
9509-
"line_number": 747,
9493+
"line_number": 780,
95109494
"type": "Secret Keyword",
95119495
"verified_result": null
95129496
}
@@ -9834,39 +9818,39 @@
98349818
"hashed_secret": "920a25ef686c4f7ca6ad23dd109d3ad653161832",
98359819
"is_secret": false,
98369820
"is_verified": false,
9837-
"line_number": 42,
9821+
"line_number": 43,
98389822
"type": "Secret Keyword",
98399823
"verified_result": null
98409824
},
98419825
{
98429826
"hashed_secret": "b44bf05d644c15c4d84f78771de011e3cce924c0",
98439827
"is_secret": false,
98449828
"is_verified": false,
9845-
"line_number": 59,
9829+
"line_number": 60,
98469830
"type": "Secret Keyword",
98479831
"verified_result": null
98489832
},
98499833
{
98509834
"hashed_secret": "999a3419d9959d3c39b11dcc67d79c7888b4b765",
98519835
"is_secret": false,
98529836
"is_verified": false,
9853-
"line_number": 71,
9837+
"line_number": 72,
98549838
"type": "Secret Keyword",
98559839
"verified_result": null
98569840
},
98579841
{
98589842
"hashed_secret": "bacac952b5cb942687d38a9eda6531d570f88b22",
98599843
"is_secret": false,
98609844
"is_verified": false,
9861-
"line_number": 84,
9845+
"line_number": 85,
98629846
"type": "Secret Keyword",
98639847
"verified_result": null
98649848
},
98659849
{
98669850
"hashed_secret": "cd1ecfcd67c8b85800a483d77e550d36727e8925",
98679851
"is_secret": false,
98689852
"is_verified": false,
9869-
"line_number": 98,
9853+
"line_number": 99,
98709854
"type": "Secret Keyword",
98719855
"verified_result": null
98729856
}
@@ -23650,23 +23634,23 @@
2365023634
"hashed_secret": "920a25ef686c4f7ca6ad23dd109d3ad653161832",
2365123635
"is_secret": false,
2365223636
"is_verified": false,
23653-
"line_number": 167,
23637+
"line_number": 175,
2365423638
"type": "Secret Keyword",
2365523639
"verified_result": null
2365623640
},
2365723641
{
2365823642
"hashed_secret": "3340ad734a33028b9498d58dc8b49e9c02157b19",
2365923643
"is_secret": false,
2366023644
"is_verified": false,
23661-
"line_number": 188,
23645+
"line_number": 196,
2366223646
"type": "Secret Keyword",
2366323647
"verified_result": null
2366423648
},
2366523649
{
2366623650
"hashed_secret": "ec09a041656818107eb855453ffbf7327d3bbc9d",
2366723651
"is_secret": false,
2366823652
"is_verified": false,
23669-
"line_number": 325,
23653+
"line_number": 333,
2367023654
"type": "Secret Keyword",
2367123655
"verified_result": null
2367223656
}
@@ -24772,15 +24756,15 @@
2477224756
"hashed_secret": "fe1bae27cb7c1fb823f496f286e78f1d2ae87734",
2477324757
"is_secret": false,
2477424758
"is_verified": false,
24775-
"line_number": 330,
24759+
"line_number": 370,
2477624760
"type": "Secret Keyword",
2477724761
"verified_result": null
2477824762
},
2477924763
{
2478024764
"hashed_secret": "945db841c03e42eef2f3d0a4ff310e2f3b3e59ec",
2478124765
"is_secret": false,
2478224766
"is_verified": false,
24783-
"line_number": 414,
24767+
"line_number": 454,
2478424768
"type": "Secret Keyword",
2478524769
"verified_result": null
2478624770
}

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ prune .pytest_cache
148148
prune .ruff_cache
149149
prune .mypy_cache
150150
prune htmlcov
151+
global-exclude **/.mypy_cache/*
151152

152153
# Virtual environments (including nested in plugins)
153154
prune venv

charts/mcp-stack/values.schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,6 +2146,9 @@
21462146
"SSO_OKTA_ENABLED": {
21472147
"type": "string"
21482148
},
2149+
"SSO_ADFS_ENABLED": {
2150+
"type": "string"
2151+
},
21492152
"SSRF_BLOCKED_HOSTS": {
21502153
"type": "string"
21512154
},

charts/mcp-stack/values.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,7 @@ mcpContextForge:
906906
SSO_KEYCLOAK_ENABLED: "false"
907907
SSO_ENTRA_ENABLED: "false"
908908
SSO_GENERIC_ENABLED: "false"
909+
SSO_ADFS_ENABLED: "false"
909910
# See .env.example for full SSO_*_CLIENT_ID, SSO_*_CLIENT_SECRET, etc.
910911

911912
# ─ Default Role Configuration ─

0 commit comments

Comments
 (0)