[java-oidc-common] branch main updated: JCOMOIDC-51 - Support OIDC logout URIs in SAML metadata

Henri Mikkonen henri.mikkonen at iki.fi
Fri Nov 4 08:29:59 UTC 2022


This is an automated email from the git hooks/post-receive script.

hjmikkon pushed a commit to branch main
in repository java-oidc-common.

View the commit online:
http://git.shibboleth.net/view/?p=java-oidc-common.git;a=commit;h=2dfe3ebe5f6a0f2ab208f23f38dfda88fa36cd34

The following commit(s) were added to refs/heads/main by this push:
     new 2dfe3eb  JCOMOIDC-51 - Support OIDC logout URIs in SAML metadata
2dfe3eb is described below

commit 2dfe3ebe5f6a0f2ab208f23f38dfda88fa36cd34
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri Nov 4 10:26:28 2022 +0200

    JCOMOIDC-51 - Support OIDC logout URIs in SAML metadata
    
    https://shibboleth.atlassian.net/browse/JCOMOIDC-51
    
    Add support for setting front-/back-channel logout URIs via
    <SingleLogoutService> -elements. The binding refers to the corresponding
    specification:
    
    - https://openid.net/specs/openid-connect-frontchannel-1_0.html
    - https://openid.net/specs/openid-connect-backchannel-1_0.html
    
    OAuthRPExtensions now supports two new attributes (flags):
    - frontchannel_logout_session_required
    - backchannel_logout_session_required
---
 .../impl/ClientInformationNodeProcessor.java       |  47 +++++++
 .../impl/ClientInformationNodeProcessorTest.java   |  30 ++++-
 .../impl/EntitiesDescriptor-with-oidcmd-logout.xml | 136 +++++++++++++++++++++
 .../oidc/saml/xmlobject/OAuthRPExtensions.java     |  46 ++++++-
 .../resources/schema/saml-metadata-ext-oidcmd.xsd  |   2 +
 .../saml/xmlobject/impl/OAuthRPExtensionsImpl.java |  25 ++++
 .../impl/OAuthRPExtensionsMarshaller.java          |  10 ++
 .../impl/OAuthRPExtensionsUnmarshaller.java        |   8 ++
 .../saml/xmlobject/impl/OAuthRPExtensionsTest.java |   6 +
 .../oidc/saml/xmlobject/impl/OAuthRPExtensions.xml |   4 +-
 .../xmlobject/impl/OAuthRPExtensions_ordered.xml   |   4 +-
 11 files changed, 314 insertions(+), 4 deletions(-)

diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessor.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessor.java
index 9a55c2d..462dd34 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessor.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessor.java
@@ -42,6 +42,7 @@ import org.opensaml.saml.saml2.metadata.Extensions;
 import org.opensaml.saml.saml2.metadata.NameIDFormat;
 import org.opensaml.saml.saml2.metadata.RoleDescriptor;
 import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml.saml2.metadata.SingleLogoutService;
 import org.opensaml.saml.security.impl.MetadataCredentialResolver;
 import org.opensaml.security.credential.Credential;
 import org.opensaml.xmlsec.keyinfo.KeyInfoCredentialResolver;
@@ -92,6 +93,14 @@ public class ClientInformationNodeProcessor implements MetadataNodeProcessor {
     /** The ACS binding identifier matching to the redirect_uri. */
     public static final String BINDING_ID_REDIRECT_URI = "https://tools.ietf.org/html/rfc6749#section-3.1.2";
     
+    /** The SLO binding identifier matching to the front-channel uri. */
+    public static final String BINDING_ID_FRONT_SLO_URI =
+            "https://openid.net/specs/openid-connect-frontchannel-1_0.html";
+
+    /** The SLO binding identifier matching to the back-channel uri. */
+    public static final String BINDING_ID_BACK_SLO_URI =
+            "https://openid.net/specs/openid-connect-backchannel-1_0.html";
+
     /** Class logger. */
     private final Logger log = LoggerFactory.getLogger(ClientInformationNodeProcessor.class);
     
@@ -217,6 +226,22 @@ public class ClientInformationNodeProcessor implements MetadataNodeProcessor {
                 metadata.setJWKSet(parseJwkSet(credentials, clientId));
             }
             metadata.setCustomField("audience", parseAudiences(extensions));
+            final Set<URI> backChannelLogoutUris = parseLogoutUris(roleDescriptor, BINDING_ID_BACK_SLO_URI);
+            if (!backChannelLogoutUris.isEmpty()) {
+                if (backChannelLogoutUris.size() > 1) {
+                    log.warn("More than one back-channel logout URI defined, picking up only one.");
+                }
+                metadata.setBackChannelLogoutURI(backChannelLogoutUris.iterator().next());
+                metadata.requiresBackChannelLogoutSession(extensions.isBackChannelLogoutSessionRequired());
+            }
+            final Set<URI> frontChannelLogoutUris = parseLogoutUris(roleDescriptor, BINDING_ID_FRONT_SLO_URI);
+            if (!frontChannelLogoutUris.isEmpty()) {
+                if (frontChannelLogoutUris.size() > 1) {
+                    log.warn("More than one front-channel logout URI defined, picking up only one.");
+                }
+                metadata.setFrontChannelLogoutURI(frontChannelLogoutUris.iterator().next());
+                metadata.requiresFrontChannelLogoutSession(extensions.isFrontChannelLogoutSessionRequired());
+            }
         } else {
             log.debug("No {} found to be processed", OAuthRPExtensions.TYPE_LOCAL_NAME);
         }
@@ -546,6 +571,28 @@ public class ClientInformationNodeProcessor implements MetadataNodeProcessor {
         return auds.isEmpty() ? null : auds;
     }
     
+    /**
+     * Parse the single logout URIs from the given role descriptor. Only the single logout service URLs whose binding
+     * matches to the one given in the parameters are taken into consideration.
+     * 
+     * @param roleDescriptor The role descriptor to parse from.
+     * @param binding The binding to look after.
+     * @return The set of single logout URIs that were successfully parsed.
+     */
+    @Nonnull protected Set<URI> parseLogoutUris(@Nonnull final SPSSODescriptor roleDescriptor,
+            @Nonnull final String binding) {
+        final Set<URI> uris = new HashSet<>();
+        for (final SingleLogoutService slo : roleDescriptor.getSingleLogoutServices()) {
+            if (binding.equals(slo.getBinding())) {
+                final URI uri = getSingleURIValue(slo.getLocation());
+                if (uri != null) {
+                    uris.add(uri);
+                }
+            }
+        }
+        return uris;
+    }
+
     /**
      * Parse an XML value list from a metadata value object into a collection of strings.
      * 
diff --git a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessorTest.java b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessorTest.java
index bdd0a51..a983f9d 100644
--- a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessorTest.java
+++ b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessorTest.java
@@ -143,7 +143,19 @@ public class ClientInformationNodeProcessorTest extends XMLObjectBaseTestCase {
         validate(role, true);
     }
 
+    @Test
+    public void testParsedXMLMetadataWithLogoutURIs() throws Exception {
+        final RoleDescriptor role =
+                parseRoleDescriptor("/net/shibboleth/oidc/metadata/impl/EntitiesDescriptor-with-oidcmd-logout.xml");
+        validate(role, false, "https://example.org/slo-back", "https://example.org/slo-front");
+    }
+
     private void validate(final RoleDescriptor role, final boolean jwkdata) throws Exception {
+        validate(role, jwkdata, null, null);
+    }
+
+    private void validate(final RoleDescriptor role, final boolean jwkdata, final String backChannelLogout,
+            final String frontChannelLogout) throws Exception {
         Assert.assertNotNull(role);
         Assert.assertTrue(role instanceof SPSSODescriptor);
         final SPSSODescriptor sp = (SPSSODescriptor) role;
@@ -218,7 +230,23 @@ public class ClientInformationNodeProcessorTest extends XMLObjectBaseTestCase {
             Assert.assertNull(metadata.getJWKSet());
             Assert.assertEquals(metadata.getJWKSetURI(), new URI("https://example.org/jwks"));
         }
-        
+
+        if (backChannelLogout != null) {
+            Assert.assertEquals(metadata.getBackChannelLogoutURI(), new URI(backChannelLogout));
+            Assert.assertTrue(metadata.requiresBackChannelLogoutSession());
+        } else {
+            Assert.assertNull(metadata.getBackChannelLogoutURI());
+            Assert.assertFalse(metadata.requiresBackChannelLogoutSession());
+        }
+
+        if (frontChannelLogout != null) {
+            Assert.assertEquals(metadata.getFrontChannelLogoutURI(), new URI(frontChannelLogout));
+            Assert.assertTrue(metadata.requiresFrontChannelLogoutSession());
+        } else {
+            Assert.assertNull(metadata.getFrontChannelLogoutURI());
+            Assert.assertFalse(metadata.requiresFrontChannelLogoutSession());
+        }
+
         final Set<URI> redirectUris = metadata.getRedirectionURIs();
         Assert.assertEquals(redirectUris.size(), 2);
         Assert.assertTrue(redirectUris.contains(new URI("https://example.org/cb")));
diff --git a/oidc-common-metadata-impl/src/test/resources/net/shibboleth/oidc/metadata/impl/EntitiesDescriptor-with-oidcmd-logout.xml b/oidc-common-metadata-impl/src/test/resources/net/shibboleth/oidc/metadata/impl/EntitiesDescriptor-with-oidcmd-logout.xml
new file mode 100644
index 0000000..f626fa4
--- /dev/null
+++ b/oidc-common-metadata-impl/src/test/resources/net/shibboleth/oidc/metadata/impl/EntitiesDescriptor-with-oidcmd-logout.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<md:EntitiesDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" Name="RP test">
+
+    <md:EntityDescriptor entityID="mockSamlClientId">
+
+        <md:SPSSODescriptor xmlns:oidcmd="urn:mace:shibboleth:metadata:oidc:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" protocolSupportEnumeration="http://openid.net/specs/openid-connect-core-1_0.html">
+            <md:Extensions>
+                <oidcmd:OAuthRPExtensions
+                    application_type="web"
+                    client_uri="https://example.org/clientUri"
+                    grant_types="authorization_code"
+                    response_types="code code+id_token id_token+token id_token"
+                    scopes="openid profile"
+                    initiate_login_uri="https://example.org/initiateLogin"
+                    software_id="mockSoftwareId"
+                    software_version="mockSoftwareVersion"
+                    token_endpoint_auth_method="client_secret_basic"
+                    sector_identifier_uri="https://example.org/sectorIdentifier"
+                    id_token_signed_response_alg="RS512"
+                    id_token_encrypted_response_alg="A256KW"
+                    id_token_encrypted_response_enc="A256GCM"
+                    userinfo_signed_response_alg="RS384"
+                    userinfo_encrypted_response_alg="A192KW"
+                    userinfo_encrypted_response_enc="A192GCM"
+                    request_object_signing_alg="RS256"
+                    request_object_encryption_alg="A128KW"
+                    request_object_encryption_enc="A128GCM"
+                    token_endpoint_auth_signing_alg="RS512"
+                    frontchannel_logout_session_required="true"
+                    backchannel_logout_session_required="true" >
+                    <oidcmd:default_acr_value>password</oidcmd:default_acr_value>
+                    <oidcmd:default_acr_value>mfa</oidcmd:default_acr_value>
+                    <oidcmd:request_uri>https://example.org/request</oidcmd:request_uri>
+                    <oidcmd:post_logout_redirect_uri>https://example.org/postLogout</oidcmd:post_logout_redirect_uri>
+                </oidcmd:OAuthRPExtensions>
+            </md:Extensions>
+
+            <md:KeyDescriptor use="signing">
+                <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    <ds:KeyName>mockX509RSA</ds:KeyName>
+                    <ds:X509Data>
+                        <ds:X509Certificate>
+                            MIIEQDCCAqigAwIBAgIVAIarXvdvyS47KJR7U40FlTufyD8vMA0GCSqGSIb3DQEB
+                            CwUAMCAxHjAcBgNVBAMMFWxvY2FsaG9zdC5sb2NhbGRvbWFpbjAeFw0xOTA2MTcx
+                            MTI5MTJaFw0zOTA2MTcxMTI5MTJaMCAxHjAcBgNVBAMMFWxvY2FsaG9zdC5sb2Nh
+                            bGRvbWFpbjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALXysGFnoBFh
+                            oasd5uMecp9OTBjvztntPUVmHfm4R3AcItEMEZEN/pETcX/wgKdo4qCBq4PrZITa
+                            T8Salgl0XL6qF1Wia3JNA7Hh/OaoQEUsbsHgsjLMKt6MJh8vIaE1o8loL7Ay4WmZ
+                            Cr3wc8ZS6CpMsv+qbxkyfl1h7MTydETnQhg/X83bj+BjJSh7QeFU0d0SWK1dN2/D
+                            nFoGOfuTfVqeDRIwMxKlR5G//8N202sLaG28NljaHhLn3jHXeiGpCQ+Q2X90dkFb
+                            EKb6sQ6SlDUAzm9MwLYjglDyOhXpUqOnvD67nggLb4Gn/4k+g5wtdfr7unOJYcHK
+                            w7JGnI8Gd0lJMd6B3SpkhUOWgKv/D6HIBArhqSEmXuTyy8FewyYuo1XkIw/Lu3bB
+                            9qoBojM1tygoGlKi7R7e719J+DSkhyGbMyQ59leoN97iGGgqjUWS5mew8zSNviyz
+                            4uGqvxmLWU9UTH1YhlARsBF1bMiMnwLz7dF74AaAkC4pN3BYzDMyHQIDAQABo3Ew
+                            bzAdBgNVHQ4EFgQUwKUd9D1Qymu2oBEVTscrAhP+sIUwTgYDVR0RBEcwRYIVbG9j
+                            YWxob3N0LmxvY2FsZG9tYWluhixodHRwczovL2xvY2FsaG9zdC5sb2NhbGRvbWFp
+                            bi9pZHAvc2hpYmJvbGV0aDANBgkqhkiG9w0BAQsFAAOCAYEAEYqh54a+j5OuR1UB
+                            /AT9k2xXVwHiqQXAC/2un8O5BWAOeOq9+0gLJO5yaJp5c9GjPXRJmnDfGP9HFF6R
+                            CjngtRCm1gV/fpj97IRQS5oroaeTWPQ9ZD5+ogs5DNt6UZeJ2GqpfA5mOytNg3cM
+                            OP1B5QnA1apOaG4FHTegJR7WOIXkkAjEJUy6R+5Q6At7DdK/SRrP5onVPFv2HgGF
+                            E9v9iX/uQepDizS5F2oi6LZCl1/b38gxA8BFL7VZu53JQguaA7SrnP+dBOErT/yh
+                            Qcx3e9wE2ms8H1qISIdl3e7gvLi5jEyDWC9Agde6EjjvVVJAF7jR0puQ39mBfoxP
+                            moVdHJQmCt3V7Ew9tYZUpG3rjp4YNXOiM+QhtwhHWT94q9uJKUQ6JvbxgLNDs5KM
+                            3PENx2C60TPFne9nRRIMVDavU4wwY7GdCgeo8PiZ5zxI0ZCkxh38ODePtKQrxJ7i
+                            E0J1BE2LIxa1T7KY0XKpsH0iI2dNfZfNpNp4v/HiDb4svYgq</ds:X509Certificate>
+                    </ds:X509Data>
+                </ds:KeyInfo>
+            </md:KeyDescriptor>
+            <md:KeyDescriptor use="signing">
+                <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    <ds:KeyName>mockX509EC</ds:KeyName>
+                    <ds:X509Data>
+                        <ds:X509Certificate>
+                            MIIBKDCBzgIJAOYlspXlaqguMAoGCCqGSM49BAMCMBwxCzAJBgNVBAYTAkZJMQ0w
+                            CwYDVQQDDAR0ZXN0MB4XDTE5MTEwMTA4Mjg0OVoXDTIwMTAzMTA4Mjg0OVowHDEL
+                            MAkGA1UEBhMCRkkxDTALBgNVBAMMBHRlc3QwWTATBgcqhkjOPQIBBggqhkjOPQMB
+                            BwNCAARCUOlFMtRj3MIbdCzXmoGz4giDwjzPoX4AxMehhlXmPOodQhLDdvDqx3KE
+                            hqadzIIsKHRQPDycscpHWpPbaQ2VMAoGCCqGSM49BAMCA0kAMEYCIQCVykSuUjlX
+                            j4lxI6YqgYVuuhL2rG4hIrXw/pCey7eF2gIhAOSSaS025lQWy09W4NlnO28OkHoI
+                            +Hbap7+DQlhbbr2d</ds:X509Certificate>
+                    </ds:X509Data>
+                </ds:KeyInfo>
+            </md:KeyDescriptor>
+            <md:KeyDescriptor use="signing">
+                <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    <ds:KeyName>mockRSA</ds:KeyName>
+                    <ds:KeyValue>
+                        <ds:RSAKeyValue>
+                            <ds:Modulus>
+                                AMP1p7GwPH64UPvBKD4DK0I6SDY7dtFPzL7L5qAIEJwIBBeDmLfVY/f9mLzDuDb19XzQxc6GEcjj
+                                K8qRe7JAD3CE1IXXD0hKSOJ7H+chWS84iv7UNukbHHBO1oaRgfHh7vbX7HnpYMoqKK75rfiQqD9e
+                                XOa2FLiH1QvnhLGKJcN+OKujetTgAhxE7ski9Gtfhhbt1qCEl7XtaUCLLexyrwWxx+NRxFgMU+nt
+                                IZQ+T8ii+JQSWnRh14PGc+K9o1dp+vjse62hFprVQhhcbAKAkWpbup77NvvuTZ2+AtUhOuNHrH2I
+                                X3jHeSWH7EzTGkPLGS6bFnYJQBqWv0POytfSyMM=</ds:Modulus>
+                            <ds:Exponent>AQAB</ds:Exponent>
+                        </ds:RSAKeyValue>
+                    </ds:KeyValue>
+                </ds:KeyInfo>
+            </md:KeyDescriptor>
+            <md:KeyDescriptor>
+                <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    <ds:KeyName>mockJwksUri</ds:KeyName>
+                    <oidcmd:JwksUri>https://example.org/jwks</oidcmd:JwksUri>
+                </ds:KeyInfo>
+            </md:KeyDescriptor>
+            <md:KeyDescriptor>
+                <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    <ds:KeyName>mockClientSecret</ds:KeyName>
+                    <oidcmd:ClientSecret>mockClientSecretValue</oidcmd:ClientSecret>
+                </ds:KeyInfo>
+            </md:KeyDescriptor>
+            <md:SingleLogoutService
+                    Binding="https://openid.net/specs/openid-connect-frontchannel-1_0.html"
+                    Location="https://example.org/slo-front"/>
+            <md:SingleLogoutService
+                    Binding="https://openid.net/specs/openid-connect-backchannel-1_0.html"
+                    Location="https://example.org/slo-back"/>
+            <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
+            <md:NameIDFormat>urn:mace:shibboleth:metadata:oidc:1.0:nameid-format:pairwise</md:NameIDFormat>
+            <md:AssertionConsumerService
+                    Binding="https://tools.ietf.org/html/rfc6749#section-3.1.2"
+                    Location="https://example.org/cb"
+                    index="1"/>
+            <md:AssertionConsumerService
+                    Binding="https://tools.ietf.org/html/rfc6749#section-3.1.2"
+                    Location="https://example.org/cb2"
+                    index="2"/>
+            <md:AssertionConsumerService
+                    Binding="http://example.org/not/supported/profile/id"
+                    Location="https://example.org/cb3"
+                    index="3"/>
+        </md:SPSSODescriptor>
+
+    </md:EntityDescriptor>
+
+</md:EntitiesDescriptor>
\ No newline at end of file
diff --git a/oidc-common-saml-api/src/main/java/net/shibboleth/oidc/saml/xmlobject/OAuthRPExtensions.java b/oidc-common-saml-api/src/main/java/net/shibboleth/oidc/saml/xmlobject/OAuthRPExtensions.java
index eff9478..31bbb46 100644
--- a/oidc-common-saml-api/src/main/java/net/shibboleth/oidc/saml/xmlobject/OAuthRPExtensions.java
+++ b/oidc-common-saml-api/src/main/java/net/shibboleth/oidc/saml/xmlobject/OAuthRPExtensions.java
@@ -117,6 +117,14 @@ public interface OAuthRPExtensions extends SAMLObject, AttributeExtensibleXMLObj
     /** Attribute local name. */
     @Nonnull @NotEmpty public static final String REQUIRE_AUTH_TIME_ATTRIB_NAME = "require_auth_time";
     
+    /** Attribute local name. */
+    @Nonnull @NotEmpty public static final String BACK_CHANNEL_LOGOUT_SESSION_REQUIRED_ATTRIB_NAME =
+            "backchannel_logout_session_required";
+
+    /** Attribute local name. */
+    @Nonnull @NotEmpty public static final String FRONT_CHANNEL_LOGOUT_SESSION_REQUIRED_ATTRIB_NAME =
+            "frontchannel_logout_session_required";
+
     /**
      * Get the token endpoint authentication method.
      * 
@@ -417,7 +425,7 @@ public interface OAuthRPExtensions extends SAMLObject, AttributeExtensibleXMLObj
      * @return The flag to require authentication time.
      */
     public boolean isRequireAuthTime();
-    
+
     /**
      * Set the flag to require authentication time.
      * 
@@ -425,6 +433,42 @@ public interface OAuthRPExtensions extends SAMLObject, AttributeExtensibleXMLObj
      */
     public void setRequireAuthTime(final boolean flag);
 
+    /**
+     * Set the flag to require session id in back-channel logout request.
+     * 
+     * @param flag The flag to require session id in back-channel logout request.
+     * 
+     * @since 2.2.0
+     */
+    public void setBackChannelLogoutSessionRequired(final boolean flag);
+
+    /**
+     * Get the flag to require session id in back-channel logout request.
+     * 
+     * @return The flag to require session id in back-channel logout request.
+     * 
+     * @since 2.2.0
+     */
+    public boolean isBackChannelLogoutSessionRequired();
+
+    /**
+     * Set the flag to require session id in front-channel logout request.
+     * 
+     * @param flag The flag to require session id in front-channel logout request.
+     * 
+     * @since 2.2.0
+     */
+    public void setFrontChannelLogoutSessionRequired(final boolean flag);
+
+    /**
+     * Get the flag to require session id in front-channel logout request.
+     * 
+     * @return The flag to require session id in front-channel logout request.
+     * 
+     * @since 2.2.0
+     */
+    public boolean isFrontChannelLogoutSessionRequired();
+
     /**
      * Get the list of default ACR values.
      * 
diff --git a/oidc-common-saml-api/src/main/resources/schema/saml-metadata-ext-oidcmd.xsd b/oidc-common-saml-api/src/main/resources/schema/saml-metadata-ext-oidcmd.xsd
index ff61873..cee0093 100644
--- a/oidc-common-saml-api/src/main/resources/schema/saml-metadata-ext-oidcmd.xsd
+++ b/oidc-common-saml-api/src/main/resources/schema/saml-metadata-ext-oidcmd.xsd
@@ -57,6 +57,8 @@
             <attribute name="initiate_login_uri" type="oidcmd:anyURI" />
             <attribute name="default_max_age" type="int" />
             <attribute name="require_auth_time" type="boolean" />
+            <attribute name="frontchannel_logout_session_required" type="boolean" />
+            <attribute name="backchannel_logout_session_required" type="boolean" />
             <anyAttribute namespace="##other" processContents="lax" />
         </complexType>
     </element>
diff --git a/oidc-common-saml-impl/src/main/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsImpl.java b/oidc-common-saml-impl/src/main/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsImpl.java
index 4025de9..3c3f3f6 100644
--- a/oidc-common-saml-impl/src/main/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsImpl.java
+++ b/oidc-common-saml-impl/src/main/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsImpl.java
@@ -105,6 +105,12 @@ public class OAuthRPExtensionsImpl extends AbstractXMLObject implements OAuthRPE
     /** Require auth time flag for this entity. */
     private boolean requireAuthTime;
     
+    /** Require back-channel logout session id flag for this entity. */
+    private boolean backChannelLogoutSessionRequired;
+
+    /** Require front-channel logout session id flag for this entity. */
+    private boolean frontChannelLogoutSessionRequired;
+
     /** Default ACR values for this entity. */
     private final XMLObjectChildrenList<DefaultAcrValue> defaultAcrValues;
         
@@ -404,4 +410,23 @@ public class OAuthRPExtensionsImpl extends AbstractXMLObject implements OAuthRPE
         return (List<XMLObject>) unknownChildren.subList(typeOrName);
     }
 
+    /** {@inheritDoc} */
+    public void setBackChannelLogoutSessionRequired(boolean flag) {
+        backChannelLogoutSessionRequired = flag;
+    }
+
+    /** {@inheritDoc} */
+    public boolean isBackChannelLogoutSessionRequired() {
+        return backChannelLogoutSessionRequired;
+    }
+
+    /** {@inheritDoc} */
+    public void setFrontChannelLogoutSessionRequired(boolean flag) {
+        frontChannelLogoutSessionRequired = flag;
+    }
+
+    /** {@inheritDoc} */
+    public boolean isFrontChannelLogoutSessionRequired() {
+        return frontChannelLogoutSessionRequired;
+    }
 }
diff --git a/oidc-common-saml-impl/src/main/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsMarshaller.java b/oidc-common-saml-impl/src/main/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsMarshaller.java
index 58c1a3c..b8aee15 100644
--- a/oidc-common-saml-impl/src/main/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsMarshaller.java
+++ b/oidc-common-saml-impl/src/main/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsMarshaller.java
@@ -146,6 +146,16 @@ public class OAuthRPExtensionsMarshaller extends AbstractSAMLObjectMarshaller {
                     Boolean.toString(rpExtensions.isRequireAuthTime()));
         }
 
+        if (rpExtensions.isBackChannelLogoutSessionRequired()) {
+            domElement.setAttributeNS(null, OAuthRPExtensions.BACK_CHANNEL_LOGOUT_SESSION_REQUIRED_ATTRIB_NAME,
+                    Boolean.toString(rpExtensions.isBackChannelLogoutSessionRequired()));
+        }
+
+        if (rpExtensions.isFrontChannelLogoutSessionRequired()) {
+            domElement.setAttributeNS(null, OAuthRPExtensions.FRONT_CHANNEL_LOGOUT_SESSION_REQUIRED_ATTRIB_NAME,
+                    Boolean.toString(rpExtensions.isFrontChannelLogoutSessionRequired()));
+        }
+
         marshallUnknownAttributes(rpExtensions, domElement);
     }
     
diff --git a/oidc-common-saml-impl/src/main/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsUnmarshaller.java b/oidc-common-saml-impl/src/main/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsUnmarshaller.java
index e080bbf..86b1f35 100644
--- a/oidc-common-saml-impl/src/main/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsUnmarshaller.java
+++ b/oidc-common-saml-impl/src/main/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsUnmarshaller.java
@@ -102,6 +102,14 @@ public class OAuthRPExtensionsUnmarshaller extends AbstractSAMLObjectUnmarshalle
                 descriptor.setTokenEndpointAuthSigningAlg(attribute.getValue());
             } else if (attribute.getLocalName().equals(OAuthRPExtensions.INITIATE_LOGIN_URI_ATTRIB_NAME)) {
                 descriptor.setInitiateLoginUri(attribute.getValue());
+            } else if (attribute.getLocalName().equals(
+                    OAuthRPExtensions.BACK_CHANNEL_LOGOUT_SESSION_REQUIRED_ATTRIB_NAME)
+                    && !Strings.isNullOrEmpty(attribute.getValue())) {
+                descriptor.setBackChannelLogoutSessionRequired(Boolean.parseBoolean(attribute.getValue()));
+            } else if (attribute.getLocalName().equals(
+                    OAuthRPExtensions.FRONT_CHANNEL_LOGOUT_SESSION_REQUIRED_ATTRIB_NAME)
+                    && !Strings.isNullOrEmpty(attribute.getValue())) {
+                descriptor.setFrontChannelLogoutSessionRequired(Boolean.parseBoolean(attribute.getValue()));
             } else {
                 super.processAttribute(samlObject, attribute);
             }
diff --git a/oidc-common-saml-impl/src/test/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsTest.java b/oidc-common-saml-impl/src/test/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsTest.java
index 32366fc..d553cd7 100644
--- a/oidc-common-saml-impl/src/test/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsTest.java
+++ b/oidc-common-saml-impl/src/test/java/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensionsTest.java
@@ -81,6 +81,8 @@ public class OAuthRPExtensionsTest extends XMLObjectProviderBaseTestCase {
         rpExtensions.setUserInfoEncryptedResponseEnc("A192GCM");
         rpExtensions.setUserInfoSignedResponseAlg("RS384");
         rpExtensions.getUnknownAttributes().put(ATTRIBUTE_EXT_QNAME, ATTRIBUTE_EXT_VALUE);
+        rpExtensions.setBackChannelLogoutSessionRequired(true);
+        rpExtensions.setFrontChannelLogoutSessionRequired(true);
 
         assertXMLEquals(expectedChildElementsDOM, rpExtensions);
     }
@@ -142,6 +144,10 @@ public class OAuthRPExtensionsTest extends XMLObjectProviderBaseTestCase {
                 "The user info encrypted response enc did not have expected value");
         Assert.assertEquals(rpExtensions.getUserInfoSignedResponseAlg(), "RS384",
                 "The user info signing response alg did not have expected value");
+        Assert.assertEquals(rpExtensions.isBackChannelLogoutSessionRequired(), true,
+                "The back-channel logout session id required did not have expected value");
+        Assert.assertEquals(rpExtensions.isFrontChannelLogoutSessionRequired(), true,
+                "The front-channel logout session id required did not have expected value");
     }
     
     protected <T extends MetadataValueSAMLObject> void assertMetadataValue(final T metadataValue,
diff --git a/oidc-common-saml-impl/src/test/resources/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensions.xml b/oidc-common-saml-impl/src/test/resources/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensions.xml
index 8d62d7c..a9059bf 100644
--- a/oidc-common-saml-impl/src/test/resources/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensions.xml
+++ b/oidc-common-saml-impl/src/test/resources/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensions.xml
@@ -21,7 +21,9 @@
     request_object_signing_alg="RS256"
     request_object_encryption_alg="A128KW"
     request_object_encryption_enc="A128GCM"
-    token_endpoint_auth_signing_alg="RS512">
+    token_endpoint_auth_signing_alg="RS512"
+    frontchannel_logout_session_required="true"
+    backchannel_logout_session_required="true" >
     <oidcmd:default_acr_value>password</oidcmd:default_acr_value>
     <oidcmd:default_acr_value>mfa</oidcmd:default_acr_value>
     <oidcmd:request_uri>https://example.org/request</oidcmd:request_uri>
diff --git a/oidc-common-saml-impl/src/test/resources/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensions_ordered.xml b/oidc-common-saml-impl/src/test/resources/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensions_ordered.xml
index 8d62d7c..a9059bf 100644
--- a/oidc-common-saml-impl/src/test/resources/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensions_ordered.xml
+++ b/oidc-common-saml-impl/src/test/resources/net/shibboleth/oidc/saml/xmlobject/impl/OAuthRPExtensions_ordered.xml
@@ -21,7 +21,9 @@
     request_object_signing_alg="RS256"
     request_object_encryption_alg="A128KW"
     request_object_encryption_enc="A128GCM"
-    token_endpoint_auth_signing_alg="RS512">
+    token_endpoint_auth_signing_alg="RS512"
+    frontchannel_logout_session_required="true"
+    backchannel_logout_session_required="true" >
     <oidcmd:default_acr_value>password</oidcmd:default_acr_value>
     <oidcmd:default_acr_value>mfa</oidcmd:default_acr_value>
     <oidcmd:request_uri>https://example.org/request</oidcmd:request_uri>

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list