KEYCLOAK-1881 Update client adapter configuration

Client adapter configuration was updated to support for customization
of HttpClient used for key retrieval similarly to OIDC. Further, it is
now possible to specify several static public keys for signature
verification in saml-client.xml.
This commit is contained in:
Hynek Mlnarik 2016-11-03 14:55:12 +01:00
parent 8ae1b1740d
commit 570d71c07b
14 changed files with 708 additions and 182 deletions

View file

@ -23,9 +23,10 @@ import org.keycloak.saml.SignatureAlgorithm;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.LinkedList;
import java.util.List;
import java.util.Set; import java.util.Set;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.keycloak.adapters.HttpClientBuilder;
import org.keycloak.adapters.saml.rotation.SamlDescriptorPublicKeyLocator; import org.keycloak.adapters.saml.rotation.SamlDescriptorPublicKeyLocator;
import org.keycloak.rotation.CompositeKeyLocator; import org.keycloak.rotation.CompositeKeyLocator;
import org.keycloak.rotation.HardcodedKeyLocator; import org.keycloak.rotation.HardcodedKeyLocator;
@ -191,8 +192,9 @@ public class DefaultSamlDeployment implements SamlDeployment {
private final CompositeKeyLocator signatureValidationKeyLocator = new CompositeKeyLocator(); private final CompositeKeyLocator signatureValidationKeyLocator = new CompositeKeyLocator();
private SingleSignOnService singleSignOnService; private SingleSignOnService singleSignOnService;
private SingleLogoutService singleLogoutService; private SingleLogoutService singleLogoutService;
private HardcodedKeyLocator hardcodedKeyLocator; private final List<PublicKey> signatureValidationKeys = new LinkedList<>();
private int minTimeBetweenDescriptorRequests; private int minTimeBetweenDescriptorRequests;
private HttpClient client;
@Override @Override
public String getEntityID() { public String getEntityID() {
@ -227,14 +229,12 @@ public class DefaultSamlDeployment implements SamlDeployment {
this.entityID = entityID; this.entityID = entityID;
} }
public void setSignatureValidationKey(PublicKey signatureValidationKey) { public void addSignatureValidationKey(PublicKey signatureValidationKey) {
this.hardcodedKeyLocator = signatureValidationKey == null ? null : new HardcodedKeyLocator(signatureValidationKey); this.signatureValidationKeys.add(signatureValidationKey);
refreshKeyLocatorConfiguration();
} }
public void setSingleSignOnService(SingleSignOnService singleSignOnService) { public void setSingleSignOnService(SingleSignOnService singleSignOnService) {
this.singleSignOnService = singleSignOnService; this.singleSignOnService = singleSignOnService;
refreshKeyLocatorConfiguration();
} }
public void setSingleLogoutService(SingleLogoutService singleLogoutService) { public void setSingleLogoutService(SingleLogoutService singleLogoutService) {
@ -245,18 +245,26 @@ public class DefaultSamlDeployment implements SamlDeployment {
this.signatureValidationKeyLocator.clear(); this.signatureValidationKeyLocator.clear();
// When key is set, use that (and only that), otherwise configure dynamic key locator // When key is set, use that (and only that), otherwise configure dynamic key locator
if (this.hardcodedKeyLocator != null) { if (! this.signatureValidationKeys.isEmpty()) {
this.signatureValidationKeyLocator.add(this.hardcodedKeyLocator); this.signatureValidationKeyLocator.add(new HardcodedKeyLocator(this.signatureValidationKeys));
} else if (this.singleSignOnService != null) { } else if (this.singleSignOnService != null) {
String samlDescriptorUrl = singleSignOnService.getRequestBindingUrl() + "/descriptor"; String samlDescriptorUrl = singleSignOnService.getRequestBindingUrl() + "/descriptor";
// TODO HttpClient httpClient = getClient();
HttpClient httpClient = new HttpClientBuilder().build();
SamlDescriptorPublicKeyLocator samlDescriptorPublicKeyLocator = SamlDescriptorPublicKeyLocator samlDescriptorPublicKeyLocator =
new SamlDescriptorPublicKeyLocator( new SamlDescriptorPublicKeyLocator(
samlDescriptorUrl, this.minTimeBetweenDescriptorRequests, DEFAULT_CACHE_TTL, httpClient); samlDescriptorUrl, this.minTimeBetweenDescriptorRequests, DEFAULT_CACHE_TTL, httpClient);
this.signatureValidationKeyLocator.add(samlDescriptorPublicKeyLocator); this.signatureValidationKeyLocator.add(samlDescriptorPublicKeyLocator);
} }
} }
@Override
public HttpClient getClient() {
return this.client;
}
public void setClient(HttpClient client) {
this.client = client;
}
} }
private IDP idp; private IDP idp;

View file

@ -23,6 +23,7 @@ import org.keycloak.saml.SignatureAlgorithm;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.util.Set; import java.util.Set;
import org.apache.http.client.HttpClient;
import org.keycloak.rotation.KeyLocator; import org.keycloak.rotation.KeyLocator;
/** /**
@ -77,6 +78,12 @@ public interface SamlDeployment {
*/ */
int getMinTimeBetweenDescriptorRequests(); int getMinTimeBetweenDescriptorRequests();
/**
* Returns {@link HttpClient} instance that will be used for http communication with this IdP.
* @return see description
*/
HttpClient getClient();
public interface SingleSignOnService { public interface SingleSignOnService {
/** /**
* Returns {@code true} if the requests to IdP need to be signed by SP key. * Returns {@code true} if the requests to IdP need to be signed by SP key.

View file

@ -19,6 +19,7 @@ package org.keycloak.adapters.saml.config;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import org.keycloak.adapters.cloned.AdapterHttpClientConfig;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -157,12 +158,97 @@ public class IDP implements Serializable {
} }
} }
public static class HttpClientConfig implements AdapterHttpClientConfig {
private String truststore;
private String truststorePassword;
private String clientKeystore;
private String clientKeystorePassword;
private boolean allowAnyHostname;
private boolean disableTrustManager;
private int connectionPoolSize;
private String proxyUrl;
@Override
public String getTruststore() {
return truststore;
}
public void setTruststore(String truststore) {
this.truststore = truststore;
}
@Override
public String getTruststorePassword() {
return truststorePassword;
}
public void setTruststorePassword(String truststorePassword) {
this.truststorePassword = truststorePassword;
}
@Override
public String getClientKeystore() {
return clientKeystore;
}
public void setClientKeystore(String clientKeystore) {
this.clientKeystore = clientKeystore;
}
@Override
public String getClientKeystorePassword() {
return clientKeystorePassword;
}
public void setClientKeystorePassword(String clientKeystorePassword) {
this.clientKeystorePassword = clientKeystorePassword;
}
@Override
public boolean isAllowAnyHostname() {
return allowAnyHostname;
}
public void setAllowAnyHostname(boolean allowAnyHostname) {
this.allowAnyHostname = allowAnyHostname;
}
@Override
public boolean isDisableTrustManager() {
return disableTrustManager;
}
public void setDisableTrustManager(boolean disableTrustManager) {
this.disableTrustManager = disableTrustManager;
}
@Override
public int getConnectionPoolSize() {
return connectionPoolSize;
}
public void setConnectionPoolSize(int connectionPoolSize) {
this.connectionPoolSize = connectionPoolSize;
}
@Override
public String getProxyUrl() {
return proxyUrl;
}
public void setProxyUrl(String proxyUrl) {
this.proxyUrl = proxyUrl;
}
}
private String entityID; private String entityID;
private String signatureAlgorithm; private String signatureAlgorithm;
private String signatureCanonicalizationMethod; private String signatureCanonicalizationMethod;
private SingleSignOnService singleSignOnService; private SingleSignOnService singleSignOnService;
private SingleLogoutService singleLogoutService; private SingleLogoutService singleLogoutService;
private List<Key> keys; private List<Key> keys;
private AdapterHttpClientConfig httpClientConfig = new HttpClientConfig();
public String getEntityID() { public String getEntityID() {
return entityID; return entityID;
@ -212,4 +298,12 @@ public class IDP implements Serializable {
this.signatureCanonicalizationMethod = signatureCanonicalizationMethod; this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
} }
public AdapterHttpClientConfig getHttpClientConfig() {
return httpClientConfig;
}
public void setHttpClientConfig(AdapterHttpClientConfig httpClientConfig) {
this.httpClientConfig = httpClientConfig;
}
} }

View file

@ -72,4 +72,15 @@ public class ConfigXmlConstants {
public static final String VALIDATE_REQUEST_SIGNATURE_ATTR = "validateRequestSignature"; public static final String VALIDATE_REQUEST_SIGNATURE_ATTR = "validateRequestSignature";
public static final String POST_BINDING_URL_ATTR = "postBindingUrl"; public static final String POST_BINDING_URL_ATTR = "postBindingUrl";
public static final String REDIRECT_BINDING_URL_ATTR = "redirectBindingUrl"; public static final String REDIRECT_BINDING_URL_ATTR = "redirectBindingUrl";
public static final String HTTP_CLIENT_ELEMENT = "HttpClient";
public static final String ALLOW_ANY_HOSTNAME_ATTR = "allowAnyHostname";
public static final String CLIENT_KEYSTORE_ATTR = "clientKeystore";
public static final String CLIENT_KEYSTORE_PASSWORD_ATTR = "clientKeystorePassword";
public static final String CONNECTION_POOL_SIZE_ATTR = "connectionPoolSize";
public static final String DISABLE_TRUST_MANAGER_ATTR = "disableTrustManager";
public static final String PROXY_URL_ATTR = "proxyUrl";
public static final String TRUSTSTORE_ATTR = "truststore";
public static final String TRUSTSTORE_PASSWORD_ATTR = "truststorePassword";
} }

View file

@ -40,6 +40,7 @@ import java.security.PublicKey;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.keycloak.adapters.cloned.HttpClientBuilder;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -178,36 +179,39 @@ public class DeploymentBuilder {
if (sp.getIdp().getKeys() != null) { if (sp.getIdp().getKeys() != null) {
for (Key key : sp.getIdp().getKeys()) { for (Key key : sp.getIdp().getKeys()) {
if (key.isSigning()) { if (key.isSigning()) {
if (key.getKeystore() != null) { processSigningKey(idp, key, resourceLoader);
KeyStore keyStore = loadKeystore(resourceLoader, key);
Certificate cert = null;
try {
cert = keyStore.getCertificate(key.getKeystore().getCertificateAlias());
} catch (KeyStoreException e) {
throw new RuntimeException(e);
}
idp.setSignatureValidationKey(cert.getPublicKey());
} else {
if (key.getPublicKeyPem() == null && key.getCertificatePem() == null) {
throw new RuntimeException("IDP signing key must have a PublicKey or Certificate defined");
}
try {
PublicKey publicKey = getPublicKeyFromPem(key);
idp.setSignatureValidationKey(publicKey);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
} }
} }
} }
idp.setClient(new HttpClientBuilder().build(sp.getIdp().getHttpClientConfig()));
idp.refreshKeyLocatorConfiguration(); idp.refreshKeyLocatorConfiguration();
return deployment; return deployment;
} }
protected static PublicKey getPublicKeyFromPem(Key key) throws Exception { private void processSigningKey(DefaultSamlDeployment.DefaultIDP idp, Key key, ResourceLoader resourceLoader) throws RuntimeException {
PublicKey publicKey;
if (key.getKeystore() != null) {
KeyStore keyStore = loadKeystore(resourceLoader, key);
Certificate cert = null;
try {
cert = keyStore.getCertificate(key.getKeystore().getCertificateAlias());
} catch (KeyStoreException e) {
throw new RuntimeException(e);
}
publicKey = cert.getPublicKey();
} else {
if (key.getPublicKeyPem() == null && key.getCertificatePem() == null) {
throw new RuntimeException("IDP signing key must have a PublicKey or Certificate defined");
}
publicKey = getPublicKeyFromPem(key);
}
idp.addSignatureValidationKey(publicKey);
}
protected static PublicKey getPublicKeyFromPem(Key key) {
PublicKey publicKey; PublicKey publicKey;
if (key.getPublicKeyPem() != null) { if (key.getPublicKeyPem() != null) {
publicKey = PemUtils.decodePublicKey(key.getPublicKeyPem().trim()); publicKey = PemUtils.decodePublicKey(key.getPublicKeyPem().trim());

View file

@ -29,6 +29,10 @@ import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement; import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent; import javax.xml.stream.events.XMLEvent;
import java.util.List; import java.util.List;
import org.keycloak.adapters.saml.config.IDP.HttpClientConfig;
import static org.keycloak.adapters.saml.config.parsers.SPXmlParser.getAttributeValue;
import static org.keycloak.adapters.saml.config.parsers.SPXmlParser.getBooleanAttributeValue;
import static org.keycloak.adapters.saml.config.parsers.SPXmlParser.getIntegerAttributeValue;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -41,16 +45,16 @@ public class IDPXmlParser extends AbstractParser {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader); StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.IDP_ELEMENT); StaxParserUtil.validate(startElement, ConfigXmlConstants.IDP_ELEMENT);
IDP idp = new IDP(); IDP idp = new IDP();
String entityID = SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR); String entityID = getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
if (entityID == null) { if (entityID == null) {
throw new ParsingException("entityID must be set on IDP"); throw new ParsingException("entityID must be set on IDP");
} }
idp.setEntityID(entityID); idp.setEntityID(entityID);
boolean signaturesRequired = SPXmlParser.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNATURES_REQUIRED_ATTR); boolean signaturesRequired = getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNATURES_REQUIRED_ATTR);
idp.setSignatureCanonicalizationMethod(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR)); idp.setSignatureCanonicalizationMethod(getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
idp.setSignatureAlgorithm(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR)); idp.setSignatureAlgorithm(getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR));
while (xmlEventReader.hasNext()) { while (xmlEventReader.hasNext()) {
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader); XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
if (xmlEvent == null) if (xmlEvent == null)
@ -75,6 +79,10 @@ public class IDPXmlParser extends AbstractParser {
IDP.SingleLogoutService slo = parseSingleLogoutService(xmlEventReader, signaturesRequired); IDP.SingleLogoutService slo = parseSingleLogoutService(xmlEventReader, signaturesRequired);
idp.setSingleLogoutService(slo); idp.setSingleLogoutService(slo);
} else if (tag.equals(ConfigXmlConstants.HTTP_CLIENT_ELEMENT)) {
HttpClientConfig config = parseHttpClientElement(xmlEventReader);
idp.setHttpClientConfig(config);
} else if (tag.equals(ConfigXmlConstants.KEYS_ELEMENT)) { } else if (tag.equals(ConfigXmlConstants.KEYS_ELEMENT)) {
KeysXmlParser parser = new KeysXmlParser(); KeysXmlParser parser = new KeysXmlParser();
List<Key> keys = (List<Key>)parser.parse(xmlEventReader); List<Key> keys = (List<Key>)parser.parse(xmlEventReader);
@ -90,29 +98,63 @@ public class IDPXmlParser extends AbstractParser {
protected IDP.SingleLogoutService parseSingleLogoutService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException { protected IDP.SingleLogoutService parseSingleLogoutService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException {
IDP.SingleLogoutService slo = new IDP.SingleLogoutService(); IDP.SingleLogoutService slo = new IDP.SingleLogoutService();
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader); StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
slo.setSignRequest(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired)); slo.setSignRequest(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
slo.setValidateResponseSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired)); slo.setValidateResponseSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
slo.setValidateRequestSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR, signaturesRequired)); slo.setValidateRequestSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR, signaturesRequired));
slo.setRequestBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR)); slo.setRequestBinding(getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
slo.setResponseBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR)); slo.setResponseBinding(getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
slo.setSignResponse(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR, signaturesRequired)); slo.setSignResponse(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR, signaturesRequired));
slo.setPostBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR)); slo.setPostBindingUrl(getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR));
slo.setRedirectBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REDIRECT_BINDING_URL_ATTR)); slo.setRedirectBindingUrl(getAttributeValue(element, ConfigXmlConstants.REDIRECT_BINDING_URL_ATTR));
return slo; return slo;
} }
protected IDP.SingleSignOnService parseSingleSignOnService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException { protected IDP.SingleSignOnService parseSingleSignOnService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException {
IDP.SingleSignOnService sso = new IDP.SingleSignOnService(); IDP.SingleSignOnService sso = new IDP.SingleSignOnService();
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader); StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
sso.setSignRequest(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired)); sso.setSignRequest(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
sso.setValidateResponseSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired)); sso.setValidateResponseSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
sso.setValidateAssertionSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_ASSERTION_SIGNATURE_ATTR)); sso.setValidateAssertionSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_ASSERTION_SIGNATURE_ATTR));
sso.setRequestBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR)); sso.setRequestBinding(getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
sso.setResponseBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR)); sso.setResponseBinding(getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
sso.setBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR)); sso.setBindingUrl(getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
return sso; return sso;
} }
private HttpClientConfig parseHttpClientElement(XMLEventReader xmlEventReader) throws ParsingException {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.HTTP_CLIENT_ELEMENT);
HttpClientConfig config = new HttpClientConfig();
config.setAllowAnyHostname(getBooleanAttributeValue(startElement, ConfigXmlConstants.ALLOW_ANY_HOSTNAME_ATTR, false));
config.setClientKeystore(getAttributeValue(startElement, ConfigXmlConstants.CLIENT_KEYSTORE_ATTR));
config.setClientKeystorePassword(getAttributeValue(startElement, ConfigXmlConstants.CLIENT_KEYSTORE_PASSWORD_ATTR));
config.setConnectionPoolSize(getIntegerAttributeValue(startElement, ConfigXmlConstants.CONNECTION_POOL_SIZE_ATTR, 0));
config.setDisableTrustManager(getBooleanAttributeValue(startElement, ConfigXmlConstants.ALLOW_ANY_HOSTNAME_ATTR, false));
config.setProxyUrl(getAttributeValue(startElement, ConfigXmlConstants.PROXY_URL_ATTR));
config.setTruststore(getAttributeValue(startElement, ConfigXmlConstants.TRUSTSTORE_ATTR));
config.setTruststorePassword(getAttributeValue(startElement, ConfigXmlConstants.TRUSTSTORE_PASSWORD_ATTR));
while (xmlEventReader.hasNext()) {
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
if (xmlEvent == null)
break;
if (xmlEvent instanceof EndElement) {
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
String endElementName = StaxParserUtil.getEndElementName(endElement);
if (endElementName.equals(ConfigXmlConstants.ROLE_IDENTIFIERS_ELEMENT))
break;
else
continue;
}
String tag = StaxParserUtil.getStartElementName(startElement);
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
}
return config;
}
@Override @Override
public boolean supports(QName qname) { public boolean supports(QName qname) {
return false; return false;

View file

@ -48,6 +48,13 @@ public class SPXmlParser extends AbstractParser {
return str; return str;
} }
public static int getIntegerAttributeValue(StartElement startElement, String tag, int defaultValue) {
String result = getAttributeValue(startElement, tag);
if (result == null)
return defaultValue;
return Integer.valueOf(result);
}
public static boolean getBooleanAttributeValue(StartElement startElement, String tag, boolean defaultValue) { public static boolean getBooleanAttributeValue(StartElement startElement, String tag, boolean defaultValue) {
String result = getAttributeValue(startElement, tag); String result = getAttributeValue(startElement, tag);
if (result == null) if (result == null)

View file

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="urn:keycloak:saml:adapter"
targetNamespace="urn:keycloak:saml:adapter"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="keycloak-saml-adapter" type="adapter-type"/>
<xs:complexType name="adapter-type">
<xs:annotation>
<xs:documentation>
<![CDATA[
The Keycloak SAML Adapter keycloak-saml.xml config file
]]>
</xs:documentation>
</xs:annotation>
<xs:all>
<xs:element name="SP" maxOccurs="1" minOccurs="0" type="sp-type"/>
</xs:all>
</xs:complexType>
<xs:complexType name="sp-type">
<xs:all>
<xs:element name="Keys" type="keys-type" minOccurs="0" maxOccurs="1"/>
<xs:element name="PrincipalNameMapping" type="principal-name-mapping-type" minOccurs="0" maxOccurs="1"/>
<xs:element name="RoleIdentifiers" type="role-identifiers-type" minOccurs="0" maxOccurs="1"/>
<xs:element name="IDP" type="idp-type" minOccurs="1" maxOccurs="1"/>
</xs:all>
<xs:attribute name="entityID" type="xs:string" use="required"/>
<xs:attribute name="sslPolicy" type="xs:string" use="optional"/>
<xs:attribute name="nameIDPolicyFormat" type="xs:string" use="optional"/>
<xs:attribute name="logoutPage" type="xs:string" use="optional"/>
<xs:attribute name="forceAuthentication" type="xs:boolean" use="optional"/>
<xs:attribute name="isPassive" type="xs:boolean" use="optional"/>
<xs:attribute name="turnOffChangeSessionIdOnLogin" type="xs:boolean" use="optional"/>
</xs:complexType>
<xs:complexType name="keys-type">
<xs:sequence>
<xs:element name="Key" type="key-type" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="key-type">
<xs:all>
<xs:element name="KeyStore" maxOccurs="1" minOccurs="0" type="key-store-type"/>
<xs:element name="PrivateKeyPem" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="PublicKeyPem" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="CertificatePem" type="xs:string" minOccurs="0" maxOccurs="1"/>
</xs:all>
<xs:attribute name="signing" type="xs:boolean" use="optional"/>
<xs:attribute name="encryption" type="xs:boolean" use="optional"/>
</xs:complexType>
<xs:complexType name="key-store-type">
<xs:all>
<xs:element name="PrivateKey" maxOccurs="1" minOccurs="0" type="private-key-type"/>
<xs:element name="Certificate" type="certificate-type" minOccurs="0" maxOccurs="1"/>
</xs:all>
<xs:attribute name="file" type="xs:string" use="optional"/>
<xs:attribute name="resource" type="xs:string" use="optional"/>
<xs:attribute name="password" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="private-key-type">
<xs:attribute name="alias" type="xs:string" use="required"/>
<xs:attribute name="password" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="certificate-type">
<xs:attribute name="alias" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="principal-name-mapping-type">
<xs:attribute name="policy" type="xs:string" use="required"/>
<xs:attribute name="attribute" type="xs:string" use="optional"/>
</xs:complexType>
<xs:complexType name="role-identifiers-type">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Attribute" maxOccurs="unbounded" minOccurs="0" type="attribute-type"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="attribute-type">
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="idp-type">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="SingleSignOnService" maxOccurs="1" minOccurs="1" type="sign-on-type"/>
<xs:element name="SingleLogoutService" type="logout-type" minOccurs="0" maxOccurs="1"/>
<xs:element name="Keys" type="keys-type" minOccurs="0" maxOccurs="1"/>
<xs:element name="HttpClient" type="http-client-type" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
<xs:attribute name="entityID" type="xs:string" use="required"/>
<xs:attribute name="signaturesRequired" type="xs:boolean" use="required"/>
<xs:attribute name="signatureAlgorithm" type="xs:string" use="optional"/>
<xs:attribute name="signatureCanonicalizationMethod" type="xs:string" use="optional"/>
<xs:attribute name="encryption" type="xs:boolean" use="optional"/>
</xs:complexType>
<xs:complexType name="sign-on-type">
<xs:attribute name="signRequest" type="xs:boolean" use="optional"/>
<xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional"/>
<xs:attribute name="validateAssertionSignature" type="xs:boolean" use="optional"/>
<xs:attribute name="requestBinding" type="xs:string" use="optional"/>
<xs:attribute name="responseBinding" type="xs:string" use="optional"/>
<xs:attribute name="bindingUrl" type="xs:string" use="optional"/>
</xs:complexType>
<xs:complexType name="logout-type">
<xs:attribute name="signRequest" type="xs:boolean" use="optional"/>
<xs:attribute name="signResponse" type="xs:boolean" use="optional"/>
<xs:attribute name="validateRequestSignature" type="xs:boolean" use="optional"/>
<xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional"/>
<xs:attribute name="requestBinding" type="xs:string" use="optional"/>
<xs:attribute name="responseBinding" type="xs:string" use="optional"/>
<xs:attribute name="postBindingUrl" type="xs:string" use="optional"/>
<xs:attribute name="redirectBindingUrl" type="xs:string" use="optional"/>
</xs:complexType>
<xs:complexType name="http-client-type">
<xs:attribute name="allowAnyHostname" type="xs:boolean" use="optional"/>
<xs:attribute name="clientKeystore" type="xs:string" use="optional"/>
<xs:attribute name="clientKeystorePassword" type="xs:string" use="optional"/>
<xs:attribute name="connectionPoolSize" type="xs:int" use="optional"/>
<xs:attribute name="disableTrustManager" type="xs:boolean" use="optional"/>
<xs:attribute name="proxyUrl" type="xs:string" use="optional"/>
<xs:attribute name="truststore" type="xs:string" use="optional"/>
<xs:attribute name="truststorePassword" type="xs:string" use="optional"/>
</xs:complexType>
</xs:schema>

View file

@ -0,0 +1,180 @@
/*
* 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.adapters.saml.config.parsers;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.junit.Test;
import org.keycloak.adapters.saml.config.IDP;
import org.keycloak.adapters.saml.config.Key;
import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
import org.keycloak.adapters.saml.config.SP;
import org.keycloak.saml.common.util.StaxParserUtil;
import java.io.InputStream;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
import org.keycloak.saml.common.exceptions.ParsingException;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakSamlAdapterXMLParserTest {
private static final String CURRENT_XSD_LOCATION = "/schema/keycloak_saml_adapter_1_7.xsd";
@Rule
public ExpectedException expectedException = ExpectedException.none();
private void testValidationValid(String fileName) throws Exception {
InputStream schema = getClass().getResourceAsStream(CURRENT_XSD_LOCATION);
InputStream is = getClass().getResourceAsStream(fileName);
assertNotNull(is);
assertNotNull(schema);
StaxParserUtil.validate(is, schema);
}
@Test
public void testValidationSimpleFile() throws Exception {
testValidationValid("keycloak-saml.xml");
}
@Test
public void testValidationMultipleKeys() throws Exception {
testValidationValid("keycloak-saml-multiple-signing-keys.xml");
}
@Test
public void testValidationWithHttpClient() throws Exception {
testValidationValid("keycloak-saml-wth-http-client-settings.xml");
}
@Test
public void testValidationKeyInvalid() throws Exception {
InputStream schemaIs = KeycloakSamlAdapterXMLParser.class.getResourceAsStream(CURRENT_XSD_LOCATION);
InputStream is = getClass().getResourceAsStream("keycloak-saml-invalid.xml");
assertNotNull(is);
assertNotNull(schemaIs);
expectedException.expect(ParsingException.class);
StaxParserUtil.validate(is, schemaIs);
}
@Test
public void testXmlParser() throws Exception {
InputStream is = getClass().getResourceAsStream("keycloak-saml.xml");
assertNotNull(is);
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
KeycloakSamlAdapter config = (KeycloakSamlAdapter)parser.parse(is);
assertNotNull(config);
assertEquals(1, config.getSps().size());
SP sp = config.getSps().get(0);
assertEquals("sp", sp.getEntityID());
assertEquals("ssl", sp.getSslPolicy());
assertEquals("format", sp.getNameIDPolicyFormat());
assertTrue(sp.isForceAuthentication());
assertTrue(sp.isIsPassive());
assertEquals(2, sp.getKeys().size());
Key signing = sp.getKeys().get(0);
assertTrue(signing.isSigning());
Key.KeyStoreConfig keystore = signing.getKeystore();
assertNotNull(keystore);
assertEquals("file", keystore.getFile());
assertEquals("cp", keystore.getResource());
assertEquals("pw", keystore.getPassword());
assertEquals("private alias", keystore.getPrivateKeyAlias());
assertEquals("private pw", keystore.getPrivateKeyPassword());
assertEquals("cert alias", keystore.getCertificateAlias());
Key encryption = sp.getKeys().get(1);
assertTrue(encryption.isEncryption());
assertEquals("private pem", encryption.getPrivateKeyPem());
assertEquals("public pem", encryption.getPublicKeyPem());
assertEquals("policy", sp.getPrincipalNameMapping().getPolicy());
assertEquals("attribute", sp.getPrincipalNameMapping().getAttributeName());
assertTrue(sp.getRoleAttributes().size() == 1);
assertTrue(sp.getRoleAttributes().contains("member"));
IDP idp = sp.getIdp();
assertEquals("idp", idp.getEntityID());
assertEquals("RSA", idp.getSignatureAlgorithm());
assertEquals("canon", idp.getSignatureCanonicalizationMethod());
assertTrue(idp.getSingleSignOnService().isSignRequest());
assertTrue(idp.getSingleSignOnService().isValidateResponseSignature());
assertEquals("post", idp.getSingleSignOnService().getRequestBinding());
assertEquals("url", idp.getSingleSignOnService().getBindingUrl());
assertTrue(idp.getSingleLogoutService().isSignRequest());
assertTrue(idp.getSingleLogoutService().isSignResponse());
assertTrue(idp.getSingleLogoutService().isValidateRequestSignature());
assertTrue(idp.getSingleLogoutService().isValidateResponseSignature());
assertEquals("redirect", idp.getSingleLogoutService().getRequestBinding());
assertEquals("post", idp.getSingleLogoutService().getResponseBinding());
assertEquals("posturl", idp.getSingleLogoutService().getPostBindingUrl());
assertEquals("redirecturl", idp.getSingleLogoutService().getRedirectBindingUrl());
assertTrue(idp.getKeys().size() == 1);
assertTrue(idp.getKeys().get(0).isSigning());
assertEquals("cert pem", idp.getKeys().get(0).getCertificatePem());
}
@Test
public void testXmlParserMultipleSigningKeys() throws Exception {
InputStream is = getClass().getResourceAsStream("keycloak-saml-multiple-signing-keys.xml");
assertNotNull(is);
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
KeycloakSamlAdapter config = (KeycloakSamlAdapter) parser.parse(is);
assertNotNull(config);
assertEquals(1, config.getSps().size());
SP sp = config.getSps().get(0);
IDP idp = sp.getIdp();
assertTrue(idp.getKeys().size() == 4);
for (int i = 0; i < 4; i ++) {
Key key = idp.getKeys().get(i);
assertTrue(key.isSigning());
assertEquals("cert pem " + i, idp.getKeys().get(i).getCertificatePem());
}
}
@Test
public void testXmlParserHttpClientSettings() throws Exception {
InputStream is = getClass().getResourceAsStream("keycloak-saml-wth-http-client-settings.xml");
assertNotNull(is);
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
KeycloakSamlAdapter config = (KeycloakSamlAdapter) parser.parse(is);
assertNotNull(config);
assertEquals(1, config.getSps().size());
SP sp = config.getSps().get(0);
IDP idp = sp.getIdp();
assertThat(idp.getHttpClientConfig(), notNullValue());
assertThat(idp.getHttpClientConfig().getClientKeystore(), is("ks"));
assertThat(idp.getHttpClientConfig().getClientKeystorePassword(), is("ks-pwd"));
assertThat(idp.getHttpClientConfig().getProxyUrl(), is("pu"));
assertThat(idp.getHttpClientConfig().getTruststore(), is("ts"));
assertThat(idp.getHttpClientConfig().getTruststorePassword(), is("tsp"));
assertThat(idp.getHttpClientConfig().getConnectionPoolSize(), is(42));
assertThat(idp.getHttpClientConfig().isAllowAnyHostname(), is(true));
assertThat(idp.getHttpClientConfig().isDisableTrustManager(), is(true));
}
}

View file

@ -1,133 +0,0 @@
/*
* 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.test.adapters.saml;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.adapters.saml.config.IDP;
import org.keycloak.adapters.saml.config.Key;
import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
import org.keycloak.adapters.saml.config.SP;
import org.keycloak.adapters.saml.config.parsers.KeycloakSamlAdapterXMLParser;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.InputStream;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class XmlParserTest {
@Test
public void testValidation() throws Exception {
{
InputStream schema = KeycloakSamlAdapterXMLParser.class.getResourceAsStream("/schema/keycloak_saml_adapter_1_6.xsd");
InputStream is = getClass().getResourceAsStream("/keycloak-saml.xml");
Assert.assertNotNull(is);
Assert.assertNotNull(schema);
StaxParserUtil.validate(is, schema);
}
{
InputStream sch = KeycloakSamlAdapterXMLParser.class.getResourceAsStream("/schema/keycloak_saml_adapter_1_6.xsd");
InputStream doc = getClass().getResourceAsStream("/keycloak-saml2.xml");
Assert.assertNotNull(doc);
Assert.assertNotNull(sch);
try {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(new StreamSource(sch));
Validator validator = schema.newValidator();
StreamSource source = new StreamSource(doc);
source.setSystemId("/keycloak-saml2.xml");
validator.validate(source);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Test
public void testXmlParser() throws Exception {
InputStream is = getClass().getResourceAsStream("/keycloak-saml.xml");
Assert.assertNotNull(is);
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
KeycloakSamlAdapter config = (KeycloakSamlAdapter)parser.parse(is);
Assert.assertNotNull(config);
Assert.assertEquals(1, config.getSps().size());
SP sp = config.getSps().get(0);
Assert.assertEquals("sp", sp.getEntityID());
Assert.assertEquals("ssl", sp.getSslPolicy());
Assert.assertEquals("format", sp.getNameIDPolicyFormat());
Assert.assertTrue(sp.isForceAuthentication());
Assert.assertTrue(sp.isIsPassive());
Assert.assertEquals(2, sp.getKeys().size());
Key signing = sp.getKeys().get(0);
Assert.assertTrue(signing.isSigning());
Key.KeyStoreConfig keystore = signing.getKeystore();
Assert.assertNotNull(keystore);
Assert.assertEquals("file", keystore.getFile());
Assert.assertEquals("cp", keystore.getResource());
Assert.assertEquals("pw", keystore.getPassword());
Assert.assertEquals("private alias", keystore.getPrivateKeyAlias());
Assert.assertEquals("private pw", keystore.getPrivateKeyPassword());
Assert.assertEquals("cert alias", keystore.getCertificateAlias());
Key encryption = sp.getKeys().get(1);
Assert.assertTrue(encryption.isEncryption());
Assert.assertEquals("private pem", encryption.getPrivateKeyPem());
Assert.assertEquals("public pem", encryption.getPublicKeyPem());
Assert.assertEquals("policy", sp.getPrincipalNameMapping().getPolicy());
Assert.assertEquals("attribute", sp.getPrincipalNameMapping().getAttributeName());
Assert.assertTrue(sp.getRoleAttributes().size() == 1);
Assert.assertTrue(sp.getRoleAttributes().contains("member"));
IDP idp = sp.getIdp();
Assert.assertEquals("idp", idp.getEntityID());
Assert.assertEquals("RSA", idp.getSignatureAlgorithm());
Assert.assertEquals("canon", idp.getSignatureCanonicalizationMethod());
Assert.assertTrue(idp.getSingleSignOnService().isSignRequest());
Assert.assertTrue(idp.getSingleSignOnService().isValidateResponseSignature());
Assert.assertEquals("post", idp.getSingleSignOnService().getRequestBinding());
Assert.assertEquals("url", idp.getSingleSignOnService().getBindingUrl());
Assert.assertTrue(idp.getSingleLogoutService().isSignRequest());
Assert.assertTrue(idp.getSingleLogoutService().isSignResponse());
Assert.assertTrue(idp.getSingleLogoutService().isValidateRequestSignature());
Assert.assertTrue(idp.getSingleLogoutService().isValidateResponseSignature());
Assert.assertEquals("redirect", idp.getSingleLogoutService().getRequestBinding());
Assert.assertEquals("post", idp.getSingleLogoutService().getResponseBinding());
Assert.assertEquals("posturl", idp.getSingleLogoutService().getPostBindingUrl());
Assert.assertEquals("redirecturl", idp.getSingleLogoutService().getRedirectBindingUrl());
Assert.assertTrue(idp.getKeys().size() == 1);
Assert.assertTrue(idp.getKeys().get(0).isSigning());
Assert.assertEquals("cert pem", idp.getKeys().get(0).getCertificatePem());
}
}

View file

@ -0,0 +1,81 @@
<!--
~ 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.
-->
<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter">
<SP entityID="sp"
sslPolicy="ssl"
nameIDPolicyFormat="format"
forceAuthentication="true"
isPassive="true">
<Keys>
<Key signing="true" >
<KeyStore file="file" resource="cp" password="pw">
<PrivateKey alias="private alias" password="private pw"/>
<Certificate alias="cert alias"/>
</KeyStore>
</Key>
<Key encryption="true">
<PrivateKeyPem>
private pem
</PrivateKeyPem>
<PublicKeyPem>
public pem
</PublicKeyPem>
</Key>
</Keys>
<PrincipalNameMapping policy="policy" attribute="attribute"/>
<RoleIdentifiers>
<Attribute name="member"/>
</RoleIdentifiers>
<IDP entityID="idp"
signatureAlgorithm="RSA"
signatureCanonicalizationMethod="canon"
signaturesRequired="true"
>
<SingleSignOnService signRequest="true"
validateResponseSignature="true"
requestBinding="post"
bindingUrl="url"
/>
<SingleLogoutService
validateRequestSignature="true"
validateResponseSignature="true"
signRequest="true"
signResponse="true"
requestBinding="redirect"
responseBinding="post"
postBindingUrl="posturl"
redirectBindingUrl="redirecturl"
/>
<Keys>
<Key signing="true">
<CertificatePem>cert pem 0</CertificatePem>
</Key>
<Key signing="true">
<CertificatePem>cert pem 1</CertificatePem>
</Key>
<Key signing="true">
<CertificatePem>cert pem 2</CertificatePem>
</Key>
<Key signing="true">
<CertificatePem>cert pem 3</CertificatePem>
</Key>
</Keys>
</IDP>
</SP>
</keycloak-saml-adapter>

View file

@ -0,0 +1,81 @@
<!--
~ 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.
-->
<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter">
<SP entityID="sp"
sslPolicy="ssl"
nameIDPolicyFormat="format"
forceAuthentication="true"
isPassive="true">
<Keys>
<Key signing="true" >
<KeyStore file="file" resource="cp" password="pw">
<PrivateKey alias="private alias" password="private pw"/>
<Certificate alias="cert alias"/>
</KeyStore>
</Key>
<Key encryption="true">
<PrivateKeyPem>
private pem
</PrivateKeyPem>
<PublicKeyPem>
public pem
</PublicKeyPem>
</Key>
</Keys>
<PrincipalNameMapping policy="policy" attribute="attribute"/>
<RoleIdentifiers>
<Attribute name="member"/>
</RoleIdentifiers>
<IDP entityID="idp"
signatureAlgorithm="RSA"
signatureCanonicalizationMethod="canon"
signaturesRequired="true"
>
<SingleSignOnService signRequest="true"
validateResponseSignature="true"
requestBinding="post"
bindingUrl="url"
/>
<SingleLogoutService
validateRequestSignature="true"
validateResponseSignature="true"
signRequest="true"
signResponse="true"
requestBinding="redirect"
responseBinding="post"
postBindingUrl="posturl"
redirectBindingUrl="redirecturl"
/>
<Keys>
<Key signing="true">
<CertificatePem>
cert pem
</CertificatePem>
</Key>
</Keys>
<HttpClient allowAnyHostname="true"
clientKeystore="ks" clientKeystorePassword="ks-pwd"
connectionPoolSize="42"
disableTrustManager="true"
proxyUrl="pu"
truststore="ts" truststorePassword="tsp"
/>
</IDP>
</SP>
</keycloak-saml-adapter>