Is checkmk SAML 2.0 capable?

In regards of setting up SAML i’ve been also looking at a decent way to logout.
The issues are as following :

  • Logging out of Check_MK returns you to the (local) authentication page / not honoring the entry-point of a saml-configured site.
  • Aslong as my IDP session is still active and my session in Check_MK times out it will automatically re-auth/set my session in Check_MK due to being authenticated at the IdP ( it even auto-refreshes)
  • IDP session is not logged out, so if you were to call the site-URL directly you are over SAML directly logged in, no questions asked, as you had previously authenticated to the IdP, and the assetion is transmitted and then used in the Apache/httpd settings.

Solutions proposed:

  • Check_MK needs to be made aware we are using an external authentication mechanism so it can act accordinly.
  • For local auth this means destroying the X-Remote-User variable (if it was enabled for specific purposes)
  • For federated login this means that when logging out (Service provider side) one needs to not only destroy the X-Remote-User variable, on logout, but redirect it to the IdP for federation logout ( SingleLogOut)
  • biggest challenge will be realising an IdP-initiated logout to be passed onto Check_MK

In this i have been looking at the links presented in Check_MK when i hover over the user menu, and that seem to point to host/site/check_mk/logout.py
However i cannot find this specific file, so i’m kinda oblivious … any directions in ths are highly appreciated.

AzureAD is working fine as well using a slightly modified way. At least this is working for RHEL 7 and Apache 2.4.6

Not functional is the connection to the REST API. Is there any way to authenticate an automation account against it?

Prerequisites:

  • Set Userprincialname as identifier in LDAP connection
  • Azure AD custom enterprise app, Userprincipalname in name attribute

auth.conf:

# Set this to the Name of your Checkmk site, e.g.# Define SITE mysite
Define SITE mysite

# ServerName from listen-ports.conf needs to be overwritten here
# and being set to the URL of the real server.

# auth_mellon uses this to generate the needed URLs in the metadata.

ServerName https://checkmk.mydomain.tld

# Load the module from the system's Apache/httpd location as we don't ship
# mod_auth_mellon within OMD yet.

<IfModule !mod_auth_mellon.c>
    # Use this line on Debian based systems.
    #LoadModule auth_mellon_module /usr/lib/apache2/modules/mod_auth_mellon.so

    # Use this line on  CentOS 7 / 8
    LoadModule auth_mellon_module /omd/sites/${SITE}/lib/apache/modules/mod_auth_mellon.so

    # When using CentOS 7 / 8 and in need of diagnostics install mod_auth_mellon-diagnostics package,
    # and use the following statement.
    #LoadModule auth_mellon_module /usr/lib64/httpd/modules/mod_auth_mellon-diagnostics.so
</IfModule>

# Only enable this for debugging purposes
#MellonDiagnosticsFile /opt/omd/sites/${SITE}/tmp/mellon_diagnostics.log
#MellonDiagnosticsEnable On

<Location /${SITE}>

# Use SAML auth only in case there is no Check_MK authentication
# cookie provided by the user and whitelist also some other required URLs.

    <If "! %{HTTP_COOKIE} =~ /auth_/ && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/register_agent.py' && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/run_cron.py' && \
        ! %{QUERY_STRING} =~ /(_secret=|auth_|register_agent)/ && \
        ! %{REQUEST_URI} =~ m#^/${SITE}/(omd/|check_mk/(images/.*\.png|login\.py|.*\.(css|js)))# ">

        RequestHeader unset X-Remote-User
        MellonIdPMetadataFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-metadata.xml
        # only needed if the IdP Metadata does not contain the certificate.
        MellonIdPPublicKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-public-key.pem
        MellonSPCertFile /opt/omd/sites/${SITE}/etc/apache/mellon/mellon.cert
        MellonSPPrivateKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/mellon.key
        MellonEndpointPath "/${SITE}/mellon"
        MellonDefaultLoginPath "/${SITE}/check_mk/"

        Order allow,deny
        Allow from all

        AuthType Mellon
        MellonEnable auth
        require valid-user

        # If your assertion offers the username for Check_MK in an attribute you can set it directly as the remote user (REMOTE_USER)
        MellonUser "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
        RequestHeader set X-Remote-User "%{MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name}e" env=MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
    # When SAML auth fails, show the login page to the user. This should only happen,
    # if e.g. the mellon cookie is lost/rejected or if the IDP is misconfigured.
    # A failed login at the IDP will not return you here at all.
    ErrorDocument 401 '<html> \
        <meta http-equiv="refresh" content="1; URL=/${SITE}/check_mk/login.py"> \
        <body>SAML authentication failed, redirecting to login page.</body></html>'
</If>

# This header is also needed after authentication (outside of the If clause)
RequestHeader set X-Remote-User "%{MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name}e" env=MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
</Location>
1 Like

Sorry for answering my own post.
I think I got the API working by excluding it from the SAML auth like the other parts.
Don’t be afraid, the REST-API will still use the documented authentication via header :wink:
A lot of credits go out to @Glowsome for posting his config which deals with attributes in the SAML assertion.

# Set this to the Name of your Checkmk site, e.g.# Define SITE mysite
Define SITE mysite

# ServerName from listen-ports.conf needs to be overwritten here
# and being set to the URL of the real server.

# auth_mellon uses this to generate the needed URLs in the metadata.

ServerName https://checkmk.mydomain.tld

# Load the module from the system's Apache/httpd location as we don't ship
# mod_auth_mellon within OMD yet.

<IfModule !mod_auth_mellon.c>
    # Use this line on Debian based systems.
    #LoadModule auth_mellon_module /usr/lib/apache2/modules/mod_auth_mellon.so

    # Use this line on  CentOS 7 / 8
    LoadModule auth_mellon_module /omd/sites/${SITE}/lib/apache/modules/mod_auth_mellon.so

    # When using CentOS 7 / 8 and in need of diagnostics install mod_auth_mellon-diagnostics package,
    # and use the following statement.
    #LoadModule auth_mellon_module /usr/lib64/httpd/modules/mod_auth_mellon-diagnostics.so
</IfModule>

# Only enable this for debugging purposes
#MellonDiagnosticsFile /opt/omd/sites/${SITE}/tmp/mellon_diagnostics.log
#MellonDiagnosticsEnable On

<Location /${SITE}>

# Use SAML auth only in case there is no Check_MK authentication
# cookie provided by the user and whitelist also some other required URLs.

    <If "! %{HTTP_COOKIE} =~ /auth_/ && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/register_agent.py' && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/run_cron.py' && \
        ! %{REQUEST_URI} -strmatch '/${SITE}/check_mk/api/*' && \
        ! %{QUERY_STRING} =~ /(_secret=|auth_|register_agent)/ && \
        ! %{REQUEST_URI} =~ m#^/${SITE}/(omd/|check_mk/(images/.*\.png|login\.py|.*\.(css|js)))# ">

        RequestHeader unset X-Remote-User
        MellonIdPMetadataFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-metadata.xml
        # only needed if the IdP Metadata does not contain the certificate.
        MellonIdPPublicKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-public-key.pem
        MellonSPCertFile /opt/omd/sites/${SITE}/etc/apache/mellon/mellon.cert
        MellonSPPrivateKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/mellon.key
        MellonEndpointPath "/${SITE}/mellon"
        MellonDefaultLoginPath "/${SITE}/check_mk/"

        Order allow,deny
        Allow from all

        AuthType Mellon
        MellonEnable auth
        require valid-user

        # If your assertion offers the username for Check_MK in an attribute you can set it directly as the remote user (REMOTE_USER)
        MellonUser "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
        RequestHeader set X-Remote-User "%{MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name}e" env=MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
    # When SAML auth fails, show the login page to the user. This should only happen,
    # if e.g. the mellon cookie is lost/rejected or if the IDP is misconfigured.
    # A failed login at the IDP will not return you here at all.
    ErrorDocument 401 '<html> \
        <meta http-equiv="refresh" content="1; URL=/${SITE}/check_mk/login.py"> \
        <body>SAML authentication failed, redirecting to login page.</body></html>'
</If>

# This header is also needed after authentication (outside of the If clause)
RequestHeader set X-Remote-User "%{MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name}e" env=MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
</Location>

@jan-hendrikscholz
i would like to see an assertion from that IDP … as you are describing atributes by namespace
I primarily use the Microfocus product ( AccessManager)

@Glowsome

Basically, the assertion is following the documented format in Azure Single Sign On SAML Protocol - Microsoft identity platform | Microsoft Docs

Here’s an anonymized example.

<samlp:Response Destination="https://checkmk.mydomain.tld/mysite/mellon/postResponse"
    ID="<ID>" 
InResponseTo="<INRESPONSETO"
    IssueInstant="2021-06-14T05:20:10.869Z" Version="2.0"
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
    <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">https://sts.windows.net/<ENTERPRISEAPPID></Issuer>
    <samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status>
    <Assertion ID="_b6b54523-a4c8-4cfe-9e5f-3435984b4100" IssueInstant="2021-06-14T05:20:10.864Z"
        Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
        <Issuer>https://sts.windows.net/<ENTERPRISEAPPID>/</Issuer>
        <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
                <Reference URI="<REFERENCE>">
                    <Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                    <DigestValue><DIGEST></DigestValue>
                </Reference>
            </SignedInfo>
            <SignatureValue><SIGNATURE></SignatureValue>
            <KeyInfo>
                <X509Data>
                    <X509Certificate><CERT></X509Certificate>
                </X509Data>
            </KeyInfo>
        </Signature>
        <Subject>
            <NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">HJqcldT/m+MNF2R5EhQHJm9z72+zoINvM/wZanXHt/E=</NameID>
            <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><SubjectConfirmationData InResponseTo="_32A5C0AD5BA152A5508CA9866B541259"
                NotOnOrAfter="2021-06-14T06:20:10.684Z"
                Recipient="https://checkmk.mydomain.tld/mysite/mellon/postResponse"/></SubjectConfirmation>
        </Subject>
        <Conditions NotBefore="2021-06-14T05:15:10.684Z" NotOnOrAfter="2021-06-14T06:20:10.684Z">
            <AudienceRestriction>
                <Audience>https://checkmk.mydomain.tld/mysite/mellon/metadata</Audience>
            </AudienceRestriction>
        </Conditions>
        <AttributeStatement>
            <Attribute Name="http://schemas.microsoft.com/identity/claims/tenantid">
                <AttributeValue><TENANTID></AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.microsoft.com/identity/claims/objectidentifier">
                <AttributeValue><USER_GUID></AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.microsoft.com/identity/claims/displayname">
                <AttributeValue><USER_LASTNAME, USER_FIRSTNAME></AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.microsoft.com/identity/claims/identityprovider">
                <AttributeValue><IDP-URL></AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.microsoft.com/claims/authnmethodsreferences">
                <AttributeValue>http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/windows</AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname">
                <AttributeValue><USER_FIRSTNAME></AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname">
                <AttributeValue><USER_LASTNAME></AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress">
                <AttributeValue>USER_mail</AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name">
                <AttributeValue>USER_UserPrincipalname</AttributeValue>
            </Attribute>
        </AttributeStatement>
        <AuthnStatement AuthnInstant="2021-06-14T05:20:10.347Z"
            SessionIndex=<SESSIONID>>
            <AuthnContext>
                <AuthnContextClassRef>urn:federation:authentication:windows</AuthnContextClassRef>
            </AuthnContext>
        </AuthnStatement>
    </Assertion>
</samlp:Response>

Some time has passed and there were a few things, which needed to be fixed:

  • Legacy Web API URL
  • Bakery URL for deploying agents

All in all, that’s my working config with AzureAd right now:

#Set this to the Name of your Checkmk site, e.g.# Define SITE mysite
Define SITE mysite

# ServerName from listen-ports.conf needs to be overwritten here
# and being set to the URL of the real server.

# auth_mellon uses this to generate the needed URLs in the metadata.

ServerName https://checkmk.mydomain.tld

# Load the module from the system's Apache/httpd location as we don't ship
# mod_auth_mellon within OMD yet.

<IfModule !mod_auth_mellon.c>
    # Use this line on Debian based systems.
    #LoadModule auth_mellon_module /usr/lib/apache2/modules/mod_auth_mellon.so

    # Use this line on  CentOS 7 / 8
    LoadModule auth_mellon_module /omd/sites/${SITE}/lib/apache/modules/mod_auth_mellon.so

    # When using CentOS 7 / 8 and in need of diagnostics install mod_auth_mellon-diagnostics package,
    # and use the following statement.
    #LoadModule auth_mellon_module /usr/lib64/httpd/modules/mod_auth_mellon-diagnostics.so

# Only enable this for debugging purposes
# MellonDiagnosticsFile /opt/omd/sites/${SITE}/tmp/mellon_diagnostics.log
# MellonDiagnosticsEnable On

<Location /${SITE}>

# Use SAML auth only in case there is no Check_MK authentication
# cookie provided by the user and whitelist also some other required URLs.

    <If "! %{HTTP_COOKIE} =~ /auth_/ && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/register_agent.py' && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/webapi.py' && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/run_cron.py' && \
        ! %{REQUEST_URI} -strmatch '/${SITE}/check_mk/api/*' && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/deploy_agent.py' && \
        ! %{QUERY_STRING} =~ /(_secret=|auth_|register_agent)/ && \
        ! %{REQUEST_URI} =~ m#^/${SITE}/(omd/|check_mk/(images/.*\.png|login\.py|.*\.(css|js)))# ">

        RequestHeader unset X-Remote-User
        MellonIdPMetadataFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-metadata.xml
        # MellonIdPPublicKeyFile not needed, Azure AD includes the key in its metadata.xml
        MellonSPCertFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp.cert
        MellonSPPrivateKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp.key
        MellonEndpointPath "/${SITE}/mellon"
        MellonDefaultLoginPath "/${SITE}/check_mk/"

        Order allow,deny
        Allow from all

        AuthType Mellon
        MellonEnable auth
        require valid-user

        # If your assertion offers the username for Check_MK in an attribute you can set it directly as the remote user (REMOTE_USER)
        MellonUser "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
        RequestHeader set X-Remote-User "%{MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name}e" env=MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
    # When SAML auth fails, show the login page to the user. This should only happen,
    # if e.g. the mellon cookie is lost/rejected or if the IDP is misconfigured.
    # A failed login at the IDP will not return you here at all.
    ErrorDocument 401 '<html> \
        <meta http-equiv="refresh" content="1; URL=/${SITE}/check_mk/login.py"> \
        <body>SAML authentication failed, redirecting to login page.</body></html>'
</If>

# This header is also needed after authentication (outside of the If clause)
RequestHeader set X-Remote-User "%{MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name}e" env=MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
</Location>
1 Like

@jan-hendrikscholz thankyou for sharing, it looks a bit different then what i am used to encountering, as the attribute tag on my end does not give the full urn/url, it just states the attribute name as configured in the assertion.

As the Microfocus accessmanager offers mapping from directory to assertion mapping one can dictate the exact name at once.

In essence for tailoring attributes in an application you create an attribute set, which then gets linked to the SAML connection.


This attribute set then gets linked to the SAML-connection, making it possible to re-use it, and select attrubutes within this connection to send with the authentication responce (as example) :

In General the implementation of SAML(2) works with the combined efforts of us participating in this thread for different IdP’s.

What remains is as mentioned previously :

  • Support for a correct logout on both Check_mk (destroy session/cookie) as application aswell as closing the authentication on the IdP end ( Single Logout (SP-initiated))
  • Support for Single Logout (IdP-initiated), as the mod_auth_mellon does advertise SLo-endpoints in its Metadata it is assumed based on this that when a logout is done (IdP-initiated) on whatever IdP-application next to Check_mk one was authenticated you are (fully logged out)logged out.
    Do we have a hook somewher in Check_mk which we could use to destroy the session ?

.svg images must be whitelisted too, since the new theme uses a svg logo on the login site

I got it working. Tip for anyone that might read this: If you are testing with dozens of browser windows and sessions - try an Inkognito one or delete Cookies (from your CheckMK site).

1 Like

As in SAML setups you are dealing with information being passed on via your browser:

  • from an SP to an IDP as in AuthnRequest
  • from the IDP to the SP (after a successfull auth) as in Response

You want to not only explicitly logoff from the SP-side, but check on the IDP-side too => IDP keeps track of what resources you are logged in to.
So even if you think you have logged out of the application make absolutely sure you are also logged out of the IDP- / federated part.

Or as @checkmk_dweb either close all instances of your browser or launch it in an incognito session so that past authentication never gets forwarded to the application when testing.

1 Like

Strange thing noticed since i switshed my (originally CentOS7) LXC container where i run CMK in to CentOS8, and afterwards to RocklyLinux 8,5.

The SAML implementation keeps functioning ok, however if i setup a new box and use the same modules it borks.
the issue seems to underlying due to Lasso, i just cannot understand that in the upgrade it did not break the CMK box, but all new ones break.
The issue revolves around : https://dev.entrouvert.org/issues/25640

details :

  • mod_auth_mellon-0.14.0-12.el8.x86_64
  • mod_auth_mellon-diagnostics-0.14.0-12.el8.x86_64
  • lasso-2.6.0-12.el8.x86_64

As both 2.6.1 and 2.7.0 have been released as versions of Lasso , somewhere 2.6.1 is not available for either CentOS8 (yes i know support has ended) or RocklyLinux 8.5
CentOS7 still functions with Lasso 2.5.1, however downgrading is not an option, next to the fact that CentOS7 does not run anymore on latest ProxMox due to not (correctly) supporting CGroupv2​ functionality.

So please do beware if this issue i have encountered ( untill a higher version of Lasso is available)

My image also was missing this dependency for mod_auth_mellon

apt-get install libxmlsec1-openssl

Here are my additions to the config

  <If "! %{HTTP_COOKIE} =~ /auth_/ && \
	        ! %{REQUEST_URI} = '/${SITE}/check_mk/register_agent.py' && \
	        ! %{REQUEST_URI} = '/${SITE}/check_mk/webapi.py' && \
	        ! %{REQUEST_URI} = '/${SITE}/check_mk/run_cron.py' && \
		! %{REQUEST_URI} = '/${SITE}/check_mk/automation.py' && \
	        ! %{REQUEST_URI} -strmatch '/${SITE}/check_mk/api/*' && \
	        ! %{REQUEST_URI} = '/${SITE}/check_mk/deploy_agent.py' && \
	        ! %{QUERY_STRING} =~ /(_secret=|auth_|register_agent)/ && \
	        ! %{REQUEST_URI} =~ m#^/${SITE}/(omd/|check_mk/(images/.*\.png|login\.py|.*\.(css|js)))# && \
	        ! %{REQUEST_URI} =~ m#^/${SITE}/(omd/|check_mk/(images/.*\.svg|login\.py|.*\.(css|js)))# ">

 MellonSecureCookie On
 MellonCookieSameSite None

1 Like

In regards of this whole SAML-implementation - and the thing i am struggling with is the issue of Single-Logout.

If i logout of my CheckMK site i am only logged off the local site, but not in a federative way.
This means that when i refresh/point my browser back to the (base) url where the module takes hold i will login (within the session-time on my IDP) without any interaction.
The module facilitates SLo features, howevcer without a means to adapt the logout link from CheckMK itself its not going to be effective.

So can we get a hook on the logout-url/ be able to manipulate it ?

For a clarification as to why this is wanted :

  • Imagine i am logging into CheckMK from a public pc ( secured over SAML, with a method which forces 2FA)
  • i logoff the CheckMK site, as i needed to do a bathroom-break, so expecting to when i logoff i am actually loged out.
  • while i am in the bathroom someone takes a seat, and presses refresh, and … uhm - unexpected he’s in my CheckMK session as it was still validated at the IDP. This soulds like a VERY bug oopsie.

Remember, such scenarios are hypothetical, but still pose a serious risk in using federated login without federated logout !

2 Likes

Federated logout is not supported in SAML because there is no way for the IdP to inform every SP that a user is logged out. The lack of backchannel communication between IdP and SP is a feature (and a useful one). An SP can redirect to the IdP logout page and the user can logout of the IdP, but they can still use valid sessions on other sites.

The only real federated logout is quitting the browser.

I must disagree on that, between IDP and SP there is a Single logout.
Conditionally when both the IDP and the SP have a Single logout endpoint defined in their Metadata.

When above is true:

  • a logout on the SP will trigger a logoutrequest to the IDP ( SP initiated)
  • a logout at the IDP will trigger a request to the SP to also logout (IDP initiated)

That being said most of the time the caveat is that when using a SAML-SP module in front of an application (like with CheckMK) there is no backchannel from application to SP to check if a user has logged off or not.
Same goes for the SP to the application, there is no webhook to let the SP inform the application the user is logging out.

When a user logs out of the application in this case one normally makes a redirect to the global logout page of the IDP, which in turn then does a logout request to the SP to also kill the session there.

@Glowsome
I’ve been playing with getting SLO working for my Checkmk instance.

I’ve got it working, however your environment may be different. I’m using a RHEL7 server and PingIdentity for my IDP.

The logout is only initiated by the SP, not the IDP. Basically I am using Apache to redirect to my IDP once Checkmk is done logging out ‘locally’

If you look at the login.py source code, there are some directives at the very end of it for the logout.

With my Apache config, I tried my best to not interfere with the way Checkmk does it’s thing out of the box. So I followed the logic in the login.py source.

That being said, here is my auth.conf :

# Set this to the Name of your Checkmk site, e.g.
#Define SITE
Define SITE master

# TODO: See if we can pull this from the local env. PassEnv wasn't working - probably because the HOSTNAME variable isn't set in the shell that is running Apache
Define HOSTNAME example.com

# ServerName from listen-ports.conf needs to be overwritten here
# and being set to the URL of the real server. auth_mellon uses this
# to generate the needed URLs in the metadata
ServerName https://example.com

# Load the module.
<IfModule !mod_auth_mellon.c>

        LoadModule auth_mellon_module /omd/sites/${SITE}/lib/apache/modules/mod_auth_mellon.so
        # When using CentOS 7 / 8 and in need of diagnostics install mod_auth_mellon-diagnostics package,
        # and use the following statement.
        # LoadModule auth_mellon_module /usr/lib64/httpd/modules/mod_auth_mellon-diagnostics.so

</IfModule>

# Only enable this for debugging purposes
# MellonDiagnosticsFile /opt/omd/sites/${SITE}/tmp/mellon_diagnostics.log
# MellonDiagnosticsEnable On
<Location /${SITE}>

        # Use SAML auth only in case there is no Check_MK authentication
        # cookie provided by the user and whitelist also some other required URLs
        <If "! %{HTTP_COOKIE} =~ /^auth_/ && \
                ! %{REQUEST_URI} = '/${SITE}/check_mk/register_agent.py' && \
                ! %{REQUEST_URI} = '/${SITE}/check_mk/deploy_agent.py' && \
                ! %{REQUEST_URI} = '/${SITE}/check_mk/run_cron.py' && \
                ! %{REQUEST_URI} = '/${SITE}/check_mk/webapi.py' && \
                ! %{REQUEST_URI} = '/${SITE}/check_mk/automation.py' && \
                ! %{REQUEST_URI} -strmatch '/${SITE}/check_mk/api/*' && \
                ! %{QUERY_STRING} =~ /(_secret=|auth_|register_agent)/ && \
                ! %{REQUEST_URI} =~ m#^/${SITE}/(omd/|check_mk/((images|themes)/.*\.(png|svg)|log(in|out)\.py|.*\.(css|js)))# ">

                MellonIdPMetadataFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-metadata.xml
                MellonIdPPublicKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-public-key.pem
                MellonSPCertFile /opt/omd/sites/${SITE}/etc/apache/mellon/mellon.cert
                MellonSPPrivateKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/mellon.key
                MellonEndpointPath "/${SITE}/mellon"
                MellonDefaultLoginPath "/${SITE}/check_mk/"

                Order allow,deny
                Allow from all

                MellonSecureCookie On
                MellonCookieSameSite None

                AuthType Mellon
                AuthName "Check_MK SAML Login"
                MellonEnable auth
                Require valid-user
                MellonUser username

                RequestHeader set X-Remote-User %{username}e env=username
        </If>
        <If "! %{HTTP_COOKIE} =~ /mellon-cookie=cookietest/ && \
                ! %{HTTP_REFERER} = 'https://${HOSTNAME}/${SITE}/check_mk/index.py?start_url=%2F${SITE}%2Fcheck_mk%2Fdashboard.py' && \
                %{REQUEST_URI} = '/${SITE}/check_mk/login.py' ">

                Redirect '/${SITE}/check_mk/login.py' '/${SITE}/mellon/logout?ReturnTo=https://${HOSTNAME}/${SITE}/check_mk/logout.py&IdP=https://exampleIDP.com/logout'
        </If>
# This header is also needed after authentication (outside of the If clause)
RequestHeader set X-Remote-User %{REMOTE_USER}e env=REMOTE_USER
</Location>

Notice that I had to whitelist logout.py as well.

Also, I had to work with my IDP folks to get them to add the SLO settings into the IDP and provide me with the updated metadata. Again, your environment my differ.

A little ‘hacky’, I agree. However, it’s working for me. If you or anyone have any suggestions for a better way to do the logout, I’m all ears.

1 Like

Good stuff,

I will test it out, the only change i see needed is the logout-url of a/the IdP for my specific product.
May take a while,as at the moment work is very demanding.

I had to add one more bit of conditional logic to my auth.conf as I was getting ‘too many redirects’ error if I pointed my browser to https://example.com/mysite/checkmk/login.py

I want this link to work because sometimes I just want to login with username/password (for an admin account for example)

Here’s the updated if statement:

        <If "%{HTTP_COOKIE} = 'mellon-cookie' && \
                ! %{HTTP_COOKIE} =~ /mellon-cookie=cookietest/ && \
                ! %{HTTP_REFERER} = 'https://${HOSTNAME}/${SITE}/check_mk/index.py?start_url=%2F${SITE}%2Fcheck_mk%2Fdashboard.py' && \
                %{REQUEST_URI} = '/${SITE}/check_mk/login.py' ">

                Redirect '/${SITE}/check_mk/login.py' '/${SITE}/mellon/logout?ReturnTo=https://${HOSTNAME}/${SITE}/check_mk/logout.py&IdP=https://exampleIDP.com/logout'
        </If>

In my case i do not want a way open for any other means then a login over SAML.

This has to do with the authentication contract i am using:

  • IF user comes from local network (my LAN) the contract will execute a username/password login via SAML
  • IF a/the user comes from any other source the contract will execute username/password/2FA login.

In short i am using a risk-based policy to entforce this.