KEYCLOAK-4057 Do not include KeyName for brokered IdPs

Active Directory Federation Services require that the subject name
matches KeyName element when present. While KeyName is beneficial for
Keycloak adapters, it breaks functionality for AD FS as the name
included there is a key ID, not certificate subject expected by AD FS.

This patch contains functionality that excludes KeyName from SAML
messages to identity providers. This behaviour should be made
configurable per client/identity provider and is prepared to do so,
however actual GUI changes are left for a separate patch.
This commit is contained in:
Hynek Mlnarik 2016-12-09 14:33:40 +01:00
parent d3e3990d77
commit 24a36e6848
12 changed files with 156 additions and 50 deletions

View file

@ -58,7 +58,7 @@ import static org.keycloak.saml.common.util.StringUtil.isNotNull;
public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
protected static final Logger logger = Logger.getLogger(BaseSAML2BindingBuilder.class);
protected String signingKeyId;
protected String signingKeyName;
protected KeyPair signingKeyPair;
protected X509Certificate signingCertificate;
protected boolean sign;
@ -86,27 +86,27 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
return (T)this;
}
public T signWith(String signingKeyId, KeyPair keyPair) {
this.signingKeyId = signingKeyId;
public T signWith(String signingKeyName, KeyPair keyPair) {
this.signingKeyName = signingKeyName;
this.signingKeyPair = keyPair;
return (T)this;
}
public T signWith(String signingKeyId, PrivateKey privateKey, PublicKey publicKey) {
this.signingKeyId = signingKeyId;
public T signWith(String signingKeyName, PrivateKey privateKey, PublicKey publicKey) {
this.signingKeyName = signingKeyName;
this.signingKeyPair = new KeyPair(publicKey, privateKey);
return (T)this;
}
public T signWith(String signingKeyId, KeyPair keyPair, X509Certificate cert) {
this.signingKeyId = signingKeyId;
public T signWith(String signingKeyName, KeyPair keyPair, X509Certificate cert) {
this.signingKeyName = signingKeyName;
this.signingKeyPair = keyPair;
this.signingCertificate = cert;
return (T)this;
}
public T signWith(String signingKeyId, PrivateKey privateKey, PublicKey publicKey, X509Certificate cert) {
this.signingKeyId = signingKeyId;
public T signWith(String signingKeyName, PrivateKey privateKey, PublicKey publicKey, X509Certificate cert) {
this.signingKeyName = signingKeyName;
this.signingKeyPair = new KeyPair(publicKey, privateKey);
this.signingCertificate = cert;
return (T)this;
@ -271,7 +271,7 @@ public class BaseSAML2BindingBuilder<T extends BaseSAML2BindingBuilder> {
samlSignature.setX509Certificate(signingCertificate);
}
samlSignature.signSAMLDocument(samlDocument, signingKeyId, signingKeyPair, canonicalizationMethodType);
samlSignature.signSAMLDocument(samlDocument, signingKeyName, signingKeyPair, canonicalizationMethodType);
}
public void signAssertion(Document samlDocument) throws ProcessingException {

View file

@ -0,0 +1,50 @@
/*
* Copyright 2016 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.saml.common.util;
import java.security.cert.X509Certificate;
/**
*
* @author hmlnarik
*/
public enum XmlKeyInfoKeyNameTransformer {
NONE { @Override public String getKeyName(String keyId, X509Certificate certificate) { return null; } },
KEY_ID { @Override public String getKeyName(String keyId, X509Certificate certificate) { return keyId; } },
CERT_SUBJECT { @Override public String getKeyName(String keyId, X509Certificate certificate) {
return certificate == null
? null
: (certificate.getSubjectDN() == null
? null
: certificate.getSubjectDN().getName());
} }
;
public abstract String getKeyName(String keyId, X509Certificate certificate);
public static XmlKeyInfoKeyNameTransformer from(String name, XmlKeyInfoKeyNameTransformer defaultValue) {
if (name == null) {
return defaultValue;
}
try {
return valueOf(name);
} catch (IllegalArgumentException ex) {
return defaultValue;
}
}
}

View file

@ -121,7 +121,7 @@ public class SAML2Signature {
* @throws MarshalException
* @throws GeneralSecurityException
*/
public Document sign(Document doc, String referenceID, String keyId, KeyPair keyPair, String canonicalizationMethodType) throws ParserConfigurationException,
public Document sign(Document doc, String referenceID, String keyName, KeyPair keyPair, String canonicalizationMethodType) throws ParserConfigurationException,
GeneralSecurityException, MarshalException, XMLSignatureException {
String referenceURI = "#" + referenceID;
@ -130,7 +130,7 @@ public class SAML2Signature {
if (sibling != null) {
SignatureUtilTransferObject dto = new SignatureUtilTransferObject();
dto.setDocumentToBeSigned(doc);
dto.setKeyId(keyId);
dto.setKeyName(keyName);
dto.setKeyPair(keyPair);
dto.setDigestMethod(digestMethod);
dto.setSignatureMethod(signatureMethod);
@ -143,7 +143,7 @@ public class SAML2Signature {
return XMLSignatureUtil.sign(dto, canonicalizationMethodType);
}
return XMLSignatureUtil.sign(doc, keyId, keyPair, digestMethod, signatureMethod, referenceURI, canonicalizationMethodType);
return XMLSignatureUtil.sign(doc, keyName, keyPair, digestMethod, signatureMethod, referenceURI, canonicalizationMethodType);
}
/**
@ -154,11 +154,11 @@ public class SAML2Signature {
*
* @throws org.keycloak.saml.common.exceptions.ProcessingException
*/
public void signSAMLDocument(Document samlDocument, String keyId, KeyPair keypair, String canonicalizationMethodType) throws ProcessingException {
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);
try {
sign(samlDocument, id, keyId, keypair, canonicalizationMethodType);
sign(samlDocument, id, keyName, keypair, canonicalizationMethodType);
} catch (ParserConfigurationException | GeneralSecurityException | MarshalException | XMLSignatureException e) {
throw new ProcessingException(logger.signatureError(e));
}

View file

@ -33,7 +33,7 @@ public class SignatureUtilTransferObject {
private Document documentToBeSigned;
private String keyId;
private String keyName;
private KeyPair keyPair;
@ -115,11 +115,11 @@ public class SignatureUtilTransferObject {
this.x509Certificate = x509Certificate;
}
public String getKeyId() {
return keyId;
public String getKeyName() {
return keyName;
}
public void setKeyId(String keyId) {
this.keyId = keyId;
public void setKeyName(String keyName) {
this.keyName = keyName;
}
}

View file

@ -216,7 +216,7 @@ public class XMLSignatureUtil {
* @throws MarshalException
* @throws GeneralSecurityException
*/
public static Document sign(Document doc, Node nodeToBeSigned, String keyId, KeyPair keyPair, String digestMethod,
public static Document sign(Document doc, Node nodeToBeSigned, String keyName, KeyPair keyPair, String digestMethod,
String signatureMethod, String referenceURI, X509Certificate x509Certificate,
String canonicalizationMethodType) throws ParserConfigurationException, GeneralSecurityException,
MarshalException, XMLSignatureException {
@ -238,7 +238,7 @@ public class XMLSignatureUtil {
if (!referenceURI.isEmpty()) {
propagateIDAttributeSetup(nodeToBeSigned, newDoc.getDocumentElement());
}
newDoc = sign(newDoc, keyId, keyPair, digestMethod, signatureMethod, referenceURI, x509Certificate, canonicalizationMethodType);
newDoc = sign(newDoc, keyName, keyPair, digestMethod, signatureMethod, referenceURI, x509Certificate, canonicalizationMethodType);
// if the signed element is a SAMLv2.0 assertion we need to move the signature element to the position
// specified in the schema (before the assertion subject element).
@ -279,10 +279,10 @@ public class XMLSignatureUtil {
* @throws MarshalException
* @throws XMLSignatureException
*/
public static void sign(Element elementToSign, Node nextSibling, String keyId, KeyPair keyPair, String digestMethod,
public static void sign(Element elementToSign, Node nextSibling, String keyName, KeyPair keyPair, String digestMethod,
String signatureMethod, String referenceURI, String canonicalizationMethodType)
throws GeneralSecurityException, MarshalException, XMLSignatureException {
sign(elementToSign, nextSibling, keyId, keyPair, digestMethod, signatureMethod, referenceURI, null, canonicalizationMethodType);
sign(elementToSign, nextSibling, keyName, keyPair, digestMethod, signatureMethod, referenceURI, null, canonicalizationMethodType);
}
/**
@ -301,7 +301,7 @@ public class XMLSignatureUtil {
* @throws XMLSignatureException
* @since 2.5.0
*/
public static void sign(Element elementToSign, Node nextSibling, String keyId, KeyPair keyPair, String digestMethod,
public static void sign(Element elementToSign, Node nextSibling, String keyName, KeyPair keyPair, String digestMethod,
String signatureMethod, String referenceURI, X509Certificate x509Certificate, String canonicalizationMethodType)
throws GeneralSecurityException, MarshalException, XMLSignatureException {
PrivateKey signingKey = keyPair.getPrivate();
@ -309,7 +309,7 @@ public class XMLSignatureUtil {
DOMSignContext dsc = new DOMSignContext(signingKey, elementToSign, nextSibling);
signImpl(dsc, digestMethod, signatureMethod, referenceURI, keyId, publicKey, x509Certificate, canonicalizationMethodType);
signImpl(dsc, digestMethod, signatureMethod, referenceURI, keyName, publicKey, x509Certificate, canonicalizationMethodType);
}
/**
@ -343,9 +343,9 @@ public class XMLSignatureUtil {
* @throws XMLSignatureException
* @throws MarshalException
*/
public static Document sign(Document doc, String keyId, KeyPair keyPair, String digestMethod, String signatureMethod, String referenceURI, String canonicalizationMethodType)
public static Document sign(Document doc, String keyName, KeyPair keyPair, String digestMethod, String signatureMethod, String referenceURI, String canonicalizationMethodType)
throws GeneralSecurityException, MarshalException, XMLSignatureException {
return sign(doc, keyId, keyPair, digestMethod, signatureMethod, referenceURI, null, canonicalizationMethodType);
return sign(doc, keyName, keyPair, digestMethod, signatureMethod, referenceURI, null, canonicalizationMethodType);
}
/**
@ -363,7 +363,7 @@ public class XMLSignatureUtil {
* @throws MarshalException
* @since 2.5.0
*/
public static Document sign(Document doc, String keyId, KeyPair keyPair, String digestMethod, String signatureMethod, String referenceURI,
public static Document sign(Document doc, String keyName, KeyPair keyPair, String digestMethod, String signatureMethod, String referenceURI,
X509Certificate x509Certificate, String canonicalizationMethodType)
throws GeneralSecurityException, MarshalException, XMLSignatureException {
logger.trace("Document to be signed=" + DocumentUtil.asString(doc));
@ -372,7 +372,7 @@ public class XMLSignatureUtil {
DOMSignContext dsc = new DOMSignContext(signingKey, doc.getDocumentElement());
signImpl(dsc, digestMethod, signatureMethod, referenceURI, keyId, publicKey, x509Certificate, canonicalizationMethodType);
signImpl(dsc, digestMethod, signatureMethod, referenceURI, keyName, publicKey, x509Certificate, canonicalizationMethodType);
return doc;
}
@ -390,7 +390,7 @@ public class XMLSignatureUtil {
public static Document sign(SignatureUtilTransferObject dto, String canonicalizationMethodType) throws GeneralSecurityException, MarshalException,
XMLSignatureException {
Document doc = dto.getDocumentToBeSigned();
String keyId = dto.getKeyId();
String keyName = dto.getKeyName();
KeyPair keyPair = dto.getKeyPair();
Node nextSibling = dto.getNextSibling();
String digestMethod = dto.getDigestMethod();
@ -404,7 +404,7 @@ public class XMLSignatureUtil {
DOMSignContext dsc = new DOMSignContext(signingKey, doc.getDocumentElement(), nextSibling);
signImpl(dsc, digestMethod, signatureMethod, referenceURI, keyId, publicKey, dto.getX509Certificate(), canonicalizationMethodType);
signImpl(dsc, digestMethod, signatureMethod, referenceURI, keyName, publicKey, dto.getX509Certificate(), canonicalizationMethodType);
return doc;
}
@ -694,7 +694,7 @@ public class XMLSignatureUtil {
throw logger.unsupportedType(key.toString());
}
private static void signImpl(DOMSignContext dsc, String digestMethod, String signatureMethod, String referenceURI, String keyId, PublicKey publicKey,
private static void signImpl(DOMSignContext dsc, String digestMethod, String signatureMethod, String referenceURI, String keyName, PublicKey publicKey,
X509Certificate x509Certificate, String canonicalizationMethodType)
throws GeneralSecurityException, MarshalException, XMLSignatureException {
dsc.setDefaultNamespacePrefix("dsig");
@ -718,22 +718,22 @@ public class XMLSignatureUtil {
KeyInfo ki;
if (includeKeyInfoInSignature) {
ki = createKeyInfo(keyId, publicKey, x509Certificate);
ki = createKeyInfo(keyName, publicKey, x509Certificate);
} else {
ki = createKeyInfo(keyId, null, null);
ki = createKeyInfo(keyName, null, null);
}
XMLSignature signature = fac.newXMLSignature(si, ki);
signature.sign(dsc);
}
private static KeyInfo createKeyInfo(String keyId, PublicKey publicKey, X509Certificate x509Certificate) throws KeyException {
private static KeyInfo createKeyInfo(String keyName, PublicKey publicKey, X509Certificate x509Certificate) throws KeyException {
KeyInfoFactory keyInfoFactory = fac.getKeyInfoFactory();
List<Object> items = new LinkedList<>();
if (keyId != null) {
items.add(keyInfoFactory.newKeyName(keyId));
if (keyName != null) {
items.add(keyInfoFactory.newKeyName(keyName));
}
if (x509Certificate != null) {

View file

@ -302,11 +302,12 @@ public class SAMLEndpoint {
boolean postBinding = config.isPostBindingResponse();
if (config.isWantAuthnRequestsSigned()) {
KeyManager.ActiveKey keys = session.keys().getActiveKey(realm);
binding.signWith(keys.getKid(), keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate())
String keyName = config.getXmlSigKeyInfoKeyNameTransformer().getKeyName(keys.getKid(), keys.getCertificate());
binding.signWith(keyName, keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate())
.signatureAlgorithm(provider.getSignatureAlgorithm())
.signDocument();
if (! postBinding && config.isAddExtensionsElementWithKeyInfo()) { // Only include extension if REDIRECT binding and signing whole SAML protocol message
builder.addExtension(new KeycloakKeySamlExtensionGenerator(keys.getKid()));
builder.addExtension(new KeycloakKeySamlExtensionGenerator(keyName));
}
}
try {

View file

@ -107,11 +107,12 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
KeyPair keypair = new KeyPair(keys.getPublicKey(), keys.getPrivateKey());
binding.signWith(keys.getKid(), keypair);
String keyName = getConfig().getXmlSigKeyInfoKeyNameTransformer().getKeyName(keys.getKid(), keys.getCertificate());
binding.signWith(keyName, keypair);
binding.signatureAlgorithm(getSignatureAlgorithm());
binding.signDocument();
if (! postBinding && getConfig().isAddExtensionsElementWithKeyInfo()) { // Only include extension if REDIRECT binding and signing whole SAML protocol message
authnRequestBuilder.addExtension(new KeycloakKeySamlExtensionGenerator(keys.getKid()));
authnRequestBuilder.addExtension(new KeycloakKeySamlExtensionGenerator(keyName));
}
}
@ -205,7 +206,8 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
.relayState(userSession.getId());
if (getConfig().isWantAuthnRequestsSigned()) {
KeyManager.ActiveKey keys = session.keys().getActiveKey(realm);
binding.signWith(keys.getKid(), keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate())
String keyName = getConfig().getXmlSigKeyInfoKeyNameTransformer().getKeyName(keys.getKid(), keys.getCertificate());
binding.signWith(keyName, keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate())
.signatureAlgorithm(getSignatureAlgorithm())
.signDocument();
}

View file

@ -18,11 +18,15 @@ package org.keycloak.broker.saml;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.saml.common.util.XmlKeyInfoKeyNameTransformer;
/**
* @author Pedro Igor
*/
public class SAMLIdentityProviderConfig extends IdentityProviderModel {
public static final XmlKeyInfoKeyNameTransformer DEFAULT_XML_KEY_INFO_KEY_NAME_TRANSFORMER = XmlKeyInfoKeyNameTransformer.NONE;
public SAMLIdentityProviderConfig() {
}
@ -165,4 +169,19 @@ public class SAMLIdentityProviderConfig extends IdentityProviderModel {
getConfig().put("backchannelSupported", String.valueOf(backchannel));
}
/**
* Always returns non-{@code null} result.
* @return Configured ransformer of {@link #DEFAULT_XML_KEY_INFO_KEY_NAME_TRANSFORMER} if not set.
*/
public XmlKeyInfoKeyNameTransformer getXmlSigKeyInfoKeyNameTransformer() {
return XmlKeyInfoKeyNameTransformer.from(getConfig().get("xmlSigKeyInfoKeyNameTransformer"), DEFAULT_XML_KEY_INFO_KEY_NAME_TRANSFORMER);
}
public void setXmlSigKeyInfoKeyNameTransformer(XmlKeyInfoKeyNameTransformer xmlSigKeyInfoKeyNameTransformer) {
getConfig().put("xmlSigKeyInfoKeyNameTransformer",
xmlSigKeyInfoKeyNameTransformer == null
? null
: xmlSigKeyInfoKeyNameTransformer.name());
}
}

View file

@ -21,6 +21,7 @@ import org.keycloak.models.ClientConfigResolver;
import org.keycloak.models.ClientModel;
import org.keycloak.saml.SignatureAlgorithm;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.util.XmlKeyInfoKeyNameTransformer;
/**
* Configuration of a SAML-enabled client.
@ -30,6 +31,8 @@ import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
*/
public class SamlClient extends ClientConfigResolver {
public static final XmlKeyInfoKeyNameTransformer DEFAULT_XML_KEY_INFO_KEY_NAME_TRANSFORMER = XmlKeyInfoKeyNameTransformer.KEY_ID;
public SamlClient(ClientModel client) {
super(client);
}
@ -198,4 +201,21 @@ public class SamlClient extends ClientConfigResolver {
}
/**
* Always returns non-{@code null} result.
* @return Configured ransformer of {@link #DEFAULT_XML_KEY_INFO_KEY_NAME_TRANSFORMER} if not set.
*/
public XmlKeyInfoKeyNameTransformer getXmlSigKeyInfoKeyNameTransformer() {
return XmlKeyInfoKeyNameTransformer.from(
client.getAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER),
DEFAULT_XML_KEY_INFO_KEY_NAME_TRANSFORMER);
}
public void setXmlSigKeyInfoKeyNameTransformer(XmlKeyInfoKeyNameTransformer xmlSigKeyInfoKeyNameTransformer) {
client.setAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER,
xmlSigKeyInfoKeyNameTransformer == null
? null
: xmlSigKeyInfoKeyNameTransformer.name());
}
}

View file

@ -32,6 +32,7 @@ public interface SamlConfigAttributes {
String SAML_FORCE_NAME_ID_FORMAT_ATTRIBUTE = "saml_force_name_id_format";
String SAML_SERVER_SIGNATURE = "saml.server.signature";
String SAML_SERVER_SIGNATURE_KEYINFO_EXT = "saml.server.signature.keyinfo.ext";
String SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER = "saml.server.signature.keyinfo.xmlSigKeyInfoKeyNameTransformer";
String SAML_FORCE_POST_BINDING = "saml.force.post.binding";
String SAML_ASSERTION_SIGNATURE = "saml.assertion.signature";
String SAML_ENCRYPT = "saml.encrypt";

View file

@ -25,6 +25,7 @@ import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.jboss.logging.Logger;
import org.keycloak.connections.httpclient.HttpClientProvider;
import org.keycloak.dom.saml.v2.assertion.AssertionType;
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
@ -54,11 +55,13 @@ import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ConfigurationException;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.exceptions.ProcessingException;
import org.keycloak.saml.common.util.XmlKeyInfoKeyNameTransformer;
import org.keycloak.services.ErrorPage;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.RealmsResource;
import org.w3c.dom.Document;
import javax.ws.rs.core.HttpHeaders;
@ -77,6 +80,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
/**
@ -101,6 +105,7 @@ public class SamlProtocol implements LoginProtocol {
public static final String SAML_REQUEST_ID = "SAML_REQUEST_ID";
public static final String SAML_LOGOUT_BINDING = "saml.logout.binding";
public static final String SAML_LOGOUT_ADD_EXTENSIONS_ELEMENT_WITH_KEY_INFO = "saml.logout.addExtensionsElementWithKeyInfo";
public static final String SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER = "SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER";
public static final String SAML_LOGOUT_REQUEST_ID = "SAML_LOGOUT_REQUEST_ID";
public static final String SAML_LOGOUT_RELAY_STATE = "SAML_LOGOUT_RELAY_STATE";
public static final String SAML_LOGOUT_CANONICALIZATION = "SAML_LOGOUT_CANONICALIZATION";
@ -379,10 +384,11 @@ public class SamlProtocol implements LoginProtocol {
KeyManager keyManager = session.keys();
KeyManager.ActiveKey keys = keyManager.getActiveKey(realm);
boolean postBinding = isPostBinding(clientSession);
String keyName = samlClient.getXmlSigKeyInfoKeyNameTransformer().getKeyName(keys.getKid(), keys.getCertificate());
try {
if ((! postBinding) && samlClient.requiresRealmSignature() && samlClient.addExtensionsElementWithKeyInfo()) {
builder.addExtension(new KeycloakKeySamlExtensionGenerator(keys.getKid()));
builder.addExtension(new KeycloakKeySamlExtensionGenerator(keyName));
}
ResponseType samlModel = builder.buildModel();
@ -410,14 +416,14 @@ public class SamlProtocol implements LoginProtocol {
if (canonicalization != null) {
bindingBuilder.canonicalizationMethod(canonicalization);
}
bindingBuilder.signatureAlgorithm(samlClient.getSignatureAlgorithm()).signWith(keys.getKid(), keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()).signDocument();
bindingBuilder.signatureAlgorithm(samlClient.getSignatureAlgorithm()).signWith(keyName, keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()).signDocument();
}
if (samlClient.requiresAssertionSignature()) {
String canonicalization = samlClient.getCanonicalizationMethod();
if (canonicalization != null) {
bindingBuilder.canonicalizationMethod(canonicalization);
}
bindingBuilder.signatureAlgorithm(samlClient.getSignatureAlgorithm()).signWith(keys.getKid(), keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()).signAssertions();
bindingBuilder.signatureAlgorithm(samlClient.getSignatureAlgorithm()).signWith(keyName, keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()).signAssertions();
}
if (samlClient.requiresEncryption()) {
PublicKey publicKey = null;
@ -513,7 +519,8 @@ public class SamlProtocol implements LoginProtocol {
SAML2LogoutRequestBuilder logoutBuilder = createLogoutRequest(bindingUri, clientSession, client);
if (samlClient.requiresRealmSignature() && samlClient.addExtensionsElementWithKeyInfo()) {
KeyManager.ActiveKey keys = session.keys().getActiveKey(realm);
logoutBuilder.addExtension(new KeycloakKeySamlExtensionGenerator(keys.getKid()));
String keyName = samlClient.getXmlSigKeyInfoKeyNameTransformer().getKeyName(keys.getKid(), keys.getCertificate());
logoutBuilder.addExtension(new KeycloakKeySamlExtensionGenerator(keyName));
}
JaxrsSAML2BindingBuilder binding = createBindingBuilder(samlClient);
return binding.redirectBinding(logoutBuilder.buildDocument()).request(bindingUri);
@ -555,10 +562,14 @@ public class SamlProtocol implements LoginProtocol {
binding.canonicalizationMethod(canonicalization);
}
KeyManager.ActiveKey keys = session.keys().getActiveKey(realm);
binding.signatureAlgorithm(algorithm).signWith(keys.getKid(), keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()).signDocument();
XmlKeyInfoKeyNameTransformer transformer = XmlKeyInfoKeyNameTransformer.from(
userSession.getNote(SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER),
SamlClient.DEFAULT_XML_KEY_INFO_KEY_NAME_TRANSFORMER);
String keyName = transformer.getKeyName(keys.getKid(), keys.getCertificate());
binding.signatureAlgorithm(algorithm).signWith(keyName, keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()).signDocument();
boolean addExtension = (! postBinding) && Objects.equals("true", userSession.getNote(SamlProtocol.SAML_LOGOUT_ADD_EXTENSIONS_ELEMENT_WITH_KEY_INFO));
if (addExtension) { // Only include extension if REDIRECT binding and signing whole SAML protocol message
builder.addExtension(new KeycloakKeySamlExtensionGenerator(keys.getKid()));
builder.addExtension(new KeycloakKeySamlExtensionGenerator(keyName));
}
}
@ -658,7 +669,8 @@ public class SamlProtocol implements LoginProtocol {
JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder();
if (samlClient.requiresRealmSignature()) {
KeyManager.ActiveKey keys = session.keys().getActiveKey(realm);
binding.signatureAlgorithm(samlClient.getSignatureAlgorithm()).signWith(keys.getKid(), keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()).signDocument();
String keyName = samlClient.getXmlSigKeyInfoKeyNameTransformer().getKeyName(keys.getKid(), keys.getCertificate());
binding.signatureAlgorithm(samlClient.getSignatureAlgorithm()).signWith(keyName, keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()).signDocument();
}
return binding;
}

View file

@ -362,6 +362,7 @@ public class SamlService extends AuthorizationEndpointBase {
userSession.setNote(SamlProtocol.SAML_LOGOUT_REQUEST_ID, logoutRequest.getID());
userSession.setNote(SamlProtocol.SAML_LOGOUT_BINDING, logoutBinding);
userSession.setNote(SamlProtocol.SAML_LOGOUT_ADD_EXTENSIONS_ELEMENT_WITH_KEY_INFO, Boolean.toString((! postBinding) && samlClient.addExtensionsElementWithKeyInfo()));
userSession.setNote(SamlProtocol.SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER, samlClient.getXmlSigKeyInfoKeyNameTransformer().name());
userSession.setNote(SamlProtocol.SAML_LOGOUT_CANONICALIZATION, samlClient.getCanonicalizationMethod());
userSession.setNote(AuthenticationManager.KEYCLOAK_LOGOUT_PROTOCOL, SamlProtocol.LOGIN_PROTOCOL);
// remove client from logout requests