Merge pull request #3471 from Infisical/feat/add-support-for-org-sso-bypass-for-sso

feat: enabled sso (google, gitlab, github) to bypass org sso
This commit is contained in:
Sheen
2025-04-28 22:35:53 +08:00
committed by GitHub
6 changed files with 90 additions and 29 deletions
+1
View File
@@ -118,6 +118,7 @@ declare module "@fastify/request-context" {
declare module "fastify" { declare module "fastify" {
interface Session { interface Session {
callbackPort: string; callbackPort: string;
isAdminLogin: boolean;
} }
interface FastifyRequest { interface FastifyRequest {
+41 -9
View File
@@ -168,17 +168,24 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
method: "GET", method: "GET",
schema: { schema: {
querystring: z.object({ querystring: z.object({
callback_port: z.string().optional() callback_port: z.string().optional(),
is_admin_login: z
.string()
.optional()
.transform((val) => val === "true")
}) })
}, },
preValidation: [ preValidation: [
async (req, res) => { async (req, res) => {
const { callback_port: callbackPort } = req.query; const { callback_port: callbackPort, is_admin_login: isAdminLogin } = req.query;
// ensure fresh session state per login attempt // ensure fresh session state per login attempt
await req.session.regenerate(); await req.session.regenerate();
if (callbackPort) { if (callbackPort) {
req.session.set("callbackPort", callbackPort); req.session.set("callbackPort", callbackPort);
} }
if (isAdminLogin) {
req.session.set("isAdminLogin", isAdminLogin);
}
return ( return (
passport.authenticate("google", { passport.authenticate("google", {
scope: ["profile", "email"], scope: ["profile", "email"],
@@ -202,10 +209,13 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
// this is due to zod type difference // this is due to zod type difference
}) as never, }) as never,
handler: async (req, res) => { handler: async (req, res) => {
const isAdminLogin = req.session.get("isAdminLogin");
await req.session.destroy(); await req.session.destroy();
if (req.passportUser.isUserCompleted) { if (req.passportUser.isUserCompleted) {
return res.redirect( return res.redirect(
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}` `${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}${
isAdminLogin ? `&isAdminLogin=${isAdminLogin}` : ""
}`
); );
} }
return res.redirect( return res.redirect(
@@ -219,18 +229,26 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
method: "GET", method: "GET",
schema: { schema: {
querystring: z.object({ querystring: z.object({
callback_port: z.string().optional() callback_port: z.string().optional(),
is_admin_login: z
.string()
.optional()
.transform((val) => val === "true")
}) })
}, },
preValidation: [ preValidation: [
async (req, res) => { async (req, res) => {
const { callback_port: callbackPort } = req.query; const { callback_port: callbackPort, is_admin_login: isAdminLogin } = req.query;
// ensure fresh session state per login attempt // ensure fresh session state per login attempt
await req.session.regenerate(); await req.session.regenerate();
if (callbackPort) { if (callbackPort) {
req.session.set("callbackPort", callbackPort); req.session.set("callbackPort", callbackPort);
} }
if (isAdminLogin) {
req.session.set("isAdminLogin", isAdminLogin);
}
return ( return (
passport.authenticate("github", { passport.authenticate("github", {
session: false, session: false,
@@ -291,6 +309,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
// this is due to zod type difference // this is due to zod type difference
}) as any, }) as any,
handler: async (req, res) => { handler: async (req, res) => {
const isAdminLogin = req.session.get("isAdminLogin");
await req.session.destroy(); await req.session.destroy();
if (req.passportUser.externalProviderAccessToken) { if (req.passportUser.externalProviderAccessToken) {
@@ -305,7 +324,9 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
if (req.passportUser.isUserCompleted) { if (req.passportUser.isUserCompleted) {
return res.redirect( return res.redirect(
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}` `${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}${
isAdminLogin ? `&isAdminLogin=${isAdminLogin}` : ""
}`
); );
} }
return res.redirect( return res.redirect(
@@ -319,18 +340,26 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
method: "GET", method: "GET",
schema: { schema: {
querystring: z.object({ querystring: z.object({
callback_port: z.string().optional() callback_port: z.string().optional(),
is_admin_login: z
.string()
.optional()
.transform((val) => val === "true")
}) })
}, },
preValidation: [ preValidation: [
async (req, res) => { async (req, res) => {
const { callback_port: callbackPort } = req.query; const { callback_port: callbackPort, is_admin_login: isAdminLogin } = req.query;
// ensure fresh session state per login attempt // ensure fresh session state per login attempt
await req.session.regenerate(); await req.session.regenerate();
if (callbackPort) { if (callbackPort) {
req.session.set("callbackPort", callbackPort); req.session.set("callbackPort", callbackPort);
} }
if (isAdminLogin) {
req.session.set("isAdminLogin", isAdminLogin);
}
return ( return (
passport.authenticate("gitlab", { passport.authenticate("gitlab", {
session: false, session: false,
@@ -355,10 +384,13 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
}) as any, }) as any,
handler: async (req, res) => { handler: async (req, res) => {
const isAdminLogin = req.session.get("isAdminLogin");
await req.session.destroy(); await req.session.destroy();
if (req.passportUser.isUserCompleted) { if (req.passportUser.isUserCompleted) {
return res.redirect( return res.redirect(
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}` `${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}${
isAdminLogin ? `&isAdminLogin=${isAdminLogin}` : ""
}`
); );
} }
return res.redirect( return res.redirect(
@@ -269,12 +269,19 @@ export const InitialStep = ({
variant="outline_bg" variant="outline_bg"
onClick={() => { onClick={() => {
const callbackPort = queryParams.get("callback_port"); const callbackPort = queryParams.get("callback_port");
const searchParams = new URLSearchParams();
window.open( if (callbackPort) {
`/api/v1/sso/redirect/google${ searchParams.append("callback_port", callbackPort);
callbackPort ? `?callback_port=${callbackPort}` : "" }
}`
); if (isAdmin) {
searchParams.append("is_admin_login", "true");
}
const queryString = searchParams.toString();
window.open(`/api/v1/sso/redirect/google${queryString ? `?${queryString}` : ""}`);
window.close(); window.close();
}} }}
className="h-10 w-full bg-mineshaft-600" className="h-10 w-full bg-mineshaft-600"
@@ -291,13 +298,19 @@ export const InitialStep = ({
variant="outline_bg" variant="outline_bg"
onClick={() => { onClick={() => {
const callbackPort = queryParams.get("callback_port"); const callbackPort = queryParams.get("callback_port");
const searchParams = new URLSearchParams();
window.open( if (callbackPort) {
`/api/v1/sso/redirect/github${ searchParams.append("callback_port", callbackPort);
callbackPort ? `?callback_port=${callbackPort}` : "" }
}`
);
if (isAdmin) {
searchParams.append("is_admin_login", "true");
}
const queryString = searchParams.toString();
window.open(`/api/v1/sso/redirect/github${queryString ? `?${queryString}` : ""}`);
window.close(); window.close();
}} }}
className="h-10 w-full bg-mineshaft-600" className="h-10 w-full bg-mineshaft-600"
@@ -314,13 +327,19 @@ export const InitialStep = ({
variant="outline_bg" variant="outline_bg"
onClick={() => { onClick={() => {
const callbackPort = queryParams.get("callback_port"); const callbackPort = queryParams.get("callback_port");
const searchParams = new URLSearchParams();
window.open( if (callbackPort) {
`/api/v1/sso/redirect/gitlab${ searchParams.append("callback_port", callbackPort);
callbackPort ? `?callback_port=${callbackPort}` : "" }
}`
);
if (isAdmin) {
searchParams.append("is_admin_login", "true");
}
const queryString = searchParams.toString();
window.open(`/api/v1/sso/redirect/gitlab${queryString ? `?${queryString}` : ""}`);
window.close(); window.close();
}} }}
className="h-10 w-full bg-mineshaft-600" className="h-10 w-full bg-mineshaft-600"
@@ -27,9 +27,16 @@ type Props = {
email: string; email: string;
password: string; password: string;
setPassword: (password: string) => void; setPassword: (password: string) => void;
isAdminLogin?: boolean;
}; };
export const PasswordStep = ({ providerAuthToken, email, password, setPassword }: Props) => { export const PasswordStep = ({
providerAuthToken,
email,
password,
setPassword,
isAdminLogin
}: Props) => {
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -114,7 +121,7 @@ export const PasswordStep = ({ providerAuthToken, email, password, setPassword }
// case: user has orgs, so we navigate the user to select an org // case: user has orgs, so we navigate the user to select an org
if (userOrgs.length > 0) { if (userOrgs.length > 0) {
navigateToSelectOrganization(callbackPort); navigateToSelectOrganization(callbackPort, isAdminLogin);
} }
// case: no orgs found, so we navigate the user to create an org // case: no orgs found, so we navigate the user to create an org
else { else {
@@ -216,7 +223,7 @@ export const PasswordStep = ({ providerAuthToken, email, password, setPassword }
// case: user has orgs, so we navigate the user to select an org // case: user has orgs, so we navigate the user to select an org
if (userOrgs.length > 0) { if (userOrgs.length > 0) {
navigateToSelectOrganization(callbackPort); navigateToSelectOrganization(callbackPort, isAdminLogin);
} }
// case: no orgs found, so we navigate the user to create an org // case: no orgs found, so we navigate the user to create an org
else { else {
@@ -249,7 +256,7 @@ export const PasswordStep = ({ providerAuthToken, email, password, setPassword }
const userOrgs = await fetchOrganizations(); const userOrgs = await fetchOrganizations();
if (userOrgs.length > 0) { if (userOrgs.length > 0) {
navigateToSelectOrganization(); navigateToSelectOrganization(undefined, isAdminLogin);
} else { } else {
await navigateUserToOrg(navigate); await navigateUserToOrg(navigate);
} }
@@ -34,6 +34,7 @@ export const LoginSsoPage = () => {
email={username} email={username}
password={password} password={password}
setPassword={setPassword} setPassword={setPassword}
isAdminLogin={search.isAdminLogin}
/> />
); );
default: default:
@@ -5,7 +5,8 @@ import { z } from "zod";
import { LoginSsoPage } from "./LoginSsoPage"; import { LoginSsoPage } from "./LoginSsoPage";
const LoginSSOQueryParamsSchema = z.object({ const LoginSSOQueryParamsSchema = z.object({
token: z.string() token: z.string(),
isAdminLogin: z.boolean().optional().catch(false)
}); });
export const Route = createFileRoute("/_restrict-login-signup/login/sso")({ export const Route = createFileRoute("/_restrict-login-signup/login/sso")({