mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 22:28:15 +00:00
feat: integrated oidc with sso login
This commit is contained in:
@@ -59,7 +59,7 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
const oidcStrategy = await server.services.oidc.getOrgAuthStrategy(oidcOrgSlug);
|
const oidcStrategy = await server.services.oidc.getOrgAuthStrategy(oidcOrgSlug);
|
||||||
await (
|
await (
|
||||||
passport.authenticate(oidcStrategy as Strategy, {
|
passport.authenticate(oidcStrategy as Strategy, {
|
||||||
failureRedirect: "/api/v1/oidc/login/error",
|
failureRedirect: "/api/v1/sso/oidc/login/error",
|
||||||
session: false,
|
session: false,
|
||||||
failureMessage: true
|
failureMessage: true
|
||||||
}) as any
|
}) as any
|
||||||
@@ -137,13 +137,13 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
schema: {
|
schema: {
|
||||||
body: z
|
body: z
|
||||||
.object({
|
.object({
|
||||||
issuer: z.string(),
|
issuer: z.string().trim(),
|
||||||
authorizationEndpoint: z.string(),
|
authorizationEndpoint: z.string().trim(),
|
||||||
jwksUri: z.string(),
|
jwksUri: z.string().trim(),
|
||||||
tokenEndpoint: z.string(),
|
tokenEndpoint: z.string().trim(),
|
||||||
userinfoEndpoint: z.string(),
|
userinfoEndpoint: z.string().trim(),
|
||||||
clientId: z.string(),
|
clientId: z.string().trim(),
|
||||||
clientSecret: z.string(),
|
clientSecret: z.string().trim(),
|
||||||
isActive: z.boolean()
|
isActive: z.boolean()
|
||||||
})
|
})
|
||||||
.partial()
|
.partial()
|
||||||
@@ -182,15 +182,15 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
schema: {
|
schema: {
|
||||||
body: z.object({
|
body: z.object({
|
||||||
issuer: z.string(),
|
issuer: z.string().trim(),
|
||||||
authorizationEndpoint: z.string(),
|
authorizationEndpoint: z.string().trim(),
|
||||||
jwksUri: z.string(),
|
jwksUri: z.string().trim(),
|
||||||
tokenEndpoint: z.string(),
|
tokenEndpoint: z.string().trim(),
|
||||||
userinfoEndpoint: z.string(),
|
userinfoEndpoint: z.string().trim(),
|
||||||
clientId: z.string(),
|
clientId: z.string().trim(),
|
||||||
clientSecret: z.string(),
|
clientSecret: z.string().trim(),
|
||||||
isActive: z.boolean(),
|
isActive: z.boolean(),
|
||||||
orgSlug: z.string()
|
orgSlug: z.string().trim()
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: OidcConfigsSchema.pick({
|
200: OidcConfigsSchema.pick({
|
||||||
|
|||||||
@@ -520,7 +520,7 @@ export const oidcConfigServiceFactory = ({
|
|||||||
const client = new openIdIssuer.Client({
|
const client = new openIdIssuer.Client({
|
||||||
client_id: oidcCfg.clientId,
|
client_id: oidcCfg.clientId,
|
||||||
client_secret: oidcCfg.clientSecret,
|
client_secret: oidcCfg.clientSecret,
|
||||||
redirect_uris: [`${appCfg.SITE_URL}/api/v1/oidc/callback`]
|
redirect_uris: [`${appCfg.SITE_URL}/api/v1/sso/oidc/callback`]
|
||||||
});
|
});
|
||||||
|
|
||||||
const strategy = new OpenIdStrategy(
|
const strategy = new OpenIdStrategy(
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useRouter } from "next/router";
|
|||||||
|
|
||||||
import { isLoggedIn } from "@app/reactQuery";
|
import { isLoggedIn } from "@app/reactQuery";
|
||||||
|
|
||||||
import { InitialStep, MFAStep, SAMLSSOStep } from "./components";
|
import { InitialStep, MFAStep, SSOStep } from "./components";
|
||||||
import { navigateUserToSelectOrg } from "./Login.utils";
|
import { navigateUserToSelectOrg } from "./Login.utils";
|
||||||
|
|
||||||
export const Login = () => {
|
export const Login = () => {
|
||||||
@@ -57,7 +57,9 @@ export const Login = () => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 2:
|
case 2:
|
||||||
return <SAMLSSOStep setStep={setStep} />;
|
return <SSOStep setStep={setStep} type="SAML" />;
|
||||||
|
case 3:
|
||||||
|
return <SSOStep setStep={setStep} type="OIDC" />;
|
||||||
default:
|
default:
|
||||||
return <div />;
|
return <div />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,11 +40,13 @@ export const InitialStep = ({ setStep, email, setEmail, password, setPassword }:
|
|||||||
const { data: serverDetails } = useFetchServerStatus();
|
const { data: serverDetails } = useFetchServerStatus();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (serverDetails?.samlDefaultOrgSlug){
|
if (serverDetails?.samlDefaultOrgSlug) {
|
||||||
const callbackPort = queryParams.get("callback_port");
|
const callbackPort = queryParams.get("callback_port");
|
||||||
const redirectUrl = `/api/v1/sso/redirect/saml2/organizations/${serverDetails?.samlDefaultOrgSlug}${callbackPort ? `?callback_port=${callbackPort}` : ""}`
|
const redirectUrl = `/api/v1/sso/redirect/saml2/organizations/${
|
||||||
router.push(redirectUrl);
|
serverDetails?.samlDefaultOrgSlug
|
||||||
}
|
}${callbackPort ? `?callback_port=${callbackPort}` : ""}`;
|
||||||
|
router.push(redirectUrl);
|
||||||
|
}
|
||||||
}, [serverDetails?.samlDefaultOrgSlug]);
|
}, [serverDetails?.samlDefaultOrgSlug]);
|
||||||
|
|
||||||
const handleLogin = async (e: FormEvent<HTMLFormElement>) => {
|
const handleLogin = async (e: FormEvent<HTMLFormElement>) => {
|
||||||
@@ -217,6 +219,19 @@ export const InitialStep = ({ setStep, email, setEmail, password, setPassword }:
|
|||||||
Continue with SAML
|
Continue with SAML
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-2 w-1/4 min-w-[21.2rem] rounded-md text-center md:min-w-[20.1rem] lg:w-1/6">
|
||||||
|
<Button
|
||||||
|
colorSchema="primary"
|
||||||
|
variant="outline_bg"
|
||||||
|
onClick={() => {
|
||||||
|
setStep(3);
|
||||||
|
}}
|
||||||
|
leftIcon={<FontAwesomeIcon icon={faLock} className="mr-2" />}
|
||||||
|
className="mx-0 h-10 w-full"
|
||||||
|
>
|
||||||
|
Continue with OIDC
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
<div className="mt-2 w-1/4 min-w-[21.2rem] rounded-md text-center md:min-w-[20.1rem] lg:w-1/6">
|
<div className="mt-2 w-1/4 min-w-[21.2rem] rounded-md text-center md:min-w-[20.1rem] lg:w-1/6">
|
||||||
<Button
|
<Button
|
||||||
colorSchema="primary"
|
colorSchema="primary"
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export { SAMLSSOStep } from "./SAMLSSOStep";
|
|
||||||
+17
-10
@@ -5,9 +5,10 @@ import { Button, Input } from "@app/components/v2";
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
setStep: (step: number) => void;
|
setStep: (step: number) => void;
|
||||||
|
type: "SAML" | "OIDC";
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SAMLSSOStep = ({ setStep }: Props) => {
|
export const SSOStep = ({ setStep, type }: Props) => {
|
||||||
const [ssoIdentifier, setSSOIdentifier] = useState("");
|
const [ssoIdentifier, setSSOIdentifier] = useState("");
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -16,21 +17,27 @@ export const SAMLSSOStep = ({ setStep }: Props) => {
|
|||||||
const handleSubmission = (e: React.FormEvent) => {
|
const handleSubmission = (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const callbackPort = queryParams.get("callback_port");
|
const callbackPort = queryParams.get("callback_port");
|
||||||
window.open(
|
if (type === "SAML") {
|
||||||
`/api/v1/sso/redirect/saml2/organizations/${ssoIdentifier}${
|
window.open(
|
||||||
callbackPort ? `?callback_port=${callbackPort}` : ""
|
`/api/v1/sso/redirect/saml2/organizations/${ssoIdentifier}${
|
||||||
}`
|
callbackPort ? `?callback_port=${callbackPort}` : ""
|
||||||
);
|
}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// TODO: Sheen - Add callback support for CLI login
|
||||||
|
window.open(`/api/v1/sso/oidc/login?orgSlug=${ssoIdentifier}`);
|
||||||
|
}
|
||||||
|
|
||||||
window.close();
|
window.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto w-full max-w-md md:px-6">
|
<div className="mx-auto w-full max-w-md md:px-6">
|
||||||
<p className="mx-auto mb-6 mb-8 flex w-max justify-center bg-gradient-to-b from-white to-bunker-200 bg-clip-text text-center text-xl font-medium text-transparent">
|
<p className="mx-auto mb-8 flex w-max justify-center bg-gradient-to-b from-white to-bunker-200 bg-clip-text text-center text-xl font-medium text-transparent">
|
||||||
What's your organization slug?
|
What's your organization slug?
|
||||||
</p>
|
</p>
|
||||||
<form onSubmit={handleSubmission}>
|
<form onSubmit={handleSubmission}>
|
||||||
<div className="relative mx-auto flex max-h-24 w-1/4 w-full min-w-[20rem] items-center justify-center rounded-lg md:max-h-28 md:min-w-[22rem] lg:w-1/6">
|
<div className="relative mx-auto flex max-h-24 w-full min-w-[20rem] items-center justify-center rounded-lg md:max-h-28 md:min-w-[22rem] lg:w-1/6">
|
||||||
<div className="flex max-h-24 w-full items-center justify-center rounded-lg md:max-h-28">
|
<div className="flex max-h-24 w-full items-center justify-center rounded-lg md:max-h-28">
|
||||||
<Input
|
<Input
|
||||||
value={ssoIdentifier}
|
value={ssoIdentifier}
|
||||||
@@ -44,7 +51,7 @@ export const SAMLSSOStep = ({ setStep }: Props) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx-auto mt-4 flex w-1/4 w-full min-w-[20rem] items-center justify-center rounded-md text-center md:min-w-[22rem] lg:w-1/6">
|
<div className="mx-auto mt-4 flex w-full min-w-[20rem] items-center justify-center rounded-md text-center md:min-w-[22rem] lg:w-1/6">
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
colorSchema="primary"
|
colorSchema="primary"
|
||||||
@@ -52,7 +59,7 @@ export const SAMLSSOStep = ({ setStep }: Props) => {
|
|||||||
isFullWidth
|
isFullWidth
|
||||||
className="h-14"
|
className="h-14"
|
||||||
>
|
>
|
||||||
Continue with SAML
|
Continue with {type}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { SSOStep } from "./SSOStep";
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
export { InitialStep } from "./InitialStep";
|
export { InitialStep } from "./InitialStep";
|
||||||
export { MFAStep } from "./MFAStep";
|
export { MFAStep } from "./MFAStep";
|
||||||
export { SAMLSSOStep } from "./SAMLSSOStep";
|
export { SSOStep } from "./SSOStep";
|
||||||
|
|
||||||
// SSO-specific step
|
// SSO-specific step
|
||||||
export { PasswordStep } from "./PasswordStep";
|
export { PasswordStep } from "./PasswordStep";
|
||||||
|
|||||||
Reference in New Issue
Block a user