import React, { useEffect, useRef, useState } from "react"; import { encodeAssertion } from "@/lib/saml"; import { GLOBAL_NONSECURE_KEY } from "@/key"; import { useStore } from "@/lib/store"; import { useParams } from "react-router"; import { z } from "zod"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { useSearchParams } from "react-router-dom"; import moment from "moment"; const formSchema = z.object({ email: z.string().email({ message: "Email must be a well-formed email." }), firstName: z.string(), lastName: z.string(), }); export function SSOPage() { const [storeData, _] = useStore(); const { appId } = useParams(); const app = storeData.apps[appId!]; const [searchParams] = useSearchParams(); const samlRequest = searchParams.get("SAMLRequest"); const [sessionId, setSessionId] = useState(""); useEffect(() => { if (!samlRequest) { return; } const samlRequestXML = atob( // url to std base64 samlRequest.replace(/-/g, "+").replace(/_/g, "/"), ); const parser = new DOMParser(); const doc = parser.parseFromString(samlRequestXML, "text/xml"); // use xpath to get the AuthnRequest ID, throwing away all namespace information to make that easier const id = doc.evaluate( "string(/_:AuthnRequest/@ID)", doc, (_) => "urn:oasis:names:tc:SAML:2.0:protocol", XPathResult.STRING_TYPE, null, ).stringValue; setSessionId(id); }, [samlRequest]); const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { email: "", firstName: "", lastName: "", }, }); async function onSubmit(values: z.infer, e: any) { const key = await window.crypto.subtle.importKey( "jwk", GLOBAL_NONSECURE_KEY, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256", }, true, ["sign"], ); const now = moment(new Date()); const expire = moment(new Date()).add(1, "hour"); inputRef.current!.value = await encodeAssertion(key, { idpEntityId: `https://dummyidp.com/apps/${app.id}`, subjectId: values.email, spEntityId: app.spEntityId, sessionId: sessionId, now: now.format(), expire: expire.format(), }); inputRef.current!.form!.submit(); } const inputRef = useRef(null); return ( <>
Log on Enter some details about who you want DummyIDP to log you in as.
( Email )} /> ( First Name )} /> ( Last Name )} />
); }