2727using System . Diagnostics . CodeAnalysis ;
2828using GovUK . Dfe . CoreLibs . Security . TokenRefresh . Extensions ;
2929using System . IO . Compression ;
30+ using Microsoft . AspNetCore . Authentication ;
3031
3132var builder = WebApplication . CreateBuilder ( args ) ;
3233
6162 options . ValueCountLimit = 1000 ; // Allow more form values
6263} ) ;
6364
65+ // Check if Cypress toggle is allowed (for shared dev/test environments)
66+ var allowCypressToggle = configuration . GetValue < bool > ( "CypressAuthentication:AllowToggle" ) ;
67+
6468builder . Services . AddRazorPages ( options =>
6569{
6670 options . Conventions . ConfigureFilter ( new ExternalApiPageExceptionFilter ( ) ) ;
6973 options . Conventions . AllowAnonymousToPage ( "/Index" ) ;
7074 options . Conventions . AllowAnonymousToPage ( "/Logout" ) ;
7175
72- // Allow anonymous access to test login page when test auth is enabled
73- if ( isTestAuthEnabled )
76+ // Allow anonymous access to test login page when test auth is enabled OR Cypress toggle is allowed
77+ if ( isTestAuthEnabled || allowCypressToggle )
7478 {
7579 options . Conventions . AllowAnonymousToPage ( "/TestLogin" ) ;
7680 options . Conventions . AllowAnonymousToPage ( "/TestLogout" ) ;
8892
8993builder . Services . AddHttpContextAccessor ( ) ;
9094
95+ // Register Cypress authentication services using CoreLibs pattern
96+ builder . Services . AddScoped < ICustomRequestChecker , ExternalAppsCypressRequestChecker > ( ) ;
97+ builder . Services . AddScoped < ICypressAuthenticationService , CypressAuthenticationService > ( ) ;
98+
9199// Add confirmation interceptor filter globally for all MVC actions
92100builder . Services . Configure < Microsoft . AspNetCore . Mvc . MvcOptions > ( options =>
93101{
112120
113121builder . Services . Configure < TokenRefreshSettings > ( configuration . GetSection ( "TokenRefresh" ) ) ;
114122
115- // Configure authentication based on test mode
116- if ( isTestAuthEnabled )
117- {
118- builder . Services . AddAuthentication ( options =>
119- {
120- options . DefaultScheme = TestAuthenticationHandler . SchemeName ;
121- options . DefaultChallengeScheme = TestAuthenticationHandler . SchemeName ;
122- options . DefaultSignInScheme = CookieAuthenticationDefaults . AuthenticationScheme ;
123- options . DefaultSignOutScheme = CookieAuthenticationDefaults . AuthenticationScheme ;
124- } )
123+ // Register both schemes once, and use a dynamic scheme provider to pick per-request
124+ builder . Services
125+ . AddAuthentication ( )
125126 . AddCookie ( )
127+ . AddCustomOpenIdConnect ( configuration , sectionName : "DfESignIn" )
126128 . AddScheme < TestAuthenticationSchemeOptions , TestAuthenticationHandler > (
127- TestAuthenticationHandler . SchemeName ,
129+ TestAuthenticationHandler . SchemeName ,
128130 options => { } ) ;
129- }
130- else
131- {
132- builder . Services . AddAuthentication ( options =>
133- {
134- options . DefaultScheme = CookieAuthenticationDefaults . AuthenticationScheme ;
135- options . DefaultChallengeScheme = OpenIdConnectDefaults . AuthenticationScheme ;
136- options . DefaultSignOutScheme = OpenIdConnectDefaults . AuthenticationScheme ;
137- } )
138- . AddCookie ( )
139- . AddCustomOpenIdConnect ( configuration , sectionName : "DfESignIn" ) ;
140- }
131+
132+ // Replace default scheme provider with dynamic provider
133+ builder . Services . AddSingleton < IAuthenticationSchemeProvider , DynamicAuthenticationSchemeProvider > ( ) ;
141134
142135builder . Services
143136 . AddApplicationAuthorization (
161154
162155builder . Services . AddExternalApplicationsApiClients ( configuration ) ;
163156
164- // Register authentication strategies in consuming app (Clean Architecture)
165- // These were moved out of the library to remove coupling
166- if ( isTestAuthEnabled )
167- {
168- // Register TestAuthenticationStrategy when test auth is enabled
169- builder . Services . AddScoped < IAuthenticationSchemeStrategy , TestAuthenticationStrategy > ( ) ;
170- }
171- else
172- {
173- // Register OidcAuthenticationStrategy when OIDC is enabled
174- builder . Services . AddScoped < IAuthenticationSchemeStrategy , OidcAuthenticationStrategy > ( ) ;
175- }
157+ // Register authentication strategies and composite selector (per-request)
158+ builder . Services . AddScoped < OidcAuthenticationStrategy > ( ) ;
159+ builder . Services . AddScoped < TestAuthenticationStrategy > ( ) ;
160+ builder . Services . AddScoped < IAuthenticationSchemeStrategy , CompositeAuthenticationSchemeStrategy > ( ) ;
176161
177162builder . Services . AddGovUkFrontend ( options => options . Rebrand = true ) ;
178163builder . Services . AddSingleton < IActionContextAccessor , ActionContextAccessor > ( ) ;
206191
207192builder . Services . AddSingleton < ITemplateStore , ApiTemplateStore > ( ) ;
208193
209-
210-
211- // Add test token handler and services when test authentication is enabled
212- if ( isTestAuthEnabled )
194+ // Add test token handler and services when test authentication or Cypress is enabled
195+ if ( isTestAuthEnabled || allowCypressToggle )
213196{
214197 builder . Services . AddUserTokenService ( configuration ) ;
215198 builder . Services . AddScoped < ITestAuthenticationService , TestAuthenticationService > ( ) ;
273256
274257
275258[ ExcludeFromCodeCoverage ]
276- public static partial class Program { }
259+ public static partial class Program { }
0 commit comments