# SAML 2.0 single sign-on (https://docs.idra.zone/docs/admin/saml)

Connect SAML service providers to IdRa for SP- or IdP-initiated single sign-on, and see what is and isn't supported.

IdRa is a SAML 2.0 identity provider. Each SAML app has its own entity ID and endpoints under:

```
https://<your IdRa address>/sso/saml/<appId>
```

| | URL |
| --- | --- |
| IdP entity ID (Issuer) | `/sso/saml/<appId>` |
| Single sign-on URL (Redirect and POST bindings) | `/sso/saml/<appId>/sso` |
| IdP-initiated sign-in | `/sso/saml/<appId>/init` |
| IdP metadata | `/sso/saml/<appId>/metadata` |

The app's **Sign On** tab lists these under **Identity provider**, together with the signing certificate.

## Create a SAML app

1. **Applications → Browse App Integration Catalog** (Slack, GitHub Enterprise Cloud, Google Workspace, AWS IAM Identity Center, Salesforce, Zoom, Atlassian Cloud, Notion, Figma, Dropbox) or **Create App Integration → SAML 2.0**.
2. On **Sign On**, either **Import SP metadata** (upload the file or paste the XML: entity ID, POST ACS URL, certificate and NameID format are read from it) or fill in:
   - **Single sign-on URL (ACS)**: the default; IdRa only posts assertions to a configured URL, matched exactly.
   - **Other requestable ACS URLs** (up to 20, optional): each with an index. An AuthnRequest can ask for one by exact URL or by `AssertionConsumerServiceIndex`. An unknown URL or index is refused. Importing metadata with several POST endpoints fills these in.
   - **SP entity ID** and **Audience restriction** (defaults to the entity ID).
   - **Default RelayState** (optional).
   - **Name ID format**: EmailAddress, Unspecified, Persistent, Transient (a new random value for each assertion), X509SubjectName, WindowsDomainQualifiedName or Kerberos, and **Application username (NameID)** (default `email`).
   - **Username expression** (optional): replaces the application username with an [expression](https://docs.idra.zone/docs/admin/expressions) over `user`, such as `String.substringBefore(user.email, "@")`. Group functions aren't available here. Someone the expression gives no text for is refused at sign-in.
3. Give the SP IdRa's metadata URL, or its SSO URL, entity ID and certificate.
4. [Assign](https://docs.idra.zone/docs/admin/applications#assignments) the app.

## Attributes

**Attribute statements** (up to 50) map SAML attribute names to IdRa values: `id`, `email`, `name`, `groups`, or any profile attribute as `profile.<key>`.

## Signing

The assertion is always signed. Turn on **Sign the whole Response too** for SPs that want a signed response. **Signature algorithm** is RSA-SHA256 with a SHA-256 digest by default, or RSA-SHA512 with a SHA-512 digest; the digest follows the signature, and SHA-1 isn't offered. Signing certificates are rotated and retired in **Settings → Keys**; after a rotation, update the certificate at the SP (or have it re-read the metadata).

## Signed AuthnRequests

Off by default. Turn on **Require signed AuthnRequests** and give the **SP certificate** (metadata import fills it in), and IdRa refuses any request without a valid signature from that certificate: a detached signature on the Redirect binding, an enveloped one on POST. RSA-SHA256 and RSA-SHA512 are accepted; an SP that signs with SHA-1 is refused. A request's `Destination`, if present, must be this app's sign-on URL. IdRa's metadata for the app then says `WantAuthnRequestsSigned="true"`. The certificate does nothing while this is off.

## ForceAuthn and authentication context

Both are off by default, and IdRa ignores what the request asks for.

- **Honor ForceAuthn:** a request with `ForceAuthn="true"` sends the person to sign in again, even with a session. The assertion's `AuthnInstant` is that new sign-in.
- **Honor RequestedAuthnContext:** IdRa knows these classes: `unspecified`, `Password`, `PasswordProtectedTransport` and `https://refeds.org/profile/sfa` (single factor), `https://refeds.org/profile/mfa` and `http://schemas.microsoft.com/claims/multipleauthn` (multi-factor). If the request needs multi-factor, the person is stepped up first. `exact`, `minimum`, `better` and `maximum` comparisons work. A request IdRa can't satisfy gets an error page.

An access policy always applies as well: a request can make sign-in stricter, never looser.

## Preview an assertion

**Preview assertion**, next to **Save**, shows the Response the form's current settings would send for you or for the person whose email you enter, before you save. It isn't signed, so it can't be used to sign in.

## Sign-in flows

- **SP-initiated:** the SP redirects to the SSO URL. IdRa signs the person in (and verifies MFA if the app's policy requires it), then posts the assertion to the ACS URL. `InResponseTo` is checked against replay.
- **IdP-initiated:** the My Apps tile opens `/init`.
- If the person must enroll a security method mid-way, the sign-in resumes automatically afterwards.

**Not supported**

  Single Logout (SLO) and assertion encryption aren't implemented. The admin API refuses settings it
  doesn't know, including `sloUrl`.