Skip to content

Commit 7260cd5

Browse files
committed
[server] make Gitpod cookie "stricter"
1 parent b6d3515 commit 7260cd5

File tree

2 files changed

+40
-6
lines changed

2 files changed

+40
-6
lines changed

components/server/src/auth/generic-auth-provider.ts

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,22 @@ export class GenericAuthProvider implements AuthProvider {
145145
protected readAuthUserSetup?: (accessToken: string, tokenResponse: object) => Promise<AuthUserSetup>;
146146

147147
authorize(req: express.Request, res: express.Response, next: express.NextFunction, scope?: string[]): void {
148-
const handler = passport.authenticate(this.getStrategy() as any, {
149-
...this.defaultStrategyOptions,
150-
...{ scope },
151-
});
152-
handler(req, res, next);
148+
// Before the OAuth process is started, the Gitpod cookie is relaxed ot be sent on cross-site request,
149+
// which makes possible to re-establish the session on a callback from the 3rd party service.
150+
// Once this callback is handled, the Gitpod cookie is elevated to a `strict` one.
151+
this.updateCookieSameSiteValue(req, "lax")
152+
.then(() => {
153+
const handler = passport.authenticate(this.getStrategy() as any, {
154+
...this.defaultStrategyOptions,
155+
...{ scope },
156+
});
157+
handler(req, res, next);
158+
})
159+
.catch((err) => {
160+
log.error(`(${this.strategyName}) Failed to store session before redirect.`, {
161+
err,
162+
});
163+
});
153164
}
154165

155166
protected getStrategy() {
@@ -466,6 +477,16 @@ export class GenericAuthProvider implements AuthProvider {
466477
...defaultLogPayload,
467478
});
468479

480+
try {
481+
// When the OAuth process is done, we want to proceed with a `strict` Gitpod cookie.
482+
// This improves the security model with Browser agents, as cross-site requests whould
483+
// not be containing the Gitpod cookie anymore.
484+
await this.updateCookieSameSiteValue(request, "strict");
485+
} catch (error) {
486+
response.redirect(this.getSorryUrl(`Failed to save session. (${error})`));
487+
return;
488+
}
489+
469490
// Complete login
470491
const { host, returnTo } = authFlow;
471492
await this.loginCompletionHandler.complete(request, response, {
@@ -478,6 +499,19 @@ export class GenericAuthProvider implements AuthProvider {
478499
}
479500
}
480501

502+
protected async updateCookieSameSiteValue(request: express.Request, newValue: "strict" | "lax") {
503+
return new Promise((resolve, reject) => {
504+
request.session.cookie.sameSite = newValue;
505+
request.session.save((err) => {
506+
if (err) {
507+
reject(err);
508+
} else {
509+
resolve(undefined);
510+
}
511+
});
512+
});
513+
}
514+
481515
protected sendCompletionRedirectWithError(response: express.Response, error: object): void {
482516
log.info(`(${this.strategyName}) Send completion redirect with error`, { error });
483517

components/server/src/session-handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export class SessionHandlerProvider {
5353
httpOnly: true, // default
5454
secure: false, // default, TODO SSL! Config proxy
5555
maxAge: config.session.maxAgeMs, // configured in Helm chart, defaults to 3 days.
56-
sameSite: "lax", // default: true. "Lax" needed for OAuth.
56+
sameSite: "strict",
5757
};
5858
}
5959

0 commit comments

Comments
 (0)