Idp login (#13)
* Support IdP login * added ldP login link * tweaked layout * redirectUrl -> acsUrl * Added secondary button class * Style and layout tweaks * Add aria-hidden to svg Co-authored-by: Aswin V <vaswin91@gmail.com>
This commit is contained in:
parent
d1f6cba776
commit
60c1fe9bf9
@ -5,7 +5,7 @@ export default function Header() {
|
|||||||
<header className='body-font text-gray-600'>
|
<header className='body-font text-gray-600'>
|
||||||
<div className='container mx-auto flex flex-col flex-wrap items-center p-5 md:flex-row'>
|
<div className='container mx-auto flex flex-col flex-wrap items-center p-5 md:flex-row'>
|
||||||
<Link href='/'>
|
<Link href='/'>
|
||||||
<a className='title-font mb-4 flex items-center font-medium text-gray-900 md:mb-0'>
|
<a className='title-font flex items-center font-medium text-gray-900 md:mb-0'>
|
||||||
<svg
|
<svg
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
fill='none'
|
fill='none'
|
||||||
@ -17,22 +17,22 @@ export default function Header() {
|
|||||||
viewBox='0 0 24 24'>
|
viewBox='0 0 24 24'>
|
||||||
<path d='M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5' />
|
<path d='M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5' />
|
||||||
</svg>
|
</svg>
|
||||||
<span className='ml-3 text-xl'>Mock SAML</span>
|
<span className='ml-3 text-2xl'>Mock SAML</span>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<span className='ml-2 text-sm text-gray-500'>
|
<nav className='mt-2 flex flex-col flex-wrap items-center text-base md:ml-auto md:mt-0 md:items-end'>
|
||||||
Powered by
|
<span className='ml-2 text-sm text-gray-500 '>
|
||||||
|
Made with <span className='text-[#e25555]'>♥</span>
|
||||||
|
<a
|
||||||
|
href='https://boxyhq.com/'
|
||||||
|
className='ml-1 text-gray-600'
|
||||||
|
rel='noopener noreferrer'
|
||||||
|
target='_blank'>
|
||||||
|
<strong>BoxyHQ</strong>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
<a
|
<a
|
||||||
href='https://boxyhq.com/'
|
className='leading-5 underline hover:text-gray-900'
|
||||||
className='ml-1 text-gray-600'
|
|
||||||
rel='noopener noreferrer'
|
|
||||||
target='_blank'>
|
|
||||||
<strong>BoxyHQ</strong>
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
<nav className='flex flex-wrap items-center justify-center text-base md:ml-auto'>
|
|
||||||
<a
|
|
||||||
className='mr-5 underline hover:text-gray-900'
|
|
||||||
href='https://github.com/boxyhq/jackson'
|
href='https://github.com/boxyhq/jackson'
|
||||||
rel='noopener noreferrer'
|
rel='noopener noreferrer'
|
||||||
target='_blank'>
|
target='_blank'>
|
||||||
|
|||||||
@ -23,39 +23,58 @@ const Home: React.FC<{ metadata: IdPMetadata }> = ({ metadata }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className='body-font text-gray-600'>
|
<section className='body-font text-gray-600'>
|
||||||
<div className='container mx-auto px-5 py-24'>
|
<div className='container mx-auto px-5 py-8'>
|
||||||
<div className='mb-12 flex w-full flex-col text-center'>
|
<div className='mb-5 flex w-full flex-col text-center'>
|
||||||
<h1 className='title-font mb-4 text-2xl font-medium text-gray-900 sm:text-3xl'>
|
|
||||||
Mock SAML Metadata
|
|
||||||
</h1>
|
|
||||||
<p className='mx-auto text-lg font-medium leading-relaxed lg:w-2/3'>
|
<p className='mx-auto text-lg font-medium leading-relaxed lg:w-2/3'>
|
||||||
A free SAML 2.0 Identity Provider for testing SAML SSO integrations.
|
A free SAML 2.0 Identity Provider for testing SAML SSO integrations.
|
||||||
|
<sup className='text-xl text-orange-600'>*</sup>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<div className='mx-auto mt-4 flex w-full justify-center px-8 lg:w-2/3'>
|
||||||
<b>Please do not use this in production.</b>
|
<Link href='/saml/login'>
|
||||||
</p>
|
<a className='button min-w-[14rem] py-3 text-xl tracking-wide'>Test IdP Login</a>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='mx-auto flex w-full items-end space-y-4 px-8 sm:space-x-4 sm:space-y-0 sm:px-0 lg:w-2/3'>
|
<h2 className='title-font mt-9 text-center text-lg font-medium text-gray-900 sm:text-3xl'>
|
||||||
<div className='relative mr-4 lg:w-full'>
|
Mock SAML Metadata
|
||||||
|
</h2>
|
||||||
|
<div className='mx-auto mt-5 flex w-full space-x-6 px-8 lg:w-2/3'>
|
||||||
|
<div className='relative flex-1'>
|
||||||
<label className='text-sm leading-7 text-gray-600'>SSO URL</label>
|
<label className='text-sm leading-7 text-gray-600'>SSO URL</label>
|
||||||
<input readOnly type='text' defaultValue={ssoUrl} className='input w-full' />
|
<input readOnly type='text' defaultValue={ssoUrl} className='input w-full' />
|
||||||
</div>
|
</div>
|
||||||
<div className='relative mr-4 lg:w-full'>
|
<div className='relative flex-1'>
|
||||||
<label className='text-sm leading-7 text-gray-600'>Entity ID</label>
|
<label className='text-sm leading-7 text-gray-600'>Entity ID</label>
|
||||||
<input readOnly type='text' defaultValue={entityId} className='input w-full' />
|
<input readOnly type='text' defaultValue={entityId} className='input w-full' />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='mx-auto mt-5 flex w-full items-end space-y-4 px-8 sm:space-x-4 sm:space-y-0 sm:px-0 lg:w-2/3'>
|
<div className='mx-auto mt-5 flex w-full px-8 lg:w-2/3'>
|
||||||
<div className='relative lg:w-full'>
|
<div className='relative w-full'>
|
||||||
<label className='text-sm leading-7 text-gray-600'>Certificate</label>
|
<label className='text-sm leading-7 text-gray-600'>Certificate</label>
|
||||||
<textarea readOnly rows={5} defaultValue={certificate} className='input w-full'></textarea>
|
<textarea readOnly rows={5} defaultValue={certificate} className='input w-full'></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='mx-auto mt-5 flex w-full items-end space-y-4 px-8 sm:space-x-4 sm:space-y-0 sm:px-0 lg:w-2/3'>
|
<div className='mx-auto mt-5 flex w-full justify-center px-8 lg:w-2/3'>
|
||||||
<Link href='/api/saml/metadata/download'>
|
<Link href='/api/saml/metadata/download'>
|
||||||
<a className='button'>Download Metadata</a>
|
<a className='button-secondary'>
|
||||||
|
<svg
|
||||||
|
className='mr-1 inline-block h-6 w-6'
|
||||||
|
fill='none'
|
||||||
|
viewBox='0 0 24 24'
|
||||||
|
stroke='currentColor'
|
||||||
|
aria-hidden
|
||||||
|
strokeWidth='2'>
|
||||||
|
<path
|
||||||
|
strokeLinecap='round'
|
||||||
|
strokeLinejoin='round'
|
||||||
|
d='M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4'
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
Download Metadata
|
||||||
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
<p className='mt-3 text-center text-lg text-orange-600'>* Caution: Not for production use</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,14 +10,20 @@ export default function Login() {
|
|||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
username: 'jackson',
|
username: 'jackson',
|
||||||
domain: 'example.com',
|
domain: 'example.com',
|
||||||
|
acsUrl: 'https://jackson-demo.boxyhq.com/api/oauth/saml',
|
||||||
|
audience: 'https://saml.boxyhq.com',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const acsUrlInp = useRef<HTMLInputElement>(null);
|
||||||
// Set focus to email input on load
|
// Set focus to email input on load
|
||||||
const emailInp = useRef<HTMLInputElement>(null);
|
const emailInp = useRef<HTMLInputElement>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (emailInp.current) {
|
if (acsUrl && emailInp.current) {
|
||||||
emailInp.current.focus();
|
emailInp.current.focus();
|
||||||
emailInp.current.select();
|
emailInp.current.select();
|
||||||
|
} else if (acsUrlInp.current) {
|
||||||
|
acsUrlInp.current.focus();
|
||||||
|
acsUrlInp.current.select();
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -43,8 +49,8 @@ export default function Login() {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
email: `${username}@${domain}`,
|
email: `${username}@${domain}`,
|
||||||
id,
|
id,
|
||||||
audience,
|
audience: audience || state.audience,
|
||||||
acsUrl,
|
acsUrl: acsUrl || state.acsUrl,
|
||||||
providerName,
|
providerName,
|
||||||
relayState,
|
relayState,
|
||||||
}),
|
}),
|
||||||
@ -69,7 +75,42 @@ export default function Login() {
|
|||||||
<div className='relative top-20 mx-auto w-[465px] max-w-[90%] rounded-md border p-10 text-[#145698]'>
|
<div className='relative top-20 mx-auto w-[465px] max-w-[90%] rounded-md border p-10 text-[#145698]'>
|
||||||
<h2 className='mb-3 text-center text-3xl font-bold'>Login</h2>
|
<h2 className='mb-3 text-center text-3xl font-bold'>Login</h2>
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<div className='flex items-end gap-x-1'>
|
{acsUrl ? null : (
|
||||||
|
<div>
|
||||||
|
<div className='mt-5'>
|
||||||
|
<label htmlFor='acsUrl' className='mb-2 block'>
|
||||||
|
ACS URL <sup>(This is where we'll post the SAML Response)</sup>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
name='acsUrl'
|
||||||
|
id='acsUrl'
|
||||||
|
ref={acsUrlInp}
|
||||||
|
autoComplete='off'
|
||||||
|
type='text'
|
||||||
|
placeholder='https://jackson-demo.boxyhq.com/api/oauth/saml'
|
||||||
|
value={state.acsUrl}
|
||||||
|
onChange={handleChange}
|
||||||
|
className='input w-full'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='mt-5'>
|
||||||
|
<label htmlFor='audience' className='mb-2 block'>
|
||||||
|
Audience
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
name='audience'
|
||||||
|
id='audience'
|
||||||
|
autoComplete='off'
|
||||||
|
type='text'
|
||||||
|
placeholder='https://saml.boxyhq.com'
|
||||||
|
value={state.audience}
|
||||||
|
onChange={handleChange}
|
||||||
|
className='input w-full'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className='mt-5 flex items-end gap-x-1'>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor='username' className='mb-2 block'>
|
<label htmlFor='username' className='mb-2 block'>
|
||||||
Email
|
Email
|
||||||
@ -84,7 +125,7 @@ export default function Login() {
|
|||||||
value={state.username}
|
value={state.username}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className='input'
|
className='input'
|
||||||
title='please provide a mock example.com email address'
|
title='Please provide a mock email address'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<select
|
<select
|
||||||
@ -99,11 +140,10 @@ export default function Login() {
|
|||||||
</div>
|
</div>
|
||||||
<div className='mt-5'>
|
<div className='mt-5'>
|
||||||
<label htmlFor='password' className='mb-2 block'>
|
<label htmlFor='password' className='mb-2 block'>
|
||||||
Password <sup>(Prefilled for you)</sup>
|
Password <sup>(Any password works)</sup>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id='password'
|
id='password'
|
||||||
readOnly={true}
|
|
||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
type='password'
|
type='password'
|
||||||
defaultValue='samlstrongpassword'
|
defaultValue='samlstrongpassword'
|
||||||
|
|||||||
@ -26,7 +26,11 @@ a {
|
|||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
.button {
|
.button {
|
||||||
@apply block rounded-md bg-indigo-500 px-4 py-2 leading-8 text-white shadow-md hover:bg-indigo-600 focus:outline-none focus:ring-4 focus:ring-indigo-300 focus:ring-opacity-100;
|
@apply block rounded-md bg-indigo-500 px-4 py-2 leading-8 text-white shadow-md hover:bg-indigo-600 focus:bg-indigo-600 focus:outline-none focus:ring-4 focus:ring-indigo-300 focus:ring-opacity-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-secondary {
|
||||||
|
@apply button border-2 border-indigo-800 bg-white text-indigo-500 hover:bg-white hover:shadow-lg focus:bg-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user