@@ -24,25 +24,36 @@ public class DynamicAuthenticationSchemeProvider(
2424 IConfiguration configuration )
2525 : AuthenticationSchemeProvider ( options )
2626{
27- // Cache the authentication mode decision per request to prevent infinite recursion
28- // If GetDefaultForbidSchemeAsync is called during a forbid flow, and it tries to check IsCypressRequest,
29- // which might trigger another auth check, we get a stack overflow
30- private const string AuthModeCacheKey = "__AuthMode_Cached__" ;
31-
3227 private bool IsTestAuthGloballyEnabled ( )
3328 {
3429 return testAuthOptions . Value . Enabled ;
3530 }
3631
3732 private bool IsCypressToggleAllowed ( )
3833 {
39- return configuration . GetValue < bool > ( "CypressAuthentication:AllowToggle" ) ;
34+ // Only allow Cypress toggle if BOTH conditions are met:
35+ // 1. Configuration setting is true
36+ // 2. Running in GitHub Actions (GITHUB_ACTIONS environment variable is set)
37+ var configAllowsToggle = configuration . GetValue < bool > ( "CypressAuthentication:AllowToggle" ) ;
38+ if ( ! configAllowsToggle )
39+ {
40+ return false ;
41+ }
42+
43+ var isGitHubActions = Environment . GetEnvironmentVariable ( "GITHUB_ACTIONS" ) == "true" ;
44+ return isGitHubActions ;
45+ }
46+
47+ private bool IsCypressRequest ( )
48+ {
49+ var httpContext = httpContextAccessor . HttpContext ;
50+ if ( httpContext == null ) return false ;
51+ if ( ! IsCypressToggleAllowed ( ) ) return false ;
52+
53+ var checker = httpContext . RequestServices . GetService < ICustomRequestChecker > ( ) ;
54+ return checker != null && checker . IsValidRequest ( httpContext ) ;
4055 }
4156
42- /// <summary>
43- /// Determines if the current request should use Test authentication.
44- /// This is cached per request to prevent infinite recursion during authentication flows.
45- /// </summary>
4657 private bool ShouldUseTestAuth ( )
4758 {
4859 // Always use test auth if globally enabled
@@ -51,38 +62,8 @@ private bool ShouldUseTestAuth()
5162 return true ;
5263 }
5364
54- var httpContext = httpContextAccessor . HttpContext ;
55- if ( httpContext == null )
56- {
57- return false ;
58- }
59-
60- // Check cache first to prevent re-entry during authentication flow
61- if ( httpContext . Items . TryGetValue ( AuthModeCacheKey , out var cachedMode ) )
62- {
63- return ( bool ) cachedMode ! ;
64- }
65-
66- // Determine if this is a Cypress request (only if toggle is allowed)
67- bool isCypressRequest = false ;
68- if ( IsCypressToggleAllowed ( ) )
69- {
70- try
71- {
72- var checker = httpContext . RequestServices . GetService < ICustomRequestChecker > ( ) ;
73- isCypressRequest = checker != null && checker . IsValidRequest ( httpContext ) ;
74- }
75- catch
76- {
77- // If we can't check (e.g., during service resolution or auth flow), default to false
78- // This prevents cascading failures during authentication
79- isCypressRequest = false ;
80- }
81- }
82-
83- // Cache the result for this request
84- httpContext . Items [ AuthModeCacheKey ] = isCypressRequest ;
85- return isCypressRequest ;
65+ // Check if this is a Cypress request (only in GitHub Actions)
66+ return IsCypressRequest ( ) ;
8667 }
8768
8869 public override Task < AuthenticationScheme ? > GetDefaultAuthenticateSchemeAsync ( )
0 commit comments