diff --git a/saml-core/src/main/java/org/keycloak/saml/common/util/DocumentUtil.java b/saml-core/src/main/java/org/keycloak/saml/common/util/DocumentUtil.java
index b5f2232a47..f516124f7b 100755
--- a/saml-core/src/main/java/org/keycloak/saml/common/util/DocumentUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/util/DocumentUtil.java
@@ -52,6 +52,7 @@ import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
+import java.util.Objects;
/**
* Utility dealing with DOM
@@ -554,4 +555,33 @@ public class DocumentUtil {
return documentBuilderFactory;
}
+
+ /**
+ * Get a (direct) child {@linkplain Element} from the parent {@linkplain Element}.
+ *
+ * @param parent parent element
+ * @param targetNamespace namespace URI
+ * @param targetLocalName local name
+ * @return a child element matching the target namespace and localname, where {@linkplain Element#getParentNode()} is the parent input parameter
+ * @return
+ */
+
+ public static Element getDirectChildElement(Element parent, String targetNamespace, String targetLocalName) {
+ Node child = parent.getFirstChild();
+
+ while(child != null) {
+ if(child instanceof Element) {
+ Element childElement = (Element)child;
+
+ String ns = childElement.getNamespaceURI();
+ String localName = childElement.getLocalName();
+
+ if(Objects.equals(targetNamespace, ns) && Objects.equals(targetLocalName, localName)) {
+ return childElement;
+ }
+ }
+ child = child.getNextSibling();
+ }
+ return null;
+ }
}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/sig/SAML2Signature.java b/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/sig/SAML2Signature.java
index ef3e3bd736..09ce9d62f8 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/sig/SAML2Signature.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/sig/SAML2Signature.java
@@ -49,8 +49,6 @@ public class SAML2Signature {
private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
- private static final String ID_ATTRIBUTE_NAME = "ID";
-
private String signatureMethod = SignatureMethod.RSA_SHA1;
private String digestMethod = DigestMethod.SHA1;
@@ -156,7 +154,7 @@ public class SAML2Signature {
*/
public void signSAMLDocument(Document samlDocument, String keyName, KeyPair keypair, String canonicalizationMethodType) throws ProcessingException {
// Get the ID from the root
- String id = samlDocument.getDocumentElement().getAttribute(ID_ATTRIBUTE_NAME);
+ String id = samlDocument.getDocumentElement().getAttribute(JBossSAMLConstants.ID.get());
try {
sign(samlDocument, id, keyName, keypair, canonicalizationMethodType);
} catch (ParserConfigurationException | GeneralSecurityException | MarshalException | XMLSignatureException e) {
@@ -210,18 +208,20 @@ public class SAML2Signature {
*
* @param document SAML document to have its ID attribute configured.
*/
- private void configureIdAttribute(Document document) {
+ public static void configureIdAttribute(Document document) {
// Estabilish the IDness of the ID attribute.
- document.getDocumentElement().setIdAttribute(ID_ATTRIBUTE_NAME, true);
+ configureIdAttribute(document.getDocumentElement());
NodeList nodes = document.getElementsByTagNameNS(JBossSAMLURIConstants.ASSERTION_NSURI.get(),
JBossSAMLConstants.ASSERTION.get());
for (int i = 0; i < nodes.getLength(); i++) {
- Node n = nodes.item(i);
- if (n instanceof Element) {
- ((Element) n).setIdAttribute(ID_ATTRIBUTE_NAME, true);
- }
+ configureIdAttribute((Element) nodes.item(i));
}
}
+
+ public static void configureIdAttribute(Element element) {
+ element.setIdAttribute(JBossSAMLConstants.ID.get(), true);
+ }
+
}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java
index bb15d233bf..244fb7d182 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java
@@ -49,11 +49,12 @@ import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
import org.keycloak.saml.processing.core.saml.v2.writers.SAMLAssertionWriter;
import org.keycloak.saml.processing.core.util.JAXPValidationUtil;
import org.keycloak.saml.processing.core.util.XMLEncryptionUtil;
-
+import org.keycloak.saml.processing.core.util.XMLSignatureUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
+import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import java.io.ByteArrayInputStream;
@@ -267,42 +268,56 @@ public class AssertionUtil {
}
/**
- * Given an assertion element, validate the signature
+ * Given an {@linkplain Element}, validate the Signature direct child element
*
- * @param assertionElement
+ * @param element parent {@linkplain Element}
* @param publicKey the {@link PublicKey}
*
- * @return
+ * @return true if signature is present and valid
*/
- public static boolean isSignatureValid(Element assertionElement, PublicKey publicKey) {
- try {
- Document doc = DocumentUtil.createDocument();
- Node n = doc.importNode(assertionElement, true);
- doc.appendChild(n);
-
- return new SAML2Signature().validate(doc, new HardcodedKeyLocator(publicKey));
- } catch (Exception e) {
- logger.signatureAssertionValidationError(e);
- }
- return false;
+ public static boolean isSignatureValid(Element element, PublicKey publicKey) {
+ return isSignatureValid(element, new HardcodedKeyLocator(publicKey));
}
/**
- * Given an assertion element, validate the signature.
+ * Given an {@linkplain Element}, validate the Signature direct child element
+ *
+ * @param element parent {@linkplain Element}
+ * @param keyLocator the {@link KeyLocator}
+ *
+ * @return true if signature is present and valid
*/
- public static boolean isSignatureValid(Element assertionElement, KeyLocator keyLocator) {
+
+ public static boolean isSignatureValid(Element element, KeyLocator keyLocator) {
try {
- Document doc = DocumentUtil.createDocument();
- Node n = doc.importNode(assertionElement, true);
- doc.appendChild(n);
-
- return new SAML2Signature().validate(doc, keyLocator);
+ SAML2Signature.configureIdAttribute(element);
+
+ Element signature = getSignature(element);
+ if(signature != null) {
+ return XMLSignatureUtil.validateSingleNode(signature, keyLocator);
+ }
} catch (Exception e) {
logger.signatureAssertionValidationError(e);
}
return false;
}
+
+ /**
+ *
+ * Given an {@linkplain Element}, check if there is a Signature direct child element
+ *
+ * @param element parent {@linkplain Element}
+ * @return true if signature is present
+ */
+ public static boolean isSignedElement(Element element) {
+ return getSignature(element) != null;
+ }
+
+ protected static Element getSignature(Element element) {
+ return DocumentUtil.getDirectChildElement(element, XMLSignature.XMLNS, "Signature");
+ }
+
/**
* Check whether the assertion has expired
*
@@ -570,8 +585,8 @@ public class AssertionUtil {
/**
* This method modifies the given responseType, and replaces the encrypted assertion with a decrypted version.
- *
- * It returns the assertion element as it was decrypted. This can be used in sginature verification.
+ * @param responseType a response containg an encrypted assertion
+ * @return the assertion element as it was decrypted. This can be used in signature verification.
*/
public static Element decryptAssertion(ResponseType responseType, PrivateKey privateKey) throws ParsingException, ProcessingException, ConfigurationException {
SAML2Response saml2Response = new SAML2Response();
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java
index 53228c971a..7093a20391 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java
@@ -468,7 +468,7 @@ public class XMLSignatureUtil {
return true;
}
- private static boolean validateSingleNode(Node signatureNode, final KeyLocator locator) throws MarshalException, XMLSignatureException {
+ public static boolean validateSingleNode(Node signatureNode, final KeyLocator locator) throws MarshalException, XMLSignatureException {
KeySelectorUtilizingKeyNameHint sel = new KeySelectorUtilizingKeyNameHint(locator);
try {
if (validateUsingKeySelector(signatureNode, sel)) {
diff --git a/saml-core/src/test/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtilTest.java b/saml-core/src/test/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtilTest.java
new file mode 100644
index 0000000000..b60bb4b893
--- /dev/null
+++ b/saml-core/src/test/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtilTest.java
@@ -0,0 +1,58 @@
+package org.keycloak.saml.processing.core.saml.v2.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.cert.X509Certificate;
+
+import org.bouncycastle.util.Arrays;
+import org.junit.Test;
+import org.keycloak.common.util.Base64;
+import org.keycloak.common.util.DerUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class AssertionUtilTest {
+
+ private static final String PRIVATE_KEY = "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==";
+
+ /**
+ * The public certificate that corresponds to {@link #PRIVATE_KEY}.
+ */
+ private static final String PUBLIC_CERT = "MIIDdzCCAl+gAwIBAgIEbySuqTANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE1MDEyODIyMTYyMFoXDTE3MTAyNDIyMTYyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAII/K9NNvXi9IySl7+l2zY/kKrGTtuR4WdCI0xLW/Jn4dLY7v1/HOnV4CC4ecFOzhdNFPtJkmEhP/q62CpmOYOKApXk3tfmm2rwEz9bWprVxgFGKnbrWlz61Z/cjLAlhD3IUj2ZRBquYgSXQPsYfXo1JmSWF5pZ9uh1FVqu9f4wvRqY20ZhUN+39F+1iaBsoqsrbXypCn1HgZkW1/9D9GZug1c3vB4wg1TwZZWRNGtxwoEhdK6dPrNcZ+6PdanVilWrbQFbBjY4wz8/7IMBzssoQ7Usmo8F1Piv0FGfaVeJqBrcAvbiBMpk8pT+27u6p8VyIX6LhGvnxIwM07NByeSUCAwEAAaMhMB8wHQYDVR0OBBYEFFlcNuTYwI9W0tQ224K1gFJlMam0MA0GCSqGSIb3DQEBCwUAA4IBAQB5snl1KWOJALtAjLqD0mLPg1iElmZP82Lq1htLBt3XagwzU9CaeVeCQ7lTp+DXWzPa9nCLhsC3QyrV3/+oqNli8C6NpeqI8FqN2yQW/QMWN1m5jWDbmrWwtQzRUn/rh5KEb5m3zPB+tOC6e/2bV3QeQebxeW7lVMD0tSCviUg1MQf1l2gzuXQo60411YwqrXwk6GMkDOhFDQKDlMchO3oRbQkGbcP8UeiKAXjMeHfzbiBr+cWz8NYZEtxUEDYDjTpKrYCSMJBXpmgVJCZ00BswbksxJwaGqGMPpUKmCV671pf3m8nq3xyiHMDGuGwtbU+GE8kVx85menmp8+964nin";
+
+ @Test
+ public void testSaml20Signed() throws Exception {
+
+ X509Certificate decodeCertificate = DerUtils.decodeCertificate(new ByteArrayInputStream(Base64.decode(PUBLIC_CERT)));
+
+ try (InputStream st = AssertionUtilTest.class.getResourceAsStream("saml20-signed-response.xml")) {
+ Document document = DocumentUtil.getDocument(st);
+
+ Element assertion = DocumentUtil.getDirectChildElement(document.getDocumentElement(), "urn:oasis:names:tc:SAML:2.0:assertion", "Assertion");
+
+ assertTrue(AssertionUtil.isSignatureValid(assertion, decodeCertificate.getPublicKey()));
+
+ // test manipulation of signature
+ Element signatureElement = AssertionUtil.getSignature(assertion);
+ byte[] validSignature = Base64.decode(signatureElement.getTextContent());
+
+ // change the signature value slightly
+ byte[] invalidSignature = Arrays.clone(validSignature);
+ invalidSignature[0] ^= invalidSignature[0];
+ signatureElement.setTextContent(Base64.encodeBytes(invalidSignature));
+
+ // check that signature now is invalid
+ assertFalse(AssertionUtil.isSignatureValid(document.getDocumentElement(), decodeCertificate.getPublicKey()));
+
+ // restore valid signature, but remove Signature element, check that still invalid
+ signatureElement.setTextContent(Base64.encodeBytes(validSignature));
+
+ assertion.removeChild(signatureElement);
+ assertFalse(AssertionUtil.isSignatureValid(document.getDocumentElement(), decodeCertificate.getPublicKey()));
+ }
+ }
+
+}
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/saml/v2/util/saml20-signed-response.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/saml/v2/util/saml20-signed-response.xml
new file mode 100644
index 0000000000..998520addb
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/saml/v2/util/saml20-signed-response.xml
@@ -0,0 +1 @@
+http://localhost:8080/auth/realms/saml-broker-realmhttp://localhost:8080/auth/realms/saml-broker-realmcCSNXxLmu411weW1kRpie4C9yaBg2In6V4oEuqya0Eo=Qe6ZqgSwFH31UTu+zHqr1/UsafH0luxP5OH/cqyHm07Kf/Fp/fm9mnHJ0kGoUn0SUo7xWvwy8AzUfPXWMYS3kDyhUsPzgz0CnCzzfTz3koKFczgyIQ8sokIDv0cTp3z1qCUVWV0CEPzhtWlaIus2W89TEi/h9KjYrkeGl3+cpm8BPEAt4EP8Oht5czK2haIfPMDUm5Y7uw/FCSsvSfFyrlJ0jR/YMeP9PP0InYYegI9QQgvXKRm6DZSNZgKYFpprc12v6vv/zTaMm5fbuuy1wNDuDTB8EF6K1yrq21DatJXUKE1oOMBrkOvbFJNtgHlQviz1OssAqzHlf0NQPIAEig==IzH2UxfMxovYTEHn4Bh-EAj-Zrvldukl_5Snu0RA0B8MIICsTCCAZkCBgFb1GERYzANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFzYW1sLWJyb2tlci1yZWFsbTAeFw0xNzA1MDQxNjUxMjJaFw0yNzA1MDQxNjUzMDJaMBwxGjAYBgNVBAMMEXNhbWwtYnJva2VyLXJlYWxtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgj8r0029eL0jJKXv6XbNj+QqsZO25HhZ0IjTEtb8mfh0tju/X8c6dXgILh5wU7OF00U+0mSYSE/+rrYKmY5g4oCleTe1+abavATP1tamtXGAUYqdutaXPrVn9yMsCWEPchSPZlEGq5iBJdA+xh9ejUmZJYXmln26HUVWq71/jC9GpjbRmFQ37f0X7WJoGyiqyttfKkKfUeBmRbX/0P0Zm6DVze8HjCDVPBllZE0a3HCgSF0rp0+s1xn7o91qdWKVattAVsGNjjDPz/sgwHOyyhDtSyajwXU+K/QUZ9pV4moGtwC9uIEymTylP7bu7qnxXIhfouEa+fEjAzTs0HJ5JQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCBuWKmcVPX4sZtpvBp8BgQwH51l5tKPuQq66/4JH40hzkrLOGcVEOafIsGoOWi8HsZWZu+APwhSrnRNd7yMV+NJyw5W1DKjhdUPWnzPNy+UMAcoUBFhXDIWog0qxgGvTdoe1lfHryUQt1cd95SFVIerJA93nFbSOoMB+N7TmfQm+sNu2pJ2tr6mx3wGCXMnWf29gwhCI3wV19hh4KugnMIEStjvQoRyh2yna64BrR3eaUyhU/Bdrq2VXLNU/9WXg9gbRLUEWkMUPKOeQ5cGCgc4JFyFXRo5ExkzmvP9vwBRtjQulk5QKqfYo251mKvTQgO7K8d4CzVS/4+bpgKvZAMgj8r0029eL0jJKXv6XbNj+QqsZO25HhZ0IjTEtb8mfh0tju/X8c6dXgILh5wU7OF00U+0mSYSE/+rrYKmY5g4oCleTe1+abavATP1tamtXGAUYqdutaXPrVn9yMsCWEPchSPZlEGq5iBJdA+xh9ejUmZJYXmln26HUVWq71/jC9GpjbRmFQ37f0X7WJoGyiqyttfKkKfUeBmRbX/0P0Zm6DVze8HjCDVPBllZE0a3HCgSF0rp0+s1xn7o91qdWKVattAVsGNjjDPz/sgwHOyyhDtSyajwXU+K/QUZ9pV4moGtwC9uIEymTylP7bu7qnxXIhfouEa+fEjAzTs0HJ5JQ==AQABG-ebb3a66f-686f-4bb9-8a8b-20b566ca747bhttp://localhost:8080/auth/realms/saml-broker-authentication-realmurn:oasis:names:tc:SAML:2.0:ac:classes:unspecifiedmanageruser
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java b/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
index 5825f60554..b439009c0f 100755
--- a/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
+++ b/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
@@ -371,13 +371,13 @@ public class SAMLEndpoint {
assertionElement = DocumentUtil.getElement(holder.getSamlDocument(), new QName(JBossSAMLConstants.ASSERTION.get()));
}
- if (config.isWantAssertionsSigned() && config.isValidateSignature()) {
- if (!AssertionUtil.isSignatureValid(assertionElement, getIDPKeyLocator())) {
- logger.error("validation failed");
- event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
- event.error(Errors.INVALID_SIGNATURE);
- return ErrorPage.error(session, Messages.INVALID_REQUESTER);
- }
+ boolean signed = AssertionUtil.isSignedElement(assertionElement);
+ if ((config.isWantAssertionsSigned() && !signed)
+ || (signed && config.isValidateSignature() && !AssertionUtil.isSignatureValid(assertionElement, getIDPKeyLocator()))) {
+ logger.error("validation failed");
+ event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
+ event.error(Errors.INVALID_SIGNATURE);
+ return ErrorPage.error(session, Messages.INVALID_REQUESTER);
}
AssertionType assertion = responseType.getAssertions().get(0).getAssertion();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedDocumentOnlyBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedDocumentOnlyBrokerTest.java
new file mode 100644
index 0000000000..5f9fd0e8be
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedDocumentOnlyBrokerTest.java
@@ -0,0 +1,83 @@
+package org.keycloak.testsuite.broker;
+
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.arquillian.SuiteContext;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.keycloak.testsuite.broker.BrokerTestConstants.*;
+
+public class KcSamlSignedDocumentOnlyBrokerTest extends KcSamlBrokerTest {
+
+ public static class KcSamlSignedBrokerConfiguration extends KcSamlBrokerConfiguration {
+
+ @Override
+ public RealmRepresentation createProviderRealm() {
+ RealmRepresentation realm = super.createProviderRealm();
+
+ realm.setPublicKey(REALM_PUBLIC_KEY);
+ realm.setPrivateKey(REALM_PRIVATE_KEY);
+
+ return realm;
+ }
+
+ @Override
+ public RealmRepresentation createConsumerRealm() {
+ RealmRepresentation realm = super.createConsumerRealm();
+
+ realm.setPublicKey(REALM_PUBLIC_KEY);
+ realm.setPrivateKey(REALM_PRIVATE_KEY);
+
+ return realm;
+ }
+
+ @Override
+ public List createProviderClients(SuiteContext suiteContext) {
+ List clientRepresentationList = super.createProviderClients(suiteContext);
+
+ for (ClientRepresentation client : clientRepresentationList) {
+ client.setClientAuthenticatorType("client-secret");
+ client.setSurrogateAuthRequired(false);
+
+ Map attributes = client.getAttributes();
+ if (attributes == null) {
+ attributes = new HashMap<>();
+ client.setAttributes(attributes);
+ }
+
+ attributes.put("saml.assertion.signature", "false");
+ attributes.put("saml.server.signature", "true");
+ attributes.put("saml.client.signature", "true");
+ attributes.put("saml.signature.algorithm", "RSA_SHA256");
+ attributes.put("saml.signing.private.key", IDP_SAML_SIGN_KEY);
+ attributes.put("saml.signing.certificate", IDP_SAML_SIGN_CERT);
+ }
+
+ return clientRepresentationList;
+ }
+
+ @Override
+ public IdentityProviderRepresentation setUpIdentityProvider(SuiteContext suiteContext) {
+ IdentityProviderRepresentation result = super.setUpIdentityProvider(suiteContext);
+
+ Map config = result.getConfig();
+
+ config.put("validateSignature", "true");
+ config.put("wantAssertionsSigned", "false");
+ config.put("wantAuthnRequestsSigned", "true");
+ config.put("signingCertificate", IDP_SAML_SIGN_CERT);
+
+ return result;
+ }
+ }
+
+ @Override
+ protected BrokerConfiguration getBrokerConfiguration() {
+ return KcSamlSignedBrokerConfiguration.INSTANCE;
+ }
+
+}