Skip to content

Commit bf277c3

Browse files
committed
[server] refactoring: promisify, add guard, ...
remove indirections
1 parent f20f4bf commit bf277c3

File tree

4 files changed

+23
-27
lines changed

4 files changed

+23
-27
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export interface AuthProvider {
7575
readonly config: AuthProviderParams;
7676
readonly info: AuthProviderInfo;
7777
readonly authCallbackPath: string;
78-
readonly callback: express.RequestHandler;
78+
callback(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void>;
7979
authorize(req: express.Request, res: express.Response, next: express.NextFunction, scopes?: string[]): void;
8080
refreshToken?(user: User): Promise<void>;
8181
}

components/server/src/auth/authenticator.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,18 @@ export class Authenticator {
6363

6464
async init(app: express.Application) {
6565
this.initHandlers.forEach(handler => app.use(handler));
66-
app.use(this.authCallback);
67-
}
68-
protected get authCallback(): express.RequestHandler {
69-
return this.authCallbackHandler.bind(this);
66+
app.use(async (req: express.Request, res: express.Response, next: express.NextFunction) => {
67+
await this.authCallbackHandler(req, res, next);
68+
});
7069
}
71-
protected authCallbackHandler(req: express.Request, res: express.Response, next: express.NextFunction) {
70+
protected async authCallbackHandler(req: express.Request, res: express.Response, next: express.NextFunction) {
7271
if (req.url.startsWith("/auth/")) {
7372
const hostContexts = this.hostContextProvider.getAll();
7473
for (const { authProvider } of hostContexts) {
7574
const authCallbackPath = authProvider.authCallbackPath;
7675
if (req.url.startsWith(authCallbackPath)) {
77-
log.info(`Auth Provider Callback. Path: ${authCallbackPath}`)
78-
authProvider.callback(req, res, next);
76+
log.info(`Auth Provider Callback. Path: ${authCallbackPath}`, { req });
77+
await authProvider.callback(req, res, next);
7978
return;
8079
}
8180
}
@@ -88,10 +87,7 @@ export class Authenticator {
8887
return hostContext && hostContext.authProvider;
8988
}
9089

91-
get authenticate(): express.RequestHandler {
92-
return this.doAuthenticate.bind(this);
93-
}
94-
protected async doAuthenticate(req: express.Request, res: express.Response, next: express.NextFunction) {
90+
async authenticate(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {
9591
if (req.isAuthenticated()) {
9692
log.info({ sessionId: req.sessionID }, `User is already authenticated. Continue.`, { 'login-flow': true });
9793
return next();

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

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ export class GenericAuthProvider implements AuthProvider {
7070

7171
@postConstruct()
7272
init() {
73-
this.strategy = new GenericOAuth2Strategy(this.strategyName, { ...this.defaultStrategyOptions }, this.verify.bind(this));
73+
this.strategy = new GenericOAuth2Strategy(this.strategyName, { ...this.defaultStrategyOptions },
74+
async (req, accessToken, refreshToken, tokenResponse, _profile, done) => await this.verify(req, accessToken, refreshToken, tokenResponse, _profile, done));
7475
this.initAuthUserSetup();
7576
log.info(`(${this.strategyName}) Initialized.`, { defaultStrategyOptions: this.defaultStrategyOptions });
7677
}
@@ -251,16 +252,16 @@ export class GenericAuthProvider implements AuthProvider {
251252
* - (3) the result of the "verify" function is first handled by passport internally and then passed to the
252253
* callback from the `passport.authenticate` call (1)
253254
*/
254-
readonly callback: express.RequestHandler = async (request, response, next) => {
255+
async callback(request: express.Request, response: express.Response, next: express.NextFunction): Promise<void> {
255256
const authProviderId = this.authProviderId;
256257
const strategyName = this.strategyName;
257258
const clientInfo = getRequestingClientInfo(request);
258-
const cxt = LogContext.from({ user: request.user, request});
259+
const cxt = LogContext.from({ user: request.user });
259260
if (response.headersSent) {
260261
log.warn(cxt, `(${strategyName}) Callback called repeatedly.`, { request, clientInfo });
261262
return;
262263
}
263-
log.info(cxt, `(${strategyName}) OAuth2 callback call. `, { clientInfo, authProviderId, requestUrl: request.originalUrl, session: request.session });
264+
log.info(cxt, `(${strategyName}) OAuth2 callback call. `, { clientInfo, authProviderId, requestUrl: request.originalUrl, request });
264265

265266
const isAlreadyLoggedIn = request.isAuthenticated() && User.is(request.user);
266267
const authFlow = AuthFlow.get(request.session);
@@ -279,7 +280,7 @@ export class GenericAuthProvider implements AuthProvider {
279280
return;
280281
}
281282

282-
const defaultLogPayload = { authFlow, clientInfo, authProviderId };
283+
const defaultLogPayload = { authFlow, clientInfo, authProviderId, request };
283284

284285
// check OAuth2 errors
285286
const error = new URL(formatURL({ protocol: request.protocol, host: request.get('host'), pathname: request.originalUrl })).searchParams.get("error");
@@ -296,13 +297,15 @@ export class GenericAuthProvider implements AuthProvider {
296297
let result: Parameters<VerifyCallback>;
297298
try {
298299
result = await new Promise((resolve) => {
299-
passport.authenticate(this.strategy as any, (...params: Parameters<VerifyCallback>) => resolve(params))(request, response, next);
300+
const authenticate = passport.authenticate(this.strategy as any, (...params: Parameters<VerifyCallback>) => resolve(params));
301+
authenticate(request, response, next);
300302
})
301303
} catch (error) {
302304
response.redirect(this.getSorryUrl(`OAuth2 error. (${error})`));
303305
return;
304306
}
305307
const [err, user, flowContext] = result;
308+
306309
/*
307310
* (3) this callback function is called after the "verify" function as the final step in the authentication process in passport.
308311
*
@@ -341,15 +344,15 @@ export class GenericAuthProvider implements AuthProvider {
341344

342345
if (TosFlow.WithIdentity.is(flowContext)) {
343346
if (User.is(request.user)) {
344-
log.error(context, `(${strategyName}) Invariant violated. Unexpected user.`, { ...defaultLogPayload, session: request.session });
347+
log.error(context, `(${strategyName}) Invariant violated. Unexpected user.`, { ...defaultLogPayload, ...defaultLogPayload });
345348
}
346349
}
347350

348351
if (TosFlow.WithIdentity.is(flowContext) || (TosFlow.WithUser.is(flowContext) && flowContext.termsAcceptanceRequired)) {
349352

350353
// This is the regular path on sign up. We just went through the OAuth2 flow but didn't create a Gitpod
351354
// account yet, as we require to accept the terms first.
352-
log.info(context, `(${strategyName}) Redirect to /api/tos`, { info: flowContext, session: request.session });
355+
log.info(context, `(${strategyName}) Redirect to /api/tos`, { info: flowContext, ...defaultLogPayload });
353356

354357
// attach the sign up info to the session, in order to proceed after acceptance of terms
355358
await TosFlow.attach(request.session!, flowContext);
@@ -358,7 +361,7 @@ export class GenericAuthProvider implements AuthProvider {
358361
return;
359362
} else {
360363
const { user, elevateScopes } = flowContext as TosFlow.WithUser;
361-
log.info(context, `(${strategyName}) Directly log in and proceed.`, { info: flowContext, session: request.session });
364+
log.info(context, `(${strategyName}) Directly log in and proceed.`, { info: flowContext, ...defaultLogPayload });
362365

363366
// Complete login
364367
const { host, returnTo } = authFlow;
@@ -386,9 +389,6 @@ export class GenericAuthProvider implements AuthProvider {
386389
let currentGitpodUser: User | undefined = User.is(req.user) ? req.user : undefined;
387390
let candidate: Identity;
388391

389-
const fail = (err: any) => done(err, currentGitpodUser || candidate, flowContext);
390-
const complete = () => done(undefined, currentGitpodUser || candidate, flowContext);
391-
392392
const isIdentityLinked = (user: User, candidate: Identity) => user.identities.some(i => Identity.equals(i, candidate));
393393

394394
try {
@@ -445,10 +445,10 @@ export class GenericAuthProvider implements AuthProvider {
445445
isBlocked
446446
}
447447
}
448-
complete()
448+
done(undefined, currentGitpodUser || candidate, flowContext);
449449
} catch (err) {
450450
log.error(`(${strategyName}) Exception in verify function`, err, { ...defaultLogPayload, err, authFlow });
451-
fail(err);
451+
done(err, undefined);
452452
}
453453
}
454454

components/server/src/user/user-controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export class UserController {
8181
}
8282

8383
// Proceed with login
84-
this.authenticator.authenticate(req, res, next);
84+
await this.authenticator.authenticate(req, res, next);
8585
});
8686
router.get("/authorize", (req: express.Request, res: express.Response, next: express.NextFunction) => {
8787
if (!User.is(req.user)) {

0 commit comments

Comments
 (0)