How to secure a Spring Boot app with SAML and Keycloak

No Comments

Using Keycloak with Spring Boot applications is usually just a matter of a few lines of code when you use Keycloak‘s adapter integrations. However, most of the integrations require using the OpenID Connect protocol for web-based Single Sign-On (SSO) and sometimes it might be necessary to use SAML instead of OpenID Connect.

In this blog post, you’ll learn how to configure your Spring Boot app to use SSO via SAML with Keycloak.

SAML is a mature standard protocol for authentication and authorization which is heavily used across many industries. Among many other things, it provides powerful Single Sign-On capabilities with the Web SSO profile.

If you want to use SAML in a Java application, you have many options, but the most common ones are using OpenSAML or Spring Security SAML.
Note that if you want to play with SAML, you could also use Shibboleth, but that’s a task for another blog post. ๐Ÿ˜‰

This time we’ll use a Spring-Boot-based app with plain Spring Security SAML without any Keycloak adapters involved as example client.

The code for the spring-boot-security-saml-sample application can be found here.
Note that this example application is based on the Spring Boot Security SAML Sample app by Vincenzo De Notaris.

SAML terminology

In our scenario we have two parties that interact during the SSO handshake. The Spring Boot app acts as a Service Provider (SP) and offers a service to the user. The Keycloak server plays the role of an Identity Provider (IDP) and provides means to authenticate a user for a Service Provider.

The SAML Web SSO profile describes a set of messages that get exchanged between the involved parties. Those messages are XML documents that contain information about authentication requests/responses with signatures and used certificates, as well as potentially signed and encrypted user information in the form of SAML assertions.

SAML describes multiple styles of communication between two parties. The most common ones are POST-Binding and Redirect-Binding.
With POST-Binding the two parties exchange SAML messages via HTTP POST requests. Those POST requests are triggered via dynamically generated, automatically submitted HTML forms, which we’ll discuss later.
The nice thing with POST-Binding is that, since all the information is sent via HTTP POST, no sensitive information can be leaked in web server or proxy logs or browser histories.

Just a quick note about the the Redirect-Binding. As the name suggests, the Redirect-Binding makes extensive use of HTTP redirects and transmits SAML messages as base64 encoded URL parameters. Although this might seem much easier than the HTTP-POST-based approach, it can lead to leaking information in the aforementioned logs.

We’ll use POST-Binding for the remainder of this blog post.

Spring Boot and Spring Security SAML

If you have worked with Spring Security, then you probably know that Spring Security SAML is usually configured via XML.
Thankfully, Vincenzo De Notaris et al. have put in a lot of effort to port the XML config to Java config. Although it’s quite a mouthful of Java config, it’s fairly practical. Still, I’m looking forward to a more bootified Spring Security SAML support in the future. ๐Ÿ™‚
An example of what this looks like can be seen in the WebSecurityConfig class in our example app.

The example contains already everything that we need. Well, almost. We need to declare one additional Spring Bean, which we add to the WebSecurityConfig class

    @Bean
    @Qualifier("idp-keycloak")
    public ExtendedMetadataDelegate keycloakExtendedMetadataProvider(Environment env)
            throws MetadataProviderException {
        String idpKeycloakMetadataURL = env.getRequiredProperty("keycloak.auth-server-url") + "/protocol/saml/descriptor";
        HTTPMetadataProvider httpMetadataProvider = new HTTPMetadataProvider(
                this.backgroundTaskTimer, httpClient(), idpKeycloakMetadataURL);
        httpMetadataProvider.setParserPool(parserPool());
        ExtendedMetadataDelegate extendedMetadataDelegate =
                new ExtendedMetadataDelegate(httpMetadataProvider, extendedMetadata());
        extendedMetadataDelegate.setMetadataTrustCheck(true);
        extendedMetadataDelegate.setMetadataRequireSignature(false);
        backgroundTaskTimer.purge();
        return extendedMetadataDelegate;
    }

We also need to ensure that the Keycloak IDP definition is automatically picked up by the Spring Security SAML infrastructure. To do this, we modify the metadata bean to let Spring autowire all available MetadataProvider instances via the providers parameter.

    @Bean
    @Qualifier("metadata")
    public CachingMetadataManager metadata(List<MetadataProvider> providers) throws MetadataProviderException {
        return new CachingMetadataManager(providers);
    }

Keycloak setup

For this blog post, we create a realm with the name demo.
Note that I tested this with Keycloak 4.8.3.Final.

Also, note that you might need to adapt the URL to your Keycloak server in the application.properties configuration file of the Spring Boot app or just pass a JVM System Property like:

-Dkeycloak.auth-server-url=http://localhost:8081/auth/realms/demo

In this demo realm, we need to create a client configuration for our Spring Boot app.

Setup Keycloak Client

Create a new SAML client in Keycloak with the client-id com:vdenotaris:spring:sp.
In the client settings tab configure the following:

  • Include AuthnStatement On
  • Include OneTimeUse Condition Off
  • Sign Documents On
  • Optimize REDIRECT signing key lookup Off
  • Sign Assertions On
  • Signature Algorithm RSA_SHA256
  • SAML Signature Key Name KEY_ID
  • Canonicalization Method EXCLUSIVE
  • Encrypt Assertions Off
  • Client Signature Required On
  • Force POST Binding On
  • Front Channel Logout On
  • Force Name ID Format Off
  • Name ID Format username
  • Root URL http://localhost:8080
  • Valid Redirect URIs /saml/*
  • Base URL /
  • Open Fine Grain SAML Endpoint Configuration
  • Assertion Consumer Service POST Binding URL /saml/SSO
  • Logout Service POST Binding URL /saml/logout

Client Configuration Part 1

Client Configuration Part 2

Client Configuration Part 3

In the SAML Keys tab you need to import the Keystore of the example app.

  • Click on import
  • Archive Format JKS
  • Key-Alias apollo
  • Store pass nalle123
  • Select configure the path to src/main/resources/saml/samlKeystore.jks

SAML Client Configuration for Signing Keys

Your client is now set up to use the POST-Binding method of the Web SSO SAML Profile.

Playing with the setup: Login and logout

You can now try to log in via Keycloak:

  • Browse to http://localhost:8080
  • Click on Getting started
  • Under Select your Identity Provider choose http://localhost:8081/auth/realms/demo and click Start 3rd Party Login
  • Login with a user, I named mine tester

Example App IDP Selection

You should now see a nice neon-cat image like

keycloak Screen after login

Now click on Global logout to log out again. As the name implies, this logs instructs Keycloak to propagate the logout to all clients which have an Admin URL configured or rely on Keycloaks Cookies, such as the Account app built-in to Keycloak.

SAML messages and protocol flow

Now that everything works, let’s dig a bit deeper and see what’s going on under the hood in your browser. To do that, we install one of the available SAML debugging tools as a browser extension. Since I’m using Chrome, I use SAML Chrome Panel.

If you enable this extension and try to log in again, you’ll see the SAML messages that are exchanged between our app and Keycloak. Note that you might need to enable the extension for incognito mode / private browsing as well.

You should now see a SAML tab in the devtools view of your browser. If you click on the SAML tab and try to log in, you can see the SAML AuthnRequest request:

<saml2p:AuthnRequest AssertionConsumerServiceURL="http://localhost:8080/saml/SSO"
    Destination="http://localhost:8081/auth/realms/demo/protocol/saml" ForceAuthn="false"
    ID="ai83b34d292de92549iij63i99jgff" IsPassive="false" IssueInstant="2019-02-28T19:58:58.486Z"
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"
    xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">com:vdenotaris:spring:sp</saml2:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
            <ds:Reference URI="#ai83b34d292de92549iij63i99jgff">
                <ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <ds:DigestValue>EAG4ntORN3mgZToX69jKh1WDuL4=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>XftgCK5io35hc6FK/er7eLQLNvGqRUeEMX6kyfDxmrDQ97eDS8H+awmYLFmrcS2TIhZNXkhbnCi8VcOUvRpu4XNzhh7wunRGxRZ5dbDewlRoQa+vFzNFXPNbXf0d6NbjiEfQy9a0zC5BTRs7Konh/lzm4EQ1h2GAWc8PEaypFASiV5uJ2kdeIuBeGRNFYqmTZyQm2JgsJ8E7BFwOKqmXnkb6jhywReuFSJZDRebq3iSzsca2wkKX/SvK6iAXPf7HSzMJ4Mz+nOxW8XTi7rRE43r1s4vYNTj3s10BwuNv/ldW3UzXTNRU868unOyk1GuZZA3V/yLpkEovw/U7zfXAig==</ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>MIIDUjCCAjqgAwIBAgIEUOLIQTANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQGEwJGSTEQMA4GA1UE
                    CBMHVXVzaW1hYTERMA8GA1UEBxMISGVsc2lua2kxGDAWBgNVBAoTD1JNNSBTb2Z0d2FyZSBPeTEM
                    MAoGA1UECwwDUiZEMQ8wDQYDVQQDEwZhcG9sbG8wHhcNMTMwMTAxMTEyODAxWhcNMjIxMjMwMTEy
                    ODAxWjBrMQswCQYDVQQGEwJGSTEQMA4GA1UECBMHVXVzaW1hYTERMA8GA1UEBxMISGVsc2lua2kx
                    GDAWBgNVBAoTD1JNNSBTb2Z0d2FyZSBPeTEMMAoGA1UECwwDUiZEMQ8wDQYDVQQDEwZhcG9sbG8w
                    ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCXqP0wqL2Ai1haeTj0alwsLafhrDtUt00E
                    5xc7kdD7PISRA270ZmpYMB4W24Uk2QkuwaBp6dI/yRdUvPfOT45YZrqIxMe2451PAQWtEKWF5Z13
                    F0J4/lB71TtrzyH94RnqSHXFfvRN8EY/rzuEzrpZrHdtNs9LRyLqcRTXMMO4z7QghBuxh3K5gu7K
                    qxpHx6No83WNZj4B3gvWLRWv05nbXh/F9YMeQClTX1iBNAhLQxWhwXMKB4u1iPQ/KSaal3R26pON
                    UUmu1qVtU1quQozSTPD8HvsDqGG19v2+/N3uf5dRYtvEPfwXN3wIY+/R93vBA6lnl5nTctZIRsyg
                    0Gv5AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAFQwAAYUjso1VwjDc2kypK/RRcB8bMAUUIG0hLGL
                    82IvnKouGixGqAcULwQKIvTs6uGmlgbSG6Gn5ROb2mlBztXqQ49zRvi5qWNRttir6eyqwRFGOM6A
                    8rxj3Jhxi2Vb/MJn7XzeVHHLzA1sV5hwl/2PLnaL2h9WyG9QwBbwtmkMEqUt/dgixKb1Rvby/tBu
                    RogWgPONNSACiW+Z5o8UdAOqNMZQozD/i1gOjBXoF0F5OksjQN7xoQZLj9xXefxCFQ69FPcFDeEW
                    bHwSoBy5hLPNALaEUoa5zPDwlixwRjFQTc5XXaRpgIjy/2gsL8+Y5QRhyXnLqgO67BlLYW/GuHE=</ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
</saml2p:AuthnRequest>

The AuthnRequest is quite dense and describes things like involved party (e.g. com:vdenotaris:spring:sp), communication methods (e.g. urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST) and certificate information.
The AssertionConsumerServiceURL which is configured as http://localhost:8080/saml/SSO denotes the endpoint that Keycloak (the IDP) should use to send SAML responses to our app (the SP), whereas the Destination denotes the SAML protocol endpoint on the Keycloak side which is http://localhost:8081/auth/realms/demo/protocol/saml.

Chrome SAML extension

This is sent via HTTP POST by your browser to the http://localhost:8081/auth/realms/demo/protocol/saml endpoint of your Keycloak IDP server, which responds with a browser-redirect to a login form to perform the authentication.

After successful authentication, Keycloak responds with HTTP status 200 and a small HTML document. This document contains the encoded SAML Response as a form parameter in an embedded HTML form that is automatically submitted via JavaScript by your browser on arrival. If JavaScript is not available, then the user will see a HTML form with a continue button, Progressive enhancement FTW. A simple, but quite effective technique ๐Ÿ™‚

<HTML>
  <HEAD>
    <TITLE>SAML HTTP Post Binding</TITLE>
  </HEAD>
  <BODY Onload="document.forms[0].submit()">
    <FORM METHOD="POST" ACTION="http://localhost:8080/saml/SSO">
      <INPUT TYPE="HIDDEN" NAME="SAMLResponse" VALUE="PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhb...Base64 encoded saml response">
      <P>JavaScript is disabled. We strongly recommend to enable it. Click the button below to continue.</P>
      <INPUT TYPE="SUBMIT" VALUE="CONTINUE"/></NOSCRIPT>
    </FORM>
  </BODY>
</HTML>

The contained SAML Response looks like this:

<samlp:Response Destination="http://localhost:8080/saml/SSO"
    ID="ID_54ee7d80-7037-4f8d-b4c5-b046e1de8ef7" InResponseTo="ai83b34d292de92549iij63i99jgff"
    IssueInstant="2019-02-28T19:59:23.535Z" Version="2.0"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml:Issuer>http://localhost:8081/auth/realms/demo</saml:Issuer>
    <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
        <dsig:SignedInfo><dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><dsig:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <dsig:Reference URI="#ID_54ee7d80-7037-4f8d-b4c5-b046e1de8ef7">
                <dsig:Transforms><dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                <dsig:DigestValue>x0cUGoSifrriU1zQuaRy4xkIR75ibzil0Pla9RS8CQ0=</dsig:DigestValue>
            </dsig:Reference>
        </dsig:SignedInfo>
        <dsig:SignatureValue>H7AfRJ+zGf3lVfLiPDnUrDNyqPVaz65A2PWJX/rjI7sPZD8KitY1+NvgGpoR/JLCQccF8HvHzeQO9c9S4tvMxkT+KE3bgufugfAL+aYMlL61/C8XA+2b1vazOv1ftKCeMthxn1iKOQQ0GcB4drGqip25UhSXpcaXeh2lTtfnV3iv2whMGZXCoWisEBH/izMYr0uYngplnJEmXSzX+BAQc8BXA+yLCEJ34Inayg3VnYm7Tx8zh9PAgx28j5HikrNG7AoBEAxF9CCAWvBLLBmx4ebpiLHdzZUHE7TYmEORfL/yJ5KG3k4BlU5w287B9UG5C4IFH8LAUOOQsVR6VRoTpw==</dsig:SignatureValue>
        <dsig:KeyInfo>
            <dsig:KeyName>PrmJE0uxLVfFemeO41pwrZ8P3Pxmi8q44V4553olejE</dsig:KeyName>
            <dsig:X509Data>
                <dsig:X509Certificate>MIIClzCCAX8CBgFo2/zejjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARkZW1vMB4XDTE5MDIxMTA5NTUwOFoXDTI5MDIxMTA5NTY0OFowDzENMAsGA1UEAwwEZGVtbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANGej7NgaqGe762Z5g2dch/Pr6G2q3fZlN8aUfU1+lzBrgL/kwRrsCr0zeQ4EcXWpfV5ayMl+0Ouc+Q8VMObVr+8+Iq2b6NUaOMR+GiOc3vCcEEtB3zfNVqE3FFeAI6vTDA4u45M0NKUkn1dMtITQj2K2Mmz/pjwmGCo1jh9MS3loZU07om8UjHNrrg/4Tct97EONnTdYgHNetNRS3xsXdzJc64KtovA+Muk93XMhQe1MR8iIdkSX1kIuJg0Ka9Y996dKstDB8nzTUlEQs/vw4iSu6IKu+cOvdrs+HFyvCVUWmqVpqh/AL+MgJxtRcfj7tPWESSe+bukwcz+icogEAUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAult+p9pECxU32gKFaMCUt0bDFsDU00nM3hPpRUijJchJe68NvXn9Pv2DwbIPpSQpYJAsG3xoK36h/S7oTF3SosnZVtrHXhzN+aNWKgoDGcR8d4WtT6kKphI8Mf123qyPPC+5v7CQxDOW6wXd+0XQFRIfHSfyH0gxRsnFoYiapnAgOVftozMCm2F2ZZQmhPtxaigQ6rhVWIDbemhKlwEV49H83Qkh9c/jfngVdYB1yA/MfSsossk6u8w47egSt73FXVAHginX4obHp+HEOOU7C8myOIyKq74nPvesvmffIv7ttgvLoEhdK/S3p7AiHppxgWb1roD/7P1Tk21eqOBW3Q==</dsig:X509Certificate>
            </dsig:X509Data>
            <dsig:KeyValue>
                <dsig:RSAKeyValue>
                    <dsig:Modulus>0Z6Ps2BqoZ7vrZnmDZ1yH8+vobard9mU3xpR9TX6XMGuAv+TBGuwKvTN5DgRxdal9XlrIyX7Q65z5DxUw5tWv7z4irZvo1Ro4xH4aI5ze8JwQS0HfN81WoTcUV4Ajq9MMDi7jkzQ0pSSfV0y0hNCPYrYybP+mPCYYKjWOH0xLeWhlTTuibxSMc2uuD/hNy33sQ42dN1iAc1601FLfGxd3Mlzrgq2i8D4y6T3dcyFB7UxHyIh2RJfWQi4mDQpr1j33p0qy0MHyfNNSURCz+/DiJK7ogq75w692uz4cXK8JVRaapWmqH8Av4yAnG1Fx+Pu09YRJJ75u6TBzP6JyiAQBQ==</dsig:Modulus>
                    <dsig:Exponent>AQAB</dsig:Exponent>
                </dsig:RSAKeyValue>
            </dsig:KeyValue>
        </dsig:KeyInfo>
    </dsig:Signature>
    <samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status>
    <saml:Assertion ID="ID_39d48e94-d0aa-4cb3-8cc9-cce064b141af" IssueInstant="2019-02-28T19:59:23.535Z"
        Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
        <saml:Issuer>http://localhost:8081/auth/realms/demo</saml:Issuer>
        <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
            <dsig:SignedInfo><dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><dsig:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
                <dsig:Reference URI="#ID_39d48e94-d0aa-4cb3-8cc9-cce064b141af">
                    <dsig:Transforms><dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                    <dsig:DigestValue>dF9OWNKEu+czMS9leQHuUPTlJys4s14+5QF2l+4KQLg=</dsig:DigestValue>
                </dsig:Reference>
            </dsig:SignedInfo>
            <dsig:SignatureValue>olNhmQb4wGMgNHg9dMpBNkfV75oLQt2jJYW+R4dYX7CNQOPeFzVN8dMNtPmKIec/ZCYdK5kXzFhcvWsVWj8S0Jdm3B7Ep4dg7urTkqTulz5W9uQFg1bx0X6VzPmwTnynkLptyQv4L21uwdENQNDa+cF8c4dbLtyHgilOPDkpTRU0ZdLNDT3ea7iKClhddPvqX3rC/hepDH+hfYzh+l8EM0xOsjLUA7id4UwFGhWqB/ExzKqnMzxVZsWzZTu4W+sWLsH65dBltJVdPuOH1SM2azTBO8Wyz1cD8FWBXHiHTigkx+iaL3PVgM0znLkikoX+BN+1GTKj8nSVsPih3SQwIA==</dsig:SignatureValue>
            <dsig:KeyInfo>
                <dsig:KeyName>PrmJE0uxLVfFemeO41pwrZ8P3Pxmi8q44V4553olejE</dsig:KeyName>
                <dsig:X509Data>
                    <dsig:X509Certificate>MIIClzCCAX8CBgFo2/zejjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARkZW1vMB4XDTE5MDIxMTA5NTUwOFoXDTI5MDIxMTA5NTY0OFowDzENMAsGA1UEAwwEZGVtbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANGej7NgaqGe762Z5g2dch/Pr6G2q3fZlN8aUfU1+lzBrgL/kwRrsCr0zeQ4EcXWpfV5ayMl+0Ouc+Q8VMObVr+8+Iq2b6NUaOMR+GiOc3vCcEEtB3zfNVqE3FFeAI6vTDA4u45M0NKUkn1dMtITQj2K2Mmz/pjwmGCo1jh9MS3loZU07om8UjHNrrg/4Tct97EONnTdYgHNetNRS3xsXdzJc64KtovA+Muk93XMhQe1MR8iIdkSX1kIuJg0Ka9Y996dKstDB8nzTUlEQs/vw4iSu6IKu+cOvdrs+HFyvCVUWmqVpqh/AL+MgJxtRcfj7tPWESSe+bukwcz+icogEAUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAult+p9pECxU32gKFaMCUt0bDFsDU00nM3hPpRUijJchJe68NvXn9Pv2DwbIPpSQpYJAsG3xoK36h/S7oTF3SosnZVtrHXhzN+aNWKgoDGcR8d4WtT6kKphI8Mf123qyPPC+5v7CQxDOW6wXd+0XQFRIfHSfyH0gxRsnFoYiapnAgOVftozMCm2F2ZZQmhPtxaigQ6rhVWIDbemhKlwEV49H83Qkh9c/jfngVdYB1yA/MfSsossk6u8w47egSt73FXVAHginX4obHp+HEOOU7C8myOIyKq74nPvesvmffIv7ttgvLoEhdK/S3p7AiHppxgWb1roD/7P1Tk21eqOBW3Q==</dsig:X509Certificate>
                </dsig:X509Data>
                <dsig:KeyValue>
                    <dsig:RSAKeyValue>
                        <dsig:Modulus>0Z6Ps2BqoZ7vrZnmDZ1yH8+vobard9mU3xpR9TX6XMGuAv+TBGuwKvTN5DgRxdal9XlrIyX7Q65z5DxUw5tWv7z4irZvo1Ro4xH4aI5ze8JwQS0HfN81WoTcUV4Ajq9MMDi7jkzQ0pSSfV0y0hNCPYrYybP+mPCYYKjWOH0xLeWhlTTuibxSMc2uuD/hNy33sQ42dN1iAc1601FLfGxd3Mlzrgq2i8D4y6T3dcyFB7UxHyIh2RJfWQi4mDQpr1j33p0qy0MHyfNNSURCz+/DiJK7ogq75w692uz4cXK8JVRaapWmqH8Av4yAnG1Fx+Pu09YRJJ75u6TBzP6JyiAQBQ==</dsig:Modulus>
                        <dsig:Exponent>AQAB</dsig:Exponent>
                    </dsig:RSAKeyValue>
                </dsig:KeyValue>
            </dsig:KeyInfo>
        </dsig:Signature>
        <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">tester</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData InResponseTo="ai83b34d292de92549iij63i99jgff"
                NotOnOrAfter="2019-02-28T20:04:21.535Z" Recipient="http://localhost:8080/saml/SSO"/></saml:SubjectConfirmation>
        </saml:Subject>
        <saml:Conditions NotBefore="2019-02-28T19:59:21.535Z" NotOnOrAfter="2019-02-28T20:00:21.535Z">
            <saml:AudienceRestriction>
                <saml:Audience>com:vdenotaris:spring:sp</saml:Audience>
            </saml:AudienceRestriction>
        </saml:Conditions>
        <saml:AuthnStatement AuthnInstant="2019-02-28T19:59:23.536Z"
            SessionIndex="c698343d-20a8-485a-82af-93f764804d45::aa87b005-0b74-45f6-a806-e2193a6288ad">
            <saml:AuthnContext>
                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
            </saml:AuthnContext>
        </saml:AuthnStatement>
        <saml:AttributeStatement>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">uma_authorization</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">view-profile</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">access</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">manage-account</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">manage-account-links</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">offline_access</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">access</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">user</saml:AttributeValue>
            </saml:Attribute>
        </saml:AttributeStatement>
    </saml:Assertion>
</samlp:Response>

So what’s in the XML?

  • The username: tester
  • The role information
  • Some restrictions about the response (time limit, audience)
  • Signature

SAML logout flow with POST Binding

But let’s see what happens when we log out, so let’s click Global logout. This triggers an HTTP POST request to http://localhost:8080/saml/logout (our Spring Boot) which in turn generates a new auto-submit HTML form, which looks like this:

<HTML>
  <HEAD>
    <TITLE>SAML HTTP Post Binding</TITLE>
  </HEAD>
  <BODY Onload="document.forms[0].submit()">
    <FORM METHOD="POST" ACTION="http://localhost:8081/auth/realms/demo/protocol/saml">
      <INPUT TYPE="HIDDEN" NAME="SAMLResponse" VALUE="PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhb...Base64 encoded SAML LogoutRequest">
      <P>JavaScript is disabled. We strongly recommend to enable it. Click the button below to continue.</P>
      <INPUT TYPE="SUBMIT" VALUE="CONTINUE"/></NOSCRIPT>
    </FORM>
  </BODY>
</HTML>

This triggers the browser to send an HTTP POST request to http://localhost:8081/auth/realms/demo/protocol/saml with the SAML LogoutRequest in the request body:

<saml2p:LogoutRequest Destination="http://localhost:8081/auth/realms/demo/protocol/saml"
    ID="a2065g8i0cf875dj174d7ja6j3d5gbh" IssueInstant="2019-02-28T20:19:06.791Z" Version="2.0"
    xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">com:vdenotaris:spring:sp</saml2:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
            <ds:Reference URI="#a2065g8i0cf875dj174d7ja6j3d5gbh">
                <ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <ds:DigestValue>ERsgSFrLFUpkbfEvYJ97eQgg3RQ=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>U/zrNEk4eJk7CXxYYaj5MUaWmAgqo8bve1wEVLFCenpGgCAKmYHhQdoLdiDDnoIqxhNTyDBEPCDMWcoDyS6SNY3luubMdPHmrBCOXjV+k3vbORHk/w6O72aUHZ4UwLeJmna8H0dDM+oXaX8tQ5y5unY57bFLEvbZGj0hQVVbphU9B+vFaBD6UPHJCSFORUayhAYWr7MNRUgz4vCM4pB0zkFXBzusKMl5VAOH5fnVvDy4k06QU4i1VGpB4dHWEdIINdUgURPj2COyRQV8TSzy+1+lGCgoubIishYSbtuhCc2Xex4Spiaxe3Z67j5xSAabRY1J3BYwt1z4bkIxfl8sKA==</ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>MIIDUjCCAjqgAwIBAgIEUOLIQTANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQGEwJGSTEQMA4GA1UE
                    CBMHVXVzaW1hYTERMA8GA1UEBxMISGVsc2lua2kxGDAWBgNVBAoTD1JNNSBTb2Z0d2FyZSBPeTEM
                    MAoGA1UECwwDUiZEMQ8wDQYDVQQDEwZhcG9sbG8wHhcNMTMwMTAxMTEyODAxWhcNMjIxMjMwMTEy
                    ODAxWjBrMQswCQYDVQQGEwJGSTEQMA4GA1UECBMHVXVzaW1hYTERMA8GA1UEBxMISGVsc2lua2kx
                    GDAWBgNVBAoTD1JNNSBTb2Z0d2FyZSBPeTEMMAoGA1UECwwDUiZEMQ8wDQYDVQQDEwZhcG9sbG8w
                    ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCXqP0wqL2Ai1haeTj0alwsLafhrDtUt00E
                    5xc7kdD7PISRA270ZmpYMB4W24Uk2QkuwaBp6dI/yRdUvPfOT45YZrqIxMe2451PAQWtEKWF5Z13
                    F0J4/lB71TtrzyH94RnqSHXFfvRN8EY/rzuEzrpZrHdtNs9LRyLqcRTXMMO4z7QghBuxh3K5gu7K
                    qxpHx6No83WNZj4B3gvWLRWv05nbXh/F9YMeQClTX1iBNAhLQxWhwXMKB4u1iPQ/KSaal3R26pON
                    UUmu1qVtU1quQozSTPD8HvsDqGG19v2+/N3uf5dRYtvEPfwXN3wIY+/R93vBA6lnl5nTctZIRsyg
                    0Gv5AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAFQwAAYUjso1VwjDc2kypK/RRcB8bMAUUIG0hLGL
                    82IvnKouGixGqAcULwQKIvTs6uGmlgbSG6Gn5ROb2mlBztXqQ49zRvi5qWNRttir6eyqwRFGOM6A
                    8rxj3Jhxi2Vb/MJn7XzeVHHLzA1sV5hwl/2PLnaL2h9WyG9QwBbwtmkMEqUt/dgixKb1Rvby/tBu
                    RogWgPONNSACiW+Z5o8UdAOqNMZQozD/i1gOjBXoF0F5OksjQN7xoQZLj9xXefxCFQ69FPcFDeEW
                    bHwSoBy5hLPNALaEUoa5zPDwlixwRjFQTc5XXaRpgIjy/2gsL8+Y5QRhyXnLqgO67BlLYW/GuHE=</ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
    <saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
        xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">tester</saml2:NameID>
    <saml2p:SessionIndex>220f505a-1928-4855-8251-1036b0f95e82::aa87b005-0b74-45f6-a806-e2193a6288ad</saml2p:SessionIndex>
</saml2p:LogoutRequest>

to which the Keycloak IDP responds with:

<HTML>
  <HEAD>
    <TITLE>SAML HTTP Post Binding</TITLE>
  </HEAD>
  <BODY Onload="document.forms[0].submit()">
    <FORM METHOD="POST" ACTION="http://localhost:8080/saml/logout">
      <INPUT TYPE="HIDDEN" NAME="SAMLResponse" VALUE="PHNhbWxwOkxvZ291d... Base64 encoded LogoutResponse"/>
      <NOSCRIPT>
        <P>JavaScript is disabled. We strongly recommend to enable it. Click the button below to continue.</P>
        <INPUT TYPE="SUBMIT" VALUE="CONTINUE"/>
       </NOSCRIPT>
     </FORM>
  </BODY>
</HTML>

…which contains the SAML LogoutResponse:

<samlp:LogoutResponse Destination="http://localhost:8080/saml/logout"
    ID="ID_c413b65d-02fe-4620-85bc-b6607ccfa90a" InResponseTo="a270a944ih90jb024di4j3cfddd98e5"
    IssueInstant="2019-02-28T20:01:24.735Z" Version="2.0"
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://localhost:8081/auth/realms/demo</saml:Issuer>
    <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
        <dsig:SignedInfo><dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><dsig:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <dsig:Reference URI="#ID_c413b65d-02fe-4620-85bc-b6607ccfa90a">
                <dsig:Transforms><dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                <dsig:DigestValue>ZDg030QoeKzEkLUrhCKC1uBIaIDc/ucdnaCXSWEYH0I=</dsig:DigestValue>
            </dsig:Reference>
        </dsig:SignedInfo>
        <dsig:SignatureValue>pnNC4Xh+XdBDdW6YQj+ZgmxgETYOOvrEfuAZsP/xTQXoTTksu+RGWSnIhNU/QFaDXCGRosfGyLWh6t7SFxUgkQ95E0VVGC7MKCsQ9cCg5sdXzxRzcPpRodPrkIp02DWv4PiMmjzLoxHKhTsLgII9JCuFTEay2U1L41/U5IiweHdYbavG946Vo7bshNOIQ9FtIZUBGh4OyQXwPJKE1G19w8bu5sGnXRnBlrfBiZYG6NuPV7zyLlhmunx4ZUBAFT0vOq4gDPe9UocOQRe3dFKFEj33DHOIv9x+wFt/VQwFbrxTkRePNp916p8+UXFjs5KM3mlOhjnqZq3dH1eYq49G3A==</dsig:SignatureValue>
        <dsig:KeyInfo>
            <dsig:KeyName>PrmJE0uxLVfFemeO41pwrZ8P3Pxmi8q44V4553olejE</dsig:KeyName>
            <dsig:X509Data>
                <dsig:X509Certificate>MIIClzCCAX8CBgFo2/zejjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARkZW1vMB4XDTE5MDIxMTA5NTUwOFoXDTI5MDIxMTA5NTY0OFowDzENMAsGA1UEAwwEZGVtbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANGej7NgaqGe762Z5g2dch/Pr6G2q3fZlN8aUfU1+lzBrgL/kwRrsCr0zeQ4EcXWpfV5ayMl+0Ouc+Q8VMObVr+8+Iq2b6NUaOMR+GiOc3vCcEEtB3zfNVqE3FFeAI6vTDA4u45M0NKUkn1dMtITQj2K2Mmz/pjwmGCo1jh9MS3loZU07om8UjHNrrg/4Tct97EONnTdYgHNetNRS3xsXdzJc64KtovA+Muk93XMhQe1MR8iIdkSX1kIuJg0Ka9Y996dKstDB8nzTUlEQs/vw4iSu6IKu+cOvdrs+HFyvCVUWmqVpqh/AL+MgJxtRcfj7tPWESSe+bukwcz+icogEAUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAult+p9pECxU32gKFaMCUt0bDFsDU00nM3hPpRUijJchJe68NvXn9Pv2DwbIPpSQpYJAsG3xoK36h/S7oTF3SosnZVtrHXhzN+aNWKgoDGcR8d4WtT6kKphI8Mf123qyPPC+5v7CQxDOW6wXd+0XQFRIfHSfyH0gxRsnFoYiapnAgOVftozMCm2F2ZZQmhPtxaigQ6rhVWIDbemhKlwEV49H83Qkh9c/jfngVdYB1yA/MfSsossk6u8w47egSt73FXVAHginX4obHp+HEOOU7C8myOIyKq74nPvesvmffIv7ttgvLoEhdK/S3p7AiHppxgWb1roD/7P1Tk21eqOBW3Q==</dsig:X509Certificate>
            </dsig:X509Data>
            <dsig:KeyValue>
                <dsig:RSAKeyValue>
                    <dsig:Modulus>0Z6Ps2BqoZ7vrZnmDZ1yH8+vobard9mU3xpR9TX6XMGuAv+TBGuwKvTN5DgRxdal9XlrIyX7Q65z5DxUw5tWv7z4irZvo1Ro4xH4aI5ze8JwQS0HfN81WoTcUV4Ajq9MMDi7jkzQ0pSSfV0y0hNCPYrYybP+mPCYYKjWOH0xLeWhlTTuibxSMc2uuD/hNy33sQ42dN1iAc1601FLfGxd3Mlzrgq2i8D4y6T3dcyFB7UxHyIh2RJfWQi4mDQpr1j33p0qy0MHyfNNSURCz+/DiJK7ogq75w692uz4cXK8JVRaapWmqH8Av4yAnG1Fx+Pu09YRJJ75u6TBzP6JyiAQBQ==</dsig:Modulus>
                    <dsig:Exponent>AQAB</dsig:Exponent>
                </dsig:RSAKeyValue>
            </dsig:KeyValue>
        </dsig:KeyInfo>
    </dsig:Signature>
    <samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status>
</samlp:LogoutResponse>

…which is then finally posted to the http://localhost:8080/saml/logout endpoint of the Spring Boot app to conclude the logout process. The Spring Boot app then sends a redirect back to the base URL where the user can log in again.

Enabling encryption of SAML assertions

Wow, that was already quite a lot to ingest, right? But we missed one important thing, encryption!
Let’s quickly configure encryption support in the Keycloak client and see how it affects the SAML messages. To enable encryption for our SAML client, we need to adjust the client configuration.

In the client settings tab, configure the following:

  • Encrypt Assertions: On

SAML Client Configuration with Enabled Encryption

In the SAML Keys tab, configure in the Encryption Key section

  • Click on import
  • Archive Format JKS
  • Key-Alias apollo
  • Store pass nalle123
  • Select configure the path to src/main/resources/saml/samlKeystore.jks
  • Click Import

Client Configuration SAML Keys

Your client is now properly configured to use encryption. Let’s have a look at the SAML Response messages with the SAML Chrome Panel.
After another login, we can see that our SAML response looks different now:

<samlp:Response Destination="http://localhost:8080/saml/SSO"
    ID="ID_8d649c98-460c-4b98-82e5-90f2c11981c5" InResponseTo="a9e038agg66a512eh5h2141731e97"
    IssueInstant="2019-02-28T20:42:13.260Z" Version="2.0"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml:Issuer>http://localhost:8081/auth/realms/demo</saml:Issuer>
    <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
        <dsig:SignedInfo><dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><dsig:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <dsig:Reference URI="#ID_8d649c98-460c-4b98-82e5-90f2c11981c5">
                <dsig:Transforms><dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                <dsig:DigestValue>CHBO9/ggJS0Cc4zphZK5a4CWYg8gqW3Um6S9P8xB4zA=</dsig:DigestValue>
            </dsig:Reference>
        </dsig:SignedInfo>
        <dsig:SignatureValue>MxIerokHeAVEv1Ag9HmIl0F8ZtKbDOVz1mUCiLGe3xGWUksUyOuvcLZFdtfx+o/TgQhnuRB0lSbUxUk642hqHcC3RvXqITbzENZ0ZyjTwxFJGF6mzZ6YOEIStApZJB8z2YvhvhcWU1eH1F1vE78w/78EgSEytkkfoAcC9ESdYpsK82iQn0/d9FxPdF7u7jkxALoh3I4MNuAqtrWL4Q4U8OqeO3Xjyr11g6gSlyiW9GlEflqKR7hTb50W2rVFS9JdB6iWTVJHrLyuiFYYLZv0kBUucM40+27QQ1eK82VCyBOJMNMNnbty6jkmKPRrqWICkkgSiKzmJ1JzyG3FV+DveA==</dsig:SignatureValue>
        <dsig:KeyInfo>
            <dsig:KeyName>PrmJE0uxLVfFemeO41pwrZ8P3Pxmi8q44V4553olejE</dsig:KeyName>
            <dsig:X509Data>
                <dsig:X509Certificate>MIIClzCCAX8CBgFo2/zejjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARkZW1vMB4XDTE5MDIxMTA5NTUwOFoXDTI5MDIxMTA5NTY0OFowDzENMAsGA1UEAwwEZGVtbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANGej7NgaqGe762Z5g2dch/Pr6G2q3fZlN8aUfU1+lzBrgL/kwRrsCr0zeQ4EcXWpfV5ayMl+0Ouc+Q8VMObVr+8+Iq2b6NUaOMR+GiOc3vCcEEtB3zfNVqE3FFeAI6vTDA4u45M0NKUkn1dMtITQj2K2Mmz/pjwmGCo1jh9MS3loZU07om8UjHNrrg/4Tct97EONnTdYgHNetNRS3xsXdzJc64KtovA+Muk93XMhQe1MR8iIdkSX1kIuJg0Ka9Y996dKstDB8nzTUlEQs/vw4iSu6IKu+cOvdrs+HFyvCVUWmqVpqh/AL+MgJxtRcfj7tPWESSe+bukwcz+icogEAUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAult+p9pECxU32gKFaMCUt0bDFsDU00nM3hPpRUijJchJe68NvXn9Pv2DwbIPpSQpYJAsG3xoK36h/S7oTF3SosnZVtrHXhzN+aNWKgoDGcR8d4WtT6kKphI8Mf123qyPPC+5v7CQxDOW6wXd+0XQFRIfHSfyH0gxRsnFoYiapnAgOVftozMCm2F2ZZQmhPtxaigQ6rhVWIDbemhKlwEV49H83Qkh9c/jfngVdYB1yA/MfSsossk6u8w47egSt73FXVAHginX4obHp+HEOOU7C8myOIyKq74nPvesvmffIv7ttgvLoEhdK/S3p7AiHppxgWb1roD/7P1Tk21eqOBW3Q==</dsig:X509Certificate>
            </dsig:X509Data>
            <dsig:KeyValue>
                <dsig:RSAKeyValue>
                    <dsig:Modulus>0Z6Ps2BqoZ7vrZnmDZ1yH8+vobard9mU3xpR9TX6XMGuAv+TBGuwKvTN5DgRxdal9XlrIyX7Q65z5DxUw5tWv7z4irZvo1Ro4xH4aI5ze8JwQS0HfN81WoTcUV4Ajq9MMDi7jkzQ0pSSfV0y0hNCPYrYybP+mPCYYKjWOH0xLeWhlTTuibxSMc2uuD/hNy33sQ42dN1iAc1601FLfGxd3Mlzrgq2i8D4y6T3dcyFB7UxHyIh2RJfWQi4mDQpr1j33p0qy0MHyfNNSURCz+/DiJK7ogq75w692uz4cXK8JVRaapWmqH8Av4yAnG1Fx+Pu09YRJJ75u6TBzP6JyiAQBQ==</dsig:Modulus>
                    <dsig:Exponent>AQAB</dsig:Exponent>
                </dsig:RSAKeyValue>
            </dsig:KeyValue>
        </dsig:KeyInfo>
    </dsig:Signature>
    <samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status>
    <saml:EncryptedAssertion>
        <xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
            xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <xenc:EncryptedKey><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
                    <xenc:CipherData>
                        <xenc:CipherValue>QE3rdGu27xzELvm9qaPUHJY+gdD4lflVps8FRkEsJUYcpK24djhM56CJGFF66DMGDtZBrXtcPgRRnm2feNMVhx9AYi+r6iS6rS8NXst/c1qcFCNE80oW4w1AtxZ/Pz9MGT/Jlor2V973RZMBrvF4suqBj00xN93KWlxLhb+d99zfiLXok/QYhFqitmJnODBaqta5dwJClbbGy2ZrjyN/oYHQw+n/Qu46tIOogxb2l7Mqk298oJrR88e2gk0rEZvfkH6MPQ2ySWCCOmGJUCE6Wf/rO0f1RfGWmXiwwYbZLvBIltnt424wDUc+9oH9ivVLHDOYjpL4NGlOV64sH19bkQ==</xenc:CipherValue>
                    </xenc:CipherData>
                </xenc:EncryptedKey>
            </ds:KeyInfo>
            <xenc:CipherData>
                <xenc:CipherValue>a7KxLQXevbgy5tHOXQF7xjDUSd9x0EO276NokLlfQgSio3KZFjU+BzeNMnz6w4sYjUyHgzJ/42P.... Base64 encoded cipher value</xenc:CipherValue>
            </xenc:CipherData>
        </xenc:EncryptedData>
    </saml:EncryptedAssertion>
</samlp:Response>

Instead of an saml:Assertion element we now see saml:EncryptedAssertion which contains the data from our previous assertion in encrypted form.

Besides the various browser extensions, there is also a useful Burp extension called SAMLRaider, which can be used to inspect and manipulate SAML messages.

This concludes our quick tour of SAML interactions with our example application. I hope you enjoyed the ride and learned something new.
Hope to see you next time. ๐Ÿ™‚

Thomas Darimont

Thomas Darimont is a Fellow at codecentric AG in Mรผnster/Germany, where he helps customers implement centralized identity management platforms.
Previously, he worked as a Principal Software Engineer in the Spring Data team at Pivotal. He has over 15 years of experience in the development of Java- and .NET-based enterprise applications and open source projects.
His working focus is centered around software architecture, the Spring ecosystem, performance tuning, and security. In his spare time, he loves organizing community meetups and contributing to open source projects like Keycloak, Spring, and Cloud Foundry.

Comment

Your email address will not be published. Required fields are marked *