AppSuite:UCS SAML SSO with OX App Suite

Revision as of 05:17, 18 May 2021 by Khgras (talk | contribs)

Univention Corporate Server SAML-SSO Configuration with OX App Suite

Preconditions

Before starting the configuration process, it is advisable to test the SAML login to UCS to ensure that it works. Authentication via SAML login works as follows.

https://<Hostname>/univention/saml

Configuration

Setting FQDNs

The following three variables have to be set according to the environment. Multiple or all variables can contain the same FQDN.

# FQDN for accessing the SSO - can be found in UCR: ucr get ucs/server/sso/fqdn
SSO_FQDN=ucs-sso.domain.name

# FQDN for accessing the portal
PORTAL_FQDN=portal.domain.name

# FQDN for accessing OX
MAIL_FQDN=mail.domain.name

Adjusting the provisioning

The UCS users are provisioned in OX via CLI interfaces and then written to a MySQL database. The database has a "imapLogin" field that is used by OX to log in to the user's inbox. As default it is set to the user's mail address. If SSO is to be used, it has to be appended with an asterisk and the mail server's master user. For Dovecot this would be dovecotadmin and looks as follows:

meinuser@maildomain.de*dovecotadmin

The following two commands have to be executed to let the users be provisioned respectively by the listener:

ucr set ox/listener/imaplogin_value='{}*dovecotadmin'
service univention-directory-listener crestart

Adjusting existing users

For already existing users, the imapLogin field has to be adjusted. See: How To: Change the OX attribute imaplogin for existing users

Installing packages

univention-install open-xchange-saml-ucs open-xchange-saml

Getting UCR variables into the shell

As we will need UCR variables for the following steps, we'll get them as shell variables:

eval "$(ucr shell)"

Importing the SAML IdPs certificate into the Java Keystore

For OX to be able to validate the certificate that is used for signing the SAML Assertions, it has to be imported into the Java Keystore.

openssl pkcs12 -export -in /etc/simplesamlphp/${SSO_FQDN}-idp-certificate.crt -inkey /etc/simplesamlphp/${SSO_FQDN}-idp-certificate.key -chain -CAfile /etc/univention/ssl/ucsCA/CAcert.pem -name "${SSO_FQDN}" -out ${SSO_FQDN}.p12 -password pass:changeit

keytool -importkeystore -deststorepass changeit -destkeystore my-keystore.jks -srckeystore ${SSO_FQDN}.p12 -srcstoretype PKCS12 -srcstorepass changeit

keytool -export -alias ${SSO_FQDN} -file ${SSO_FQDN}.cer -keystore my-keystore.jks -deststorepass changeit

keytool -import -alias ${SSO_FQDN} -file ${SSO_FQDN}.cer -keystore /etc/ssl/certs/java/cacerts -deststorepass changeit

Basic configuration in UCR

We change some configuration parameters so that OX uses SSO. Furthermore we use a master password for Dovecot to enable OX to open the user's inbox without the user's password. *Attention*: If the master password will be changed in the future, it has to be changed in `/etc/dovecot/master-users` as well as in `/etc/dovecot-master.secret`.

p="$(cat /etc/dovecot/master-users | sed -e 's|.*{PLAIN}||;s|:.*||')"

echo -n "$p" > /etc/dovecot-master.secret
chmod 600 /etc/dovecot-master.secret

ucr set ox/cfg/mailfilter.properties/com.openexchange.mail.filter.masterPassword="@&@/etc/dovecot-master.secret@&@" \
       ox/cfg/mail.properties/com.openexchange.mail.masterPassword="@&@/etc/dovecot-master.secret@&@"

ucr set ox/cfg/mailfilter.properties/com.openexchange.mail.filter.loginType='global' \
        ox/cfg/mailfilter.properties/com.openexchange.mail.filter.passwordSource='global' \
        ox/cfg/mail.properties/com.openexchange.mail.mailServerSource='global' \
        ox/cfg/mail.properties/com.openexchange.mail.passwordSource='global' \
        ox/cfg/sessiond.properties/com.openexchange.sessiond.autologin='false'

Configuration files for SAML IdP

Besides the UCR configuration parameters, we also have to set up two configuration files. Those will contain the FQDNs of SSO, Portal and OX itself in various locations.

cat <<__EOT_asconfig__ > /opt/open-xchange/etc/as-config.yml
# Override certain settings
default:
    host: all
    samlLogin: true
    logoutLocation: 'https://${SSO_FQDN}/simplesamlphp/saml2/idp/initSLO.php?RelayState=/simplesamlphp/logout.php'

# Override certain settings for certain hosts
#myhost:
#    host: myexchange.myhost.mytld
#    someConfig: some overriding value
__EOT_asconfig__

saml.properties is a relatively big file. This is reflected in the following command.

cat <<__EOT__ >/opt/open-xchange/etc/saml.properties
# Configuration of SAML UCS properties
# Please refer to: https://documentation.open-xchange.com/components/middleware/config/7.10.1/#mode=search&term=open-xchange-saml-ucs

# If UCS SAMLBackend is enabled
com.openexchange.saml.ucs.enabled = true

# The id inside the saml authnResponse which holds the userinformation
#com.openexchange.saml.ucs.id = mailPrimaryAddress
com.openexchange.saml.ucs.id = uid

# URL of where the users are redirected after logout
com.openexchange.saml.ucs.logoutRedirectUrl = https://${PORTAL_FQDN}/univention/portal/

# The URL to redirect to in case the SAML back-end fails to look up the authenticated user. When left empty or not set, an HTTP 500 error page is sent instead.
#com.openexchange.saml.ucs.failureRedirect

# The URL to redirect to in case the SAML back-end has an error, when the user logs out. When left empty or not set, the value of com.openexchange.saml.ucs.failure.redirect is used.
#com.openexchange.saml.ucs.logoutFailureRedirect

# The full path to a Java keyStore containing the IdPs certificate.
com.openexchange.saml.ucs.keyStore = /etc/ssl/certs/java/cacerts
#com.openexchange.saml.ucs.keyStore = /root/my-keystore.jks

# Password to open the keyStore.
com.openexchange.saml.ucs.keyStorePass = changeit

# The alias of the IdP certificate entry within the keyStore.
#com.openexchange.saml.ucs.certAlias = Univention_Corporate_Server_Root_CA_(ID=ImIfa9H9)
com.openexchange.saml.ucs.certAlias = ${SSO_FQDN}

# The alias of the signingKey entry within the keyStore.
#com.openexchange.saml.ucs.signingKeyAlias

# The password of the signingKey entry within the keyStore.
#com.openexchange.saml.ucs.signingKeyPassword

# The alias of the decryptionKey entry within the keyStore.
#com.openexchange.saml.ucs.decryptionKeyAlias

# The password of the decryptionKey entry within the keystore.
#com.openexchange.saml.ucs.decryptionKeyPassword

SAML core feature configuration

# Must be set to 'true' to enable the feature, otherwise it is fully deactivated.
#
# Default: false
com.openexchange.saml.enabled = true

# Whether the SPs metadata XML shall be made available via HTTP. The according
# servlet will then be available under 'http(s)://{hostname}/{prefix}/saml/metadata'.
#
# Default: false
#com.openexchange.saml.enableMetadataService = false
com.openexchange.saml.enableMetadataService = true

# Whether the single logout profile is enabled.
#
# Default: false
com.openexchange.saml.enableSingleLogout = true

# Sets the entity ID of the service provider.
#
# This property is mandatory.
# Default: <empty>
com.openexchange.saml.entityID = https://${MAIL_FQDN}/appsuite/

# Sets the human-readable name of the service provider.
#
# This property is mandatory.
# Default: <empty>
com.openexchange.saml.providerName = Open-Xchange Service Provider

# Sets the URL of the local assertion consumer service (ACS). This value is used within
# authentication requests, compared against Destination attributes in IdP responses
# and will be contained in the service providers metadata XML. The according endpoint
# is always registered with '{prefix}/saml/acs' as servlet alias.
#
# This property is mandatory.
# Default: <empty>
# Example: https://appsuite.example.com/appsuite/api/saml/acs
com.openexchange.saml.acsURL = https://${MAIL_FQDN}/appsuite/api/saml/acs

# Sets the URL of the local single logout service. This value is compared against Destination
# attributes in IdP responses and will be contained in the service providers metadata XML.
# The according endpoint is always registered with '{prefix}/saml/sls' as servlet alias.
#
# This property is mandatory if 'com.openexchange.saml.enableSingleLogout' is 'true'.
# Default: <empty>
# Example: https://appsuite.example.com/appsuite/api/saml/sls
com.openexchange.saml.slsURL = https://${MAIL_FQDN}/appsuite/api/saml/sls

# The binding via which logout responses shall be sent to the IdP on IdP-initiated single
# logout flows. Must be 'http-redirect' or 'http-post'.
#
# This property is mandatory if 'com.openexchange.saml.enableSingleLogout' is 'true'.
# Default: http-redirect
com.openexchange.saml.logoutResponseBinding = http-redirect

# The HTML template to use when logout responses are sent to the IdP via HTTP POST.
# The template must be located in '/opt/open-xchange/templates'.
#
# This property is mandatory if 'com.openexchange.saml.enableSingleLogout' is 'true'
# and 'com.openexchange.saml.logoutResponseBinding' is set to 'http-post'.
# Default: saml.logout.response.html.tmpl
com.openexchange.saml.logoutResponseTemplate = saml.logout.response.html.tmpl

# The entity ID of the IdP. It will be used to validate the 'Issuer' elements of SAML responses.
#
# This property is mandatory.
# Default: <empty>
com.openexchange.saml.idpEntityID = https://${SSO_FQDN}/simplesamlphp/saml2/idp/metadata.php

# The URL of the IdP endpoint where authentication requests are to be sent to.
#
# This property is mandatory.
# Default: <empty>
com.openexchange.saml.idpAuthnURL = https://${SSO_FQDN}/simplesamlphp/saml2/idp/SSOService.php

# The URL of the IdP endpoint where logout requests are to be sent to.
#
# This property is mandatory if 'com.openexchange.saml.enableSingleLogout' is 'true'.
# Default: <empty>
com.openexchange.saml.idpLogoutURL = https://${SSO_FQDN}/simplesamlphp/saml2/idp/SingleLogoutService.php

# It is possible to enable a special kind of auto login mechanism that allows user agents to
# re-use an existing OX session if it was created during the same browser session. If enabled,
# a special cookie will be set, which is linked to the OX session and bound to the browser sessions
# life time. The advantage of this mechanism is, that sessions are simply re-entered if the user
# refreshes his browser window. He is then also able to open more than one tab of OX App Suite
# at the same time. This mechanism can only re-use sticky sessions, i.e. it is mandatory that the
# requests are always routed to the same backend for a certain session.
#
# --- SECURITY WARNING ---
# Enabling this setting is not compliant to the SAML specification as it bypasses the IdP in
# certain cases. Additionally in scenarios where a public device is used, a foreign user might
# take over a formerly authenticated users session if that user forgets to log out and doesn't
# close his web browser (even if he closes the App Suite tab). As no login screen is displayed
# by OX in SAML environments, the user is even not able to decide, whether the application shall
# remember him or not.
#
# Default: false
com.openexchange.saml.enableAutoLogin = false

# Whether unsolicited responses will be accepted or not.
#
# Default: true
com.openexchange.saml.allowUnsolicitedResponses = true
__EOT__

Adjusting the Dovecot configuration

Dovecot only allows the access with a master user by OX if the following file has been created:

cat <<_EOT_ACL_ >>/etc/dovecot/conf.d/90-acl.conf
plugin {
 acl_user = %u
}
auth_master_user_separator = *
_EOT_ACL_

Re-starting services

Dovecot and OX have to be re-started now. The commands shouldn't run long; the OX re-start in the background though can take some time, depending on the system.

/etc/init.d/dovecot restart

/etc/init.d/open-xchange restart

Creating service provider in UCS

To make OX Service Provider known by the UCS Identity Provider, we'll add it via UDM:

udm saml/serviceprovider create \
--ignore_exists \
--position "cn=saml-serviceprovider,cn=univention,$ldap_base" \
--set Identifier="https://${MAIL_FQDN}/appsuite/" \
--set AssertionConsumerService="https://${MAIL_FQDN}/appsuite/api/saml/acs" \
--set singleLogoutService="https://${MAIL_FQDN}/appsuite/api/saml/sls" \
--set LDAPattributes="mailPrimaryAddress" \
--set LDAPattributes="uid" \
--set NameIDFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" \
--set attributesNameFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" \
--set isActivated="TRUE" \
--set serviceProviderOrganizationName="Open-Xchange Service Provider" \
--set simplesamlAttributes="TRUE" \
--set simplesamlNameIDAttribute="uid" \
--set signLogouts="TRUE"

Single users or groups can now get permissions for this service provider. To e.g. grant access to all users, the Domain Users group can get permission for the service provider. This does not work for UCS@school environments. For those, the respective "Domain Users <School>" groups have to get separate permissions.

udm groups/group modify \
--dn "cn=Domain Users,cn=groups,${ldap_base}" \
--append serviceprovidergroup=SAMLServiceProviderIdentifier=https://${MAIL_FQDN}/appsuite/,cn=saml-serviceprovider,cn=univention,${ldap_base}