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:
parent
8ae1b1740d
commit
570d71c07b
14 changed files with 708 additions and 182 deletions
|
@ -23,9 +23,10 @@ import org.keycloak.saml.SignatureAlgorithm;
|
|||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.keycloak.adapters.HttpClientBuilder;
|
||||
import org.keycloak.adapters.saml.rotation.SamlDescriptorPublicKeyLocator;
|
||||
import org.keycloak.rotation.CompositeKeyLocator;
|
||||
import org.keycloak.rotation.HardcodedKeyLocator;
|
||||
|
@ -191,8 +192,9 @@ public class DefaultSamlDeployment implements SamlDeployment {
|
|||
private final CompositeKeyLocator signatureValidationKeyLocator = new CompositeKeyLocator();
|
||||
private SingleSignOnService singleSignOnService;
|
||||
private SingleLogoutService singleLogoutService;
|
||||
private HardcodedKeyLocator hardcodedKeyLocator;
|
||||
private final List<PublicKey> signatureValidationKeys = new LinkedList<>();
|
||||
private int minTimeBetweenDescriptorRequests;
|
||||
private HttpClient client;
|
||||
|
||||
@Override
|
||||
public String getEntityID() {
|
||||
|
@ -227,14 +229,12 @@ public class DefaultSamlDeployment implements SamlDeployment {
|
|||
this.entityID = entityID;
|
||||
}
|
||||
|
||||
public void setSignatureValidationKey(PublicKey signatureValidationKey) {
|
||||
this.hardcodedKeyLocator = signatureValidationKey == null ? null : new HardcodedKeyLocator(signatureValidationKey);
|
||||
refreshKeyLocatorConfiguration();
|
||||
public void addSignatureValidationKey(PublicKey signatureValidationKey) {
|
||||
this.signatureValidationKeys.add(signatureValidationKey);
|
||||
}
|
||||
|
||||
public void setSingleSignOnService(SingleSignOnService singleSignOnService) {
|
||||
this.singleSignOnService = singleSignOnService;
|
||||
refreshKeyLocatorConfiguration();
|
||||
}
|
||||
|
||||
public void setSingleLogoutService(SingleLogoutService singleLogoutService) {
|
||||
|
@ -245,18 +245,26 @@ public class DefaultSamlDeployment implements SamlDeployment {
|
|||
this.signatureValidationKeyLocator.clear();
|
||||
|
||||
// When key is set, use that (and only that), otherwise configure dynamic key locator
|
||||
if (this.hardcodedKeyLocator != null) {
|
||||
this.signatureValidationKeyLocator.add(this.hardcodedKeyLocator);
|
||||
if (! this.signatureValidationKeys.isEmpty()) {
|
||||
this.signatureValidationKeyLocator.add(new HardcodedKeyLocator(this.signatureValidationKeys));
|
||||
} else if (this.singleSignOnService != null) {
|
||||
String samlDescriptorUrl = singleSignOnService.getRequestBindingUrl() + "/descriptor";
|
||||
// TODO
|
||||
HttpClient httpClient = new HttpClientBuilder().build();
|
||||
HttpClient httpClient = getClient();
|
||||
SamlDescriptorPublicKeyLocator samlDescriptorPublicKeyLocator =
|
||||
new SamlDescriptorPublicKeyLocator(
|
||||
samlDescriptorUrl, this.minTimeBetweenDescriptorRequests, DEFAULT_CACHE_TTL, httpClient);
|
||||
this.signatureValidationKeyLocator.add(samlDescriptorPublicKeyLocator);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClient getClient() {
|
||||
return this.client;
|
||||
}
|
||||
|
||||
public void setClient(HttpClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
}
|
||||
|
||||
private IDP idp;
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.keycloak.saml.SignatureAlgorithm;
|
|||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.util.Set;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.keycloak.rotation.KeyLocator;
|
||||
|
||||
/**
|
||||
|
@ -77,6 +78,12 @@ public interface SamlDeployment {
|
|||
*/
|
||||
int getMinTimeBetweenDescriptorRequests();
|
||||
|
||||
/**
|
||||
* Returns {@link HttpClient} instance that will be used for http communication with this IdP.
|
||||
* @return see description
|
||||
*/
|
||||
HttpClient getClient();
|
||||
|
||||
public interface SingleSignOnService {
|
||||
/**
|
||||
* Returns {@code true} if the requests to IdP need to be signed by SP key.
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.adapters.saml.config;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import org.keycloak.adapters.cloned.AdapterHttpClientConfig;
|
||||
|
||||
/**
|
||||
* @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 signatureAlgorithm;
|
||||
private String signatureCanonicalizationMethod;
|
||||
private SingleSignOnService singleSignOnService;
|
||||
private SingleLogoutService singleLogoutService;
|
||||
private List<Key> keys;
|
||||
private AdapterHttpClientConfig httpClientConfig = new HttpClientConfig();
|
||||
|
||||
public String getEntityID() {
|
||||
return entityID;
|
||||
|
@ -212,4 +298,12 @@ public class IDP implements Serializable {
|
|||
this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
|
||||
}
|
||||
|
||||
public AdapterHttpClientConfig getHttpClientConfig() {
|
||||
return httpClientConfig;
|
||||
}
|
||||
|
||||
public void setHttpClientConfig(AdapterHttpClientConfig httpClientConfig) {
|
||||
this.httpClientConfig = httpClientConfig;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -72,4 +72,15 @@ public class ConfigXmlConstants {
|
|||
public static final String VALIDATE_REQUEST_SIGNATURE_ATTR = "validateRequestSignature";
|
||||
public static final String POST_BINDING_URL_ATTR = "postBindingUrl";
|
||||
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";
|
||||
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import java.security.PublicKey;
|
|||
import java.security.cert.Certificate;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.keycloak.adapters.cloned.HttpClientBuilder;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -178,36 +179,39 @@ public class DeploymentBuilder {
|
|||
if (sp.getIdp().getKeys() != null) {
|
||||
for (Key key : sp.getIdp().getKeys()) {
|
||||
if (key.isSigning()) {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
processSigningKey(idp, key, resourceLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idp.setClient(new HttpClientBuilder().build(sp.getIdp().getHttpClientConfig()));
|
||||
idp.refreshKeyLocatorConfiguration();
|
||||
|
||||
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;
|
||||
if (key.getPublicKeyPem() != null) {
|
||||
publicKey = PemUtils.decodePublicKey(key.getPublicKeyPem().trim());
|
||||
|
|
|
@ -29,6 +29,10 @@ import javax.xml.stream.events.EndElement;
|
|||
import javax.xml.stream.events.StartElement;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
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>
|
||||
|
@ -41,16 +45,16 @@ public class IDPXmlParser extends AbstractParser {
|
|||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.IDP_ELEMENT);
|
||||
IDP idp = new IDP();
|
||||
String entityID = SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
|
||||
String entityID = getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
|
||||
if (entityID == null) {
|
||||
throw new ParsingException("entityID must be set on IDP");
|
||||
|
||||
}
|
||||
idp.setEntityID(entityID);
|
||||
|
||||
boolean signaturesRequired = SPXmlParser.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNATURES_REQUIRED_ATTR);
|
||||
idp.setSignatureCanonicalizationMethod(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
|
||||
idp.setSignatureAlgorithm(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR));
|
||||
boolean signaturesRequired = getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNATURES_REQUIRED_ATTR);
|
||||
idp.setSignatureCanonicalizationMethod(getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
|
||||
idp.setSignatureAlgorithm(getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR));
|
||||
while (xmlEventReader.hasNext()) {
|
||||
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
||||
if (xmlEvent == null)
|
||||
|
@ -75,6 +79,10 @@ public class IDPXmlParser extends AbstractParser {
|
|||
IDP.SingleLogoutService slo = parseSingleLogoutService(xmlEventReader, signaturesRequired);
|
||||
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)) {
|
||||
KeysXmlParser parser = new KeysXmlParser();
|
||||
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 {
|
||||
IDP.SingleLogoutService slo = new IDP.SingleLogoutService();
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
slo.setSignRequest(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
|
||||
slo.setValidateResponseSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
|
||||
slo.setValidateRequestSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR, signaturesRequired));
|
||||
slo.setRequestBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
|
||||
slo.setResponseBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
||||
slo.setSignResponse(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR, signaturesRequired));
|
||||
slo.setPostBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR));
|
||||
slo.setRedirectBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REDIRECT_BINDING_URL_ATTR));
|
||||
slo.setSignRequest(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
|
||||
slo.setValidateResponseSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
|
||||
slo.setValidateRequestSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR, signaturesRequired));
|
||||
slo.setRequestBinding(getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
|
||||
slo.setResponseBinding(getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
||||
slo.setSignResponse(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR, signaturesRequired));
|
||||
slo.setPostBindingUrl(getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR));
|
||||
slo.setRedirectBindingUrl(getAttributeValue(element, ConfigXmlConstants.REDIRECT_BINDING_URL_ATTR));
|
||||
return slo;
|
||||
}
|
||||
|
||||
protected IDP.SingleSignOnService parseSingleSignOnService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException {
|
||||
IDP.SingleSignOnService sso = new IDP.SingleSignOnService();
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
sso.setSignRequest(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
|
||||
sso.setValidateResponseSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
|
||||
sso.setValidateAssertionSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_ASSERTION_SIGNATURE_ATTR));
|
||||
sso.setRequestBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
|
||||
sso.setResponseBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
||||
sso.setBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
|
||||
sso.setSignRequest(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
|
||||
sso.setValidateResponseSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
|
||||
sso.setValidateAssertionSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_ASSERTION_SIGNATURE_ATTR));
|
||||
sso.setRequestBinding(getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
|
||||
sso.setResponseBinding(getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
||||
sso.setBindingUrl(getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
|
||||
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
|
||||
public boolean supports(QName qname) {
|
||||
return false;
|
||||
|
|
|
@ -48,6 +48,13 @@ public class SPXmlParser extends AbstractParser {
|
|||
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) {
|
||||
String result = getAttributeValue(startElement, tag);
|
||||
if (result == null)
|
||||
|
|
|
@ -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>
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
Loading…
Reference in a new issue