Security Assertion Markup Language (SAML) is an open standard for exchanging authentication and authorization data between an identity provider and a service provider.
The SAML specification defines three roles:
- A principal
- An identity provider (IdP)
- A service provider (SP)
The Kong SAML plugin acts as the SP and is responsible for initiating a login to the IdP. This is called an SP Initiated Login.
The minimum configuration required is:
- An IdP certificate
idp_certificate
. The SP needs to obtain the public certificate from the IdP to validate the signature. The certificate is stored on the SP and is to verify that a response is coming from the IdP. - ACS Endpoint
assertion_consumer_path
. This is the endpoint provided by the SP where SAML responses are posted. The SP needs to provide this information to the IdP. - IdP Sign-in URL
idp_sso_url
. This is the IdP endpoint where SAML will issuePOST
requests. The SP needs to obtain this information from the IdP. - Issuer
issuer
. Unique identifier of the IdP application.
The plugin currently supports SAML 2.0 with Microsoft Azure Active Directory. Please refer to the Microsoft AzureAD SAML documentation for more information about SAML authentication with Azure AD.
As the SP initiated mode of SAML requires the client to authenticate to the IdP using a web browser, the plugin is only useful when it is used with a browser-based web application.
It is designed to intercept requests sent from the client to the upstream to detect whether a session has been established by authenticating with the IdP. If no session is found, the request is redirected to the IdP’s login page for authentication. Once the user has successfully authenticated, the user is redirected to the application and the original request is sent to the upstream server.
The authentication process can only be initiated when the request is
coming from a web browser. The plugin determines this by matching
the request’s Accept
header. If it contains the string
“text/html”, the request is redirected to the IdP, otherwise it is
responded to with a 401 (Unauthorized) status code.
The plugin initiates the redirection to the IdP’s login page by responding with an HTML form that contains the authentication request details in hidden parameters and some JavaScript code to automatically submit the form. This is needed because the authentication parameters need to be transmitted to Azure’s SAML implementation using a POST request, which cannot be done with a HTTP redirect response.
The plugin supports initiating the IdP authentication flow from a
POST request, to support the use case that the session expires while
the user is filling out a web form. In such scenarios, the plugin
transmits the posted form parameters to the IdP in the RelayState
parameter in encrypted form. When the authentication process
finishes, the IdP sends the RelayState
back to the plugin. After
decryption, the plugin then responds back to the web browser with
another automatically self-submitting form containing the original
form parameters as hidden parameters. This feature is only
available with forms that use “application/x-www-form-urlencoded” as
their content type. Forms that use “text/plain” or
“multipart/form-data” are not supported.
When the authentication process has finished, the plugin creates and maintains a session inside of Kong gateway. A cookie in the browser is used to track the session. Data that is attached to the session can be stored in redis, memcached or in the cookie itself. Note that the lifetime of the session that is created by the IdP is needs to be configured in the plugin itself.
Configuration Reference
This plugin is compatible with DB-less mode.
In DB-less mode, you configure Kong Gateway declaratively. Therefore, the Admin API is mostly read-only. The only tasks it can perform are all related to handling the declarative config, including:
- Setting a target's health status in the load balancer
- Validating configurations against schemas
- Uploading the declarative configuration using the
/config
endpoint
Example plugin configuration
Parameters
Here's a list of all the parameters which can be used in this plugin's configuration:
Form Parameter | Description |
---|---|
name
required Type: string |
The name of the plugin, in this case saml . |
service.name or service.id
Type: string |
The name or ID of the service the plugin targets.
Set one of these parameters if adding the plugin to a service through the top-level /plugins endpoint.
Not required if using /services/SERVICE_NAME|SERVICE_ID/plugins . |
route.name or route.id
Type: string |
The name or ID of the route the plugin targets.
Set one of these parameters if adding the plugin to a route through the top-level /plugins endpoint.
Not required if using /routes/ROUTE_NAME|ROUTE_ID/plugins . |
enabled
Type: boolean Default value: true |
Whether this plugin will be applied. |
config.anonymous
optional Type: string |
An optional string (consumer UUID or username) value to use as an “anonymous” consumer. If not set, a Kong Consumer must exist for the SAML IdP user credentials, mapping the username format to the Kong Consumer username. |
config.assertion_consumer_path
required Type: url |
The relative path the SAML IdP provider uses when responding with an authentication response. |
config.idp_sso_url
required Type: url |
The Single Sign-On URL exposed by the IdP provider. This is where SAML requests are posted. The IdP provides this information. |
config.idp_certificate
required Type: string |
The public certificate provided by the IdP. This is used to validate responses from the IdP. This field is referenceable, which means it can be securely stored as a secret in a vault. References must follow a specific format. |
config.encryption_key
optional Type: string |
The private encryption key required to decrypt encrypted assertions. This field is referenceable, which means it can be securely stored as a secret in a vault. References must follow a specific format. |
config.request_signing_key
optional Type: string |
The private key for signing requests. If this parameter is
set, requests sent to the IdP are signed. The
This field is referenceable, which means it can be securely stored as a secret in a vault. References must follow a specific format. |
config.request_signing_certificate
optional Type: string |
The certificate for signing requests. This field is referenceable, which means it can be securely stored as a secret in a vault. References must follow a specific format. |
config.request_signature_algorithm
optional Type: string Default value: SHA256
|
The signature algorithm for signing Authn requests. Options available are:
|
config.request_digest_algorithm
optional Type: string Default value: SHA256
|
The digest algorithm for Authn requests:
|
config.response_signature_algorithm
optional Type: string Default value: SHA256
|
The algorithm for validating signatures in SAML responses. Options available are:
|
config.response_digest_algorithm
optional Type: string Default value: SHA256
|
The algorithm for verifying digest in SAML responses:
|
config.issuer
required Type: string |
The unique identifier of the IdP application. Formatted as a URL containing information about the IdP so the SP can validate that the SAML assertions it receives are issued from the correct IdP. |
config.nameid_format
optional Type: string Default value: EmailAddress
|
The requested
|
config.validate_assertion_signature
optional Type: boolean Default value: true
|
Enable signature validation for SAML responses. |
Session cookie Parameters used with session cookie authentication. | |
Form Parameter | Description |
config.session_cookie_name
optional Type: string Default value: session
|
The session cookie name. |
config.session_cookie_lifetime
optional Type: integer Default value: 3600
|
The session cookie lifetime in seconds. |
config.session_cookie_idletime
optional Type: integer |
The session cookie idle time in seconds. |
config.session_cookie_renew
optional Type: integer Default value: 600
|
The session cookie renew time in seconds. |
config.session_cookie_path
optional Type: string Default value: /
|
The session cookie path flag. |
config.session_cookie_domain
optional Type: string |
The session cookie domain flag. |
config.session_cookie_samesite
optional Type: string Default value: Lax
|
Controls whether a cookie is sent with cross-origin requests, providing some protection against cross-site request forgery attacks:
|
config.session_cookie_httponly
optional Type: boolean Default value: true
|
Forbids JavaScript from accessing the cookie, for example, through the |
config.session_cookie_secure
optional Type: boolean Default value: (from the request scheme)
|
The cookie is only sent to the server when a request is made with the https:scheme (except on localhost), and therefore is more resistant to man-in-the-middle attacks. |
config.session_cookie_maxsize
optional Type: integer Default value: 4000
|
The maximum size of each cookie in bytes. |
Session Settings | |
Form Parameter | Description |
config.session_secret
required Type: string |
The session secret. This must be a random string of 32
characters from the base64 alphabet (letters, numbers, If keyring database encryption is enabled, this value will be encrypted. This field is referenceable, which means it can be securely stored as a secret in a vault. References must follow a specific format. |
config.session_strategy
optional Type: string Default value: default
|
The session strategy:
|
config.session_compressor
optional Type: string Default value: none
|
The session strategy:
|
config.session_storage
optional Type: string Default value: cookie
|
The session storage for session data:
|
config.reverify
optional Type: boolean Default value: false
|
Specifies whether to always verify tokens stored in the session. |
Session Settings for Memcached | |
Form Parameter | Description |
config.session_memcache_prefix
optional Type: string Default value: sessions
|
The memcached session key prefix. |
config.session_memcache_socket
optional Type: string |
The memcached unix socket path. |
config.session_memcache_host
optional Type: string Default value: 127.0.0.1
|
The memcached host. |
config.session_memcache_port
optional Type: integer Default value: 11211
|
The memcached port. |
Session Settings for Redis | |
Form Parameter | Description |
config.session_redis_prefix
optional Type: string Default value: sessions
|
The Redis session key prefix. |
config.session_redis_socket
optional Type: string |
The Redis unix socket path. |
config.session_redis_host
optional Type: string Default value: 127.0.0.1
|
The Redis host IP. |
config.session_redis_port
optional Type: integer Default value: 6379
|
The Redis port. |
config.session_redis_username
optional Type: string |
Redis username if the This requires Redis v6.0.0+. The username cannot be set to This field is referenceable, which means it can be securely stored as a secret in a vault. References must follow a specific format. |
config.session_redis_password
optional Type: string Default value: (from kong)
|
Password to use for Redis connection when the If keyring database encryption is enabled, this value will be encrypted. This field is referenceable, which means it can be securely stored as a secret in a vault. References must follow a specific format. |
config.session_redis_connect_timeout
optional Type: integer Default value: (from kong)
|
The Redis connection timeout in milliseconds. |
config.session_redis_read_timeout
optional Type: integer Default value: (from kong)
|
The Redis read timeout in milliseconds. |
config.session_redis_send_timeout
optional Type: integer Default value: (from kong)
|
The Redis send timeout in milliseconds. |
config.session_redis_ssl
optional Type: boolean Default value: false
|
Use SSL/TLS for the Redis connection. |
config.session_redis_ssl_verify
optional Type: boolean Default value: false
|
Verify the Redis server certificate. |
config.session_redis_server_name
optional Type: string |
The SNI used for connecting to the Redis server. |
config.session_redis_cluster_nodes
optional Type: array of host records |
The Redis cluster node host. Takes an array of host records, with
either |
config.session_redis_cluster_maxredirections
optional Type: integer |
The Redis cluster’s maximum redirects. |
Kong Configuration
Create an Anonymous Consumer:
curl --request PUT \
--url http://localhost:8001/consumers/anonymous
{
"created_at": 1667352450,
"custom_id": null,
"id": "bec9d588-073d-4491-b210-1d07099bfcde",
"tags": null,
"type": 0,
"username": "anonymous",
"username_lower": null
}
Create a Service
curl --request PUT \
--url http://localhost:8001/services/saml-service \
--data url=https://httpbin.org/anything
{
"id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd",
"name": "saml-service",
"protocol": "https",
"host": "httpbin.org",
"port": 443,
"path": "/anything"
}
Create a Route
curl --request PUT \
--url http://localhost:8001/services/saml-service/routes/saml-route \
--data paths=/saml
{
"id": "ac1e86bd-4bce-4544-9b30-746667aaa74a",
"name": "saml-route",
"paths": [ "/saml" ]
}
Setup Microsoft AzureAD
- Create a SAML Enterprise Application. Refer to the Microsoft AzureAD documentation for more information.
- Note the identifier (entity ID) and sign on URL parameters
- Configure the reply URL (Assertion Consumer Service URL), for example,
https://kong-proxy:8443/saml/consume
- Assign users to the SAML enterprise application
Create a Plugin on a Service
Validation of the SAML response assertion is disabled in the plugin configuration below. This configuration should not be used in a production environment.
Replace the Azure_Identity_ID
value below, with the identifier
value from the single sign-on - basic SAML configuration from the Manage section of the Microsoft AzureAD enterprise application:
Replace the AzureAD_Sign_on_URL
value below, with the Login URL
value from the single sign-on - Set up Service Provider section from the Manage section of the Microsoft AzureAD enterprise application:
curl --request POST \
--url http://localhost:8001/services/saml-service/plugins \
--header 'Content-Type: multipart/form-data' \
--form name=saml \
--form config.anonymous=anonymous \
--form service.name=saml-service \
--form config.issuer=AzureAD_Identity_ID \
--form config.idp_sso_url=AzureAD_Sign_on_URL \
--form config.assertion_consumer_path=/consume \
--form config.validate_assertion_signature=false
{
"id": "a8655ba0-de99-48fc-b52f-d7ed030a755c",
"name": "saml",
"service": {
"id": "5fa9e468-0007-4d7e-9aeb-49ca9edd6ccd"
},
"config": {
"assertion_consumer_path": "/consume",
"validate_assertion_signature": true,
"idp_sso_url": "https://login.microsoftonline.com/f177c1d6-50cf-49e0-818a-a0585cbafd8d/saml2",
"issuer": "https://samltoolkit.azurewebsites.net/kong_saml"
}
}
Test the SAML plugin
- Using a browser, go to the URL (https://kong:8443/saml)
- The browser is redirected to the AzureAD Sign in page. Enter the user credentials of a user configured in AzureAD
- If user credentials are valid, the browser will be redirected to https://httpbin.org/anything
- If the user credentials are invalid, a
401
unauthorized HTTP status code is returned