Skip to content

Commit

Permalink
feat: split authentication methods and org access check
Browse files Browse the repository at this point in the history
  • Loading branch information
Geoffroy Empain committed Dec 3, 2020
1 parent a9f166b commit 8877034
Show file tree
Hide file tree
Showing 27 changed files with 275 additions and 243 deletions.
17 changes: 5 additions & 12 deletions src/auth/utils/authenticate.ts → src/auth/authenticate.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
import {
NextFunction, Request, Response,
} from 'express';
import { createOrUpdateUser, PassportUser } from '../create-or-update-user';
import { env } from '../../env';
import { UnauthorizedError } from '../../commons/errors/unauthorized-error';
import { createOrUpdateUser, PassportUser } from './create-or-update-user';
import { env } from '../env';
import {
authCookieName, cookieOptions, JwtToken,
} from '../auth';
} from './auth';
import jwt from 'jsonwebtoken';
import { Logger } from '../../commons/logger/logger';
import { wrapAsyncMiddleware } from '../../commons/utils/wrap-async-middleware';
import { Logger } from '../commons/logger/logger';
import { wrapAsyncMiddleware } from '../commons/utils/wrap-async-middleware';

const logger = new Logger('meli.server:authenticate');

const allowedOrgs = new Set(env.MELI_ORGS);

async function handler(req: Request, res: Response, next: NextFunction) {
const passportUser = req.user as PassportUser;
if (allowedOrgs.size !== 0 && passportUser.orgs && passportUser.orgs.every(org => !allowedOrgs.has(org))) {
logger.debug('user', passportUser, 'not allowed to login as none of their orgs are allowed', env.MELI_ORGS);
return next(new UnauthorizedError('Not an org member'));
}

const user = await createOrUpdateUser(passportUser);

Expand Down
8 changes: 5 additions & 3 deletions src/auth/create-or-update-user.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { User, Users } from '../entities/users/user';
import { Logger } from '../commons/logger/logger';
import { AuthProviderType, AuthProviderUser } from './providers/auth-provider';
import { uuid } from '../utils/uuid';
import { Members } from '../entities/members/member';

const logger = new Logger('meli.server:createOrUpdateUser');

export interface PassportUser extends AuthProviderUser {
authProvider: AuthProviderType;
export interface PassportUser {
authProvider: string;
id: any;
name: string;
email: string;
}

export async function createOrUpdateUser(passportUser: PassportUser): Promise<User> {
Expand Down
2 changes: 1 addition & 1 deletion src/auth/handlers/get-auth-methods.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Request, Response } from 'express';
import { authMethods } from '../passport';
import { authMethods } from '../passport/auth-methods';

export function handler(req: Request, res: Response) {
res.json(authMethods);
Expand Down
168 changes: 5 additions & 163 deletions src/auth/passport.ts
Original file line number Diff line number Diff line change
@@ -1,167 +1,9 @@
/* eslint-disable camelcase */
import { authMethods } from './passport/auth-methods';

import chalk from 'chalk';
import { IncomingMessage } from 'http';
import passport from 'passport';
import GoogleStrategy from 'passport-google-oauth20';
import OAuth2Strategy from 'passport-oauth2';
import { Gitea } from './providers/gitea/gitea';
import { Github } from './providers/github/github';
import { Gitlab } from './providers/gitlab/gitlab';
import { Logger } from '../commons/logger/logger';
import { env } from '../env';
import { PassportUser } from './create-or-update-user';

const logger = new Logger('meli.server:passport');

export const authMethods: string[] = [];

export const gitlab_redirect = '/auth/gitlab';
export const gitlab_callback = '/auth/gitlab/callback';

if (
env.MELI_GITLAB_URL
&& env.MELI_GITLAB_CLIENT_ID
&& env.MELI_GITLAB_CLIENT_SECRET
) {
const oauthCallbackUrl = `${env.MELI_HOST}${gitlab_callback}`;
logger.debug('Enabling gitlab auth', oauthCallbackUrl);

passport.use('gitlab', new OAuth2Strategy(
{
authorizationURL: `${env.MELI_GITLAB_URL}/oauth/authorize`,
tokenURL: `${env.MELI_GITLAB_URL}/oauth/token`,
clientID: env.MELI_GITLAB_CLIENT_ID,
clientSecret: env.MELI_GITLAB_CLIENT_SECRET,
callbackURL: oauthCallbackUrl,
scope: 'read_api',
passReqToCallback: true,
},
(req: IncomingMessage, accessToken, refreshToken, params, profile, cb) => {
const gitlab = new Gitlab(accessToken, env.MELI_GITLAB_URL);
gitlab
.getUser(profile)
.then(gitUser => (
cb(undefined, <PassportUser>{
...gitUser,
authProvider: 'gitlab',
})
))
.catch(cb);
},
));

logger.info(`Enabled ${chalk.blue('gitlab')} auth`);
authMethods.push('gitlab');
}

export const gitea_redirect = '/auth/gitea';
export const gitea_callback = '/auth/gitea/callback';

if (
env.MELI_GITEA_URL
&& env.MELI_GITEA_CLIENT_ID
&& env.MELI_GITEA_CLIENT_SECRET
) {
const oauthCallbackUrl = `${env.MELI_HOST}${gitea_callback}`;
logger.debug('Enabling gitea auth', oauthCallbackUrl);

passport.use('gitea', new OAuth2Strategy(
{
authorizationURL: `${env.MELI_GITEA_URL}/login/oauth/authorize`,
tokenURL: `${env.MELI_GITEA_URL}/login/oauth/access_token`,
clientID: env.MELI_GITEA_CLIENT_ID,
clientSecret: env.MELI_GITEA_CLIENT_SECRET,
callbackURL: oauthCallbackUrl,
passReqToCallback: true,
},
(req, accessToken, refreshToken, params, profile, cb) => {
const gitea = new Gitea(accessToken, env.MELI_GITEA_URL);
gitea
.getUser(profile)
.then(gitUser => (
cb(undefined, <PassportUser>{
...gitUser,
authProvider: 'gitea',
})
))
.catch(cb);
},
));

logger.info(`Enabled ${chalk.blue('gitea')} auth`);
authMethods.push('gitea');
}

export const github_redirect = '/auth/github';
export const github_callback = '/auth/github/callback';

if (
env.MELI_GITHUB_URL
&& env.MELI_GITHUB_CLIENT_ID
&& env.MELI_GITHUB_CLIENT_SECRET
) {
const oauthCallbackUrl = `${env.MELI_HOST}${github_callback}`;
logger.debug('Enabling github auth', oauthCallbackUrl);

passport.use('github', new OAuth2Strategy(
{
authorizationURL: `${env.MELI_GITHUB_URL}/login/oauth/authorize`,
tokenURL: `${env.MELI_GITHUB_URL}/login/oauth/access_token`,
clientID: env.MELI_GITHUB_CLIENT_ID,
clientSecret: env.MELI_GITHUB_CLIENT_SECRET,
callbackURL: oauthCallbackUrl,
scope: 'read:user,user:email,read:org',
passReqToCallback: true,
},
(req, accessToken, refreshToken, params, profile, cb) => {
const github = new Github(accessToken, env.MELI_GITHUB_URL);
github
.getUser(profile)
.then(gitUser => (
cb(undefined, <PassportUser>{
...gitUser,
authProvider: 'github',
})
))
.catch(cb);
},
));

logger.info(`Enabled ${chalk.blue('github')} auth`);
authMethods.push('github');
}

export const google_redirect = '/auth/google';
export const google_callback = '/auth/google/callback';

if (
env.MELI_GOOGLE_CLIENT_ID
&& env.MELI_GOOGLE_CLIENT_SECRET
) {
const oauthCallbackUrl = `${env.MELI_HOST}${google_callback}`;
logger.debug('Enabling google auth', oauthCallbackUrl);

// TODO could we use the OAuth2 strategy ?
passport.use('google', new GoogleStrategy(
{
clientID: env.MELI_GOOGLE_CLIENT_ID,
clientSecret: env.MELI_GOOGLE_CLIENT_SECRET,
callbackURL: oauthCallbackUrl,
},
(accessToken, refreshToken, profile, cb) => {
cb(undefined, <PassportUser>{
authProvider: 'google',
id: profile.id,
name: profile.displayName,
email: profile.emails[0].value,
});
},
));

logger.info(`Enabled ${chalk.blue('google')} auth`);
authMethods.push('google');
}
require('./passport/github');
require('./passport/gitlab');
require('./passport/gitea');
require('./passport/google');

if (authMethods.length === 0) {
throw new Error('No auth methods enabled, please configure one');
Expand Down
1 change: 1 addition & 0 deletions src/auth/passport/auth-methods.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const authMethods: string[] = [];
55 changes: 55 additions & 0 deletions src/auth/passport/gitea.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { env } from '../../env';
import passport from 'passport';
import { Gitea } from './providers/gitea/gitea';
import { PassportUser } from '../create-or-update-user';
import chalk from 'chalk';
import OAuth2Strategy from 'passport-oauth2';
import { Logger } from '../../commons/logger/logger';
import { authMethods } from './auth-methods';

const logger = new Logger('meli.server.passport:gitea');

export const gitea_redirect = '/auth/gitea';
export const gitea_callback = '/auth/gitea/callback';

const allowedOrgs = new Set(env.MELI_GITEA_ORGS);

if (
env.MELI_GITEA_URL
&& env.MELI_GITEA_CLIENT_ID
&& env.MELI_GITEA_CLIENT_SECRET
) {
const oauthCallbackUrl = `${env.MELI_HOST}${gitea_callback}`;
logger.debug('Enabling gitea auth', oauthCallbackUrl);

passport.use('gitea', new OAuth2Strategy(
{
authorizationURL: `${env.MELI_GITEA_URL}/login/oauth/authorize`,
tokenURL: `${env.MELI_GITEA_URL}/login/oauth/access_token`,
clientID: env.MELI_GITEA_CLIENT_ID,
clientSecret: env.MELI_GITEA_CLIENT_SECRET,
callbackURL: oauthCallbackUrl,
passReqToCallback: true,
},
(req, accessToken, refreshToken, params, profile, cb) => {
const gitea = new Gitea(accessToken, env.MELI_GITEA_URL);
gitea
.getUser()
.then(giteaUser => {
if (giteaUser.orgs.some(org => allowedOrgs.has(org))) {
cb(undefined, <PassportUser>{
...giteaUser,
authProvider: 'gitea',
});
} else {
logger.warn(`User ${giteaUser.name} tried to login but is not a member of orgs ${allowedOrgs}`);
cb();
}
})
.catch(cb);
},
));

logger.info(`Enabled ${chalk.blue('gitea')} auth`);
authMethods.push('gitea');
}
56 changes: 56 additions & 0 deletions src/auth/passport/github.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { env } from '../../env';
import passport from 'passport';
import { Github } from './providers/github/github';
import { PassportUser } from '../create-or-update-user';
import chalk from 'chalk';
import OAuth2Strategy from 'passport-oauth2';
import { Logger } from '../../commons/logger/logger';
import { authMethods } from './auth-methods';

const logger = new Logger('meli.server.passport:github');

export const github_redirect = '/auth/github';
export const github_callback = '/auth/github/callback';

const allowedOrgs = new Set(env.MELI_GITHUB_ORGS);

if (
env.MELI_GITHUB_URL
&& env.MELI_GITHUB_CLIENT_ID
&& env.MELI_GITHUB_CLIENT_SECRET
) {
const oauthCallbackUrl = `${env.MELI_HOST}${github_callback}`;
logger.debug('Enabling github auth', oauthCallbackUrl);

passport.use('github', new OAuth2Strategy(
{
authorizationURL: `${env.MELI_GITHUB_URL}/login/oauth/authorize`,
tokenURL: `${env.MELI_GITHUB_URL}/login/oauth/access_token`,
clientID: env.MELI_GITHUB_CLIENT_ID,
clientSecret: env.MELI_GITHUB_CLIENT_SECRET,
callbackURL: oauthCallbackUrl,
scope: 'read:user,user:email,read:org',
passReqToCallback: true,
},
(req, accessToken, refreshToken, params, profile, cb) => {
const github = new Github(accessToken, env.MELI_GITHUB_URL);
github
.getUser()
.then(githubUser => {
if (githubUser.orgs.some(org => allowedOrgs.has(org))) {
cb(undefined, <PassportUser>{
...githubUser,
authProvider: 'github',
});
} else {
logger.warn(`User ${githubUser.name} tried to login but is not a member of orgs ${allowedOrgs}`);
cb();
}
})
.catch(cb);
},
));

logger.info(`Enabled ${chalk.blue('github')} auth`);
authMethods.push('github');
}

0 comments on commit 8877034

Please sign in to comment.