Adding support for rsa-oaep for SAML encryption
Closes https://github.com/keycloak/keycloak/issues/19689
This commit is contained in:
parent
035fdc4047
commit
04ac3a64ee
10 changed files with 292 additions and 45 deletions
|
@ -73,6 +73,9 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
|
||||||
protected String encryptionAlgorithm = "AES";
|
protected String encryptionAlgorithm = "AES";
|
||||||
protected boolean encrypt;
|
protected boolean encrypt;
|
||||||
protected String canonicalizationMethodType = CanonicalizationMethod.EXCLUSIVE;
|
protected String canonicalizationMethodType = CanonicalizationMethod.EXCLUSIVE;
|
||||||
|
protected String keyEncryptionAlgorithm;
|
||||||
|
protected String keyEncryptionDigestMethod;
|
||||||
|
protected String keyEncryptionMgfAlgorithm;
|
||||||
|
|
||||||
public T canonicalizationMethod(String method) {
|
public T canonicalizationMethod(String method) {
|
||||||
this.canonicalizationMethodType = method;
|
this.canonicalizationMethodType = method;
|
||||||
|
@ -136,6 +139,21 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
|
||||||
return (T)this;
|
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) {
|
public T relayState(String relayState) {
|
||||||
this.relayState = relayState;
|
this.relayState = relayState;
|
||||||
return (T)this;
|
return (T)this;
|
||||||
|
@ -271,8 +289,8 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
|
||||||
|
|
||||||
// encrypt the Assertion element and replace it with a EncryptedAssertion element.
|
// encrypt the Assertion element and replace it with a EncryptedAssertion element.
|
||||||
XMLEncryptionUtil.encryptElement(new QName(JBossSAMLURIConstants.ASSERTION_NSURI.get(),
|
XMLEncryptionUtil.encryptElement(new QName(JBossSAMLURIConstants.ASSERTION_NSURI.get(),
|
||||||
JBossSAMLConstants.ASSERTION.get(), samlNSPrefix), samlDocument, encryptionPublicKey,
|
JBossSAMLConstants.ASSERTION.get(), samlNSPrefix), samlDocument, encryptionPublicKey, secretKey, encryptionKeySize,
|
||||||
secretKey, encryptionKeySize, encryptedAssertionElementQName, true);
|
encryptedAssertionElementQName, true, keyEncryptionAlgorithm, keyEncryptionDigestMethod, keyEncryptionMgfAlgorithm);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ProcessingException("failed to encrypt", e);
|
throw new ProcessingException("failed to encrypt", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,14 +79,16 @@ public class SPMetadataDescriptor {
|
||||||
return entityDescriptor;
|
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();
|
KeyDescriptorType keyDescriptor = new KeyDescriptorType();
|
||||||
keyDescriptor.setUse(use);
|
keyDescriptor.setUse(use);
|
||||||
keyDescriptor.setKeyInfo(keyInfo);
|
keyDescriptor.setKeyInfo(keyInfo);
|
||||||
|
|
||||||
if (algorithm != null) {
|
if (algorithm != null) {
|
||||||
EncryptionMethodType encMethod = new EncryptionMethodType(algorithm);
|
for (String alg : algorithm) {
|
||||||
keyDescriptor.addEncryptionMethod(encMethod);
|
EncryptionMethodType encMethod = new EncryptionMethodType(alg);
|
||||||
|
keyDescriptor.addEncryptionMethod(encMethod);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return keyDescriptor;
|
return keyDescriptor;
|
||||||
|
|
|
@ -99,14 +99,15 @@ public class XMLEncryptionUtil {
|
||||||
* @throws org.keycloak.saml.common.exceptions.ProcessingException
|
* @throws org.keycloak.saml.common.exceptions.ProcessingException
|
||||||
*/
|
*/
|
||||||
private static EncryptedKey encryptKey(Document document, SecretKey keyToBeEncrypted, PublicKey keyUsedToEncryptSecretKey,
|
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;
|
XMLCipher keyCipher;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
keyCipher = XMLCipher.getInstance(encryptionUrlForKeyUnwrap);
|
keyCipher = XMLCipher.getInstance(keyEncryptionAlgorithm, null, keyEncryptionDigestMethod);
|
||||||
|
|
||||||
keyCipher.init(XMLCipher.WRAP_MODE, keyUsedToEncryptSecretKey);
|
keyCipher.init(XMLCipher.WRAP_MODE, keyUsedToEncryptSecretKey);
|
||||||
return keyCipher.encryptKey(document, keyToBeEncrypted);
|
return keyCipher.encryptKey(document, keyToBeEncrypted, keyEncryptionMgfAlgorithm, null);
|
||||||
} catch (XMLEncryptionException e) {
|
} catch (XMLEncryptionException e) {
|
||||||
throw logger.processingError(e);
|
throw logger.processingError(e);
|
||||||
}
|
}
|
||||||
|
@ -115,7 +116,14 @@ public class XMLEncryptionUtil {
|
||||||
public static void encryptElement(QName elementQName, Document document, PublicKey publicKey, SecretKey secretKey,
|
public static void encryptElement(QName elementQName, Document document, PublicKey publicKey, SecretKey secretKey,
|
||||||
int keySize, QName wrappingElementQName, boolean addEncryptedKeyInKeyInfo) throws ProcessingException {
|
int keySize, QName wrappingElementQName, boolean addEncryptedKeyInKeyInfo) throws ProcessingException {
|
||||||
encryptElement(elementQName, document, publicKey, secretKey, keySize, wrappingElementQName, addEncryptedKeyInKeyInfo,
|
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
|
* data
|
||||||
*
|
*
|
||||||
* @param elementQName QName of the element that we like to encrypt
|
* @param elementQName QName of the element that we like to encrypt
|
||||||
* @param document
|
* @param document The document with the element to encrypt
|
||||||
* @param publicKey
|
* @param publicKey The public Key to wrap the secret key
|
||||||
* @param secretKey
|
* @param secretKey The secret key to use for encryption
|
||||||
* @param keySize
|
* @param keySize The size of the public key
|
||||||
* @param wrappingElementQName A QName of an element that will wrap the encrypted element
|
* @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 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
|
* @throws ProcessingException
|
||||||
*/
|
*/
|
||||||
public static void encryptElement(QName elementQName, Document document, PublicKey publicKey, SecretKey secretKey,
|
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)
|
if (elementQName == null)
|
||||||
throw logger.nullArgumentError("elementQName");
|
throw logger.nullArgumentError("elementQName");
|
||||||
if (document == null)
|
if (document == null)
|
||||||
|
@ -148,7 +160,11 @@ public class XMLEncryptionUtil {
|
||||||
throw logger.domMissingDocElementError(elementQName.toString());
|
throw logger.domMissingDocElementError(elementQName.toString());
|
||||||
|
|
||||||
XMLCipher cipher = null;
|
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);
|
String encryptionAlgorithm = getXMLEncryptionURL(secretKey.getAlgorithm(), keySize);
|
||||||
// Encrypt the Document
|
// Encrypt the Document
|
||||||
|
|
|
@ -397,7 +397,7 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
||||||
throw new RuntimeException(e);
|
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());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
|
|
@ -20,40 +20,73 @@ package org.keycloak.protocol.saml;
|
||||||
import org.apache.xml.security.encryption.XMLCipher;
|
import org.apache.xml.security.encryption.XMLCipher;
|
||||||
import org.keycloak.crypto.Algorithm;
|
import org.keycloak.crypto.Algorithm;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
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.
|
* 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.
|
* It is used to make sure we are using keys generated for given algorithm only with that algorithm.
|
||||||
*/
|
*/
|
||||||
public enum SAMLEncryptionAlgorithms {
|
public enum SAMLEncryptionAlgorithms {
|
||||||
RSA_OAEP(XMLCipher.RSA_OAEP, Algorithm.RSA_OAEP),
|
RSA_OAEP(Algorithm.RSA_OAEP, XMLCipher.RSA_OAEP, XMLCipher.RSA_OAEP_11),
|
||||||
RSA1_5(XMLCipher.RSA_v1dot5, Algorithm.RSA1_5);
|
RSA1_5(Algorithm.RSA1_5, XMLCipher.RSA_v1dot5);
|
||||||
|
|
||||||
private String xmlEncIdentifier;
|
private final String[] xmlEncIdentifier;
|
||||||
private String keycloakIdentifier;
|
private final 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;
|
||||||
private static final Map<String, SAMLEncryptionAlgorithms> forKeycloakIdentifier = Arrays.stream(values()).collect(Collectors.toMap(SAMLEncryptionAlgorithms::getKeycloakIdentifier, Function.identity()));
|
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.xmlEncIdentifier = xmlEncIdentifier;
|
||||||
this.keycloakIdentifier = keycloakIdentifier;
|
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;
|
return xmlEncIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for the keycloak identifier.
|
||||||
|
* @return The keycloak identifier.
|
||||||
|
*/
|
||||||
public String getKeycloakIdentifier() {
|
public String getKeycloakIdentifier() {
|
||||||
return keycloakIdentifier;
|
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) {
|
public static SAMLEncryptionAlgorithms forXMLEncIdentifier(String xmlEncIdentifier) {
|
||||||
return forXMLEncIdentifier.get(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) {
|
public static SAMLEncryptionAlgorithms forKeycloakIdentifier(String keycloakIdentifier) {
|
||||||
return forKeycloakIdentifier.get(keycloakIdentifier);
|
return forKeycloakIdentifier.get(keycloakIdentifier);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.broker;
|
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.hamcrest.Matchers;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -25,7 +27,6 @@ import org.keycloak.common.util.PemUtils;
|
||||||
import org.keycloak.crypto.Algorithm;
|
import org.keycloak.crypto.Algorithm;
|
||||||
import org.keycloak.crypto.KeyUse;
|
import org.keycloak.crypto.KeyUse;
|
||||||
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
|
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
|
||||||
import org.keycloak.protocol.saml.SAMLEncryptionAlgorithms;
|
|
||||||
import org.keycloak.representations.idm.KeysMetadataRepresentation;
|
import org.keycloak.representations.idm.KeysMetadataRepresentation;
|
||||||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||||
import org.keycloak.saml.common.exceptions.ConfigurationException;
|
import org.keycloak.saml.common.exceptions.ConfigurationException;
|
||||||
|
@ -75,14 +76,14 @@ public abstract class AbstractKcSamlEncryptedElementsTest extends AbstractBroker
|
||||||
public void testEncryptedElementIsReadable() throws ConfigurationException, ParsingException, ProcessingException {
|
public void testEncryptedElementIsReadable() throws ConfigurationException, ParsingException, ProcessingException {
|
||||||
KeysMetadataRepresentation.KeyMetadataRepresentation activeEncryptingKey = KeyUtils.findActiveEncryptingKey(adminClient.realm(bc.consumerRealmName()), Algorithm.RSA_OAEP);
|
KeysMetadataRepresentation.KeyMetadataRepresentation activeEncryptingKey = KeyUtils.findActiveEncryptingKey(adminClient.realm(bc.consumerRealmName()), Algorithm.RSA_OAEP);
|
||||||
assertThat(activeEncryptingKey.getProviderId(), equalTo(encProviderId));
|
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
|
@Test
|
||||||
public void testSignatureKeyEncryptedElementIsNotReadableWithoutDeprecatedMode() throws ConfigurationException, ParsingException, ProcessingException {
|
public void testSignatureKeyEncryptedElementIsNotReadableWithoutDeprecatedMode() throws ConfigurationException, ParsingException, ProcessingException {
|
||||||
KeysMetadataRepresentation.KeyMetadataRepresentation activeSignatureKey = KeyUtils.findActiveSigningKey(adminClient.realm(bc.consumerRealmName()));
|
KeysMetadataRepresentation.KeyMetadataRepresentation activeSignatureKey = KeyUtils.findActiveSigningKey(adminClient.realm(bc.consumerRealmName()));
|
||||||
assertThat(activeSignatureKey.getProviderId(), equalTo(sigProviderId));
|
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
|
@Test
|
||||||
|
@ -94,7 +95,7 @@ public abstract class AbstractKcSamlEncryptedElementsTest extends AbstractBroker
|
||||||
});
|
});
|
||||||
KeysMetadataRepresentation.KeyMetadataRepresentation activeSignatureKey = KeyUtils.findActiveSigningKey(adminClient.realm(bc.consumerRealmName()));
|
KeysMetadataRepresentation.KeyMetadataRepresentation activeSignatureKey = KeyUtils.findActiveSigningKey(adminClient.realm(bc.consumerRealmName()));
|
||||||
assertThat(activeSignatureKey.getProviderId(), equalTo(sigProviderId));
|
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 {
|
} finally {
|
||||||
// Clear flag
|
// Clear flag
|
||||||
testingClient.server().run(session -> {
|
testingClient.server().run(session -> {
|
||||||
|
@ -111,13 +112,21 @@ public abstract class AbstractKcSamlEncryptedElementsTest extends AbstractBroker
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(() -> new RuntimeException("Cannot find key created on the previous line"));
|
.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());
|
createRolesForRealm(bc.consumerRealmName());
|
||||||
|
|
||||||
AuthnRequestType loginRep = SamlClient.createLoginRequestDocument(SAML_CLIENT_ID_SALES_POST + ".dot/ted", getConsumerRoot() + "/sales-post/saml", null);
|
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()
|
.login().user(bc.getUserLogin(), bc.getUserPassword()).build()
|
||||||
|
|
||||||
.processSamlResponse(SamlClient.Binding.POST) // Response from producer IdP
|
.processSamlResponse(SamlClient.Binding.POST) // Response from producer IdP
|
||||||
.transformDocument(encryptDocument(publicKey, keyEncryptionAlgorithm))
|
.transformDocument(encryptDocument(publicKey, keyEncryptionAlgorithm, keyEncryptionDigestMethod, keyEncryptionMgfAlgorithm))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
if (shouldPass) {
|
if (shouldPass) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ import static org.keycloak.testsuite.utils.io.IOUtil.setDocElementAttributeValue
|
||||||
public class KcSamlEncryptedAssertionTest extends AbstractKcSamlEncryptedElementsTest {
|
public class KcSamlEncryptedAssertionTest extends AbstractKcSamlEncryptedElementsTest {
|
||||||
|
|
||||||
@Override
|
@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
|
return document -> { // Replace Assertion with EncryptedAssertion
|
||||||
Node assertionElement = document.getDocumentElement()
|
Node assertionElement = document.getDocumentElement()
|
||||||
.getElementsByTagNameNS(ASSERTION_NSURI.get(), JBossSAMLConstants.ASSERTION.get()).item(0);
|
.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.
|
// encrypt the Assertion element and replace it with a EncryptedAssertion element.
|
||||||
XMLEncryptionUtil.encryptElement(new QName(JBossSAMLURIConstants.ASSERTION_NSURI.get(),
|
XMLEncryptionUtil.encryptElement(new QName(JBossSAMLURIConstants.ASSERTION_NSURI.get(),
|
||||||
JBossSAMLConstants.ASSERTION.get(), samlNSPrefix), document, publicKey,
|
JBossSAMLConstants.ASSERTION.get(), samlNSPrefix), document, publicKey,
|
||||||
secretKey, encryptionKeySize, encryptedAssertionElementQName, true, keyEncryptionAlgorithm);
|
secretKey, encryptionKeySize, encryptedAssertionElementQName, true, keyEncryptionAlgorithm, keyEncryptionDigestMethod, keyEncryptionMgfAlgorithm);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ProcessingException("failed to encrypt", e);
|
throw new ProcessingException("failed to encrypt", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.ASSERTION
|
||||||
public class KcSamlEncryptedIdTest extends AbstractKcSamlEncryptedElementsTest {
|
public class KcSamlEncryptedIdTest extends AbstractKcSamlEncryptedElementsTest {
|
||||||
|
|
||||||
@Override
|
@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
|
return document -> { // Replace Subject -> NameID with EncryptedId
|
||||||
Node assertionElement = document.getDocumentElement()
|
Node assertionElement = document.getDocumentElement()
|
||||||
.getElementsByTagNameNS(ASSERTION_NSURI.get(), JBossSAMLConstants.ASSERTION.get()).item(0);
|
.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.
|
// encrypt the Assertion element and replace it with a EncryptedAssertion element.
|
||||||
XMLEncryptionUtil.encryptElement(nameIdQName, document, publicKey,
|
XMLEncryptionUtil.encryptElement(nameIdQName, document, publicKey,
|
||||||
secretKey, 128, encryptedIdElementQName, true, keyEncryptionAlgorithm);
|
secretKey, 128, encryptedIdElementQName, true, keyEncryptionAlgorithm, keyEncryptionDigestMethod, keyEncryptionMgfAlgorithm);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ProcessingException("failed to encrypt", e);
|
throw new ProcessingException("failed to encrypt", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,11 +30,13 @@ import org.keycloak.testsuite.updaters.IdentityProviderAttributeUpdater;
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.xml.crypto.dsig.XMLSignature;
|
import javax.xml.crypto.dsig.XMLSignature;
|
||||||
|
|
||||||
|
@ -234,7 +236,7 @@ public class KcSamlSpDescriptorTest extends AbstractBrokerTest {
|
||||||
Assert.assertNotNull(signingCert);
|
Assert.assertNotNull(signingCert);
|
||||||
Assert.assertNotNull(encCert);
|
Assert.assertNotNull(encCert);
|
||||||
Assert.assertNotEquals(signingCert, 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")
|
// 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(signingCert);
|
||||||
Assert.assertNotNull(encCert);
|
Assert.assertNotNull(encCert);
|
||||||
Assert.assertNotEquals(signingCert, 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()) {
|
.update()) {
|
||||||
spDescriptor = getExportedSamlProvider();
|
spDescriptor = getExportedSamlProvider();
|
||||||
hasEncAlgorithms(spDescriptor,
|
hasEncAlgorithms(spDescriptor,
|
||||||
SAMLEncryptionAlgorithms.RSA1_5.getXmlEncIdentifier(),
|
Stream.concat(Arrays.stream(SAMLEncryptionAlgorithms.RSA1_5.getXmlEncIdentifiers()),
|
||||||
SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifier()
|
Arrays.stream(SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifiers())).toArray(String[]::new)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +284,7 @@ public class KcSamlSpDescriptorTest extends AbstractBrokerTest {
|
||||||
.update()) {
|
.update()) {
|
||||||
spDescriptor = getExportedSamlProvider();
|
spDescriptor = getExportedSamlProvider();
|
||||||
hasEncAlgorithms(spDescriptor,
|
hasEncAlgorithms(spDescriptor,
|
||||||
SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifier()
|
SAMLEncryptionAlgorithms.RSA_OAEP.getXmlEncIdentifiers()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +294,7 @@ public class KcSamlSpDescriptorTest extends AbstractBrokerTest {
|
||||||
.update()) {
|
.update()) {
|
||||||
spDescriptor = getExportedSamlProvider();
|
spDescriptor = getExportedSamlProvider();
|
||||||
hasEncAlgorithms(spDescriptor,
|
hasEncAlgorithms(spDescriptor,
|
||||||
SAMLEncryptionAlgorithms.RSA1_5.getXmlEncIdentifier()
|
SAMLEncryptionAlgorithms.RSA1_5.getXmlEncIdentifiers()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue