Adding support for rsa-oaep for SAML encryption

Closes https://github.com/keycloak/keycloak/issues/19689
This commit is contained in:
rmartinc 2023-04-20 16:59:11 +02:00 committed by Marek Posolda
parent 035fdc4047
commit 04ac3a64ee
10 changed files with 292 additions and 45 deletions

View file

@ -73,6 +73,9 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
protected String encryptionAlgorithm = "AES";
protected boolean encrypt;
protected String canonicalizationMethodType = CanonicalizationMethod.EXCLUSIVE;
protected String keyEncryptionAlgorithm;
protected String keyEncryptionDigestMethod;
protected String keyEncryptionMgfAlgorithm;
public T canonicalizationMethod(String method) {
this.canonicalizationMethodType = method;
@ -136,6 +139,21 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
return (T)this;
}
public T keyEncryptionAlgorithm(String keyEncryptionAlgorithm) {
this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
return (T)this;
}
public T keyEncryptionDigestMethod(String keyEncryptionDigestMethod) {
this.keyEncryptionDigestMethod = keyEncryptionDigestMethod;
return (T)this;
}
public T keyEncryptionMgfAlgorithm(String keyEncryptionMgfAlgorithm) {
this.keyEncryptionMgfAlgorithm = keyEncryptionMgfAlgorithm;
return (T)this;
}
public T relayState(String relayState) {
this.relayState = relayState;
return (T)this;
@ -271,8 +289,8 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
// encrypt the Assertion element and replace it with a EncryptedAssertion element.
XMLEncryptionUtil.encryptElement(new QName(JBossSAMLURIConstants.ASSERTION_NSURI.get(),
JBossSAMLConstants.ASSERTION.get(), samlNSPrefix), samlDocument, encryptionPublicKey,
secretKey, encryptionKeySize, encryptedAssertionElementQName, true);
JBossSAMLConstants.ASSERTION.get(), samlNSPrefix), samlDocument, encryptionPublicKey, secretKey, encryptionKeySize,
encryptedAssertionElementQName, true, keyEncryptionAlgorithm, keyEncryptionDigestMethod, keyEncryptionMgfAlgorithm);
} catch (Exception e) {
throw new ProcessingException("failed to encrypt", e);
}

View file

@ -79,14 +79,16 @@ public class SPMetadataDescriptor {
return entityDescriptor;
}
public static KeyDescriptorType buildKeyDescriptorType(Element keyInfo, KeyTypes use, String algorithm) {
public static KeyDescriptorType buildKeyDescriptorType(Element keyInfo, KeyTypes use, String... algorithm) {
KeyDescriptorType keyDescriptor = new KeyDescriptorType();
keyDescriptor.setUse(use);
keyDescriptor.setKeyInfo(keyInfo);
if (algorithm != null) {
EncryptionMethodType encMethod = new EncryptionMethodType(algorithm);
keyDescriptor.addEncryptionMethod(encMethod);
for (String alg : algorithm) {
EncryptionMethodType encMethod = new EncryptionMethodType(alg);
keyDescriptor.addEncryptionMethod(encMethod);
}
}
return keyDescriptor;

View file

@ -99,14 +99,15 @@ public class XMLEncryptionUtil {
* @throws org.keycloak.saml.common.exceptions.ProcessingException
*/
private static EncryptedKey encryptKey(Document document, SecretKey keyToBeEncrypted, PublicKey keyUsedToEncryptSecretKey,
int keySize, String encryptionUrlForKeyUnwrap) throws ProcessingException {
int keySize, String keyEncryptionAlgorithm, String keyEncryptionDigestMethod,
String keyEncryptionMgfAlgorithm) throws ProcessingException {
XMLCipher keyCipher;
try {
keyCipher = XMLCipher.getInstance(encryptionUrlForKeyUnwrap);
keyCipher = XMLCipher.getInstance(keyEncryptionAlgorithm, null, keyEncryptionDigestMethod);
keyCipher.init(XMLCipher.WRAP_MODE, keyUsedToEncryptSecretKey);
return keyCipher.encryptKey(document, keyToBeEncrypted);
return keyCipher.encryptKey(document, keyToBeEncrypted, keyEncryptionMgfAlgorithm, null);
} catch (XMLEncryptionException e) {
throw logger.processingError(e);
}
@ -115,7 +116,14 @@ public class XMLEncryptionUtil {
public static void encryptElement(QName elementQName, Document document, PublicKey publicKey, SecretKey secretKey,
int keySize, QName wrappingElementQName, boolean addEncryptedKeyInKeyInfo) throws ProcessingException {
encryptElement(elementQName, document, publicKey, secretKey, keySize, wrappingElementQName, addEncryptedKeyInKeyInfo,
getXMLEncryptionURLForKeyUnwrap(publicKey.getAlgorithm(), keySize));
null, null, null);
}
public static void encryptElement(QName elementQName, Document document, PublicKey publicKey, SecretKey secretKey,
int keySize, QName wrappingElementQName, boolean addEncryptedKeyInKeyInfo,
String keyEncryptionAlgorithm) throws ProcessingException {
encryptElement(elementQName, document, publicKey, secretKey, keySize, wrappingElementQName,
addEncryptedKeyInKeyInfo, keyEncryptionAlgorithm, null, null);
}
/**
@ -123,17 +131,21 @@ public class XMLEncryptionUtil {
* data
*
* @param elementQName QName of the element that we like to encrypt
* @param document
* @param publicKey
* @param secretKey
* @param keySize
* @param document The document with the element to encrypt
* @param publicKey The public Key to wrap the secret key
* @param secretKey The secret key to use for encryption
* @param keySize The size of the public key
* @param wrappingElementQName A QName of an element that will wrap the encrypted element
* @param addEncryptedKeyInKeyInfo Need for the EncryptedKey to be placed in ds:KeyInfo
* @param keyEncryptionAlgorithm The wrap algorithm for the secret key (can be null, default is used depending the publicKey type)
* @param keyEncryptionDigestMethod An optional digestMethod to use (can be null)
* @param keyEncryptionMgfAlgorithm The xenc11 MGF Algorithm to use (can be null)
*
* @throws ProcessingException
*/
public static void encryptElement(QName elementQName, Document document, PublicKey publicKey, SecretKey secretKey,
int keySize, QName wrappingElementQName, boolean addEncryptedKeyInKeyInfo, String encryptionUrlForKeyUnwrap) throws ProcessingException {
int keySize, QName wrappingElementQName, boolean addEncryptedKeyInKeyInfo, String keyEncryptionAlgorithm,
String keyEncryptionDigestMethod, String keyEncryptionMgfAlgorithm) throws ProcessingException {
if (elementQName == null)
throw logger.nullArgumentError("elementQName");
if (document == null)
@ -148,7 +160,11 @@ public class XMLEncryptionUtil {
throw logger.domMissingDocElementError(elementQName.toString());
XMLCipher cipher = null;
EncryptedKey encryptedKey = encryptKey(document, secretKey, publicKey, keySize, encryptionUrlForKeyUnwrap);
if (keyEncryptionAlgorithm == null) {
// get default one for the public key
keyEncryptionAlgorithm = getXMLEncryptionURLForKeyUnwrap(publicKey.getAlgorithm(), keySize);
}
EncryptedKey encryptedKey = encryptKey(document, secretKey, publicKey, keySize, keyEncryptionAlgorithm, keyEncryptionDigestMethod, keyEncryptionMgfAlgorithm);
String encryptionAlgorithm = getXMLEncryptionURL(secretKey.getAlgorithm(), keySize);
// Encrypt the Document

View file

@ -397,7 +397,7 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
throw new RuntimeException(e);
}
return SPMetadataDescriptor.buildKeyDescriptorType(keyInfo, KeyTypes.ENCRYPTION, SAMLEncryptionAlgorithms.forKeycloakIdentifier(key.getAlgorithm()).getXmlEncIdentifier());
return SPMetadataDescriptor.buildKeyDescriptorType(keyInfo, KeyTypes.ENCRYPTION, SAMLEncryptionAlgorithms.forKeycloakIdentifier(key.getAlgorithm()).getXmlEncIdentifiers());
})
.collect(Collectors.toList());

View file

@ -20,40 +20,73 @@ package org.keycloak.protocol.saml;
import org.apache.xml.security.encryption.XMLCipher;
import org.keycloak.crypto.Algorithm;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* This enum provides mapping between Keycloak provided encryption algorithms and algorithms from xmlsec.
* It is used to make sure we are using keys generated for given algorithm only with that algorithm.
*/
public enum SAMLEncryptionAlgorithms {
RSA_OAEP(XMLCipher.RSA_OAEP, Algorithm.RSA_OAEP),
RSA1_5(XMLCipher.RSA_v1dot5, Algorithm.RSA1_5);
RSA_OAEP(Algorithm.RSA_OAEP, XMLCipher.RSA_OAEP, XMLCipher.RSA_OAEP_11),
RSA1_5(Algorithm.RSA1_5, XMLCipher.RSA_v1dot5);
private String xmlEncIdentifier;
private String keycloakIdentifier;
private static final Map<String, SAMLEncryptionAlgorithms> forXMLEncIdentifier = Arrays.stream(values()).collect(Collectors.toMap(SAMLEncryptionAlgorithms::getXmlEncIdentifier, Function.identity()));
private static final Map<String, SAMLEncryptionAlgorithms> forKeycloakIdentifier = Arrays.stream(values()).collect(Collectors.toMap(SAMLEncryptionAlgorithms::getKeycloakIdentifier, Function.identity()));
private final String[] xmlEncIdentifier;
private final String keycloakIdentifier;
private static final Map<String, SAMLEncryptionAlgorithms> forKeycloakIdentifier;
private static final Map<String, SAMLEncryptionAlgorithms> forXMLEncIdentifier;
SAMLEncryptionAlgorithms(String xmlEncIdentifier, String keycloakIdentifier) {
static {
Map<String, SAMLEncryptionAlgorithms> forKeycloakIdentifierTmp = new HashMap<>();
Map<String, SAMLEncryptionAlgorithms> forXMLEncIdentifierTmp = new HashMap<>();
for (SAMLEncryptionAlgorithms alg: values()) {
forKeycloakIdentifierTmp.put(alg.getKeycloakIdentifier(), alg);
for (String xmlAlg : alg.getXmlEncIdentifiers()) {
forXMLEncIdentifierTmp.put(xmlAlg, alg);
}
}
forKeycloakIdentifier = Collections.unmodifiableMap(forKeycloakIdentifierTmp);
forXMLEncIdentifier = Collections.unmodifiableMap(forXMLEncIdentifierTmp);
}
SAMLEncryptionAlgorithms(String keycloakIdentifier, String... xmlEncIdentifier) {
assert xmlEncIdentifier.length > 0 : "xmlEncIdentifier should contain at least one identifier";
this.xmlEncIdentifier = xmlEncIdentifier;
this.keycloakIdentifier = keycloakIdentifier;
}
public String getXmlEncIdentifier() {
/**
* Getter for all the XML encoding identifiers.
* There should be at least one.
* @return The array of XML encoding identifiers
*/
public String[] getXmlEncIdentifiers() {
return xmlEncIdentifier;
}
/**
* Getter for the keycloak identifier.
* @return The keycloak identifier.
*/
public String getKeycloakIdentifier() {
return keycloakIdentifier;
}
/**
* Returns the SAMLEncryptionAlgorithms that contains the xml enc identifier.
* @param xmlEncIdentifier The Xml encoding identifier
* @return The associated SAMLEncryptionAlgorithms or null
*/
public static SAMLEncryptionAlgorithms forXMLEncIdentifier(String xmlEncIdentifier) {
return forXMLEncIdentifier.get(xmlEncIdentifier);
}
/**
* Returns the SAMLEncryptionAlgorithms for the keycloak identifier.
* @param keycloakIdentifier The keycloak identifier
* @return The associated SAMLEncryptionAlgorithms or null
*/
public static SAMLEncryptionAlgorithms forKeycloakIdentifier(String keycloakIdentifier) {
return forKeycloakIdentifier.get(keycloakIdentifier);
}

View file

@ -0,0 +1,167 @@
/*
* Copyright 2023 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.protocol.saml;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import org.apache.xml.security.encryption.XMLCipher;
import org.apache.xml.security.utils.EncryptionConstants;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.dom.saml.v2.assertion.AssertionType;
import org.keycloak.dom.saml.v2.assertion.NameIDType;
import org.keycloak.dom.saml.v2.protocol.ResponseType;
import org.keycloak.models.KeycloakSession;
import org.keycloak.protocol.saml.JaxrsSAML2BindingBuilder;
import org.keycloak.protocol.saml.SAMLEncryptionAlgorithms;
import org.keycloak.saml.SAML2LoginResponseBuilder;
import org.keycloak.saml.SAMLRequestParser;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.util.DocumentUtil;
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
import org.keycloak.saml.processing.core.saml.v2.util.AssertionUtil;
import org.keycloak.services.DefaultKeycloakSession;
import org.keycloak.services.DefaultKeycloakSessionFactory;
import org.w3c.dom.Document;
/**
* <p>Simple test class that checks SAML encryption with different algorithms.
* No server needed.</p>
*
* @author rmartinc
*/
public class SamlEncryptionTest {
private static final KeyPair rsaKeyPair;
static {
try {
KeyPairGenerator rsa = KeyPairGenerator.getInstance("RSA");
rsa.initialize(2048);
rsaKeyPair = rsa.generateKeyPair();
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
}
@BeforeClass
public static void beforeClass() {
Cipher cipher = null;
SecureRandom random = null;
try {
// Apache santuario 2.2.3 needs to have SHA1PRNG (fixed in 3.0.2)
// see: https://issues.apache.org/jira/browse/SANTUARIO-589
random = SecureRandom.getInstance("SHA1PRNG");
// FIPS mode removes needed ciphers like "RSA/ECB/OAEPPadding"
cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
} catch (NoSuchAlgorithmException|NoSuchPaddingException e) {
// ignore
}
Assume.assumeNotNull("OAEPPadding not supported", cipher);
Assume.assumeNotNull("SHA1PRNG required for Apache santuario xmlsec", random);
}
private void testEncryption(KeyPair pair, String alg, int keySize, String keyWrapAlg, String keyWrapHashMethod, String keyWrapMgf) throws Exception {
SAML2LoginResponseBuilder builder = new SAML2LoginResponseBuilder();
builder.requestID("requestId")
.destination("http://localhost")
.issuer("issuer")
.assertionExpiration(300)
.subjectExpiration(300)
.sessionExpiration(300)
.requestIssuer("clientId")
.authMethod(JBossSAMLURIConstants.AC_UNSPECIFIED.get())
.sessionIndex("sessionIndex")
.nameIdentifier(JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get(), "nameId");
ResponseType samlModel = builder.buildModel();
KeycloakSession session = new DefaultKeycloakSession(new DefaultKeycloakSessionFactory());
JaxrsSAML2BindingBuilder bindingBuilder = new JaxrsSAML2BindingBuilder(session);
if (alg != null) {
bindingBuilder.encryptionAlgorithm(alg);
}
if (keySize > 0) {
bindingBuilder.encryptionKeySize(keySize);
}
if (keyWrapAlg != null) {
bindingBuilder.keyEncryptionAlgorithm(keyWrapAlg);
}
if (keyWrapHashMethod != null) {
bindingBuilder.keyEncryptionDigestMethod(keyWrapHashMethod);
}
if (keyWrapMgf != null) {
bindingBuilder.keyEncryptionMgfAlgorithm(keyWrapMgf);
}
bindingBuilder.encrypt(pair.getPublic());
Document samlDocument = builder.buildDocument(samlModel);
bindingBuilder.postBinding(samlDocument);
String samlResponse = DocumentUtil.getDocumentAsString(samlDocument);
SAMLDocumentHolder holder = SAMLRequestParser.parseResponseDocument(samlResponse.getBytes(StandardCharsets.UTF_8));
ResponseType responseType = (ResponseType) holder.getSamlObject();
Assert.assertTrue("Assertion is not encrypted", AssertionUtil.isAssertionEncrypted(responseType));
AssertionType assertion = AssertionUtil.getAssertion(holder, responseType, pair.getPrivate());
Assert.assertEquals("issuer", assertion.getIssuer().getValue());
MatcherAssert.assertThat(assertion.getSubject().getSubType().getBaseID(), Matchers.instanceOf(NameIDType.class));
NameIDType nameId = (NameIDType) assertion.getSubject().getSubType().getBaseID();
Assert.assertEquals("nameId", nameId.getValue());
}
@Test
public void testDefault() throws Exception {
testEncryption(rsaKeyPair, null, -1, null, null, null);
}
@Test
public void testAES256() throws Exception {
testEncryption(rsaKeyPair, "AES", 256, null, null, null);
}
@Test
public void testDefaultKeyWraps() throws Exception {
for (SAMLEncryptionAlgorithms alg : SAMLEncryptionAlgorithms.values()) {
for (String keyWrapAlg : alg.getXmlEncIdentifiers()) {
testEncryption(rsaKeyPair, null, -1, keyWrapAlg, null, null);
}
}
}
@Test
public void testKeyWrapsWithSha512() throws Exception {
for (SAMLEncryptionAlgorithms alg : SAMLEncryptionAlgorithms.values()) {
for (String keyWrapAlg : alg.getXmlEncIdentifiers()) {
testEncryption(rsaKeyPair, null, -1, keyWrapAlg, XMLCipher.SHA512, null);
}
}
}
@Test
public void testRsaOaep11WithSha512AndMgfSha512() throws Exception {
testEncryption(rsaKeyPair, "AES", 256, XMLCipher.RSA_OAEP_11, XMLCipher.SHA512, EncryptionConstants.MGF1_SHA512);
}
}

View file

@ -17,6 +17,8 @@
package org.keycloak.testsuite.broker;
import org.apache.xml.security.encryption.XMLCipher;
import org.apache.xml.security.utils.EncryptionConstants;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
@ -25,7 +27,6 @@ import org.keycloak.common.util.PemUtils;
import org.keycloak.crypto.Algorithm;
import org.keycloak.crypto.KeyUse;
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
import org.keycloak.protocol.saml.SAMLEncryptionAlgorithms;
import org.keycloak.representations.idm.KeysMetadataRepresentation;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ConfigurationException;
@ -75,14 +76,14 @@ public abstract class AbstractKcSamlEncryptedElementsTest extends AbstractBroker
public void testEncryptedElementIsReadable() throws ConfigurationException, ParsingException, ProcessingException {
KeysMetadataRepresentation.KeyMetadataRepresentation activeEncryptingKey = KeyUtils.findActiveEncryptingKey(adminClient.realm(bc.consumerRealmName()), Algorithm.RSA_OAEP);
assertThat(activeEncryptingKey.getProviderId(), equalTo(encProviderId));
sendDocumentWithEncryptedElement(PemUtils.decodePublicKey(activeEncryptingKey.getPublicKey()), SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifier(), true);
sendDocumentWithEncryptedElement(PemUtils.decodePublicKey(activeEncryptingKey.getPublicKey()), XMLCipher.RSA_OAEP, null, null, true);
}
@Test
public void testSignatureKeyEncryptedElementIsNotReadableWithoutDeprecatedMode() throws ConfigurationException, ParsingException, ProcessingException {
KeysMetadataRepresentation.KeyMetadataRepresentation activeSignatureKey = KeyUtils.findActiveSigningKey(adminClient.realm(bc.consumerRealmName()));
assertThat(activeSignatureKey.getProviderId(), equalTo(sigProviderId));
sendDocumentWithEncryptedElement(PemUtils.decodePublicKey(activeSignatureKey.getPublicKey()), SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifier(), false);
sendDocumentWithEncryptedElement(PemUtils.decodePublicKey(activeSignatureKey.getPublicKey()), XMLCipher.RSA_OAEP, null, null, false);
}
@Test
@ -94,7 +95,7 @@ public abstract class AbstractKcSamlEncryptedElementsTest extends AbstractBroker
});
KeysMetadataRepresentation.KeyMetadataRepresentation activeSignatureKey = KeyUtils.findActiveSigningKey(adminClient.realm(bc.consumerRealmName()));
assertThat(activeSignatureKey.getProviderId(), equalTo(sigProviderId));
sendDocumentWithEncryptedElement(PemUtils.decodePublicKey(activeSignatureKey.getPublicKey()), SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifier(), true);
sendDocumentWithEncryptedElement(PemUtils.decodePublicKey(activeSignatureKey.getPublicKey()), XMLCipher.RSA_OAEP, null, null, true);
} finally {
// Clear flag
testingClient.server().run(session -> {
@ -111,13 +112,21 @@ public abstract class AbstractKcSamlEncryptedElementsTest extends AbstractBroker
.findFirst()
.orElseThrow(() -> new RuntimeException("Cannot find key created on the previous line"));
sendDocumentWithEncryptedElement(PemUtils.decodePublicKey(key.getPublicKey()), SAMLEncryptionAlgorithms.RSA1_5.getXmlEncIdentifier(), true);
sendDocumentWithEncryptedElement(PemUtils.decodePublicKey(key.getPublicKey()), XMLCipher.RSA_v1dot5, null, null, true);
}
}
protected abstract SamlDocumentStepBuilder.Saml2DocumentTransformer encryptDocument(PublicKey publicKey, String keyEncryptionAlgorithm);
@Test
public void testRsaOaepAlgorithm() throws Exception {
RealmResource realm = adminClient.realm(bc.consumerRealmName());
KeysMetadataRepresentation.KeyMetadataRepresentation key = KeyUtils.findActiveEncryptingKey(realm, Algorithm.RSA_OAEP);
assertThat(key.getProviderId(), equalTo(encProviderId));
sendDocumentWithEncryptedElement(PemUtils.decodePublicKey(key.getPublicKey()), XMLCipher.RSA_OAEP_11, XMLCipher.SHA256, EncryptionConstants.MGF1_SHA256, true);
}
private void sendDocumentWithEncryptedElement(PublicKey publicKey, String keyEncryptionAlgorithm, boolean shouldPass) throws ConfigurationException, ParsingException, ProcessingException {
protected abstract SamlDocumentStepBuilder.Saml2DocumentTransformer encryptDocument(PublicKey publicKey, String keyEncryptionAlgorithm, String keyEncryptionDigestMethod, String keyEncryptionMgfAlgorithm);
private void sendDocumentWithEncryptedElement(PublicKey publicKey, String keyEncryptionAlgorithm, String keyEncryptionDigestMethod, String keyEncryptionMgfAlgorithm, boolean shouldPass) throws ConfigurationException, ParsingException, ProcessingException {
createRolesForRealm(bc.consumerRealmName());
AuthnRequestType loginRep = SamlClient.createLoginRequestDocument(SAML_CLIENT_ID_SALES_POST + ".dot/ted", getConsumerRoot() + "/sales-post/saml", null);
@ -138,7 +147,7 @@ public abstract class AbstractKcSamlEncryptedElementsTest extends AbstractBroker
.login().user(bc.getUserLogin(), bc.getUserPassword()).build()
.processSamlResponse(SamlClient.Binding.POST) // Response from producer IdP
.transformDocument(encryptDocument(publicKey, keyEncryptionAlgorithm))
.transformDocument(encryptDocument(publicKey, keyEncryptionAlgorithm, keyEncryptionDigestMethod, keyEncryptionMgfAlgorithm))
.build();
if (shouldPass) {

View file

@ -39,7 +39,7 @@ import static org.keycloak.testsuite.utils.io.IOUtil.setDocElementAttributeValue
public class KcSamlEncryptedAssertionTest extends AbstractKcSamlEncryptedElementsTest {
@Override
protected SamlDocumentStepBuilder.Saml2DocumentTransformer encryptDocument(PublicKey publicKey, String keyEncryptionAlgorithm) {
protected SamlDocumentStepBuilder.Saml2DocumentTransformer encryptDocument(PublicKey publicKey, String keyEncryptionAlgorithm, String keyEncryptionDigestMethod, String keyEncryptionMgfAlgorithm) {
return document -> { // Replace Assertion with EncryptedAssertion
Node assertionElement = document.getDocumentElement()
.getElementsByTagNameNS(ASSERTION_NSURI.get(), JBossSAMLConstants.ASSERTION.get()).item(0);
@ -69,7 +69,7 @@ public class KcSamlEncryptedAssertionTest extends AbstractKcSamlEncryptedElement
// encrypt the Assertion element and replace it with a EncryptedAssertion element.
XMLEncryptionUtil.encryptElement(new QName(JBossSAMLURIConstants.ASSERTION_NSURI.get(),
JBossSAMLConstants.ASSERTION.get(), samlNSPrefix), document, publicKey,
secretKey, encryptionKeySize, encryptedAssertionElementQName, true, keyEncryptionAlgorithm);
secretKey, encryptionKeySize, encryptedAssertionElementQName, true, keyEncryptionAlgorithm, keyEncryptionDigestMethod, keyEncryptionMgfAlgorithm);
} catch (Exception e) {
throw new ProcessingException("failed to encrypt", e);
}

View file

@ -23,7 +23,7 @@ import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.ASSERTION
public class KcSamlEncryptedIdTest extends AbstractKcSamlEncryptedElementsTest {
@Override
protected SamlDocumentStepBuilder.Saml2DocumentTransformer encryptDocument(PublicKey publicKey, String keyEncryptionAlgorithm) {
protected SamlDocumentStepBuilder.Saml2DocumentTransformer encryptDocument(PublicKey publicKey, String keyEncryptionAlgorithm, String keyEncryptionDigestMethod, String keyEncryptionMgfAlgorithm) {
return document -> { // Replace Subject -> NameID with EncryptedId
Node assertionElement = document.getDocumentElement()
.getElementsByTagNameNS(ASSERTION_NSURI.get(), JBossSAMLConstants.ASSERTION.get()).item(0);
@ -54,7 +54,7 @@ public class KcSamlEncryptedIdTest extends AbstractKcSamlEncryptedElementsTest {
// encrypt the Assertion element and replace it with a EncryptedAssertion element.
XMLEncryptionUtil.encryptElement(nameIdQName, document, publicKey,
secretKey, 128, encryptedIdElementQName, true, keyEncryptionAlgorithm);
secretKey, 128, encryptedIdElementQName, true, keyEncryptionAlgorithm, keyEncryptionDigestMethod, keyEncryptionMgfAlgorithm);
} catch (Exception e) {
throw new ProcessingException("failed to encrypt", e);
}

View file

@ -30,11 +30,13 @@ import org.keycloak.testsuite.updaters.IdentityProviderAttributeUpdater;
import java.io.Closeable;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.xml.crypto.dsig.XMLSignature;
@ -234,7 +236,7 @@ public class KcSamlSpDescriptorTest extends AbstractBrokerTest {
Assert.assertNotNull(signingCert);
Assert.assertNotNull(encCert);
Assert.assertNotEquals(signingCert, encCert);
hasEncAlgorithms(spDescriptor, SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifier());
hasEncAlgorithms(spDescriptor, SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifiers());
}
// Enable signing and encryption and set encryption algorithm. Both keys are present and mapped to different realm key (signing to "rsa-generated"m encryption to "rsa-enc-generated")
@ -253,7 +255,7 @@ public class KcSamlSpDescriptorTest extends AbstractBrokerTest {
Assert.assertNotNull(signingCert);
Assert.assertNotNull(encCert);
Assert.assertNotEquals(signingCert, encCert);
hasEncAlgorithms(spDescriptor, SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifier());
hasEncAlgorithms(spDescriptor, SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifiers());
}
}
@ -270,8 +272,8 @@ public class KcSamlSpDescriptorTest extends AbstractBrokerTest {
.update()) {
spDescriptor = getExportedSamlProvider();
hasEncAlgorithms(spDescriptor,
SAMLEncryptionAlgorithms.RSA1_5.getXmlEncIdentifier(),
SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifier()
Stream.concat(Arrays.stream(SAMLEncryptionAlgorithms.RSA1_5.getXmlEncIdentifiers()),
Arrays.stream(SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifiers())).toArray(String[]::new)
);
}
@ -282,7 +284,7 @@ public class KcSamlSpDescriptorTest extends AbstractBrokerTest {
.update()) {
spDescriptor = getExportedSamlProvider();
hasEncAlgorithms(spDescriptor,
SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifier()
SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifiers()
);
}
@ -292,7 +294,7 @@ public class KcSamlSpDescriptorTest extends AbstractBrokerTest {
.update()) {
spDescriptor = getExportedSamlProvider();
hasEncAlgorithms(spDescriptor,
SAMLEncryptionAlgorithms.RSA1_5.getXmlEncIdentifier()
SAMLEncryptionAlgorithms.RSA1_5.getXmlEncIdentifiers()
);
}
}