mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 14:28:20 +00:00
270 lines
9.1 KiB
TypeScript
270 lines
9.1 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
// All the any rules are disabled because passport typesense with fastify is really poor
|
|
|
|
import { Authenticator } from "@fastify/passport";
|
|
import fastifySession from "@fastify/session";
|
|
import { Strategy as GitHubStrategy } from "passport-github";
|
|
import { Strategy as GitLabStrategy } from "passport-gitlab2";
|
|
import { Strategy as GoogleStrategy } from "passport-google-oauth20";
|
|
import { z } from "zod";
|
|
|
|
import { getConfig } from "@app/lib/config/env";
|
|
import { BadRequestError } from "@app/lib/errors";
|
|
import { logger } from "@app/lib/logger";
|
|
import { fetchGithubEmails } from "@app/lib/requests/github";
|
|
import { AuthMethod } from "@app/services/auth/auth-type";
|
|
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
|
|
|
|
export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|
const appCfg = getConfig();
|
|
const passport = new Authenticator({ key: "sso", userProperty: "passportUser" });
|
|
await server.register(fastifySession, { secret: appCfg.COOKIE_SECRET_SIGN_KEY });
|
|
await server.register(passport.initialize());
|
|
await server.register(passport.secureSession());
|
|
// passport oauth strategy for Google
|
|
const isGoogleOauthActive = Boolean(appCfg.CLIENT_ID_GOOGLE_LOGIN && appCfg.CLIENT_SECRET_GOOGLE_LOGIN);
|
|
if (isGoogleOauthActive) {
|
|
passport.use(
|
|
new GoogleStrategy(
|
|
{
|
|
passReqToCallback: true,
|
|
clientID: appCfg.CLIENT_ID_GOOGLE_LOGIN as string,
|
|
clientSecret: appCfg.CLIENT_SECRET_GOOGLE_LOGIN as string,
|
|
callbackURL: `${appCfg.SITE_URL}/api/v1/sso/google`,
|
|
scope: ["profile", " email"]
|
|
},
|
|
// eslint-disable-next-line
|
|
async (req, _accessToken, _refreshToken, profile, cb) => {
|
|
try {
|
|
const email = profile?.emails?.[0]?.value;
|
|
const serverCfg = await getServerCfg();
|
|
if (!email)
|
|
throw new BadRequestError({
|
|
message: "Email not found",
|
|
name: "Oauth Google Register"
|
|
});
|
|
|
|
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
|
email,
|
|
firstName: profile?.name?.givenName || "",
|
|
lastName: profile?.name?.familyName || "",
|
|
authMethod: AuthMethod.GOOGLE,
|
|
callbackPort: req.query.state as string,
|
|
isSignupAllowed: Boolean(serverCfg.allowSignUp)
|
|
});
|
|
cb(null, { isUserCompleted, providerAuthToken });
|
|
} catch (error) {
|
|
logger.error(error);
|
|
cb(null, false);
|
|
}
|
|
}
|
|
)
|
|
);
|
|
}
|
|
|
|
// Passport strategy for Github
|
|
const isGithubOauthActive = Boolean(appCfg.CLIENT_SECRET_GITHUB_LOGIN && appCfg.CLIENT_ID_GITHUB_LOGIN);
|
|
if (isGithubOauthActive) {
|
|
passport.use(
|
|
new GitHubStrategy(
|
|
{
|
|
passReqToCallback: true,
|
|
clientID: appCfg.CLIENT_ID_GITHUB_LOGIN as string,
|
|
clientSecret: appCfg.CLIENT_SECRET_GITHUB_LOGIN as string,
|
|
callbackURL: `${appCfg.SITE_URL}/api/v1/sso/github`,
|
|
scope: ["user:email"]
|
|
},
|
|
// eslint-disable-next-line
|
|
async (req, accessToken, _refreshToken, profile, cb) => {
|
|
try {
|
|
const ghEmails = await fetchGithubEmails(accessToken);
|
|
const { email } = ghEmails.filter((gitHubEmail) => gitHubEmail.primary)[0];
|
|
const serverCfg = await getServerCfg();
|
|
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
|
email,
|
|
firstName: profile.displayName,
|
|
lastName: "",
|
|
authMethod: AuthMethod.GITHUB,
|
|
callbackPort: req.query.state as string,
|
|
isSignupAllowed: Boolean(serverCfg.allowSignUp)
|
|
});
|
|
return cb(null, { isUserCompleted, providerAuthToken });
|
|
} catch (error) {
|
|
logger.error(error);
|
|
cb(null, false);
|
|
}
|
|
}
|
|
)
|
|
);
|
|
}
|
|
|
|
// passport strategy for gitlab
|
|
const isGitlabOauthActive = Boolean(
|
|
appCfg.CLIENT_ID_GITLAB_LOGIN && appCfg.CLIENT_SECRET_GITLAB_LOGIN && appCfg.CLIENT_GITLAB_LOGIN_URL
|
|
);
|
|
if (isGitlabOauthActive) {
|
|
passport.use(
|
|
new GitLabStrategy(
|
|
{
|
|
passReqToCallback: true,
|
|
clientID: appCfg.CLIENT_ID_GITLAB_LOGIN,
|
|
clientSecret: appCfg.CLIENT_SECRET_GITLAB_LOGIN,
|
|
callbackURL: `${appCfg.SITE_URL}/api/v1/sso/gitlab`,
|
|
baseURL: appCfg.CLIENT_GITLAB_LOGIN_URL
|
|
},
|
|
async (req: any, _accessToken: string, _refreshToken: string, profile: any, cb: any) => {
|
|
try {
|
|
const email = profile.emails[0].value;
|
|
const serverCfg = await getServerCfg();
|
|
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
|
email,
|
|
firstName: profile.displayName,
|
|
lastName: "",
|
|
authMethod: AuthMethod.GITLAB,
|
|
callbackPort: req.query.state as string,
|
|
isSignupAllowed: Boolean(serverCfg.allowSignUp)
|
|
});
|
|
|
|
return cb(null, { isUserCompleted, providerAuthToken });
|
|
} catch (error) {
|
|
logger.error(error);
|
|
cb(null, false);
|
|
}
|
|
}
|
|
)
|
|
);
|
|
}
|
|
|
|
server.route({
|
|
url: "/redirect/google",
|
|
method: "GET",
|
|
schema: {
|
|
querystring: z.object({
|
|
callback_port: z.string().optional()
|
|
})
|
|
},
|
|
preValidation: (req, res) =>
|
|
(
|
|
passport.authenticate("google", {
|
|
scope: ["profile", "email"],
|
|
session: false,
|
|
state: req.query.callback_port,
|
|
authInfo: false
|
|
// this is due to zod type difference
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
}) as any
|
|
)(req, res),
|
|
handler: () => {}
|
|
});
|
|
|
|
server.route({
|
|
url: "/google",
|
|
method: "GET",
|
|
preValidation: passport.authenticate("google", {
|
|
session: false,
|
|
failureRedirect: "/login/provider/error",
|
|
authInfo: false
|
|
// this is due to zod type difference
|
|
}) as never,
|
|
handler: (req, res) => {
|
|
if (req.passportUser.isUserCompleted) {
|
|
return res.redirect(
|
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
|
);
|
|
}
|
|
return res.redirect(
|
|
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
|
);
|
|
}
|
|
});
|
|
|
|
server.route({
|
|
url: "/redirect/github",
|
|
method: "GET",
|
|
schema: {
|
|
querystring: z.object({
|
|
callback_port: z.string().optional()
|
|
})
|
|
},
|
|
preValidation: (req, res) =>
|
|
(
|
|
passport.authenticate("github", {
|
|
session: false,
|
|
state: req.query.callback_port,
|
|
authInfo: false
|
|
// this is due to zod type difference
|
|
}) as any
|
|
)(req, res),
|
|
handler: () => {}
|
|
});
|
|
|
|
server.route({
|
|
url: "/github",
|
|
method: "GET",
|
|
preValidation: passport.authenticate("github", {
|
|
session: false,
|
|
failureRedirect: "/login/provider/error",
|
|
authInfo: false
|
|
// this is due to zod type difference
|
|
}) as any,
|
|
handler: (req, res) => {
|
|
if (req.passportUser.isUserCompleted) {
|
|
return res.redirect(
|
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
|
);
|
|
}
|
|
return res.redirect(
|
|
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
|
);
|
|
}
|
|
});
|
|
|
|
server.route({
|
|
url: "/redirect/gitlab",
|
|
method: "GET",
|
|
schema: {
|
|
querystring: z.object({
|
|
callback_port: z.string().optional()
|
|
})
|
|
},
|
|
preValidation: (req, res) =>
|
|
(
|
|
passport.authenticate("gitlab", {
|
|
session: false,
|
|
state: req.query.callback_port,
|
|
authInfo: false
|
|
// this is due to zod type difference
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
}) as any
|
|
)(req, res),
|
|
handler: () => {}
|
|
});
|
|
|
|
server.route({
|
|
url: "/gitlab",
|
|
method: "GET",
|
|
preValidation: passport.authenticate("gitlab", {
|
|
session: false,
|
|
failureRedirect: "/login/provider/error",
|
|
authInfo: false
|
|
// this is due to zod type difference
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
}) as any,
|
|
handler: (req, res) => {
|
|
if (req.passportUser.isUserCompleted) {
|
|
return res.redirect(
|
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
|
);
|
|
}
|
|
return res.redirect(
|
|
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
|
);
|
|
}
|
|
});
|
|
};
|