mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 04:29:36 +00:00
Add Google SSO
This commit is contained in:
Generated
+1866
-1797
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,30 @@ import {
|
||||
getSiteURL
|
||||
} from "../../../config";
|
||||
|
||||
router.get(
|
||||
"/redirect/google",
|
||||
authLimiter,
|
||||
passport.authenticate("google", {
|
||||
scope: ["profile", "email"],
|
||||
session: false,
|
||||
})
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/google",
|
||||
passport.authenticate("google", {
|
||||
failureRedirect: "/login/provider/error",
|
||||
session: false
|
||||
}),
|
||||
async (req, res) => {
|
||||
if (req.isUserCompleted) {
|
||||
res.redirect(`${await getSiteURL()}/login/sso?token=${encodeURIComponent(req.providerAuthToken)}`);
|
||||
} else {
|
||||
res.redirect(`${await getSiteURL()}/signup/sso?token=${encodeURIComponent(req.providerAuthToken)}`);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/redirect/saml2/:ssoIdentifier",
|
||||
authLimiter,
|
||||
@@ -32,7 +56,7 @@ router.post("/saml2/:ssoIdentifier",
|
||||
failureFlash: true,
|
||||
session: false
|
||||
}),
|
||||
async (req, res) => {
|
||||
async (req, res) => { // TODO: move this into controller
|
||||
if (req.isUserCompleted) {
|
||||
return res.redirect(`${await getSiteURL()}/login/sso?token=${encodeURIComponent(req.providerAuthToken)}`);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ interface FeatureSet {
|
||||
customRateLimits: boolean;
|
||||
customAlerts: boolean;
|
||||
auditLogs: boolean;
|
||||
samlSSO: boolean;
|
||||
status: "incomplete" | "incomplete_expired" | "trialing" | "active" | "past_due" | "canceled" | "unpaid" | null;
|
||||
trial_end: number | null;
|
||||
has_used_trial: boolean;
|
||||
@@ -63,6 +64,7 @@ class EELicenseService {
|
||||
customRateLimits: true,
|
||||
customAlerts: true,
|
||||
auditLogs: false,
|
||||
samlSSO: false,
|
||||
status: null,
|
||||
trial_end: null,
|
||||
has_used_trial: true
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import express from "express";
|
||||
const router = express.Router();
|
||||
import { body } from "express-validator";
|
||||
import passport from "passport";
|
||||
import { requireAuth, validateRequest } from "../../middleware";
|
||||
import { authController } from "../../controllers/v1";
|
||||
import { authLimiter } from "../../helpers/rateLimiter";
|
||||
@@ -44,21 +43,6 @@ router.post(
|
||||
authController.checkAuth
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/redirect/google",
|
||||
authLimiter,
|
||||
passport.authenticate("google", {
|
||||
scope: ["profile", "email"],
|
||||
session: false,
|
||||
}),
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/callback/google",
|
||||
passport.authenticate("google", { failureRedirect: "/login/provider/error", session: false }),
|
||||
authController.handleAuthProviderCallback,
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/common-passwords",
|
||||
authLimiter,
|
||||
|
||||
+34
-17
@@ -18,16 +18,15 @@ import {
|
||||
getJwtProviderAuthSecret,
|
||||
} from "../config";
|
||||
import { getSSOConfigHelper } from "../ee/helpers/organizations";
|
||||
import { OrganizationNotFoundError } from "./errors";
|
||||
import { OrganizationNotFoundError, InternalServerError } from "./errors";
|
||||
import { MEMBER, INVITED } from "../variables";
|
||||
import { getSiteURL } from "../config";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const GoogleStrategy = require("passport-google-oauth20").Strategy;
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { MultiSamlStrategy } = require("@node-saml/passport-saml");
|
||||
|
||||
// TODO: find a more optimal folder structure to store these types of functions
|
||||
|
||||
/**
|
||||
* Returns an object containing the id of the authentication data payload
|
||||
* @param {AuthData} authData - authentication data object
|
||||
@@ -75,45 +74,57 @@ const initializePassport = async () => {
|
||||
passReqToCallback: true,
|
||||
clientID: googleClientId,
|
||||
clientSecret: googleClientSecret,
|
||||
callbackURL: "/api/v1/auth/callback/google",
|
||||
callbackURL: "/api/v1/sso/google",
|
||||
scope: ["profile", " email"],
|
||||
}, async (
|
||||
req: express.Request,
|
||||
accessToken: string,
|
||||
refreshToken: string,
|
||||
profile: any,
|
||||
cb: any
|
||||
done: any
|
||||
) => {
|
||||
try {
|
||||
const email = profile.emails[0].value;
|
||||
const firstName = profile.name.givenName;
|
||||
const lastName = profile.name.familyName;
|
||||
|
||||
let user = await User.findOne({
|
||||
authProvider: AuthProvider.GOOGLE,
|
||||
authId: profile.id,
|
||||
}).select("+publicKey")
|
||||
email
|
||||
}).select("+publicKey");
|
||||
|
||||
if (user && user.authProvider !== AuthProvider.GOOGLE) {
|
||||
done(InternalServerError());
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
user = await new User({
|
||||
email,
|
||||
authProvider: AuthProvider.GOOGLE,
|
||||
authId: profile.id,
|
||||
firstName,
|
||||
lastName
|
||||
}).save();
|
||||
}
|
||||
|
||||
const isUserCompleted = !!user.publicKey;
|
||||
const providerAuthToken = createToken({
|
||||
payload: {
|
||||
userId: user._id.toString(),
|
||||
email: user.email,
|
||||
firstName,
|
||||
lastName,
|
||||
authProvider: user.authProvider,
|
||||
isUserCompleted: !!user.publicKey,
|
||||
isUserCompleted
|
||||
},
|
||||
expiresIn: await getJwtProviderAuthLifetime(),
|
||||
secret: await getJwtProviderAuthSecret(),
|
||||
});
|
||||
|
||||
req.isUserCompleted = isUserCompleted;
|
||||
req.providerAuthToken = providerAuthToken;
|
||||
cb(null, profile);
|
||||
done(null, profile);
|
||||
} catch (err) {
|
||||
cb(null, false);
|
||||
done(null, false);
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -129,7 +140,7 @@ const initializePassport = async () => {
|
||||
|
||||
const samlConfig = ({
|
||||
path: "/api/v1/auth/callback/saml",
|
||||
callbackURL: "http://localhost:8080/api/v1/auth/callback/saml", // TODO: get rid of localhost:8080 here
|
||||
callbackURL: `${await getSiteURL()}/api/v1/auth/callback/saml`,
|
||||
entryPoint: ssoConfig.entryPoint,
|
||||
issuer: ssoConfig.issuer,
|
||||
cert: ssoConfig.cert,
|
||||
@@ -142,24 +153,30 @@ const initializePassport = async () => {
|
||||
},
|
||||
},
|
||||
async (req: any, profile: any, done: any) => {
|
||||
|
||||
if (!req.ssoConfig.isActive) return done(InternalServerError());
|
||||
|
||||
const organization = await Organization.findById(req.ssoConfig.organization);
|
||||
|
||||
if (!organization) done(OrganizationNotFoundError());
|
||||
if (!organization) return done(OrganizationNotFoundError());
|
||||
|
||||
const email = profile.email;
|
||||
const firstName = profile.firstName;
|
||||
const lastName = profile.lastName;
|
||||
|
||||
|
||||
let user = await User.findOne({
|
||||
authProvider: AuthProvider.OKTA_SAML,
|
||||
email
|
||||
}).select("+publicKey");
|
||||
|
||||
if (user && user.authProvider !== AuthProvider.OKTA_SAML) {
|
||||
done(InternalServerError());
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
user = await new User({
|
||||
email,
|
||||
authProvider: AuthProvider.OKTA_SAML,
|
||||
authId: profile.id,
|
||||
firstName,
|
||||
lastName
|
||||
}).save();
|
||||
@@ -178,8 +195,8 @@ const initializePassport = async () => {
|
||||
payload: {
|
||||
userId: user._id.toString(),
|
||||
email: user.email,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
firstName,
|
||||
lastName,
|
||||
organizationName: organization?.name,
|
||||
authProvider: user.authProvider,
|
||||
isUserCompleted
|
||||
|
||||
Reference in New Issue
Block a user