SAML authentication plugin
Security Assertion Markup Language (SAML) can be used for external authentication of users for both the Deephaven Web interface and the Deephaven Classic (Java/Swing) interface.
SAML is an open standard whereby third-party Identity Providers such as Google, Okta, OneLogin, and others, can validate the identity of a user requesting to log on to a Deephaven system. The main benefits of SAML authentication are single sign-on to multiple services, including Deephaven, and the possibility to manage various forms of two-factor authentication.
There are two systems involved in authentication using SAML: the Identity Provider and the Service Provider. The Identity Provider is responsible for authenticating a user and providing evidence of that user's identity in the form of a SAML assertion. Google, Okta, and other accounts management solutions that support SAML 2.0 can act as Identity Providers for Deephaven. The other side of the configuration is the Service Provider, which makes services available to authenticated users. In the context of this document, the Service Provider is the Deephaven installation, with the Service Provider endpoint being a component of the Deephaven authentication server.
Both systems need to be configured for SAML authentication: the Identity Provider so it will accept authentication requests and return responses in the expected format from the specific Service Provider installation, and the Service Provider so it will know what Identity Provider instance to work with and will trust assertions received from it.
Once both systems are properly configured, users attempting to log in to Deephaven can choose to authenticate with the external Identity Provider. If they do so, they will be redirected to a login process managed by the Identity Provider. Upon completion of that process, the result will be sent as a SAML-formatted assertion message to the Deephaven authentication server. If the login was successful, the authentication server will grant the user the rights associated with the user name indicated in the assertion.
For a user to access Deephaven with SAML authentication, the Identity Provider administrator must create a login in the Identity Provider system and then grant the user access to the Deephaven application there. In addition, a Deephaven administrator must create a Deephaven login to match the user's Identity Provider login name, and grant the user's Deephaven account any needed privileges with the Deephaven system.
Configure Deephaven to use SAML Authentication
The extensions to the authentication process are implemented as a Deephaven plugin. This plugin is installed from an RPM using yum
, which will place its components into /etc/sysconfig/illumon.d/plugins
:
sudo yum localinstall ./SamlAuth-<versionnumber>.x86_64.rpm
After this step, activate the plugin:
sudo /etc/sysconfig/deephaven/plugins/samlAuth/bin/activate.sh --classpath
To configure the authentication server to present the option of SAML authentication, two sets of properties need to be added to the iris-environment.prop
properties: one for front-end configuration and one for server-level configuration.
Configure front-end
The front-end must also be configured to properly utilize the server-level module. The front-end configuration is defined within the following stanza in the iris-environment.prop
file. These properties are used to enable the SAML login option within the Deephaven console and web UI:
[service.name=iris_console|interactive_console|web_api_service] {
####################################################################################################################
# Enable SAML-Auth LoginPanel at Client-level.
# Must be set if SAML is intended as an authentication mechanism in the swing console.
authentication.client.customlogin.class.SAMLAuth = com.illumon.iris.console.utils.AuthenticationSAMLLoginMethodPanel
####################################################################################################################
# Identify the priority of the SAML-Auth LoginPanel in the case that multiple panels exist. A class with no
# priority listed will be treated as 'last'; only one such class may exist. The lowest numbers will be listed
# first in the login-method drop-down.
authentication.client.custlogin.priority.SAMLAuth = 1
####################################################################################################################
# Identifies the internal URL (which the Deephaven login screen links to) that redirects to the Identity Provider,
# which may be determined by the "authentication.samlauth.jetty.port", "authentication.samlauth.jetty.context", and
# "authentication.samlauth.jetty.dologin" properties in the authentication_server section.
# The example below assumes default values at the server-side.
authentication.client.samlauth.login.url = <URL on which the SAML auth client will listen for authentication assertions from the Identity Provider>:9032/dh-saml/
####################################################################################################################
# The name of this IdP, which will be seen within the front-end login screen; "Google", "Okta", "RSA", etc. If not
# set, will default to "SAML"
authentication.client.samlauth.provider.name=<your_provider; e.g.,Okta>
####################################################################################################################
# A list of properties required for the web front-end to enable SAML authentication. This is required only for web
# login access; the Java client will work without this setting.
authentication.client.configuration.list=authentication.client.samlauth.provider.name,authentication.client.samlauth.login.url,authentication.client.customlogin.class.SAMLAuth
####################################################################################################################
# Authentication Server-list must be set, with at least one of the specified addresses being a server that is
# listening for SAML-authentication on the URL identified by "authentication.client.samlauth.login.url". This
# property is used by all authentication methods.
# Typically, this is set in iris-endpoints.prop and does not need to be changed as part of configuring SAML.
#authentication.server.list = ${host1}[,${host2}[,${host3}...]]
}
Enable SAML-based auth requests
The second set is to enable the authentication server to accept and handle SAML-based authentication requests. This set of properties should be added to the authentication server stanza:
[service.name=authentication_server] {
####################################################################################################################
# Enable SAML auth at server level. Custom auth modules must be enabled.
authentication.server.customauth.enabled = true
# Configure the authentication server to look for the plugin's fully-qualified class name:
authentication.server.customauth.class.SAMLAuth = io.deephaven.samlauth.SAMLAuthModule
# If there are multiple authentication mechanisms, such as SAML and SSH, the priority property defines
# which is attempted first by the server, with the lowest value being attempted first.
authentication.server.customauth.priority.SAMLAuth = 0
####################################################################################################################
# Use the WebServices keystore for TLS configuration, which is used for browser-level communication.
# If the authentication server is on the same host as the web API service, then the webServices keystore can be used.
SAMLAuth.tls.keystore=/etc/sysconfig/illumon.d/auth-user/webServices-keystore.p12
SAMLAuth.tls.passphrase.file=/etc/sysconfig/illumon.d/auth-user/.webapi_passphrase
####################################################################################################################
# The following properties define the http/https server configuration, including protocol, port, and URLs for
# the server. The resultant URL(s) should be configured within the SAML IdP. The options below list the default
# values, which this configuration may override as required.
#authentication.samlauth.jetty.https = true
#authentication.samlauth.jetty.port = 9032
#authentication.samlauth.jetty.context = /dh-saml
#authentication.samlauth.jetty.dologon =
#authentication.samlauth.jetty.onlogon = acs
####################################################################################################################
# This property identifies a landing-page on successful IdP response. By default, a small "success" page is
# dynamically generated, which will attempt to close the browser (tab) instance. This will usually not work, but
# the administrator has the ability to redirect this to a more meaningful page, such as the latest system docs.
# Note that this property may be superseded by a client-level redirection-request which is permitted by the
# "authentication.samlauth.jetty.redirect.list" property below.
#authentication.samlauth.jetty.onsuccess = https://docs.deephaven.io/latest/Content/index.htm
####################################################################################################################
# This property defines a whitelist of URLs to which client front-end applications may request redirection via URL
# parameter ("?...&redirect=${url}"). Any client requesting end-of-authentication redirection to a URL which is not
# in this list will be rejected prior to IdP-redirection. Note that the above `onsuccess' property does not need to
# be included in this list, since it is server-level-configuration-defined. A URL within the whitelist ending with
# "/*" permits redirection to any sub-path of the provided URL
#authentication.samlauth.jetty.redirect.list = ${comma-separated url-whitelist}
####################################################################################################################
# The following property identifies a default number of milliseconds before a SAML IdP token is timed-out in the
# case that no usable timeout is received from the IdP. Default time is 60s.
#authentication.samlauth.tokentimeoutmillis = 60000
####################################################################################################################
# This identifies the number of milliseconds that the saml-module will block on the auth-server request for an
# "external-auth" response. This is the maximum amount of time we will wait for a client to successfully register
# with an IdP. In the case that 2FA is used, it may be necessary to increase this to an amount of time in which a
# user may perform the second-level of authentication. In many cases, the IdP will already "know" the requesting
# user, at which point the actual delay will be sub-second. Note that each request will consume a thread on the
# auth-server for a maximum of this time. Default time is 60s.
#authentication.samlauth.waitforusertimeoutMillis = 60000
####################################################################################################################
# Defines the SAML attribute which shall be used as the iris-id. If no attribute is specified, the SAML 'NameID'
# will be used.
#authentication.samlauth.nameattribute = IrisUser
####################################################################################################################
# URL to an appropriate stylesheet for failure message and default landing-page.
#authentication.samlauth.stylesheet.url = ${Stylesheet-URL}
####################################################################################################################
#
# The following properties are used to configure the OneLogin Toolkit. The value for each "authentication.samlauth.*"
# property is applied to the corresponding "onelogin.saml2.*" property.
# Most of these properties do not need to be explicitly defined as they have reasonable defaults defined within the toolkit.
#
####################################################################################################################
#authentication.samlauth.strict = true
#authentication.samlauth.unique_id_prefix = DEEPHAVEN_
####################################################################################################################
# Service Provider Data that we are deploying.
# The following properties must match the values defined with the Identity Provider (IdP).
# The default entity ID is "deephaven:iris:saml:sp".
#authentication.samlauth.sp.entityid = deephaven:iris:saml:sp
# The URL of the assertion-consumer. Must be shared with the IdP; on successful authentication,
# the IdP will redirect the browser to this URL.
authentication.samlauth.sp.assertion_consumer_service.url = <URL of the Deephaven authentication server system>:9032/dh-saml/acs
#authentication.samlauth.sp.assertion_consumer_service.binding = urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
#authentication.samlauth.sp.nameidformat = urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
# If we are encrypting our outbound traffic, the public-cert and private-key must be set -- either directly in this
# file (not recommended), or from flat-files on disk.
#authentication.samlauth.sp.x509cert.file =
#authentication.samlauth.sp.x509cert =
#authentication.samlauth.sp.privatekey.file =
#authentication.samlauth.sp.privatekey =
####################################################################################################################
# Identity Provider Data that we want to connect with our Service Provider.
# The following must match properties defined by the IdP.
authentication.samlauth.idp.entityid = <URL>
authentication.samlauth.idp.single_sign_on_service.url = <URL>
#authentication.samlauth.idp.single_sign_on_service.binding = urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect
# The IdP public key may be entered directly into the configuration or may be loaded from a flat-file on disk
authentication.samlauth.idp.x509cert.file = /etc/sysconfig/illumon.d/auth/{IdP-Cert-In-File}.pem
#authentication.samlauth.idp.x509cert = -----BEGIN CERTIFICATE-----\n${IdP-Defined-Cert}\n-----END CERTIFICATE-----
####################################################################################################################
# Security settings
#
#authentication.samlauth.security.nameid_encrypted = false
#authentication.samlauth.security.authnrequest_signed = false
#authentication.samlauth.security.logoutrequest_signed = false
#authentication.samlauth.security.logoutresponse_signed = false
#authentication.samlauth.security.want_messages_signed = false
#authentication.samlauth.security.want_assertions_signed = false
#authentication.samlauth.security.sign_metadata =
#authentication.samlauth.security.want_assertions_encrypted = false
#authentication.samlauth.security.want_nameid_encrypted = false
#authentication.samlauth.security.requested_authncontext = urn:oasis:names:tc:SAML:2.0:ac:classes:Password
#authentication.samlauth.security.requested_authncontextcomparison = exact
#authentication.samlauth.security.want_xml_validation = true
#authentication.samlauth.security.signature_algorithm = http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
####################################################################################################################
# Organization
#
#authentication.samlauth.organization.name = Deephaven Client
#authentication.samlauth.organization.displayname = Deephaven SAML-Auth Module
#authentication.samlauth.organization.url = http://deephaven.io
#authentication.samlauth.organization.lang =
#authentication.samlauth.contacts.technical.given_name = Technical Support
#authentication.samlauth.contacts.technical.email_address = technical@example.com
# The following entries will appear on the login-failure screen.
authentication.samlauth.contacts.support.given_name = <Contact name to display in case of SSO authentication failure>
authentication.samlauth.contacts.support.email_address = <Contact email to display in case of SSO authentication failure>support@example.com
}
When SAML is configured, the Deephaven login screen will look similar to the following:
For a complete list of properties and sample configurations for the Okta and Google IdPs, see the README.md included in the installer. This can be found in the /etc/sysconfig/deephaven/plugins/samlAuth
directory once the plugin is installed.
Example configuration
This plugin leverages the OneLogin java-saml toolkit. For additional details on the available properties, see the OneLogin Java-SAML Toolkit Configuration. Please note that the "onelogin.saml." properties required by this toolkit are identified in the SAML-Auth plugin as "authentication.samlauth."; these properties will be copied to the appropriate property-names during startup.
Minimal Okta-IdP Example
[service.name=authentication_server] {
####################################################################################################################
# Enable the module within the auth-server. The server where this is defined must be targeted in the console-level
# configuration's "authentication.server.list"
authentication.server.customauth.enabled = true
authentication.server.customauth.class.SAMLAuth = io.deephaven.samlauth.SAMLAuthModule
authentication.server.customauth.priority.SAMLAuth = 0
####################################################################################################################
# Use the WebServices keystore for browser-level TLS
SAMLAuth.tls.keystore=/etc/sysconfig/illumon.d/auth-user/webServices-keystore.p12
SAMLAuth.tls.passphrase.file=/etc/sysconfig/illumon.d/auth-user/.webapi_passphrase
####################################################################################################################
# Permit end-of-authentication browser redirection to the WebService url
authentication.samlauth.jetty.redirect.list = https://XXXXXXXXXXXX:8123/iriside/*
####################################################################################################################
# Okta requires us to define an application-specific user-name for each user. Each user should be configured at the
# IdP level as a valid Deephaven user name; no special attribute is required
#authentication.samlauth.nameattribute = NameID
####################################################################################################################
# Service Provider Data that we are deploying; note that these must also be configured within the IdP (Okta)
#
#authentication.samlauth.sp.entityid = deephaven:iris:saml:sp
authentication.samlauth.sp.assertion_consumer_service.url = https://XXXXXXXXXXXX:9032/dh-saml/acs
####################################################################################################################
# Identity Provider Data that we are using (Okta); these values are determined by the IdP
#
authentication.samlauth.idp.entityid = http://www.okta.com/XXXXXXXXXXXX
authentication.samlauth.idp.single_sign_on_service.url = https://ZZZZZZZZ.okta.com/app/YYYYYYYY/XXXXXXXXXXXX/sso/saml
authentication.samlauth.idp.x509cert.file = /etc/sysconfig/illumon.d/auth/okta.cert
#authentication.samlauth.idp.x509cert = -----BEGIN CERTIFICATE-----\nXXXXXXXXXXXXXXXX\n-----END CERTIFICATE-----
####################################################################################################################
# Information to help users with troubleshooting
#
authentication.samlauth.contacts.support.given_name = Support Group
authentication.samlauth.contacts.support.email_address = support@XXXXXXXX.com
####################################################################################################################
}
Minimal Google-IdP Example
[service.name=authentication_server] {
####################################################################################################################
# Enable the module within the auth-server. The server where this is defines must be targeted in the console-level
# configuration's "authentication.server.list"
authentication.server.customauth.enabled = true
authentication.server.customauth.class.SAMLAuth = io.deephaven.samlauth.SAMLAuthModule
authentication.server.customauth.priority.SAMLAuth = 0
####################################################################################################################
# Use the WebServices keystore for browser-level TLS
SAMLAuth.tls.keystore=/etc/sysconfig/illumon.d/auth-user/webServices-keystore.p12
SAMLAuth.tls.passphrase.file=/etc/sysconfig/illumon.d/auth-user/.webapi_passphrase
####################################################################################################################
# Permit end-of-authentication browser redirection to the WebService url
authentication.samlauth.jetty.redirect.list = https://XXXXXXXXXXXX:8123/iriside/*
####################################################################################################################
# This value must be set for each valid user within the IdP. If not set, the email address known to Google will be
# used, which must match the Deephaven user name for a successful login.
authentication.samlauth.nameattribute = XXXXXXXX
####################################################################################################################
# Service Provider Data that we are deploying; note that these must also be configured within the IdP (Google)
#
#authentication.samlauth.sp.entityid = deephaven:iris:saml:sp
authentication.samlauth.sp.assertion_consumer_service.url = https://XXXXXXXXXXXX:9032/dh-saml/acs
####################################################################################################################
# Identity Provider Data that we are using (Google); these values are determined by the IdP
#
authentication.samlauth.idp.entityid = https://accounts.google.com/o/saml2?idpid=XXXXXXXXX
authentication.samlauth.idp.single_sign_on_service.url = https://accounts.google.com/o/saml2/idp?idpid=XXXXXXXXX
authentication.samlauth.idp.x509cert.file = /etc/sysconfig/illumon.d/auth/GoogleIDPCertificate-XXXXXXXX.pem
#authentication.samlauth.idp.x509cert = -----BEGIN CERTIFICATE-----\nXXXXXXXXXXXXXXXX\n-----END CERTIFICATE-----
####################################################################################################################
# Information to help users with troubleshooting
#
authentication.samlauth.contacts.support.given_name = Support Group
authentication.samlauth.contacts.support.email_address = support@XXXXXXXX.com
####################################################################################################################
}
SAML over Envoy
Once the Envoy Proxy is properly configured on the system, it is possible to use SAML authentication through the proxy by leveraging Extra Envoy XDS routes. In addition to changing the target-port from 9032 to the appropriate envoy port in all of the above properties, it is also required that the IdP's ACS be redirected to the Envoy port. That is, the IdP should always be configured to use the URL identified by authentication.samlauth.sp.assertion_consumer_service.url
. The following should be added to the configuration so that appropriate routing is done for the SAML URLs.
# initial login-request needs to be properly routed to the SAML service so that it may be redirect to the IdP
envoy.xds.extra.routes.saml-launch.host=<Hostname of Deephaven authentication server>
envoy.xds.extra.routes.saml-launch.port=9032
envoy.xds.extra.routes.saml-launch.prefix=/dh-saml
envoy.xds.extra.routes.saml-launch.prefixRewrite=/dh-saml/
envoy.xds.extra.routes.saml-launch.tls=true
# upon successful login to the IdP, the login assertion will be sent to envoy; this needs to be forwarded to the actual ACS
envoy.xds.extra.routes.saml-acs.host=<Hostname of Deephaven authentication server>
envoy.xds.extra.routes.saml-acs.port=9032
envoy.xds.extra.routes.saml-acs.prefix=/dh-saml/acs
envoy.xds.extra.routes.saml-acs.prefixRewrite=/dh-saml/acs
envoy.xds.extra.routes.saml-acs.tls=true
# the following line ensures that a trailing "/" is not appended to the URL by the proxy
envoy.xds.extra.routes.saml-acs.exactPrefix=true
# route static resources (css and images) in the login success/failure pages
envoy.xds.extra.routes.saml-static.host=<Hostname of Deephaven authentication server>
envoy.xds.extra.routes.saml-static.port=9032
envoy.xds.extra.routes.saml-static.prefix=/static/
envoy.xds.extra.routes.saml-static.prefixRewrite=/static/
envoy.xds.extra.routes.saml-static.tls=true