Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions app/forms/idp/create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ import { useSiloSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { Checkbox } from '~/ui/lib/Checkbox'
import { FormDivider } from '~/ui/lib/Divider'
import { Message } from '~/ui/lib/Message'
import { SideModal } from '~/ui/lib/SideModal'
import { readBlobAsBase64 } from '~/util/file'
import { links } from '~/util/links'
import { pb } from '~/util/path-builder'

import { MetadataSourceField, type IdpCreateFormValues } from './shared'
Expand Down Expand Up @@ -128,7 +130,35 @@ export function CreateIdpSideModalForm() {
submitError={createIdp.error}
submitLabel="Create provider"
>
<NameField name="name" control={form.control} />
<Message
content={
<>
Read the{' '}
<a
href={links.identityProvidersDocs}
className="underline"
target="_blank"
rel="noreferrer"
>
Rack Configuration
</a>{' '}
guide to learn more about setting up an identity provider.
</>
}
/>
<NameField
name="name"
control={form.control}
description={
<>
A short name for the provider in our system. Users will see it in the path to
the login page:{' '}
<code>
/login/{silo}/saml/{name.trim() || 'idp-name'}
</code>
</>
}
/>
<DescriptionField name="description" control={form.control} required />
<TextField
name="technicalContactEmail"
Expand Down Expand Up @@ -179,14 +209,17 @@ export function CreateIdpSideModalForm() {
control={form.control}
/>

<FormDivider />

<SideModal.Heading>Request signing</SideModal.Heading>
{/* We don't bother validating that you have both of these or neither even
though the API requires that because we are going to change the API to
always require both, at which point these become simple `required` fields */}
<FileField
id="public-cert-file-input"
name="signingKeypair.publicCert"
description="DER-encoded X.509 certificate"
label="Public cert"
label="Public certificate"
control={form.control}
/>
<FileField
Expand Down
2 changes: 1 addition & 1 deletion app/ui/lib/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const Message = ({
// TODO: convert content to a children prop
content,
className,
variant = 'success',
variant = 'info',
cta,
icon,
}: MessageProps) => {
Expand Down
20 changes: 16 additions & 4 deletions test/e2e/silos.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ test('Default silo', async ({ page }) => {
page.getByText('Silo viewerFleet viewer'),
])
})

test('Identity providers', async ({ page }) => {
await page.goto('/system/silos/maze-war')

Expand Down Expand Up @@ -199,21 +200,32 @@ test('Identity providers', async ({ page }) => {

await expect(dialog).toBeVisible()

const nameField = dialog.getByLabel('Name', { exact: true })
const acsUrlField = dialog.getByLabel('ACS URL', { exact: true })
// test login URL preview in name field description
await expect(page.getByText('login page: /login/maze-war/saml/idp-name')).toBeVisible()

const nameField = dialog.getByLabel('Name', { exact: true })
await nameField.fill('test-provider')

// preview updates as you type
await expect(
page.getByText('login page: /login/maze-war/saml/test-provider')
).toBeVisible()

// ACS URL should be populated with generated value
const acsUrlField = dialog.getByLabel('ACS URL', { exact: true })
const acsUrl = 'https://maze-war.sys.placeholder/login/maze-war/saml/test-provider'
await expect(acsUrlField).toHaveValue(acsUrl)

const acsUrlCheckbox = dialog.getByRole('checkbox', { name: 'Use standard ACS URL' })
await expect(acsUrlCheckbox).toBeChecked()

// uncheck the box and change the value
await dialog.getByRole('checkbox', { name: 'Use standard ACS URL' }).click()
await acsUrlCheckbox.click()
await acsUrlField.fill('https://example.com')
await expect(acsUrlField).toHaveValue('https://example.com')

// re-check the box and verify that the value is regenerated
await dialog.getByRole('checkbox', { name: 'Use standard ACS URL' }).click()
await acsUrlCheckbox.click()
await expect(acsUrlField).toHaveValue(acsUrl)

await page.getByRole('button', { name: 'Create provider' }).click()
Expand Down
Loading