@@ -19,9 +19,8 @@ import { AuthFlow, AuthProvider } from "./auth-provider";
1919import { HostContextProvider } from "./host-context-provider" ;
2020import { SignInJWT } from "./jwt" ;
2121import { NonceService } from "./nonce-service" ;
22- import { ensureUrlHasFragment } from "./fragment-utils" ;
2322import { getFeatureFlagEnableNonceValidation , getFeatureFlagEnableStrictAuthorizeReturnTo } from "../util/featureflags" ;
24- import { validateLoginReturnToUrl , validateAuthorizeReturnToUrl } from "../express-util" ;
23+ import { validateLoginReturnToUrl , validateAuthorizeReturnToUrl , safeRedirect } from "../express-util" ;
2524
2625@injectable ( )
2726export class Authenticator {
@@ -94,7 +93,7 @@ export class Authenticator {
9493 pathname : req . path ,
9594 search : new URL ( req . url , this . config . hostUrl . url ) . search ,
9695 } ) ;
97- res . redirect ( baseUrl . toString ( ) ) ;
96+ safeRedirect ( res , baseUrl . toString ( ) ) ;
9897 return ;
9998 }
10099
@@ -190,21 +189,20 @@ export class Authenticator {
190189 // Validate returnTo URL against allowlist for login API
191190 if ( ! validateLoginReturnToUrl ( returnToParam , this . config . hostUrl ) ) {
192191 log . warn ( `Invalid returnTo URL rejected for login: ${ returnToParam } ` , { "login-flow" : true } ) ;
193- res . redirect ( this . getSorryUrl ( `Invalid return URL.` ) ) ;
192+ safeRedirect ( res , this . getSorryUrl ( `Invalid return URL.` ) ) ;
194193 return ;
195194 }
196195 }
197196 // returnTo defaults to workspaces url
198197 const workspaceUrl = this . config . hostUrl . asDashboard ( ) . toString ( ) ;
199198 returnToParam = returnToParam || workspaceUrl ;
200- // Ensure returnTo URL has a fragment to prevent OAuth token inheritance attacks
201- const returnTo = ensureUrlHasFragment ( returnToParam ) ;
199+ const returnTo = returnToParam ;
202200
203201 const host : string = req . query . host ?. toString ( ) || "" ;
204202 const authProvider = host && ( await this . getAuthProviderForHost ( host ) ) ;
205203 if ( ! host || ! authProvider ) {
206204 log . info ( `Bad request: missing parameters.` , { "login-flow" : true } ) ;
207- res . redirect ( this . getSorryUrl ( `Bad request: missing parameters.` ) ) ;
205+ safeRedirect ( res , this . getSorryUrl ( `Bad request: missing parameters.` ) ) ;
208206 return ;
209207 }
210208 // Logins with organizational Git Auth is not permitted
@@ -213,12 +211,12 @@ export class Authenticator {
213211 "authorize-flow" : true ,
214212 ap : authProvider . info ,
215213 } ) ;
216- res . redirect ( this . getSorryUrl ( `Login with "${ host } " is not permitted.` ) ) ;
214+ safeRedirect ( res , this . getSorryUrl ( `Login with "${ host } " is not permitted.` ) ) ;
217215 return ;
218216 }
219217 if ( this . config . disableDynamicAuthProviderLogin && ! authProvider . params . builtin ) {
220218 log . info ( `Auth Provider is not allowed.` , { ap : authProvider . info } ) ;
221- res . redirect ( this . getSorryUrl ( `Login with ${ authProvider . params . host } is not allowed.` ) ) ;
219+ safeRedirect ( res , this . getSorryUrl ( `Login with ${ authProvider . params . host } is not allowed.` ) ) ;
222220 return ;
223221 }
224222
@@ -228,7 +226,7 @@ export class Authenticator {
228226 "login-flow" : true ,
229227 ap : authProvider . info ,
230228 } ) ;
231- res . redirect ( this . getSorryUrl ( `Login with "${ host } " is not permitted.` ) ) ;
229+ safeRedirect ( res , this . getSorryUrl ( `Login with "${ host } " is not permitted.` ) ) ;
232230 return ;
233231 }
234232
@@ -250,7 +248,7 @@ export class Authenticator {
250248 const user = req . user ;
251249 if ( ! req . isAuthenticated ( ) || ! User . is ( user ) ) {
252250 log . info ( `User is not authenticated.` ) ;
253- res . redirect ( this . getSorryUrl ( `Not authenticated. Please login.` ) ) ;
251+ safeRedirect ( res , this . getSorryUrl ( `Not authenticated. Please login.` ) ) ;
254252 return ;
255253 }
256254 const returnTo : string = req . query . returnTo ?. toString ( ) || this . config . hostUrl . asDashboard ( ) . toString ( ) ;
@@ -260,20 +258,21 @@ export class Authenticator {
260258
261259 if ( ! host || ! authProvider ) {
262260 log . warn ( `Bad request: missing parameters.` ) ;
263- res . redirect ( this . getSorryUrl ( `Bad request: missing parameters.` ) ) ;
261+ safeRedirect ( res , this . getSorryUrl ( `Bad request: missing parameters.` ) ) ;
264262 return ;
265263 }
266264
267265 try {
268266 await this . userAuthentication . deauthorize ( user , authProvider . authProviderId ) ;
269- res . redirect ( returnTo ) ;
267+ safeRedirect ( res , returnTo ) ;
270268 } catch ( error ) {
271269 next ( error ) ;
272270 log . error ( `Failed to disconnect a provider.` , error , {
273271 host,
274272 userId : user . id ,
275273 } ) ;
276- res . redirect (
274+ safeRedirect (
275+ res ,
277276 this . getSorryUrl (
278277 `Failed to disconnect a provider: ${ error && error . message ? error . message : "unknown reason" } ` ,
279278 ) ,
@@ -285,12 +284,13 @@ export class Authenticator {
285284 const user = req . user ;
286285 if ( ! req . isAuthenticated ( ) || ! User . is ( user ) ) {
287286 log . info ( `User is not authenticated.` , { "authorize-flow" : true } ) ;
288- res . redirect ( this . getSorryUrl ( `Not authenticated. Please login.` ) ) ;
287+ safeRedirect ( res , this . getSorryUrl ( `Not authenticated. Please login.` ) ) ;
289288 return ;
290289 }
291290 if ( user . id === BUILTIN_INSTLLATION_ADMIN_USER_ID ) {
292291 log . info ( `Authorization is not permitted for admin user.` ) ;
293- res . redirect (
292+ safeRedirect (
293+ res ,
294294 this . getSorryUrl ( `Authorization is not permitted for admin user. Please login with a user account.` ) ,
295295 ) ;
296296 return ;
@@ -303,7 +303,7 @@ export class Authenticator {
303303
304304 if ( ! returnToParam || ! host || ! authProvider ) {
305305 log . info ( `Bad request: missing parameters.` , { "authorize-flow" : true } ) ;
306- res . redirect ( this . getSorryUrl ( `Bad request: missing parameters.` ) ) ;
306+ safeRedirect ( res , this . getSorryUrl ( `Bad request: missing parameters.` ) ) ;
307307 return ;
308308 }
309309
@@ -319,12 +319,11 @@ export class Authenticator {
319319 "authorize-flow" : true ,
320320 strictValidation : isStrictAuthorizeValidationEnabled ,
321321 } ) ;
322- res . redirect ( this . getSorryUrl ( `Invalid return URL.` ) ) ;
322+ safeRedirect ( res , this . getSorryUrl ( `Invalid return URL.` ) ) ;
323323 return ;
324324 }
325325
326- // Ensure returnTo URL has a fragment to prevent OAuth token inheritance attacks
327- const returnTo = ensureUrlHasFragment ( returnToParam ) ;
326+ const returnTo = returnToParam ;
328327
329328 // For non-verified org auth provider, ensure user is an owner of the org
330329 if ( ! authProvider . info . verified && authProvider . info . organizationId ) {
@@ -334,7 +333,7 @@ export class Authenticator {
334333 "authorize-flow" : true ,
335334 ap : authProvider . info ,
336335 } ) ;
337- res . redirect ( this . getSorryUrl ( `Authorization with "${ host } " is not permitted.` ) ) ;
336+ safeRedirect ( res , this . getSorryUrl ( `Authorization with "${ host } " is not permitted.` ) ) ;
338337 return ;
339338 }
340339 }
@@ -345,7 +344,7 @@ export class Authenticator {
345344 "authorize-flow" : true ,
346345 ap : authProvider . info ,
347346 } ) ;
348- res . redirect ( this . getSorryUrl ( `Authorization with "${ host } " is not permitted.` ) ) ;
347+ safeRedirect ( res , this . getSorryUrl ( `Authorization with "${ host } " is not permitted.` ) ) ;
349348 return ;
350349 }
351350
@@ -357,7 +356,7 @@ export class Authenticator {
357356 "authorize-flow" : true ,
358357 ap : authProvider . info ,
359358 } ) ;
360- res . redirect ( this . getSorryUrl ( `Authorization with "${ host } " is not permitted.` ) ) ;
359+ safeRedirect ( res , this . getSorryUrl ( `Authorization with "${ host } " is not permitted.` ) ) ;
361360 return ;
362361 }
363362 }
@@ -411,6 +410,6 @@ export class Authenticator {
411410 return [ ] ;
412411 }
413412 private getSorryUrl ( message : string ) {
414- return ensureUrlHasFragment ( this . config . hostUrl . asSorry ( message ) . toString ( ) ) ;
413+ return this . config . hostUrl . asSorry ( message ) . toString ( ) ;
415414 }
416415}
0 commit comments