SAML Plugin
====================

Overview
--------------------

### Description

This plugin adds a SAML 2.0 entry point for user authentication in Squash TM,
which provides the application with stronger authentication schemes and
Single Sign On services.

Note that it doesn't replace the default entry point and the users can
still authenticate using the login form at `/login`, which itself
remains compatible with other security plugins (ad or ldap).

### Features

The following features are supported :

* Web SSO,
* Web SSO with holder-of-key profile,
* SP or IDP-initiated SSO,
* HTTP-POST, HTTP-Redirect
* Trust management using Metadata Interoperability or PKIX,
* Metadata loading by local file or HTTP,
* Support for scoping and authentication contexts,
* Publication of SP metadata

With the current limitations :

* Supports only one IDP and one SP definition
* No IDP discovery

### Requirements

* Squash TM 10
* Java 21

### ⚠️ Major Changes in v10 ⚠️

Version **10.0** introduces significant updates. Please review the following changes:

### Endpoint Modifications
Some endpoints have been updated :

| **Old Endpoint**        | **New Endpoint**                         | **Description**           |
|-------------------------|------------------------------------------|---------------------------|
| `/auth/saml/login`      | `/auth/saml/login/{registrationId}`      | The SAML entry point      |
| `/auth/saml/SSO`        | `/auth/saml/sso/{registrationId}`        | Endpoint for SSO profiles |
| `/auth/saml/metadata`   | `/auth/saml/metadata/{registrationId}`   | SP metadata publication   |

* `/auth/saml/SingleLogout` : single logout URL

### Keystore Replacement
In previous versions, **Squash** used a **keystore** to store various keys. As of v10, the keystore is no longer supported. The configuration now requires a **private key in PKCS8 format** and its corresponding **certificate**.

### Service Provider Metadata
Service Provider metadata is now **automatically generated** and available at the following URL:
```
/auth/saml/metadata/{registrationId}
```
This ensures easier integration and better compatibility with identity providers.

____________________
Usage overview
--------------------

### For the users

Users can now authenticate by accessing the application at url `/auth/saml/login/{registrationId}`.
An SSO negotiation will initiate immediately.
If the IDP approves the user, he/she will be authenticated on Squash TM
with the auth. assertion \<NameID\> as login name. The user
account will be created on the fly if it doesn't exist already.

### For administrators

Squash TM metadata are published at url `/auth/saml/metadata/{registrationId}`.

____________________
Configuration
--------------------
This section covers the required steps to configure and enable the plugin
properly. Other optional behavior can be configured, but here we will restrict
to the absolute essentials.

In order to work the following items must be made available to Squash TM :
* the plugin binary,
* the configuration file,
* the Identity Provider metadata

### Binary

Copy the jar in directory `plugins` and paste it in the same folder in Squash TM.

### Configuration file

The most convenient way is to copy `config/squash.tm.cfg-saml.properties`
and paste it in the home configuration directory. In the standalone distribution
of Squash-TM that directory is usually `SQUASH_HOME/conf`. Then you must
enable it by setting the property `spring.profiles.include=saml` in the
main configuration file `squash.tm.cfg.properties`.

The configuration _must_ define the following properties :

* `saml.enabled` : the main switch for the whole feature
* `saml.idp.metadata-url` : the location where Squash TM will find the IDP metadata
* `saml.sp.registration-id` : the registration identifier used to distinguish this SP in the configuration
* `saml.sp.entity-id` : the unique identifier for your Service Provider (SP) in the SAML ecosystem
* `saml.sp.metadata.private-key` : private key in PKCS#8 format used by the Service Provider (SP) to sign requests and decrypt messages.
* `saml.sp.metadata.certificate` : X.509 certificate of the Service Provider (SP) used for signature validation and encryption. This certificate is shared with the IDP.

Many more options are available for fine-tuning the behavior of the plugin.
The comments in `squash.tm.cfg-saml.properties` will give you additional
information about this step.

### Identity Provider metadata

They are usually published by the IDP server so you won't (as a Squash TM administrator) have to generate them.
Squash TM can load them either by HTTP(S) or from a local drive. The location is configured by the property `saml.idp.metadata.url`.

Remember : only one IDP is supported. If the metadata declare more than one IDP the first of the list will be used.

### Service Provider metadata

Spring Security automatically generates SAML metadata for the registration ID configured in the application.
This metadata contains the necessary information to establish trust between the SP (our application) and the Identity Provider (IdP).

The metadata includes:
    
* The entity identifier (entityId)
* Endpoints for ACS (Assertion Consumer Service)
* Signing and encryption certificates
* Supported bindings (HTTP-POST, HTTP-Redirect)
* Endpoints for Single Logout (SLO)
* Supported NameID formats

The metadata file is dynamically generated at application startup and is accessible via the following URL: `/auth/saml/metadata/{registration-id}`
where `{registration-id}` corresponds to the SAML registration identifier configured in the application (for example "okta", "azure-ad", etc.).

This metadata can be provided to the IdP when configuring SAML integration to establish the trust relationship.
The IdP uses this information to know how to communicate with our application and verify the authenticity of exchanged messages.

____________________
Logging
--------------------

If the plugin is not working as expected you can enable more logging by appending this to the configuration :

```
logging.level.org.squashtest.tm.plugin.saml=TRACE
logging.level.sqsaml.org.springframework.security=TRACE
logging.level.org.springframework.security.web.authentication=TRACE
logging.level.org.opensaml=TRACE
```

TRACE is the finer logging level available. If this is too verbose you can use the DEBUG level instead.

Note that Squash-TM must be rebooted to account for your new configuration.

____________________
Troubleshooting
--------------------

#### Question ####

I cannot log in using saml, and the logs show the following instead :

`org.opensaml.saml2.metadata.provider.MetadataProviderException: No hosted service provider is configured and no alias was selected`

#### Answer ####

At boot time and then periodically after that, the underlying library checks for expiration date in metadata files (if specified). If a metadata has expired it won't be processed and the plugin initialization continues while barely reporting the problem. Later on, when accessing to the SAML portal the plugin attempts to resolve the service provider or identity provider and can't find any, it will then abort the authentication process with this MetadataProviderException. Unfortunately we have no control over that code and cannot set a fail-fast policy for that.

You can verify this by turning the loggers on (see above) and looking for the following string :

```
org.opensaml.saml2.metadata.provider.AbstractReloadingMetadataProvider: Entire metadata document from '<your metadata>' was expired at time of loading, existing metadata retained
```

If such line appear you can extend the expiration date in the metadata (or delete the attribute `validUntil` altogether) to fix the problem.


#### Question ####

I successfully reached my IDP, but then Squash-TM displays an error page with the following message : `An unexpected error happened... Error is SecurityException : SAML message intended destination endpoint did not match recipient endpoint`

#### Answer ####

If Squash-TM runs behind a reverse proxy or a load balancer, several plumbing issues may disrupt the message flow. For instance if the front proxy (eg for SSL offload duty) serves Squash-TM with HTTP only, while on the other hand the ACS expects HTTPS, the aforementioned error will happen because of the protocol mismatch.

You can advise Squash-TM for such situations in the configuration file, in the section `saml.proxy`.

____________________
More
--------------------

Check the documentation for details about the functional behavior and fine-tuning options.
