keycloak-aplcache

saml undertow sp

9/22/2015 9:27:08 PM

Changes

pom.xml 5(+5 -0)

Details

pom.xml 5(+5 -0)

diff --git a/pom.xml b/pom.xml
index ce53528..c0a1cc1 100755
--- a/pom.xml
+++ b/pom.xml
@@ -992,6 +992,11 @@
             </dependency>
             <dependency>
                 <groupId>org.keycloak</groupId>
+                <artifactId>keycloak-undertow-saml-adapter</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.keycloak</groupId>
                 <artifactId>keycloak-services</artifactId>
                 <version>${project.version}</version>
             </dependency>
diff --git a/saml/client-adapter/core/pom.xml b/saml/client-adapter/core/pom.xml
index 59bd4d5..605d87f 100755
--- a/saml/client-adapter/core/pom.xml
+++ b/saml/client-adapter/core/pom.xml
@@ -10,7 +10,7 @@
     <modelVersion>4.0.0</modelVersion>
 
     <artifactId>keycloak-saml-adapter-core</artifactId>
-    <name>Keycloak SAML Adapter Core</name>
+    <name>Keycloak SAML Client Adapter Core</name>
     <description/>
 
     <properties>
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java
new file mode 100755
index 0000000..813f52e
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java
@@ -0,0 +1,190 @@
+package org.keycloak.adapters.saml.config;
+
+import org.keycloak.adapters.saml.SamlDeployment;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class IDP implements Serializable {
+    public static class SingleSignOnService implements Serializable {
+        private boolean signRequest;
+        private boolean validateResponseSignature;
+        private String signatureCanonicalizationMethod;
+        private String requestBinding;
+        private String responseBinding;
+        private String bindingUrl;
+
+        public boolean isSignRequest() {
+            return signRequest;
+        }
+
+        public void setSignRequest(boolean signRequest) {
+            this.signRequest = signRequest;
+        }
+
+        public boolean isValidateResponseSignature() {
+            return validateResponseSignature;
+        }
+
+        public void setValidateResponseSignature(boolean validateResponseSignature) {
+            this.validateResponseSignature = validateResponseSignature;
+        }
+
+        public String getSignatureCanonicalizationMethod() {
+            return signatureCanonicalizationMethod;
+        }
+
+        public void setSignatureCanonicalizationMethod(String signatureCanonicalizationMethod) {
+            this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
+        }
+
+        public String getRequestBinding() {
+            return requestBinding;
+        }
+
+        public void setRequestBinding(String requestBinding) {
+            this.requestBinding = requestBinding;
+        }
+
+        public String getResponseBinding() {
+            return responseBinding;
+        }
+
+        public void setResponseBinding(String responseBinding) {
+            this.responseBinding = responseBinding;
+        }
+
+        public String getBindingUrl() {
+            return bindingUrl;
+        }
+
+        public void setBindingUrl(String bindingUrl) {
+            this.bindingUrl = bindingUrl;
+        }
+    }
+
+    public static class SingleLogoutService implements Serializable {
+        private boolean signRequest;
+        private boolean signResponse;
+        private boolean validateRequestSignature;
+        private boolean validateResponseSignature;
+        private String signatureCanonicalizationMethod;
+        private String requestBinding;
+        private String responseBinding;
+        private String postBindingUrl;
+        private String redirectBindingUrl;
+
+        public boolean isSignRequest() {
+            return signRequest;
+        }
+
+        public void setSignRequest(boolean signRequest) {
+            this.signRequest = signRequest;
+        }
+
+        public boolean isSignResponse() {
+            return signResponse;
+        }
+
+        public void setSignResponse(boolean signResponse) {
+            this.signResponse = signResponse;
+        }
+
+        public boolean isValidateRequestSignature() {
+            return validateRequestSignature;
+        }
+
+        public void setValidateRequestSignature(boolean validateRequestSignature) {
+            this.validateRequestSignature = validateRequestSignature;
+        }
+
+        public boolean isValidateResponseSignature() {
+            return validateResponseSignature;
+        }
+
+        public void setValidateResponseSignature(boolean validateResponseSignature) {
+            this.validateResponseSignature = validateResponseSignature;
+        }
+
+        public String getSignatureCanonicalizationMethod() {
+            return signatureCanonicalizationMethod;
+        }
+
+        public void setSignatureCanonicalizationMethod(String signatureCanonicalizationMethod) {
+            this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
+        }
+
+        public String getRequestBinding() {
+            return requestBinding;
+        }
+
+        public void setRequestBinding(String requestBinding) {
+            this.requestBinding = requestBinding;
+        }
+
+        public String getResponseBinding() {
+            return responseBinding;
+        }
+
+        public void setResponseBinding(String responseBinding) {
+            this.responseBinding = responseBinding;
+        }
+
+        public String getPostBindingUrl() {
+            return postBindingUrl;
+        }
+
+        public void setPostBindingUrl(String postBindingUrl) {
+            this.postBindingUrl = postBindingUrl;
+        }
+
+        public String getRedirectBindingUrl() {
+            return redirectBindingUrl;
+        }
+
+        public void setRedirectBindingUrl(String redirectBindingUrl) {
+            this.redirectBindingUrl = redirectBindingUrl;
+        }
+    }
+
+    private String entityID;
+    private SingleSignOnService singleSignOnService;
+    private SingleLogoutService singleLogoutService;
+    private List<Key> keys;
+
+    public String getEntityID() {
+        return entityID;
+    }
+
+    public void setEntityID(String entityID) {
+        this.entityID = entityID;
+    }
+
+    public SingleSignOnService getSingleSignOnService() {
+        return singleSignOnService;
+    }
+
+    public void setSingleSignOnService(SingleSignOnService singleSignOnService) {
+        this.singleSignOnService = singleSignOnService;
+    }
+
+    public SingleLogoutService getSingleLogoutService() {
+        return singleLogoutService;
+    }
+
+    public void setSingleLogoutService(SingleLogoutService singleLogoutService) {
+        this.singleLogoutService = singleLogoutService;
+    }
+
+    public List<Key> getKeys() {
+        return keys;
+    }
+
+    public void setKeys(List<Key> keys) {
+        this.keys = keys;
+    }
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/Key.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/Key.java
new file mode 100755
index 0000000..3d94f78
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/Key.java
@@ -0,0 +1,143 @@
+package org.keycloak.adapters.saml.config;
+
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class Key implements Serializable {
+
+    public static class KeyStoreConfig implements Serializable {
+        private String file;
+        private String resource;
+        private String password;
+        private String type;
+        private String alias;
+        private String privateKeyAlias;
+        private String privateKeyPassword;
+        private String certificateAlias;
+
+
+        public String getFile() {
+            return file;
+        }
+
+        public void setFile(String file) {
+            this.file = file;
+        }
+
+        public String getResource() {
+            return resource;
+        }
+
+        public void setResource(String resource) {
+            this.resource = resource;
+        }
+
+        public String getPassword() {
+            return password;
+        }
+
+        public void setPassword(String password) {
+            this.password = password;
+        }
+
+        public String getPrivateKeyAlias() {
+            return privateKeyAlias;
+        }
+
+        public void setPrivateKeyAlias(String privateKeyAlias) {
+            this.privateKeyAlias = privateKeyAlias;
+        }
+
+        public String getPrivateKeyPassword() {
+            return privateKeyPassword;
+        }
+
+        public void setPrivateKeyPassword(String privateKeyPassword) {
+            this.privateKeyPassword = privateKeyPassword;
+        }
+
+        public String getCertificateAlias() {
+            return certificateAlias;
+        }
+
+        public void setCertificateAlias(String certificateAlias) {
+            this.certificateAlias = certificateAlias;
+        }
+
+        public String getType() {
+            return type;
+        }
+
+        public void setType(String type) {
+            this.type = type;
+        }
+
+        public String getAlias() {
+            return alias;
+        }
+
+        public void setAlias(String alias) {
+            this.alias = alias;
+        }
+    }
+
+
+    private boolean signing;
+    private boolean encryption;
+    private KeyStoreConfig keystore;
+    private String privateKeyPem;
+    private String publicKeyPem;
+    private String certificatePem;
+
+
+    public boolean isSigning() {
+        return signing;
+    }
+
+    public void setSigning(boolean signing) {
+        this.signing = signing;
+    }
+
+    public boolean isEncryption() {
+        return encryption;
+    }
+
+    public void setEncryption(boolean encryption) {
+        this.encryption = encryption;
+    }
+
+    public KeyStoreConfig getKeystore() {
+        return keystore;
+    }
+
+    public void setKeystore(KeyStoreConfig keystore) {
+        this.keystore = keystore;
+    }
+
+    public String getPrivateKeyPem() {
+        return privateKeyPem;
+    }
+
+    public void setPrivateKeyPem(String privateKeyPem) {
+        this.privateKeyPem = privateKeyPem;
+    }
+
+    public String getPublicKeyPem() {
+        return publicKeyPem;
+    }
+
+    public void setPublicKeyPem(String publicKeyPem) {
+        this.publicKeyPem = publicKeyPem;
+    }
+
+    public String getCertificatePem() {
+        return certificatePem;
+    }
+
+    public void setCertificatePem(String certificatePem) {
+        this.certificatePem = certificatePem;
+    }
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/KeycloakSamlAdapter.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/KeycloakSamlAdapter.java
new file mode 100755
index 0000000..9370dba
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/KeycloakSamlAdapter.java
@@ -0,0 +1,21 @@
+package org.keycloak.adapters.saml.config;
+
+import java.io.Serializable;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakSamlAdapter implements Serializable {
+    private List<SP> sps = new LinkedList<>();
+
+    public List<SP> getSps() {
+        return sps;
+    }
+
+    public void setSps(List<SP> sps) {
+        this.sps = sps;
+    }
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java
new file mode 100755
index 0000000..a714b0a
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java
@@ -0,0 +1,56 @@
+package org.keycloak.adapters.saml.config.parsers;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ConfigXmlConstants {
+    public static final String KEYCLOAK_SAML_ADAPTER ="keycloak-saml-adapter";
+    public static final String SP_ELEMENT="SP";
+    public static final String ENTITY_ID_ATTR = "entityID";
+    public static final String SSL_POLICY_ATTR = "sslPolicy";
+    public static final String NAME_ID_POLICY_FORMAT_ATTR = "nameIDPolicyFormat";
+    public static final String FORCE_AUTHENTICATION_ATTR = "forceAuthentication";
+    public static final String LOGOUT_PAGE_ATTR = "logoutPage";
+
+
+    public static final String KEYS_ELEMENT = "Keys";
+    public static final String KEY_ELEMENT = "Key";
+    public static final String SIGNING_ATTR = "signing";
+    public static final String ENCRYPTION_ATTR = "encryption";
+    public static final String CERTIFICATE_PEM_ELEMENT = "CertificatePem";
+    public static final String PRIVATE_KEY_PEM_ELEMENT = "PrivateKeyPem";
+    public static final String PUBLIC_KEY_PEM_ELEMENT = "PublicKeyPem";
+    public static final String FILE_ATTR = "file";
+    public static final String TYPE_ATTR = "type";
+    public static final String RESOURCE_ATTR = "resource";
+    public static final String PASSWORD_ATTR = "password";
+    public static final String ALIAS_ATTR = "alias";
+    public static final String KEYS_STORE_ELEMENT = "KeyStore";
+    public static final String CERTIFICATE_ELEMENT = "Certificate";
+    public static final String PRIVATE_KEY_ELEMENT = "PrivateKey";
+
+    public static final String PRINCIPAL_NAME_MAPPING_ELEMENT = "PrincipalNameMapping";
+    public static final String POLICY_ATTR = "policy";
+    public static final String ATTRIBUTE_ATTR = "attribute";
+
+
+    public static final String ROLE_MAPPING_ELEMENT = "RoleMapping";
+    public static final String ATTRIBUTE_ELEMENT = "Attribute";
+    public static final String FRIENDLY_ATTRIBUTE_ELEMENT = "FriendlyAttribute";
+    public static final String NAME_ATTR = "name";
+
+    public static final String IDP_ELEMENT = "IDP";
+    public static final String SINGLE_SIGN_ON_SERVICE_ELEMENT = "SingleSignOnService";
+    public static final String SINGLE_LOGOUT_SERVICE_ELEMENT = "SingleLogoutService";
+    public static final String SIGN_REQUEST_ATTR = "signRequest";
+    public static final String SIGN_RESPONSE_ATTR = "signResponse";
+    public static final String SIGNATURE_CANONICALIZATION_METHOD_ATTR = "signatureCanonicalizationMethod";
+    public static final String REQUEST_BINDING_ATTR = "requestBinding";
+    public static final String RESPONSE_BINDING_ATTR = "responseBinding";
+    public static final String BINDING_URL_ATTR = "bindingUrl";
+    public static final String VALIDATE_RESPONSE_SIGNATURE_ATTR = "validateResponseSignature";
+    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";
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java
new file mode 100755
index 0000000..24f9101
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java
@@ -0,0 +1,195 @@
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.DefaultSamlDeployment;
+import org.keycloak.adapters.saml.SamlDeployment;
+import org.keycloak.adapters.saml.config.Key;
+import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
+import org.keycloak.adapters.saml.config.SP;
+import org.keycloak.enums.SslRequired;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.util.PemUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.cert.Certificate;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class DeploymentBuilder {
+    public SamlDeployment build(InputStream xml, ResourceLoader resourceLoader) throws ParsingException {
+        DefaultSamlDeployment deployment = new DefaultSamlDeployment();
+        DefaultSamlDeployment.DefaultIDP idp = new DefaultSamlDeployment.DefaultIDP();
+        DefaultSamlDeployment.DefaultSingleSignOnService sso = new DefaultSamlDeployment.DefaultSingleSignOnService();
+        DefaultSamlDeployment.DefaultSingleLogoutService slo = new DefaultSamlDeployment.DefaultSingleLogoutService();
+        idp.setSingleSignOnService(sso);
+        idp.setSingleLogoutService(slo);
+
+        KeycloakSamlAdapter adapter = (KeycloakSamlAdapter)(new KeycloakSamlAdapterXMLParser().parse(xml));
+        SP sp = adapter.getSps().get(0);
+        deployment.setConfigured(true);
+        deployment.setEntityID(sp.getEntityID());
+        deployment.setForceAuthentication(sp.isForceAuthentication());
+        deployment.setNameIDPolicyFormat(sp.getNameIDPolicyFormat());
+        deployment.setLogoutPage(sp.getLogoutPage());
+        if (sp.getPrincipalNameMapping() != null) {
+            SamlDeployment.PrincipalNamePolicy policy = SamlDeployment.PrincipalNamePolicy.valueOf(sp.getPrincipalNameMapping().getPolicy());
+            deployment.setPrincipalNamePolicy(policy);
+            deployment.setPrincipalAttributeName(sp.getPrincipalNameMapping().getAttributeName());
+        }
+        deployment.setRoleAttributeNames(sp.getRoleAttributes());
+        deployment.setRoleFriendlyAttributeNames(sp.getRoleFriendlyAttributes());
+        if (sp.getSslPolicy() != null) {
+            SslRequired ssl = SslRequired.valueOf(sp.getSslPolicy());
+            deployment.setSslRequired(ssl);
+        }
+        for (Key key : sp.getKeys()) {
+            if (key.isSigning()) {
+                PrivateKey privateKey = null;
+                PublicKey publicKey = null;
+                if (key.getKeystore() != null) {
+                    KeyStore keyStore = loadKeystore(resourceLoader, key);
+                    Certificate cert  = null;
+                    try {
+                        cert = keyStore.getCertificate(key.getKeystore().getCertificateAlias());
+                        privateKey = (PrivateKey)keyStore.getKey(key.getKeystore().getPrivateKeyAlias(), key.getKeystore().getPrivateKeyPassword().toCharArray());
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                    publicKey = cert.getPublicKey();
+                } else {
+                    if (key.getPrivateKeyPem() == null) {
+                        throw new RuntimeException("SP signing key must have a PrivateKey defined");
+                    }
+                    try {
+                        privateKey = PemUtils.decodePrivateKey(key.getPrivateKeyPem().trim());
+                        if (key.getPublicKeyPem() == null &&key.getCertificatePem() == null) {
+                            throw new RuntimeException("Sp signing key must have a PublicKey or Certificate defined");
+                        }
+                        publicKey = getPublicKeyFromPem(key);
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+                KeyPair keyPair = new KeyPair(publicKey, privateKey);
+                deployment.setSigningKeyPair(keyPair);
+
+            } else if (key.isEncryption()) {
+                KeyStore keyStore = loadKeystore(resourceLoader, key);
+                try {
+                    PrivateKey privateKey = (PrivateKey)keyStore.getKey(key.getKeystore().getPrivateKeyAlias(), key.getKeystore().getPrivateKeyPassword().toCharArray());
+                    deployment.setDecryptionKey(privateKey);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+
+        deployment.setIdp(idp);
+        idp.setEntityID(sp.getIdp().getEntityID());
+        sso.setRequestBinding(SamlDeployment.Binding.parseBinding(sp.getIdp().getSingleSignOnService().getRequestBinding()));
+        sso.setRequestBindingUrl(sp.getIdp().getSingleSignOnService().getBindingUrl());
+        sso.setResponseBinding(SamlDeployment.Binding.parseBinding(sp.getIdp().getSingleSignOnService().getResponseBinding()));
+        sso.setSignatureCanonicalizationMethod(sp.getIdp().getSingleSignOnService().getSignatureCanonicalizationMethod());
+        sso.setSignRequest(sp.getIdp().getSingleSignOnService().isSignRequest());
+        sso.setValidateResponseSignature(sp.getIdp().getSingleSignOnService().isValidateResponseSignature());
+
+        slo.setSignRequest(sp.getIdp().getSingleLogoutService().isSignRequest());
+        slo.setSignResponse(sp.getIdp().getSingleLogoutService().isSignResponse());
+        slo.setValidateResponseSignature(sp.getIdp().getSingleLogoutService().isValidateResponseSignature());
+        slo.setValidateRequestSignature(sp.getIdp().getSingleLogoutService().isValidateRequestSignature());
+        slo.setSignatureCanonicalizationMethod(sp.getIdp().getSingleLogoutService().getSignatureCanonicalizationMethod());
+        slo.setRequestBinding(SamlDeployment.Binding.parseBinding(sp.getIdp().getSingleLogoutService().getRequestBinding()));
+        slo.setResponseBinding(SamlDeployment.Binding.parseBinding(sp.getIdp().getSingleLogoutService().getResponseBinding()));
+        if (slo.getRequestBinding() == SamlDeployment.Binding.POST) {
+            slo.setRequestBindingUrl(sp.getIdp().getSingleLogoutService().getPostBindingUrl());
+        } else {
+            slo.setRequestBindingUrl(sp.getIdp().getSingleLogoutService().getRedirectBindingUrl());
+        }
+        if (slo.getResponseBinding() == SamlDeployment.Binding.POST) {
+            slo.setResponseBindingUrl(sp.getIdp().getSingleLogoutService().getPostBindingUrl());
+        } else {
+            slo.setResponseBindingUrl(sp.getIdp().getSingleLogoutService().getRedirectBindingUrl());
+        }
+        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);
+                    }
+                }
+            }
+        }
+
+
+        return deployment;
+    }
+
+    protected static PublicKey getPublicKeyFromPem(Key key) throws Exception {
+        PublicKey publicKey;
+        if (key.getPublicKeyPem() != null) {
+            publicKey = PemUtils.decodePublicKey(key.getPublicKeyPem().trim());
+        } else {
+            Certificate cert = PemUtils.decodeCertificate(key.getCertificatePem().trim());
+            publicKey = cert.getPublicKey();
+        }
+        return publicKey;
+    }
+
+    protected static KeyStore loadKeystore(ResourceLoader resourceLoader, Key key) {
+        String type = key.getKeystore().getType();
+        if (type == null) type = "JKS";
+        KeyStore keyStore = null;
+        try {
+            keyStore = KeyStore.getInstance(type);
+        } catch (KeyStoreException e) {
+            throw new RuntimeException(e);
+        }
+        InputStream is = null;
+        if (key.getKeystore().getFile() != null) {
+            File fp = new File(key.getKeystore().getFile());
+            if (!fp.exists()) {
+            }
+            try {
+                is = new FileInputStream(fp);
+            } catch (FileNotFoundException e) {
+                throw new RuntimeException("KeyStore " + key.getKeystore().getFile() + " does not exist");
+            }
+
+        } else {
+            is = resourceLoader.getResourceAsStream(key.getKeystore().getResource());
+            if (is == null) {
+                throw new RuntimeException("KeyStore " + key.getKeystore().getResource() + " does not exist");
+            }
+        }
+        try {
+            keyStore.load(is, key.getKeystore().getPassword().toCharArray());
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return keyStore;
+    }
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java
new file mode 100755
index 0000000..c4e9a6e
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java
@@ -0,0 +1,100 @@
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.IDP;
+import org.keycloak.adapters.saml.config.Key;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.parsers.AbstractParser;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class IDPXmlParser extends AbstractParser {
+
+    @Override
+    public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
+        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
+        StaxParserUtil.validate(startElement, ConfigXmlConstants.IDP_ELEMENT);
+        IDP idp = new IDP();
+        String entityID = StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
+        if (entityID == null) {
+            throw new ParsingException("entityID must be set on IDP");
+
+        }
+        idp.setEntityID(entityID);
+        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.IDP_ELEMENT))
+                    break;
+                else
+                    continue;
+            }
+            startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
+            if (startElement == null)
+                break;
+            String tag = StaxParserUtil.getStartElementName(startElement);
+            if (tag.equals(ConfigXmlConstants.SINGLE_SIGN_ON_SERVICE_ELEMENT)) {
+                IDP.SingleSignOnService sso = parseSingleSignOnService(xmlEventReader);
+                idp.setSingleSignOnService(sso);
+
+            } else if (tag.equals(ConfigXmlConstants.SINGLE_LOGOUT_SERVICE_ELEMENT)) {
+                IDP.SingleLogoutService slo = parseSingleLogoutService(xmlEventReader);
+                idp.setSingleLogoutService(slo);
+
+            } else if (tag.equals(ConfigXmlConstants.KEYS_ELEMENT)) {
+                KeysXmlParser parser = new KeysXmlParser();
+                List<Key> keys = (List<Key>)parser.parse(xmlEventReader);
+                idp.setKeys(keys);
+            } else {
+                StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
+            }
+
+        }
+        return idp;
+    }
+
+    protected IDP.SingleLogoutService parseSingleLogoutService(XMLEventReader xmlEventReader) throws ParsingException {
+        IDP.SingleLogoutService slo = new IDP.SingleLogoutService();
+        StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
+        slo.setSignRequest(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR));
+        slo.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR));
+        slo.setValidateRequestSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR));
+        slo.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
+        slo.setRequestBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
+        slo.setResponseBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
+        slo.setSignResponse(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR));
+        slo.setPostBindingUrl(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR));
+        slo.setRedirectBindingUrl(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.REDIRECT_BINDING_URL_ATTR));
+        return slo;
+    }
+
+    protected IDP.SingleSignOnService parseSingleSignOnService(XMLEventReader xmlEventReader) throws ParsingException {
+        IDP.SingleSignOnService sso = new IDP.SingleSignOnService();
+        StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
+        sso.setSignRequest(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR));
+        sso.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR));
+        sso.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
+        sso.setRequestBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
+        sso.setResponseBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
+        sso.setBindingUrl(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
+        return sso;
+    }
+
+    @Override
+    public boolean supports(QName qname) {
+        return false;
+    }
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterXMLParser.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterXMLParser.java
new file mode 100755
index 0000000..d5b9ee6
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterXMLParser.java
@@ -0,0 +1,46 @@
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
+import org.keycloak.adapters.saml.config.SP;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.parsers.AbstractParser;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakSamlAdapterXMLParser extends AbstractParser {
+
+    @Override
+    public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
+        KeycloakSamlAdapter adapter = new KeycloakSamlAdapter();
+        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
+        StaxParserUtil.validate(startElement, ConfigXmlConstants.KEYCLOAK_SAML_ADAPTER);
+        while (xmlEventReader.hasNext()) {
+            startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
+            if (startElement == null)
+                break;
+            String tag = StaxParserUtil.getStartElementName(startElement);
+            if (tag.equals(ConfigXmlConstants.SP_ELEMENT)) {
+                SPXmlParser parser = new SPXmlParser();
+                SP sp = (SP)parser.parse(xmlEventReader);
+                if (sp != null) adapter.getSps().add(sp);
+            } else {
+                StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
+            }
+
+        }
+        return adapter;
+    }
+
+    @Override
+    public boolean supports(QName qname) {
+        return false;
+    }
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeysXmlParser.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeysXmlParser.java
new file mode 100755
index 0000000..a63a6ac
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeysXmlParser.java
@@ -0,0 +1,60 @@
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.Key;
+import org.keycloak.adapters.saml.config.SP;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.parsers.AbstractParser;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeysXmlParser extends AbstractParser {
+
+    @Override
+    public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
+        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
+        StaxParserUtil.validate(startElement, ConfigXmlConstants.KEYS_ELEMENT);
+        List<Key> keys = new LinkedList<>();
+        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.KEYS_ELEMENT))
+                    break;
+                else
+                    throw logger.parserUnknownEndElement(endElementName);
+            }
+            startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
+            if (startElement == null)
+                break;
+            String tag = StaxParserUtil.getStartElementName(startElement);
+            if (tag.equals(ConfigXmlConstants.KEY_ELEMENT)) {
+                KeyXmlParser parser = new KeyXmlParser();
+                Key key = (Key)parser.parse(xmlEventReader);
+                keys.add(key);
+            } else {
+                StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
+            }
+
+        }
+        return keys;
+    }
+
+    @Override
+    public boolean supports(QName qname) {
+        return false;
+    }
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java
new file mode 100755
index 0000000..787af69
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java
@@ -0,0 +1,128 @@
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.Key;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.parsers.AbstractParser;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeyXmlParser extends AbstractParser {
+
+    @Override
+    public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
+        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
+        StaxParserUtil.validate(startElement, ConfigXmlConstants.KEY_ELEMENT);
+        Key key = new Key();
+        key.setSigning(StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNING_ATTR));
+        key.setEncryption(StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.ENCRYPTION_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.KEY_ELEMENT))
+                    break;
+                else
+                    throw logger.parserUnknownEndElement(endElementName);
+            }
+            startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
+            if (startElement == null)
+                break;
+            String tag = StaxParserUtil.getStartElementName(startElement);
+            if (tag.equals(ConfigXmlConstants.KEYS_STORE_ELEMENT)) {
+                key.setKeystore(parseKeyStore(xmlEventReader));
+            } else if (tag.equals(ConfigXmlConstants.CERTIFICATE_PEM_ELEMENT)) {
+                StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
+                key.setCertificatePem(StaxParserUtil.getElementText(xmlEventReader));
+            } else if (tag.equals(ConfigXmlConstants.PUBLIC_KEY_PEM_ELEMENT)) {
+                StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
+                key.setPublicKeyPem(StaxParserUtil.getElementText(xmlEventReader));
+            } else if (tag.equals(ConfigXmlConstants.PRIVATE_KEY_PEM_ELEMENT)) {
+                StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
+                key.setPrivateKeyPem(StaxParserUtil.getElementText(xmlEventReader));
+            } else {
+                StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
+            }
+
+        }
+        return key;
+    }
+
+    protected Key.KeyStoreConfig parseKeyStore(XMLEventReader xmlEventReader)  throws ParsingException {
+        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
+        StaxParserUtil.validate(startElement, ConfigXmlConstants.KEYS_STORE_ELEMENT);
+        Key.KeyStoreConfig keyStore = new Key.KeyStoreConfig();
+        keyStore.setType(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.TYPE_ATTR));
+        keyStore.setAlias(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.ALIAS_ATTR));
+        keyStore.setFile(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.FILE_ATTR));
+        keyStore.setResource(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.RESOURCE_ATTR));
+        if (keyStore.getFile() == null && keyStore.getResource() == null) {
+            throw new ParsingException("KeyStore element must have the url or classpath attribute set");
+        }
+        keyStore.setPassword(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.PASSWORD_ATTR));
+        if (keyStore.getPassword() == null) {
+            throw new ParsingException("KeyStore element must have the password attribute set");
+        }
+
+
+
+        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.KEYS_STORE_ELEMENT))
+                    break;
+                else
+                    continue;
+            }
+            startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
+            if (startElement == null)
+                break;
+            String tag = StaxParserUtil.getStartElementName(startElement);
+            if (tag.equals(ConfigXmlConstants.CERTIFICATE_ELEMENT)) {
+                StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
+                keyStore.setCertificateAlias(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
+                if (keyStore.getCertificateAlias() == null) {
+                    throw new ParsingException("KeyStore Certificate element must have the alias attribute set");
+
+                }
+            } else if (tag.equals(ConfigXmlConstants.PRIVATE_KEY_ELEMENT)) {
+                StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
+                keyStore.setPrivateKeyAlias(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
+                if (keyStore.getPrivateKeyAlias() == null) {
+                    throw new ParsingException("KeyStore PrivateKey element must have the alias attribute set");
+
+                }
+                keyStore.setPrivateKeyPassword(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.PASSWORD_ATTR));
+                if (keyStore.getPrivateKeyPassword() == null) {
+                    throw new ParsingException("KeyStore PrivateKey element must have the password attribute set");
+
+                }
+            } else {
+                StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
+            }
+
+        }
+        return keyStore;
+
+    }
+
+    @Override
+    public boolean supports(QName qname) {
+        return false;
+    }
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ResourceLoader.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ResourceLoader.java
new file mode 100755
index 0000000..296f31e
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ResourceLoader.java
@@ -0,0 +1,11 @@
+package org.keycloak.adapters.saml.config.parsers;
+
+import java.io.InputStream;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ResourceLoader {
+    InputStream getResourceAsStream(String resource);
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java
new file mode 100755
index 0000000..8df8500
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java
@@ -0,0 +1,139 @@
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.IDP;
+import org.keycloak.adapters.saml.config.Key;
+import org.keycloak.adapters.saml.config.SP;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.parsers.AbstractParser;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SPXmlParser extends AbstractParser {
+
+    @Override
+    public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
+        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
+        StaxParserUtil.validate(startElement, ConfigXmlConstants.SP_ELEMENT);
+        SP sp = new SP();
+        String entityID = StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
+        if (entityID == null) {
+            throw new ParsingException("entityID must be set on SP");
+
+        }
+        sp.setEntityID(entityID);
+        sp.setSslPolicy(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SSL_POLICY_ATTR));
+        sp.setLogoutPage(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.LOGOUT_PAGE_ATTR));
+        sp.setNameIDPolicyFormat(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.NAME_ID_POLICY_FORMAT_ATTR));
+        sp.setForceAuthentication(StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.FORCE_AUTHENTICATION_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.SP_ELEMENT))
+                    break;
+                else
+                    continue;
+            }
+            startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
+            if (startElement == null)
+                break;
+            String tag = StaxParserUtil.getStartElementName(startElement);
+            if (tag.equals(ConfigXmlConstants.KEYS_ELEMENT)) {
+                KeysXmlParser parser = new KeysXmlParser();
+                List<Key> keys = (List<Key>)parser.parse(xmlEventReader);
+                sp.setKeys(keys);
+            } else if (tag.equals(ConfigXmlConstants.PRINCIPAL_NAME_MAPPING_ELEMENT)) {
+                StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
+                String policy = StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.POLICY_ATTR);
+                if (policy == null) {
+                    throw new ParsingException("PrincipalNameMapping element must have the policy attribute set");
+
+                }
+                String attribute = StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.ATTRIBUTE_ATTR);
+                SP.PrincipalNameMapping mapping = new SP.PrincipalNameMapping();
+                mapping.setPolicy(policy);
+                mapping.setAttributeName(attribute);
+                sp.setPrincipalNameMapping(mapping);
+
+            } else if (tag.equals(ConfigXmlConstants.ROLE_MAPPING_ELEMENT)) {
+                parseRoleMapping(xmlEventReader, sp);
+            } else if (tag.equals(ConfigXmlConstants.IDP_ELEMENT)) {
+                IDPXmlParser parser = new IDPXmlParser();
+                IDP idp = (IDP)parser.parse(xmlEventReader);
+                sp.setIdp(idp);
+            } else {
+                StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
+            }
+
+        }
+        return sp;
+    }
+
+    protected void parseRoleMapping(XMLEventReader xmlEventReader, SP sp)  throws ParsingException {
+        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
+        StaxParserUtil.validate(startElement, ConfigXmlConstants.ROLE_MAPPING_ELEMENT);
+        Set<String> roleAttributes = new HashSet<>();
+        Set<String> roleFriendlyAttributes = new HashSet<>();
+        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_MAPPING_ELEMENT))
+                    break;
+                else
+                    continue;
+            }
+            startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
+            if (startElement == null)
+                break;
+            String tag = StaxParserUtil.getStartElementName(startElement);
+            if (tag.equals(ConfigXmlConstants.ATTRIBUTE_ELEMENT)) {
+                StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
+                String attributeValue = StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.NAME_ATTR);
+                if (attributeValue == null) {
+                    throw new ParsingException("RoleMapping Attribute element must have the name attribute set");
+
+                }
+                roleAttributes.add(attributeValue);
+            } else if (tag.equals(ConfigXmlConstants.FRIENDLY_ATTRIBUTE_ELEMENT)) {
+                StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
+                String attributeValue = StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.NAME_ATTR);
+                if (attributeValue == null) {
+                    throw new ParsingException("RoleMapping FriendlyAttribute element must have the name attribute set");
+
+                }
+                roleFriendlyAttributes.add(attributeValue);
+            } else {
+                StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
+            }
+
+        }
+        sp.setRoleAttributes(roleAttributes);
+        sp.setRoleFriendlyAttributes(roleFriendlyAttributes);
+    }
+
+
+    @Override
+    public boolean supports(QName qname) {
+        return false;
+    }
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/SP.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/SP.java
new file mode 100755
index 0000000..addafdb
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/SP.java
@@ -0,0 +1,126 @@
+package org.keycloak.adapters.saml.config;
+
+import org.keycloak.adapters.saml.SamlDeployment;
+import org.keycloak.enums.SslRequired;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SP implements Serializable {
+    public static class PrincipalNameMapping implements Serializable {
+        private String policy;
+        private String attributeName;
+
+        public String getPolicy() {
+            return policy;
+        }
+
+        public void setPolicy(String policy) {
+            this.policy = policy;
+        }
+
+        public String getAttributeName() {
+            return attributeName;
+        }
+
+        public void setAttributeName(String attributeName) {
+            this.attributeName = attributeName;
+        }
+    }
+
+    private String entityID;
+    private String sslPolicy;
+    private boolean forceAuthentication;
+    private String logoutPage;
+    private List<Key> keys;
+    private String nameIDPolicyFormat;
+    private PrincipalNameMapping principalNameMapping;
+    private Set<String> roleAttributes;
+    private Set<String> roleFriendlyAttributes;
+    private IDP idp;
+
+    public String getEntityID() {
+        return entityID;
+    }
+
+    public void setEntityID(String entityID) {
+        this.entityID = entityID;
+    }
+
+    public String getSslPolicy() {
+        return sslPolicy;
+    }
+
+    public void setSslPolicy(String sslPolicy) {
+        this.sslPolicy = sslPolicy;
+    }
+
+    public boolean isForceAuthentication() {
+        return forceAuthentication;
+    }
+
+    public void setForceAuthentication(boolean forceAuthentication) {
+        this.forceAuthentication = forceAuthentication;
+    }
+
+    public List<Key> getKeys() {
+        return keys;
+    }
+
+    public void setKeys(List<Key> keys) {
+        this.keys = keys;
+    }
+
+    public String getNameIDPolicyFormat() {
+        return nameIDPolicyFormat;
+    }
+
+    public void setNameIDPolicyFormat(String nameIDPolicyFormat) {
+        this.nameIDPolicyFormat = nameIDPolicyFormat;
+    }
+
+    public PrincipalNameMapping getPrincipalNameMapping() {
+        return principalNameMapping;
+    }
+
+    public void setPrincipalNameMapping(PrincipalNameMapping principalNameMapping) {
+        this.principalNameMapping = principalNameMapping;
+    }
+
+    public Set<String> getRoleAttributes() {
+        return roleAttributes;
+    }
+
+    public void setRoleAttributes(Set<String> roleAttributes) {
+        this.roleAttributes = roleAttributes;
+    }
+
+    public Set<String> getRoleFriendlyAttributes() {
+        return roleFriendlyAttributes;
+    }
+
+    public void setRoleFriendlyAttributes(Set<String> roleFriendlyAttributes) {
+        this.roleFriendlyAttributes = roleFriendlyAttributes;
+    }
+
+    public IDP getIdp() {
+        return idp;
+    }
+
+    public void setIdp(IDP idp) {
+        this.idp = idp;
+    }
+
+    public String getLogoutPage() {
+        return logoutPage;
+    }
+
+    public void setLogoutPage(String logoutPage) {
+        this.logoutPage = logoutPage;
+    }
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java
new file mode 100755
index 0000000..65612b3
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java
@@ -0,0 +1,363 @@
+package org.keycloak.adapters.saml;
+
+import org.keycloak.adapters.saml.SamlDeployment;
+import org.keycloak.adapters.saml.config.IDP;
+import org.keycloak.enums.SslRequired;
+
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class DefaultSamlDeployment implements SamlDeployment {
+
+    public static class DefaultSingleSignOnService implements IDP.SingleSignOnService {
+        private boolean signRequest;
+        private boolean validateResponseSignature;
+        private String signatureCanonicalizationMethod;
+        private Binding requestBinding;
+        private Binding responseBinding;
+        private String requestBindingUrl;
+
+        @Override
+        public boolean signRequest() {
+            return signRequest;
+        }
+
+        @Override
+        public boolean validateResponseSignature() {
+            return validateResponseSignature;
+        }
+
+        @Override
+        public String getSignatureCanonicalizationMethod() {
+            return signatureCanonicalizationMethod;
+        }
+
+        @Override
+        public Binding getRequestBinding() {
+            return requestBinding;
+        }
+
+        @Override
+        public Binding getResponseBinding() {
+            return responseBinding;
+        }
+
+        @Override
+        public String getRequestBindingUrl() {
+            return requestBindingUrl;
+        }
+
+        public void setSignRequest(boolean signRequest) {
+            this.signRequest = signRequest;
+        }
+
+        public void setValidateResponseSignature(boolean validateResponseSignature) {
+            this.validateResponseSignature = validateResponseSignature;
+        }
+
+        public void setSignatureCanonicalizationMethod(String signatureCanonicalizationMethod) {
+            this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
+        }
+
+        public void setRequestBinding(Binding requestBinding) {
+            this.requestBinding = requestBinding;
+        }
+
+        public void setResponseBinding(Binding responseBinding) {
+            this.responseBinding = responseBinding;
+        }
+
+        public void setRequestBindingUrl(String requestBindingUrl) {
+            this.requestBindingUrl = requestBindingUrl;
+        }
+    }
+
+    public static class DefaultSingleLogoutService implements IDP.SingleLogoutService {
+        private boolean validateRequestSignature;
+        private boolean validateResponseSignature;
+        private boolean signRequest;
+        private boolean signResponse;
+        private String signatureCanonicalizationMethod;
+        private Binding requestBinding;
+        private Binding responseBinding;
+        private String requestBindingUrl;
+        private String responseBindingUrl;
+
+        @Override
+        public boolean validateRequestSignature() {
+            return validateRequestSignature;
+        }
+
+        @Override
+        public boolean validateResponseSignature() {
+            return validateResponseSignature;
+        }
+
+        @Override
+        public boolean signRequest() {
+            return signRequest;
+        }
+
+        @Override
+        public boolean signResponse() {
+            return signResponse;
+        }
+
+        @Override
+        public String getSignatureCanonicalizationMethod() {
+            return signatureCanonicalizationMethod;
+        }
+
+        @Override
+        public Binding getRequestBinding() {
+            return requestBinding;
+        }
+
+        @Override
+        public Binding getResponseBinding() {
+            return responseBinding;
+        }
+
+        @Override
+        public String getRequestBindingUrl() {
+            return requestBindingUrl;
+        }
+
+        @Override
+        public String getResponseBindingUrl() {
+            return responseBindingUrl;
+        }
+
+        public void setValidateRequestSignature(boolean validateRequestSignature) {
+            this.validateRequestSignature = validateRequestSignature;
+        }
+
+        public void setValidateResponseSignature(boolean validateResponseSignature) {
+            this.validateResponseSignature = validateResponseSignature;
+        }
+
+        public void setSignRequest(boolean signRequest) {
+            this.signRequest = signRequest;
+        }
+
+        public void setSignResponse(boolean signResponse) {
+            this.signResponse = signResponse;
+        }
+
+        public void setSignatureCanonicalizationMethod(String signatureCanonicalizationMethod) {
+            this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
+        }
+
+        public void setRequestBinding(Binding requestBinding) {
+            this.requestBinding = requestBinding;
+        }
+
+        public void setResponseBinding(Binding responseBinding) {
+            this.responseBinding = responseBinding;
+        }
+
+        public void setRequestBindingUrl(String requestBindingUrl) {
+            this.requestBindingUrl = requestBindingUrl;
+        }
+
+        public void setResponseBindingUrl(String responseBindingUrl) {
+            this.responseBindingUrl = responseBindingUrl;
+        }
+    }
+
+
+
+    public static class DefaultIDP implements IDP {
+
+
+
+        private String entityID;
+        private PublicKey signatureValidationKey;
+        private SingleSignOnService singleSignOnService;
+        private SingleLogoutService singleLogoutService;
+
+        @Override
+        public String getEntityID() {
+            return entityID;
+        }
+
+        @Override
+        public SingleSignOnService getSingleSignOnService() {
+            return singleSignOnService;
+        }
+
+        @Override
+        public SingleLogoutService getSingleLogoutService() {
+            return singleLogoutService;
+        }
+
+        @Override
+        public PublicKey getSignatureValidationKey() {
+            return signatureValidationKey;
+        }
+
+        public void setEntityID(String entityID) {
+            this.entityID = entityID;
+        }
+
+        public void setSignatureValidationKey(PublicKey signatureValidationKey) {
+            this.signatureValidationKey = signatureValidationKey;
+        }
+
+        public void setSingleSignOnService(SingleSignOnService singleSignOnService) {
+            this.singleSignOnService = singleSignOnService;
+        }
+
+        public void setSingleLogoutService(SingleLogoutService singleLogoutService) {
+            this.singleLogoutService = singleLogoutService;
+        }
+    }
+
+    private IDP idp;
+    private boolean configured;
+    private SslRequired sslRequired = SslRequired.EXTERNAL;
+    private String entityID;
+    private String nameIDPolicyFormat;
+    private boolean forceAuthentication;
+    private PrivateKey decryptionKey;
+    private KeyPair signingKeyPair;
+    private String assertionConsumerServiceUrl;
+    private Set<String> roleAttributeNames;
+    private Set<String> roleFriendlyAttributeNames;
+    private PrincipalNamePolicy principalNamePolicy = PrincipalNamePolicy.FROM_NAME_ID;
+    private String principalAttributeName;
+    private String logoutPage;
+
+
+    @Override
+    public IDP getIDP() {
+        return idp;
+    }
+
+    @Override
+    public boolean isConfigured() {
+        return configured;
+    }
+
+    @Override
+    public SslRequired getSslRequired() {
+        return sslRequired;
+    }
+
+    @Override
+    public String getEntityID() {
+        return entityID;
+    }
+
+    @Override
+    public String getNameIDPolicyFormat() {
+        return nameIDPolicyFormat;
+    }
+
+    @Override
+    public boolean isForceAuthentication() {
+        return forceAuthentication;
+    }
+
+    @Override
+    public PrivateKey getDecryptionKey() {
+        return decryptionKey;
+    }
+
+    @Override
+    public KeyPair getSigningKeyPair() {
+        return signingKeyPair;
+    }
+
+    @Override
+    public String getAssertionConsumerServiceUrl() {
+        return assertionConsumerServiceUrl;
+    }
+
+    @Override
+    public Set<String> getRoleAttributeNames() {
+        return roleAttributeNames;
+    }
+
+    @Override
+    public Set<String> getRoleAttributeFriendlyNames() {
+        return roleFriendlyAttributeNames;
+    }
+
+    @Override
+    public PrincipalNamePolicy getPrincipalNamePolicy() {
+        return principalNamePolicy;
+    }
+
+    @Override
+    public String getPrincipalAttributeName() {
+        return principalAttributeName;
+    }
+
+    public void setIdp(IDP idp) {
+        this.idp = idp;
+    }
+
+    public void setConfigured(boolean configured) {
+        this.configured = configured;
+    }
+
+    public void setSslRequired(SslRequired sslRequired) {
+        this.sslRequired = sslRequired;
+    }
+
+    public void setEntityID(String entityID) {
+        this.entityID = entityID;
+    }
+
+    public void setNameIDPolicyFormat(String nameIDPolicyFormat) {
+        this.nameIDPolicyFormat = nameIDPolicyFormat;
+    }
+
+    public void setForceAuthentication(boolean forceAuthentication) {
+        this.forceAuthentication = forceAuthentication;
+    }
+
+    public void setDecryptionKey(PrivateKey decryptionKey) {
+        this.decryptionKey = decryptionKey;
+    }
+
+    public void setSigningKeyPair(KeyPair signingKeyPair) {
+        this.signingKeyPair = signingKeyPair;
+    }
+
+    public void setAssertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
+        this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
+    }
+
+    public void setRoleAttributeNames(Set<String> roleAttributeNames) {
+        this.roleAttributeNames = roleAttributeNames;
+    }
+
+    public void setRoleFriendlyAttributeNames(Set<String> roleFriendlyAttributeNames) {
+        this.roleFriendlyAttributeNames = roleFriendlyAttributeNames;
+    }
+
+    public void setPrincipalNamePolicy(PrincipalNamePolicy principalNamePolicy) {
+        this.principalNamePolicy = principalNamePolicy;
+    }
+
+    public void setPrincipalAttributeName(String principalAttributeName) {
+        this.principalAttributeName = principalAttributeName;
+    }
+
+    @Override
+    public String getLogoutPage() {
+        return logoutPage;
+    }
+
+    public void setLogoutPage(String logoutPage) {
+        this.logoutPage = logoutPage;
+    }
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/InitiateLogin.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/InitiateLogin.java
index d5f86d7..690a99c 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/InitiateLogin.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/InitiateLogin.java
@@ -34,8 +34,8 @@ public class InitiateLogin implements AuthChallenge {
     @Override
     public boolean challenge(HttpFacade httpFacade) {
         try {
-            String issuerURL = deployment.getIssuer();
-            String actionUrl = deployment.getSingleSignOnServiceUrl();
+            String issuerURL = deployment.getEntityID();
+            String actionUrl = deployment.getIDP().getSingleSignOnService().getRequestBindingUrl();
             String destinationUrl = actionUrl;
             String nameIDPolicyFormat = deployment.getNameIDPolicyFormat();
 
@@ -45,28 +45,30 @@ public class InitiateLogin implements AuthChallenge {
 
             String protocolBinding = JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get();
 
-            if (deployment.getResponseBinding() == SamlDeployment.Binding.POST) {
+            if (deployment.getIDP().getSingleSignOnService().getResponseBinding() == SamlDeployment.Binding.POST) {
                 protocolBinding = JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get();
             }
 
             SAML2AuthnRequestBuilder authnRequestBuilder = new SAML2AuthnRequestBuilder()
-                    .assertionConsumerUrl(deployment.getAssertionConsumerServiceUrl())
                     .destination(destinationUrl)
                     .issuer(issuerURL)
                     .forceAuthn(deployment.isForceAuthentication())
                     .protocolBinding(protocolBinding)
                     .nameIdPolicy(SAML2NameIDPolicyBuilder.format(nameIDPolicyFormat));
+            if (deployment.getAssertionConsumerServiceUrl() != null) {
+                authnRequestBuilder.assertionConsumerUrl(deployment.getAssertionConsumerServiceUrl());
+            }
             BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder();
 
-            if (deployment.isRequestsSigned()) {
+            if (deployment.getIDP().getSingleSignOnService().signRequest()) {
 
 
                 KeyPair keypair = deployment.getSigningKeyPair();
                 if (keypair == null) {
                     throw new RuntimeException("Signing keys not configured");
                 }
-                if (deployment.getSignatureCanonicalizationMethod() != null) {
-                    binding.canonicalizationMethod(deployment.getSignatureCanonicalizationMethod());
+                if (deployment.getIDP().getSingleSignOnService().getSignatureCanonicalizationMethod() != null) {
+                    binding.canonicalizationMethod(deployment.getIDP().getSingleSignOnService().getSignatureCanonicalizationMethod());
                 }
 
                 binding.signWith(keypair);
@@ -75,7 +77,7 @@ public class InitiateLogin implements AuthChallenge {
             sessionStore.saveRequest();
 
             Document document = authnRequestBuilder.toDocument();
-            SamlDeployment.Binding samlBinding = deployment.getRequestBinding();
+            SamlDeployment.Binding samlBinding = deployment.getIDP().getSingleSignOnService().getRequestBinding();
             SamlUtil.sendSaml(httpFacade, actionUrl, binding, document, samlBinding);
         } catch (Exception e) {
             throw new RuntimeException("Could not create authentication request.", e);
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java
index 8c393bd..ca2da00 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java
@@ -90,12 +90,12 @@ public abstract class SamlAuthenticator {
         SamlSession account = sessionStore.getAccount();
         SAML2LogoutRequestBuilder logoutBuilder = new SAML2LogoutRequestBuilder()
                 .assertionExpiration(30)
-                .issuer(deployment.getIssuer())
+                .issuer(deployment.getEntityID())
                 .sessionIndex(account.getSessionIndex())
                 .userPrincipal(account.getPrincipal().getSamlSubject(), account.getPrincipal().getNameIDFormat())
-                .destination(deployment.getSingleLogoutServiceUrl());
+                .destination(deployment.getIDP().getSingleLogoutService().getRequestBindingUrl());
         BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder();
-        if (deployment.isRequestsSigned()) {
+        if (deployment.getIDP().getSingleLogoutService().signRequest()) {
             binding.signWith(deployment.getSigningKeyPair())
                     .signDocument();
         }
@@ -103,7 +103,7 @@ public abstract class SamlAuthenticator {
         binding.relayState("logout");
 
         try {
-            SamlUtil.sendSaml(facade, deployment.getSingleLogoutServiceUrl(), binding, logoutBuilder.buildDocument(), deployment.getRequestBinding());
+            SamlUtil.sendSaml(facade, deployment.getIDP().getSingleLogoutService().getRequestBindingUrl(), binding, logoutBuilder.buildDocument(), deployment.getIDP().getSingleLogoutService().getRequestBinding());
         } catch (ProcessingException e) {
             throw new RuntimeException(e);
         } catch (ConfigurationException e) {
@@ -129,9 +129,11 @@ public abstract class SamlAuthenticator {
         if (!facade.getRequest().getURI().toString().equals(requestAbstractType.getDestination())) {
             throw new RuntimeException("destination not equal to request");
         }
-        validateSamlSignature(holder, postBinding, GeneralConstants.SAML_REQUEST_KEY);
 
         if (requestAbstractType instanceof LogoutRequestType) {
+            if (deployment.getIDP().getSingleLogoutService().validateRequestSignature()) {
+                validateSamlSignature(holder, postBinding, GeneralConstants.SAML_REQUEST_KEY);
+            }
             LogoutRequestType logout = (LogoutRequestType) requestAbstractType;
             return logoutRequest(logout, relayState);
 
@@ -147,21 +149,22 @@ public abstract class SamlAuthenticator {
             sessionStore.logoutBySsoId(request.getSessionIndex());
         }
 
-        String issuerURL = deployment.getIssuer();
+        String issuerURL = deployment.getEntityID();
         SAML2LogoutResponseBuilder builder = new SAML2LogoutResponseBuilder();
         builder.logoutRequestID(request.getID());
-        builder.destination(deployment.getSingleLogoutServiceUrl());
+        builder.destination(deployment.getIDP().getSingleLogoutService().getResponseBindingUrl());
         builder.issuer(issuerURL);
         BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder().relayState(relayState);
-        if (deployment.isRequestsSigned()) {
+        if (deployment.getIDP().getSingleLogoutService().signResponse()) {
             binding.signWith(deployment.getSigningKeyPair())
                     .signDocument();
+            binding.canonicalizationMethod(deployment.getIDP().getSingleLogoutService().getSignatureCanonicalizationMethod());
         }
 
 
         try {
-            SamlUtil.sendSaml(facade, deployment.getSingleLogoutServiceUrl(), binding, builder.buildDocument(),
-                    deployment.getResponseBinding());
+            SamlUtil.sendSaml(facade, deployment.getIDP().getSingleLogoutService().getResponseBindingUrl(), binding, builder.buildDocument(),
+                    deployment.getIDP().getSingleLogoutService().getResponseBinding());
         } catch (ConfigurationException e) {
             throw new RuntimeException(e);
         } catch (ProcessingException e) {
@@ -188,11 +191,16 @@ public abstract class SamlAuthenticator {
         if (!facade.getRequest().getURI().toString().equals(statusResponse.getDestination())) {
             throw new RuntimeException("destination not equal to request");
         }
-        validateSamlSignature(holder, postBinding, GeneralConstants.SAML_RESPONSE_KEY);
         if (statusResponse instanceof ResponseType) {
+            if (deployment.getIDP().getSingleSignOnService().validateResponseSignature()) {
+                validateSamlSignature(holder, postBinding, GeneralConstants.SAML_REQUEST_KEY);
+            }
             return handleLoginResponse((ResponseType)statusResponse);
 
         } else {
+            if (deployment.getIDP().getSingleLogoutService().validateResponseSignature()) {
+                validateSamlSignature(holder, postBinding, GeneralConstants.SAML_REQUEST_KEY);
+            }
             // todo need to check that it is actually a LogoutResponse
             return handleLogoutResponse(holder, statusResponse, relayState);
         }
@@ -200,24 +208,22 @@ public abstract class SamlAuthenticator {
     }
 
     private void validateSamlSignature(SAMLDocumentHolder holder, boolean postBinding, String paramKey) {
-        if (deployment.isValidateSignatures()) {
-            try {
-                if (postBinding) {
-                    verifyPostBindingSignature(holder.getSamlDocument(), deployment.getSignatureValidationKey());
-                } else {
-                    verifyRedirectBindingSignature(deployment.getSignatureValidationKey(), paramKey);
-                }
-            } catch (VerificationException e) {
-                log.error("validation failed", e);
-                throw new RuntimeException("invalid document signature");
+        try {
+            if (postBinding) {
+                verifyPostBindingSignature(holder.getSamlDocument(), deployment.getIDP().getSignatureValidationKey());
+            } else {
+                verifyRedirectBindingSignature(deployment.getIDP().getSignatureValidationKey(), paramKey);
             }
+        } catch (VerificationException e) {
+            log.error("validation failed", e);
+            throw new RuntimeException("invalid document signature");
         }
     }
 
     protected AuthOutcome handleLoginResponse(ResponseType responseType)  {
         AssertionType assertion = null;
         try {
-            assertion = AssertionUtil.getAssertion(responseType, deployment.getAssertionDecryptionKey());
+            assertion = AssertionUtil.getAssertion(responseType, deployment.getDecryptionKey());
             if (AssertionUtil.hasExpired(assertion)) {
                 return initiateLogin();
             }
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlConfigResolver.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlConfigResolver.java
new file mode 100755
index 0000000..2479a23
--- /dev/null
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlConfigResolver.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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;
+
+import org.keycloak.adapters.HttpFacade.Request;
+
+/**
+ * On multi-tenant scenarios, Keycloak will defer the resolution of a
+ * SamlDeployment to the target application at the request-phase.
+ *
+ * A Request object is passed to the resolver and callers expect a complete
+ * SamlDeployment. Based on this SamlDeployment, Keycloak will resume
+ * authenticating and authorizing the request.
+ *
+ * The easiest way to build a SamlDeployment is to use
+ * DeploymentBuilder , passing the InputStream of an existing
+ * keycloak-saml.xml to the build() method.
+ *
+ * @author Juraci Paixão Kröhling <juraci at kroehling.de>
+ */
+public interface SamlConfigResolver {
+
+    public SamlDeployment resolve(Request facade);
+
+}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java
index 1de9d72..9363624 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java
@@ -14,26 +14,53 @@ import java.util.Set;
 public interface SamlDeployment {
     enum Binding {
         POST,
-        REDIRECT
+        REDIRECT;
+
+        public static Binding parseBinding(String val) {
+            if (val == null) return POST;
+            return Binding.valueOf(val);
+        }
+    }
+
+    public interface IDP {
+        String getEntityID();
+
+        SingleSignOnService getSingleSignOnService();
+        SingleLogoutService getSingleLogoutService();
+        PublicKey getSignatureValidationKey();
+
+        public interface SingleSignOnService {
+            boolean signRequest();
+            boolean validateResponseSignature();
+            String getSignatureCanonicalizationMethod();
+            Binding getRequestBinding();
+            Binding getResponseBinding();
+            String getRequestBindingUrl();
+        }
+        public interface SingleLogoutService {
+            boolean validateRequestSignature();
+            boolean validateResponseSignature();
+            boolean signRequest();
+            boolean signResponse();
+            String getSignatureCanonicalizationMethod();
+            Binding getRequestBinding();
+            Binding getResponseBinding();
+            String getRequestBindingUrl();
+            String getResponseBindingUrl();
+        }
     }
 
+    public IDP getIDP();
+
     public boolean isConfigured();
     SslRequired getSslRequired();
-    String getSingleSignOnServiceUrl();
-    String getSingleLogoutServiceUrl();
-    String getIssuer();
+    String getEntityID();
     String getNameIDPolicyFormat();
-    String getAssertionConsumerServiceUrl();
-    Binding getRequestBinding();
-    Binding getResponseBinding();
-    KeyPair getSigningKeyPair();
-    String getSignatureCanonicalizationMethod();
     boolean isForceAuthentication();
-    boolean isRequestsSigned();
-
-    boolean isValidateSignatures();
-    PublicKey getSignatureValidationKey();
-    PrivateKey getAssertionDecryptionKey();
+    PrivateKey getDecryptionKey();
+    KeyPair getSigningKeyPair();
+    String getAssertionConsumerServiceUrl();
+    String getLogoutPage();
 
     Set<String> getRoleAttributeNames();
     Set<String> getRoleAttributeFriendlyNames();
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeploymentContext.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeploymentContext.java
index b8ea94d..cb8ea77 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeploymentContext.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeploymentContext.java
@@ -7,7 +7,13 @@ import org.keycloak.adapters.HttpFacade;
  * @version $Revision: 1 $
  */
 public class SamlDeploymentContext {
+    private SamlDeployment deployment = null;
+
+    public SamlDeploymentContext(SamlDeployment deployment) {
+        this.deployment = deployment;
+    }
+
     public SamlDeployment resolveDeployment(HttpFacade facade) {
-        return null;
+        return deployment;
     }
 }
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlPrincipal.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlPrincipal.java
index f336c92..68b23da 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlPrincipal.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlPrincipal.java
@@ -40,7 +40,7 @@ public class SamlPrincipal implements Serializable, Principal {
 
     @Override
     public String getName() {
-        return null;
+        return name;
     }
 
 
diff --git a/saml/client-adapter/core/src/test/java/org/keycloak/test/adapters/saml/XmlParserTest.java b/saml/client-adapter/core/src/test/java/org/keycloak/test/adapters/saml/XmlParserTest.java
new file mode 100755
index 0000000..84f03ea
--- /dev/null
+++ b/saml/client-adapter/core/src/test/java/org/keycloak/test/adapters/saml/XmlParserTest.java
@@ -0,0 +1,80 @@
+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 java.io.InputStream;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class XmlParserTest {
+
+    @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.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"));
+        Assert.assertTrue(sp.getRoleFriendlyAttributes().size() == 1);
+        Assert.assertTrue(sp.getRoleFriendlyAttributes().contains("memberOf"));
+
+        IDP idp = sp.getIdp();
+        Assert.assertEquals("idp", idp.getEntityID());
+        Assert.assertTrue(idp.getSingleSignOnService().isSignRequest());
+        Assert.assertTrue(idp.getSingleSignOnService().isValidateResponseSignature());
+        Assert.assertEquals("canon", idp.getSingleSignOnService().getSignatureCanonicalizationMethod());
+        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("canon", idp.getSingleLogoutService().getSignatureCanonicalizationMethod());
+        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());
+
+
+
+
+    }
+}
diff --git a/saml/client-adapter/core/src/test/resources/keycloak-saml.xml b/saml/client-adapter/core/src/test/resources/keycloak-saml.xml
new file mode 100755
index 0000000..5755fd7
--- /dev/null
+++ b/saml/client-adapter/core/src/test/resources/keycloak-saml.xml
@@ -0,0 +1,61 @@
+<keycloak-saml-adapter>
+    <SP entityID="sp"
+        sslPolicy="ssl"
+        nameIDPolicyFormat="format"
+        forceAuthentication="true">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore file="file" classpath="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"/>
+        <RoleMapping>
+            <Attribute name="member"/>
+            <FriendlyAttribute name="memberOf"/>
+        </RoleMapping>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 signatureCanonicalizationMethod="canon"
+                                 requestBinding="post"
+                                 bindingUrl="url"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    signatureCanonicalizationMethod="canon"
+                    requestBinding="redirect"
+                    responseBinding="post"
+                    postBindingUrl="posturl"
+                    redirectBindingUrl="redirecturl"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <CertificatePem>
+                        cert pem
+                    </CertificatePem>
+                </Key>
+            </Keys>
+        </IDP>
+        <Keys>
+            <KeyStore>
+
+            </KeyStore>
+        </Keys>
+
+    </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/AbstractSamlAuthMech.java b/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/AbstractSamlAuthMech.java
index 6a21c5e..9b29618 100755
--- a/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/AbstractSamlAuthMech.java
+++ b/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/AbstractSamlAuthMech.java
@@ -42,16 +42,13 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
     public static final AttachmentKey<AuthChallenge> KEYCLOAK_CHALLENGE_ATTACHMENT_KEY = AttachmentKey.create(AuthChallenge.class);
     protected SamlDeploymentContext deploymentContext;
     protected UndertowUserSessionManagement sessionManagement;
-    protected String logoutPage;
     protected String errorPage;
 
     public AbstractSamlAuthMech(SamlDeploymentContext deploymentContext, UndertowUserSessionManagement sessionManagement,
-                                String logoutPage,
                                 String errorPage) {
         this.deploymentContext = deploymentContext;
         this.sessionManagement = sessionManagement;
         this.errorPage = errorPage;
-        this.logoutPage = logoutPage;
     }
 
     @Override
@@ -62,7 +59,7 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
                 Integer code = servePage(exchange, errorPage);
                 return new ChallengeResult(true, code);
             }
-            UndertowHttpFacade facade = new UndertowHttpFacade(exchange);
+            UndertowHttpFacade facade = createFacade(exchange);
             if (challenge.challenge(facade)) {
                 return new ChallengeResult(true, exchange.getResponseCode());
             }
@@ -91,7 +88,7 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
                 if (notification.getEventType() != SecurityNotification.EventType.LOGGED_OUT) return;
 
                 HttpServerExchange exchange = notification.getExchange();
-                UndertowHttpFacade facade = new UndertowHttpFacade(exchange);
+                UndertowHttpFacade facade = createFacade(exchange);
                 SamlDeployment deployment = deploymentContext.resolveDeployment(facade);
                 SamlSessionStore sessionStore = getTokenStore(exchange, facade, deployment, securityContext);
                 sessionStore.logoutAccount();
@@ -105,7 +102,7 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
      * Call this inside your authenticate method.
      */
     public AuthenticationMechanismOutcome authenticate(HttpServerExchange exchange, SecurityContext securityContext) {
-        UndertowHttpFacade facade = new UndertowHttpFacade(exchange);
+        UndertowHttpFacade facade = createFacade(exchange);
         SamlDeployment deployment = deploymentContext.resolveDeployment(facade);
         if (!deployment.isConfigured()) {
             return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
@@ -120,10 +117,8 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
         }
         if (outcome == AuthOutcome.LOGGED_OUT) {
             securityContext.logout();
-            if (logoutPage != null) {
-                sendRedirect(exchange, logoutPage);
-                exchange.setResponseCode(302);
-                exchange.endExchange();
+            if (deployment.getLogoutPage() != null) {
+                redirectLogout(deployment, exchange);
             }
             return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
         }
@@ -138,5 +133,16 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
         return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
     }
 
+    protected void redirectLogout(SamlDeployment deployment, HttpServerExchange exchange) {
+        String page = deployment.getLogoutPage();
+        sendRedirect(exchange, page);
+        exchange.setResponseCode(302);
+        exchange.endExchange();
+    }
+
+    protected UndertowHttpFacade createFacade(HttpServerExchange exchange) {
+        return new UndertowHttpFacade(exchange);
+    }
+
     protected abstract SamlSessionStore getTokenStore(HttpServerExchange exchange, HttpFacade facade, SamlDeployment deployment, SecurityContext securityContext);
 }
\ No newline at end of file
diff --git a/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/SamlServletExtension.java b/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/SamlServletExtension.java
new file mode 100755
index 0000000..ac3da61
--- /dev/null
+++ b/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/SamlServletExtension.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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.undertow;
+
+import io.undertow.security.api.AuthenticationMechanism;
+import io.undertow.security.api.AuthenticationMechanismFactory;
+import io.undertow.security.idm.Account;
+import io.undertow.security.idm.Credential;
+import io.undertow.security.idm.IdentityManager;
+import io.undertow.server.handlers.form.FormParserFactory;
+import io.undertow.servlet.ServletExtension;
+import io.undertow.servlet.api.AuthMethodConfig;
+import io.undertow.servlet.api.DeploymentInfo;
+import io.undertow.servlet.api.LoginConfig;
+import io.undertow.servlet.api.ServletSessionConfig;
+import org.jboss.logging.Logger;
+import org.keycloak.adapters.saml.DefaultSamlDeployment;
+import org.keycloak.adapters.saml.SamlConfigResolver;
+import org.keycloak.adapters.saml.SamlDeployment;
+import org.keycloak.adapters.saml.SamlDeploymentContext;
+import org.keycloak.adapters.saml.config.parsers.DeploymentBuilder;
+import org.keycloak.adapters.saml.config.parsers.ResourceLoader;
+import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
+import org.keycloak.saml.common.exceptions.ParsingException;
+
+import javax.servlet.ServletContext;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SamlServletExtension implements ServletExtension {
+
+    protected static Logger log = Logger.getLogger(SamlServletExtension.class);
+
+    // todo when this DeploymentInfo method of the same name is fixed.
+    public boolean isAuthenticationMechanismPresent(DeploymentInfo deploymentInfo, final String mechanismName) {
+        LoginConfig loginConfig = deploymentInfo.getLoginConfig();
+        if (loginConfig != null) {
+            for (AuthMethodConfig method : loginConfig.getAuthMethods()) {
+                if (method.getName().equalsIgnoreCase(mechanismName)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static InputStream getConfigInputStream(ServletContext context) {
+        InputStream is = null;
+        if (is == null) {
+            String path = context.getInitParameter("keycloak.config.file");
+            if (path == null) {
+                log.debug("using /WEB-INF/keycloak-saml.xml");
+                is = context.getResourceAsStream("/WEB-INF/keycloak-saml.xml");
+            } else {
+                try {
+                    is = new FileInputStream(path);
+                } catch (FileNotFoundException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+        return is;
+    }
+
+
+    @Override
+    @SuppressWarnings("UseSpecificCatch")
+    public void handleDeployment(DeploymentInfo deploymentInfo, final ServletContext servletContext) {
+        if (!isAuthenticationMechanismPresent(deploymentInfo, "KEYCLOAK-SAML")) {
+            log.debug("auth-method is not keycloak saml!");
+            return;
+        }
+        log.debug("SamlServletException initialization");
+
+        // Possible scenarios:
+        // 1) The deployment has a keycloak.config.resolver specified and it exists:
+        //    Outcome: adapter uses the resolver
+        // 2) The deployment has a keycloak.config.resolver and isn't valid (doesn't exists, isn't a resolver, ...) :
+        //    Outcome: adapter is left unconfigured
+        // 3) The deployment doesn't have a keycloak.config.resolver , but has a keycloak.json (or equivalent)
+        //    Outcome: adapter uses it
+        // 4) The deployment doesn't have a keycloak.config.resolver nor keycloak.json (or equivalent)
+        //    Outcome: adapter is left unconfigured
+
+        SamlConfigResolver configResolver;
+        String configResolverClass = servletContext.getInitParameter("keycloak.config.resolver");
+        SamlDeploymentContext deploymentContext = null;
+        if (configResolverClass != null) {
+            try {
+                throw new RuntimeException("Not implemented yet");
+                //configResolver = (SamlConfigResolver) deploymentInfo.getClassLoader().loadClass(configResolverClass).newInstance();
+                //deploymentContext = new AdapterDeploymentContext(configResolver);
+                //log.info("Using " + configResolverClass + " to resolve Keycloak configuration on a per-request basis.");
+            } catch (Exception ex) {
+                log.warn("The specified resolver " + configResolverClass + " could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: " + ex.getMessage());
+                //deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
+            }
+        } else {
+            InputStream is = getConfigInputStream(servletContext);
+            final SamlDeployment deployment;
+            if (is == null) {
+                log.warn("No adapter configuration.  Keycloak is unconfigured and will deny all requests.");
+                deployment = new DefaultSamlDeployment();
+            } else {
+                try {
+                    ResourceLoader loader = new ResourceLoader() {
+                        @Override
+                        public InputStream getResourceAsStream(String resource) {
+                            return servletContext.getResourceAsStream(resource);
+                        }
+                    };
+                    deployment = new DeploymentBuilder().build(is, loader);
+                } catch (ParsingException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+            deploymentContext = new SamlDeploymentContext(deployment);
+            log.debug("Keycloak is using a per-deployment configuration.");
+        }
+
+        servletContext.setAttribute(SamlDeploymentContext.class.getName(), deploymentContext);
+        UndertowUserSessionManagement userSessionManagement = new UndertowUserSessionManagement();
+        final ServletSamlAuthMech mech = new ServletSamlAuthMech(deploymentContext, userSessionManagement, getErrorPage(deploymentInfo));
+
+
+        // setup handlers
+
+        deploymentInfo.addAuthenticationMechanism("KEYCLOAK-SAML", new AuthenticationMechanismFactory() {
+            @Override
+            public AuthenticationMechanism create(String s, FormParserFactory formParserFactory, Map<String, String> stringStringMap) {
+                return mech;
+            }
+        }); // authentication
+
+        deploymentInfo.setIdentityManager(new IdentityManager() {
+            @Override
+            public Account verify(Account account) {
+                return account;
+            }
+
+            @Override
+            public Account verify(String id, Credential credential) {
+                throw new IllegalStateException("Should never be called in Keycloak flow");
+            }
+
+            @Override
+            public Account verify(Credential credential) {
+                throw new IllegalStateException("Should never be called in Keycloak flow");
+            }
+        });
+
+        log.debug("Setting jsession cookie path to: " + deploymentInfo.getContextPath());
+        ServletSessionConfig cookieConfig = new ServletSessionConfig();
+        cookieConfig.setPath(deploymentInfo.getContextPath());
+        deploymentInfo.setServletSessionConfig(cookieConfig);
+
+     }
+
+    protected String getErrorPage(DeploymentInfo deploymentInfo) {
+        LoginConfig loginConfig = deploymentInfo.getLoginConfig();
+        String errorPage = null;
+        if (loginConfig != null) {
+            errorPage = loginConfig.getErrorPage();
+        }
+        return errorPage;
+    }
+}
diff --git a/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlAuthMech.java b/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlAuthMech.java
index ec2444a..cd52536 100755
--- a/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlAuthMech.java
+++ b/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlAuthMech.java
@@ -2,24 +2,67 @@ package org.keycloak.adapters.saml.undertow;
 
 import io.undertow.security.api.SecurityContext;
 import io.undertow.server.HttpServerExchange;
+import io.undertow.servlet.handlers.ServletRequestContext;
+import io.undertow.util.Headers;
 import org.keycloak.adapters.HttpFacade;
 import org.keycloak.adapters.saml.SamlDeployment;
 import org.keycloak.adapters.saml.SamlDeploymentContext;
 import org.keycloak.adapters.saml.SamlSessionStore;
+import org.keycloak.adapters.undertow.ServletHttpFacade;
+import org.keycloak.adapters.undertow.UndertowHttpFacade;
 import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
 
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import java.io.IOException;
+
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
 public class ServletSamlAuthMech extends AbstractSamlAuthMech {
-    public ServletSamlAuthMech(SamlDeploymentContext deploymentContext, UndertowUserSessionManagement sessionManagement,
-                               String logoutPage, String errorPage) {
-        super(deploymentContext, sessionManagement, logoutPage, errorPage);
+    public ServletSamlAuthMech(SamlDeploymentContext deploymentContext, UndertowUserSessionManagement sessionManagement, String errorPage) {
+        super(deploymentContext, sessionManagement, errorPage);
     }
 
     @Override
     protected SamlSessionStore getTokenStore(HttpServerExchange exchange, HttpFacade facade, SamlDeployment deployment, SecurityContext securityContext) {
         return new ServletSamlSessionStore(exchange, sessionManagement, securityContext);
     }
+
+    @Override
+    protected UndertowHttpFacade createFacade(HttpServerExchange exchange) {
+        return new ServletHttpFacade(exchange);
+    }
+
+    @Override
+    protected void redirectLogout(SamlDeployment deployment, HttpServerExchange exchange) {
+       servePage(exchange, deployment.getLogoutPage());
+    }
+
+    @Override
+    protected Integer servePage(HttpServerExchange exchange, String location) {
+        final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
+        ServletRequest req = servletRequestContext.getServletRequest();
+        ServletResponse resp = servletRequestContext.getServletResponse();
+        RequestDispatcher disp = req.getRequestDispatcher(location);
+        //make sure the login page is never cached
+        exchange.getResponseHeaders().add(Headers.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
+        exchange.getResponseHeaders().add(Headers.PRAGMA, "no-cache");
+        exchange.getResponseHeaders().add(Headers.EXPIRES, "0");
+
+
+        try {
+            disp.forward(req, resp);
+        } catch (ServletException e) {
+            throw new RuntimeException(e);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return null;
+    }
+
+
 }
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java
index fb32fef..7941729 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java
@@ -105,6 +105,23 @@ public class StaxParserUtil {
     }
 
     /**
+     * Get the Attribute value
+     *
+     * @param startElement
+     * @param tag localpart of the qname of the attribute
+     *
+     * @return false if attribute not set
+     */
+    public static boolean getBooleanAttributeValue(StartElement startElement, String tag) {
+        String result = null;
+        Attribute attr = startElement.getAttributeByName(new QName(tag));
+        if (attr != null)
+            result = getAttributeValue(attr);
+        if (result == null) return false;
+        return Boolean.valueOf(result);
+    }
+
+    /**
      * Given that the {@code XMLEventReader} is in {@code XMLStreamConstants.START_ELEMENT} mode, we parse into a DOM
      * Element
      *
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 7948e97..166fa4b 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -103,6 +103,14 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-saml-adapter-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-undertow-saml-adapter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-jaxrs-oauth-client</artifactId>
         </dependency>
         <dependency>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlBindingTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlBindingTest.java
new file mode 100755
index 0000000..9639aab
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlBindingTest.java
@@ -0,0 +1,510 @@
+package org.keycloak.testsuite.keycloaksaml;
+
+import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.Config;
+import org.keycloak.dom.saml.v2.assertion.AssertionType;
+import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
+import org.keycloak.dom.saml.v2.assertion.AttributeType;
+import org.keycloak.dom.saml.v2.protocol.ResponseType;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.TokenManager;
+import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
+import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper;
+import org.keycloak.protocol.saml.mappers.HardcodedRole;
+import org.keycloak.protocol.saml.mappers.RoleListMapper;
+import org.keycloak.protocol.saml.mappers.RoleNameMapper;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.processing.api.saml.v2.response.SAML2Response;
+import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
+import org.keycloak.saml.processing.web.util.PostBindingUtil;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.resources.admin.AdminRoot;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.openqa.selenium.WebDriver;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SamlBindingTest {
+
+    @ClassRule
+    public static SamlKeycloakRule keycloakRule = new SamlKeycloakRule() {
+        @Override
+        public void initWars() {
+             ClassLoader classLoader = SamlBindingTest.class.getClassLoader();
+
+            //initializeSamlSecuredWar("/keycloak-saml/simple-post", "/sales-post",  "post.war", classLoader);
+            initializeSamlSecuredWar("/keycloak-saml/signed-post", "/sales-post-sig",  "post-sig.war", classLoader);
+            //initializeSamlSecuredWar("/keycloak-saml/signed-post-email", "/sales-post-sig-email",  "post-sig-email.war", classLoader);
+            //initializeSamlSecuredWar("/keycloak-saml/signed-post-transient", "/sales-post-sig-transient",  "post-sig-transient.war", classLoader);
+            //initializeSamlSecuredWar("/keycloak-saml/signed-post-persistent", "/sales-post-sig-persistent",  "post-sig-persistent.war", classLoader);
+            //initializeSamlSecuredWar("/keycloak-saml/signed-metadata", "/sales-metadata",  "post-metadata.war", classLoader);
+            //initializeSamlSecuredWar("/keycloak-saml/signed-get", "/employee-sig",  "employee-sig.war", classLoader);
+            //initializeSamlSecuredWar("/saml/simple-get", "/employee",  "employee.war", classLoader);
+            //initializeSamlSecuredWar("/keycloak-saml/signed-front-get", "/employee-sig-front",  "employee-sig-front.war", classLoader);
+            //initializeSamlSecuredWar("/keycloak-saml/bad-client-signed-post", "/bad-client-sales-post-sig",  "bad-client-post-sig.war", classLoader);
+            //initializeSamlSecuredWar("/keycloak-saml/bad-realm-signed-post", "/bad-realm-sales-post-sig",  "bad-realm-post-sig.war", classLoader);
+            //initializeSamlSecuredWar("/keycloak-saml/encrypted-post", "/sales-post-enc",  "post-enc.war", classLoader);
+            //uploadSP();
+            //server.getServer().deploy(createDeploymentInfo("employee.war", "/employee", SamlSPFacade.class));
+
+
+
+        }
+
+        @Override
+        public String getRealmJson() {
+            return "/saml/testsaml.json";
+        }
+    };
+
+    public static class SamlSPFacade extends HttpServlet {
+        public static String samlResponse;
+        public static String RELAY_STATE = "http://test.com/foo/bar";
+        public static String sentRelayState;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+            handler(req, resp);
+        }
+
+        @Override
+        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+            handler(req, resp);
+        }
+
+        private void handler(HttpServletRequest req, HttpServletResponse resp) {
+            System.out.println("********* HERE ******");
+            if (req.getParameterMap().isEmpty()) {
+                System.out.println("redirecting");
+                resp.setStatus(302);
+                // Redirect
+                // UriBuilder builder = UriBuilder.fromUri("http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVLRTsIwFP2Vpe%2BjG4wxG0YyWYxL0BBAH3wx3XYnTbp29nYof%2B8YEvEBNOlD03vOveec2ynyWjYsae1WreC9BbTOZy0Vsr4Qk9YopjkKZIrXgMwWbJ08LNhw4LHGaKsLLcmRch3MEcFYoRVxktN1rhW2NZg1mJ0o4Gm1iMnW2oZRKnXB5VajZZEX%2BRTqRuo9ACVO2mkUih%2F4l9C8s0MNcFkjLaHW9KSUHlwR506bAnrPMam4RCBOlsYkS1%2BD3MvLcDJxAx9KN4jCkXszrG5cP%2BCVH4y8IM8PYFx2dsQOfuiILWQKLVc2JkPPH7te6HrRxh%2BzUdidwSSIXoiz%2FBZyK1Qp1Nv1yPIjCNn9ZrN0V1AKA4UlzjMY7N13IDKbHjyxXoA5291%2FtzH7I%2FApPet%2FHNawx65hli61FMXeSaTUH%2FMubtvlYU0LfcA1t5cl%2BAO%2FfxGlW%2FVQ1ipsoBCVgJLQ2XHo7385%2BwI%3D");
+                UriBuilder builder = UriBuilder.fromUri("http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVJbT8IwFP4rS99HuwluNIwEIUYSLwugD76Y2h2kSdfOng7l31uGRn0ATfrQ9HznfJfTEYpaN3zS%2Bo1ZwGsL6KP3WhvkXaEgrTPcClTIjagBuZd8Obm55mmP8cZZb6XV5NByGiwQwXllDYkmX9epNdjW4JbgtkrC%2FeK6IBvvG06ptlLojUXPc5YnFOpG2x0AJdEsaFRG7PuPoUWwQx0IXSOtoLb0SynduyLRpXUSOs8FWQuNQKL5rCDz2VO%2FymEgIY2zlJ3H%2FSx9jkU%2BzOK0ys8yNmSSsUEAYxnsqC18tyO2MDfohfEFSVkyiNlZzM5XacrDSbJePug%2Fkqj8FHKhTKXMy%2BnIng8g5FerVRmXd8sViR7AYec8AMh4tPfDO3L3Y2%2F%2F3cT4j7BH9Mf8A1nDb8PA%2Bay0WsldNNHavk1D1D5k4V0LXbi18MclJL2ke1FVvO6gvDXYgFRrBRWh4wPp7z85%2FgA%3D");
+                builder.queryParam("RelayState", RELAY_STATE);
+                resp.setHeader("Location", builder.build().toString());
+                return;
+            }
+            System.out.println("received response");
+            samlResponse = req.getParameter("SAMLResponse");
+            sentRelayState = req.getParameter("RelayState");
+        }
+    }
+
+    @Rule
+    public WebRule webRule = new WebRule(this);
+    @WebResource
+    protected WebDriver driver;
+    @WebResource
+    protected LoginPage loginPage;
+
+    protected void checkLoggedOut(String mainUrl) {
+        String pageSource = driver.getPageSource();
+        System.out.println("*** logout pagesource ***");
+        System.out.println(pageSource);
+        System.out.println("driver url: " + driver.getCurrentUrl());
+        Assert.assertTrue(pageSource.contains("request-path: /logout.jsp"));
+        driver.navigate().to(mainUrl);
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+    }
+
+    //@Test
+    public void ideTesting() throws Exception {
+        Thread.sleep(100000000);
+    }
+
+    @Test
+    public void testPostSimpleLoginLogout() {
+        driver.navigate().to("http://localhost:8081/sales-post/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post/");
+        System.out.println(driver.getPageSource());
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+        driver.navigate().to("http://localhost:8081/sales-post?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post/");
+    }
+    @Test
+    public void testPostSimpleLoginLogoutIdpInitiated() {
+        driver.navigate().to("http://localhost:8081/auth/realms/demo/protocol/saml/clients/sales-post");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post/");
+        System.out.println(driver.getPageSource());
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+        driver.navigate().to("http://localhost:8081/sales-post?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post/");
+    }
+
+    @Test
+    public void testPostSignedLoginLogout() {
+        driver.navigate().to("http://localhost:8081/sales-post-sig/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+        driver.navigate().to("http://localhost:8081/sales-post-sig?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post-sig/");
+
+    }
+    @Test
+    public void testPostSignedLoginLogoutTransientNameID() {
+        driver.navigate().to("http://localhost:8081/sales-post-sig-transient/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-transient/");
+        System.out.println(driver.getPageSource());
+        Assert.assertFalse(driver.getPageSource().contains("bburke"));
+        Assert.assertTrue(driver.getPageSource().contains("principal=G-"));
+        driver.navigate().to("http://localhost:8081/sales-post-sig-transient?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post-sig-transient/");
+
+    }
+    @Test
+    public void testPostSignedLoginLogoutPersistentNameID() {
+        driver.navigate().to("http://localhost:8081/sales-post-sig-persistent/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-persistent/");
+        System.out.println(driver.getPageSource());
+        Assert.assertFalse(driver.getPageSource().contains("bburke"));
+        Assert.assertTrue(driver.getPageSource().contains("principal=G-"));
+        driver.navigate().to("http://localhost:8081/sales-post-sig-persistent?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post-sig-persistent/");
+
+    }
+    @Test
+    public void testPostSignedLoginLogoutEmailNameID() {
+        driver.navigate().to("http://localhost:8081/sales-post-sig-email/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-email/");
+        System.out.println(driver.getPageSource());
+        Assert.assertTrue(driver.getPageSource().contains("principal=bburke@redhat.com"));
+        driver.navigate().to("http://localhost:8081/sales-post-sig-email?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post-sig-email/");
+
+    }
+
+    @Test
+    public void testRelayStateEncoding() throws Exception {
+        // this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
+        // at the relay state
+        SamlSPFacade.samlResponse = null;
+        driver.navigate().to("http://localhost:8081/employee/");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+        System.out.println(driver.getCurrentUrl());
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
+        Assert.assertEquals(SamlSPFacade.sentRelayState, SamlSPFacade.RELAY_STATE);
+        Assert.assertNotNull(SamlSPFacade.samlResponse);
+
+    }
+
+
+    @Test
+    public void testAttributes() throws Exception {
+        // this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
+        // at the assertions sent.  This is because Picketlink, AFAICT, does not give you any way to get access to
+        // the assertion.
+
+        {
+            SamlSPFacade.samlResponse = null;
+            driver.navigate().to("http://localhost:8081/employee/");
+            Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+            System.out.println(driver.getCurrentUrl());
+            loginPage.login("bburke", "password");
+            Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
+            Assert.assertNotNull(SamlSPFacade.samlResponse);
+            SAML2Response saml2Response = new SAML2Response();
+            byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse);
+            ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse));
+            Assert.assertTrue(rt.getAssertions().size() == 1);
+            AssertionType assertion = rt.getAssertions().get(0).getAssertion();
+
+            // test attributes and roles
+
+            boolean email = false;
+            boolean phone = false;
+            boolean userRole = false;
+            boolean managerRole = false;
+            for (AttributeStatementType statement : assertion.getAttributeStatements()) {
+                for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
+                    AttributeType attr = choice.getAttribute();
+                    if (X500SAMLProfileConstants.EMAIL.getFriendlyName().equals(attr.getFriendlyName())) {
+                        Assert.assertEquals(X500SAMLProfileConstants.EMAIL.get(), attr.getName());
+                        Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_URI.get(), attr.getNameFormat());
+                        Assert.assertEquals(attr.getAttributeValue().get(0), "bburke@redhat.com");
+                        email = true;
+                    } else if (attr.getName().equals("phone")) {
+                        Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.get(), attr.getNameFormat());
+                        Assert.assertEquals(attr.getAttributeValue().get(0), "617");
+                        phone = true;
+                    } else if (attr.getName().equals("Role")) {
+                        if (attr.getAttributeValue().get(0).equals("manager")) managerRole = true;
+                        if (attr.getAttributeValue().get(0).equals("user")) userRole = true;
+                    }
+                }
+
+            }
+
+            Assert.assertTrue(email);
+            Assert.assertTrue(phone);
+            Assert.assertTrue(userRole);
+            Assert.assertTrue(managerRole);
+        }
+
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                ClientModel app = appRealm.getClientByClientId("http://localhost:8081/employee/");
+                for (ProtocolMapperModel mapper : app.getProtocolMappers()) {
+                    if (mapper.getName().equals("role-list")) {
+                        app.removeProtocolMapper(mapper);
+                        mapper.setId(null);
+                        mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true");
+                        mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf");
+                        app.addProtocolMapper(mapper);
+                    }
+                }
+                app.addProtocolMapper(HardcodedAttributeMapper.create("hardcoded-attribute", "hardcoded-attribute", "Basic", null, "hard", false, null));
+                app.addProtocolMapper(HardcodedRole.create("hardcoded-role", "hardcoded-role"));
+                app.addProtocolMapper(RoleNameMapper.create("renamed-role", "manager", "el-jefe"));
+                app.addProtocolMapper(RoleNameMapper.create("renamed-employee-role", "http://localhost:8081/employee/.employee", "pee-on"));
+            }
+        }, "demo");
+
+        System.out.println(">>>>>>>>>> single role attribute <<<<<<<<");
+
+        {
+            SamlSPFacade.samlResponse = null;
+            driver.navigate().to("http://localhost:8081/employee/");
+            System.out.println(driver.getCurrentUrl());
+            Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
+            Assert.assertNotNull(SamlSPFacade.samlResponse);
+            SAML2Response saml2Response = new SAML2Response();
+            byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse);
+            ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse));
+            Assert.assertTrue(rt.getAssertions().size() == 1);
+            AssertionType assertion = rt.getAssertions().get(0).getAssertion();
+
+            // test attributes and roles
+
+            boolean userRole = false;
+            boolean managerRole = false;
+            boolean single = false;
+            boolean hardcodedRole = false;
+            boolean hardcodedAttribute = false;
+            boolean peeOn = false;
+            for (AttributeStatementType statement : assertion.getAttributeStatements()) {
+                for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
+                    AttributeType attr = choice.getAttribute();
+                    if (attr.getName().equals("memberOf")) {
+                        if (single) Assert.fail("too many role attributes");
+                        single = true;
+                        for (Object value : attr.getAttributeValue()) {
+                            if (value.equals("el-jefe")) managerRole = true;
+                            if (value.equals("user")) userRole = true;
+                            if (value.equals("hardcoded-role")) hardcodedRole = true;
+                            if (value.equals("pee-on")) peeOn = true;
+                        }
+                    } else if (attr.getName().equals("hardcoded-attribute")) {
+                        hardcodedAttribute = true;
+                        Assert.assertEquals(attr.getAttributeValue().get(0), "hard");
+                    }
+                }
+
+            }
+
+            Assert.assertTrue(single);
+            Assert.assertTrue(hardcodedAttribute);
+            Assert.assertTrue(hardcodedRole);
+            Assert.assertTrue(peeOn);
+            Assert.assertTrue(userRole);
+            Assert.assertTrue(managerRole);
+        }
+    }
+
+    @Test
+    public void testRedirectSignedLoginLogout() {
+        driver.navigate().to("http://localhost:8081/employee-sig/");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+        driver.navigate().to("http://localhost:8081/employee-sig?GLO=true");
+        checkLoggedOut("http://localhost:8081/employee-sig/");
+
+    }
+
+    @Test
+    public void testRedirectSignedLoginLogoutFrontNoSSO() {
+        driver.navigate().to("http://localhost:8081/employee-sig-front/");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+        driver.navigate().to("http://localhost:8081/employee-sig-front?GLO=true");
+        checkLoggedOut("http://localhost:8081/employee-sig-front/");
+
+    }
+
+    @Test
+    public void testRedirectSignedLoginLogoutFront() {
+        // visit 1st app an logg in
+        System.out.println("visit 1st app ");
+        driver.navigate().to("http://localhost:8081/employee-sig/");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+        System.out.println("login to form");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+
+        // visit 2nd app
+        System.out.println("visit 2nd app ");
+        driver.navigate().to("http://localhost:8081/employee-sig-front/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+
+        // visit 3rd app
+        System.out.println("visit 3rd app ");
+        driver.navigate().to("http://localhost:8081/sales-post-sig/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+
+        // logout of first app
+        System.out.println("GLO");
+        driver.navigate().to("http://localhost:8081/employee-sig?GLO=true");
+        checkLoggedOut("http://localhost:8081/employee-sig/");
+        driver.navigate().to("http://localhost:8081/employee-sig-front/");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+        driver.navigate().to("http://localhost:8081/sales-post-sig/");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+
+    }
+
+    @Test
+    public void testPostEncryptedLoginLogout() {
+        driver.navigate().to("http://localhost:8081/sales-post-enc/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-enc/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+        driver.navigate().to("http://localhost:8081/sales-post-enc?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post-enc/");
+
+    }
+    @Test
+    public void testPostBadClientSignature() {
+        driver.navigate().to("http://localhost:8081/bad-client-sales-post-sig/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        Assert.assertEquals(driver.getTitle(), "We're sorry...");
+
+    }
+
+    @Test
+    public void testPostBadRealmSignature() {
+        driver.navigate().to("http://localhost:8081/bad-realm-sales-post-sig/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/bad-realm-sales-post-sig/");
+        Assert.assertTrue(driver.getPageSource().contains("null"));
+    }
+
+    private static String createToken() {
+        KeycloakSession session = keycloakRule.startSession();
+        try {
+            RealmManager manager = new RealmManager(session);
+
+            RealmModel adminRealm = manager.getRealm(Config.getAdminRealm());
+            ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID);
+            TokenManager tm = new TokenManager();
+            UserModel admin = session.users().getUserByUsername("admin", adminRealm);
+            ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
+            clientSession.setNote(OIDCLoginProtocol.ISSUER, "http://localhost:8081/auth/realms/master");
+            UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null);
+            AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
+            return tm.encodeToken(adminRealm, token);
+        } finally {
+            keycloakRule.stopSession(session, true);
+        }
+    }
+
+
+    @Test
+    public void testMetadataPostSignedLoginLogout() throws Exception {
+
+        driver.navigate().to("http://localhost:8081/sales-metadata/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-metadata/");
+        String pageSource = driver.getPageSource();
+        Assert.assertTrue(pageSource.contains("bburke"));
+        driver.navigate().to("http://localhost:8081/sales-metadata?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-metadata/");
+
+    }
+
+    public static void uploadSP() {
+        String token = createToken();
+        final String authHeader = "Bearer " + token;
+        ClientRequestFilter authFilter = new ClientRequestFilter() {
+            @Override
+            public void filter(ClientRequestContext requestContext) throws IOException {
+                requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
+            }
+        };
+        Client client = ClientBuilder.newBuilder().register(authFilter).build();
+        UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth");
+        WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase));
+
+
+        MultipartFormDataOutput formData = new MultipartFormDataOutput();
+        InputStream is = SamlBindingTest.class.getResourceAsStream("/saml/sp-metadata.xml");
+        Assert.assertNotNull(is);
+        formData.addFormData("file", is, MediaType.APPLICATION_XML_TYPE);
+
+        WebTarget upload = adminRealms.path("demo/client-importers/saml2-entity-descriptor/upload");
+        System.out.println(upload.getUri());
+        Response response = upload.request().post(Entity.entity(formData, MediaType.MULTIPART_FORM_DATA));
+        Assert.assertEquals(204, response.getStatus());
+        response.close();
+        client.close();
+    }
+
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlKeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlKeycloakRule.java
new file mode 100755
index 0000000..17b849f
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlKeycloakRule.java
@@ -0,0 +1,167 @@
+package org.keycloak.testsuite.keycloaksaml;
+
+import io.undertow.security.idm.Account;
+import io.undertow.security.idm.Credential;
+import io.undertow.security.idm.IdentityManager;
+import io.undertow.server.handlers.resource.Resource;
+import io.undertow.server.handlers.resource.ResourceChangeListener;
+import io.undertow.server.handlers.resource.ResourceManager;
+import io.undertow.server.handlers.resource.URLResource;
+import io.undertow.servlet.api.DeploymentInfo;
+import io.undertow.servlet.api.LoginConfig;
+import io.undertow.servlet.api.SecurityConstraint;
+import io.undertow.servlet.api.ServletInfo;
+import io.undertow.servlet.api.WebResourceCollection;
+import org.keycloak.adapters.saml.undertow.SamlServletExtension;
+import org.keycloak.testsuite.rule.AbstractKeycloakRule;
+import org.picketlink.identity.federation.bindings.wildfly.sp.SPServletExtension;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URL;
+import java.security.Principal;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public abstract class SamlKeycloakRule extends AbstractKeycloakRule {
+
+    public static class SendUsernameServlet extends HttpServlet {
+        @Override
+        protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+            resp.setContentType("text/plain");
+            OutputStream stream = resp.getOutputStream();
+            Principal principal = req.getUserPrincipal();
+            stream.write("request-path: ".getBytes());
+            stream.write(req.getPathInfo().getBytes());
+            stream.write("\n".getBytes());
+            stream.write("principal=".getBytes());
+            if (principal == null) {
+                stream.write("null".getBytes());
+                return;
+            }
+            String name = principal.getName();
+            stream.write(name.getBytes());
+        }
+        @Override
+        protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+            resp.setContentType("text/plain");
+            OutputStream stream = resp.getOutputStream();
+            Principal principal = req.getUserPrincipal();
+            stream.write("request-path: ".getBytes());
+            stream.write(req.getPathInfo().getBytes());
+            stream.write("\n".getBytes());
+            stream.write("principal=".getBytes());
+            if (principal == null) {
+                stream.write("null".getBytes());
+                return;
+            }
+            String name = principal.getName();
+            stream.write(name.getBytes());
+        }
+    }
+
+    public static class TestResourceManager implements ResourceManager {
+
+        private final String basePath;
+
+        public TestResourceManager(String basePath){
+            this.basePath = basePath;
+        }
+
+        @Override
+        public Resource getResource(String path) throws IOException {
+            String temp = path;
+            String fullPath = basePath + temp;
+            URL url = getClass().getResource(fullPath);
+            if (url == null) {
+                System.out.println("url is null: " + fullPath);
+            }
+            return new URLResource(url, url.openConnection(), path);
+        }
+
+        @Override
+        public boolean isResourceChangeListenerSupported() {
+            throw new RuntimeException();
+        }
+
+        @Override
+        public void registerResourceChangeListener(ResourceChangeListener listener) {
+            throw new RuntimeException();
+        }
+
+        @Override
+        public void removeResourceChangeListener(ResourceChangeListener listener) {
+            throw new RuntimeException();
+        }
+
+        @Override
+        public void close() throws IOException {
+            throw new RuntimeException();
+        }
+    }
+
+    public static class TestIdentityManager implements IdentityManager {
+        @Override
+        public Account verify(Account account) {
+            return account;
+        }
+
+        @Override
+        public Account verify(String userName, Credential credential) {
+            throw new RuntimeException("WTF");
+        }
+
+        @Override
+        public Account verify(Credential credential) {
+            throw new RuntimeException();
+        }
+    }
+
+    @Override
+    protected void setupKeycloak() {
+        String realmJson = getRealmJson();
+        server.importRealm(getClass().getResourceAsStream(realmJson));
+        initWars();
+    }
+
+    public abstract void initWars();
+
+    public void initializeSamlSecuredWar(String warResourcePath, String contextPath, String warDeploymentName, ClassLoader classLoader) {
+
+        ServletInfo regularServletInfo = new ServletInfo("servlet", SendUsernameServlet.class)
+                .addMapping("/*");
+
+        SecurityConstraint constraint = new SecurityConstraint();
+        WebResourceCollection collection = new WebResourceCollection();
+        collection.addUrlPattern("/*");
+        constraint.addWebResourceCollection(collection);
+        constraint.addRoleAllowed("manager");
+        LoginConfig loginConfig = new LoginConfig("KEYCLOAK-SAML", "Test Realm");
+
+        ResourceManager resourceManager = new TestResourceManager(warResourcePath);
+
+        DeploymentInfo deploymentInfo = new DeploymentInfo()
+                .setClassLoader(classLoader)
+                .setIdentityManager(new TestIdentityManager())
+                .setContextPath(contextPath)
+                .setDeploymentName(warDeploymentName)
+                .setLoginConfig(loginConfig)
+                .setResourceManager(resourceManager)
+                .addServlets(regularServletInfo)
+                .addSecurityConstraint(constraint)
+                .addServletExtension(new SamlServletExtension());
+        server.getServer().deploy(deploymentInfo);
+    }
+
+    public String getRealmJson() {
+        return "/keycloak-saml/testsaml.json";
+    }
+
+
+}
diff --git a/testsuite/integration/src/test/resources/keycloak-saml/signed-post/WEB-INF/keycloak-saml.xml b/testsuite/integration/src/test/resources/keycloak-saml/signed-post/WEB-INF/keycloak-saml.xml
new file mode 100755
index 0000000..0a907ce
--- /dev/null
+++ b/testsuite/integration/src/test/resources/keycloak-saml/signed-post/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,45 @@
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8081/sales-post-sig/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8080/sales-post-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleMapping>
+            <Attribute name="Role"/>
+        </RoleMapping>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/keycloak-saml/signed-post/WEB-INF/keystore.jks b/testsuite/integration/src/test/resources/keycloak-saml/signed-post/WEB-INF/keystore.jks
new file mode 100755
index 0000000..144830b
Binary files /dev/null and b/testsuite/integration/src/test/resources/keycloak-saml/signed-post/WEB-INF/keystore.jks differ
diff --git a/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json b/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json
new file mode 100755
index 0000000..e929c24
--- /dev/null
+++ b/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json
@@ -0,0 +1,310 @@
+{
+    "id": "demo",
+    "realm": "demo",
+    "enabled": true,
+    "sslRequired": "external",
+    "registrationAllowed": true,
+    "resetPasswordAllowed": true,
+    "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+    "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "requiredCredentials": [ "password" ],
+    "defaultRoles": [ "user" ],
+    "smtpServer": {
+        "from": "auto@keycloak.org",
+        "host": "localhost",
+        "port":"3025"
+    },
+    "users" : [
+        {
+            "username" : "bburke",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "credentials" : [
+                { "type" : "password",
+                  "value" : "password" }
+            ],
+            "attributes" : {
+                "phone": "617"
+            },
+            "realmRoles": ["manager", "user"],
+            "applicationRoles": {
+                "http://localhost:8081/employee/": [ "employee" ]
+            }
+        }
+    ],
+    "applications": [
+        {
+            "name": "http://localhost:8081/sales-post/",
+            "enabled": true,
+            "fullScopeAllowed": true,
+            "protocol": "saml",
+            "baseUrl": "http://localhost:8081/sales-post",
+            "redirectUris": [
+                "http://localhost:8081/sales-post/*"
+            ],
+            "attributes": {
+                "saml.authnstatement": "true",
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post/",
+                "saml_idp_initiated_sso_url_name": "sales-post"
+            }
+        },
+        {
+            "name": "http://localhost:8081/sales-post-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/sales-post-sig",
+            "redirectUris": [
+                "http://localhost:8081/sales-post-sig/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig/",
+                "saml.server.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8081/sales-post-sig-transient/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/sales-post-sig-transient",
+            "adminUrl": "http://localhost:8081/sales-post-sig-transient",
+            "redirectUris": [
+                "http://localhost:8081/sales-post-sig-transient/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-transient/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-transient/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-transient/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig-transient/",
+                "saml.server.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8081/sales-post-sig-persistent/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/sales-post-sig-persistent",
+            "redirectUris": [
+                "http://localhost:8081/sales-post-sig-persistent/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-persistent/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-persistent/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-persistent/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig-persistent/",
+                "saml.server.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8081/sales-post-sig-email/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/sales-post-sig-email",
+            "adminUrl": "http://localhost:8081/sales-post-sig-email",
+            "redirectUris": [
+                "http://localhost:8081/sales-post-sig-email/*"
+            ],
+            "attributes": {
+                "saml_force_name_id_format": "true",
+                "saml_name_id_format": "email",
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-email/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-email/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-email/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig-email/",
+                "saml.server.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8081/bad-realm-sales-post-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/bad-realm-sales-post-sig/",
+            "adminUrl": "http://localhost:8081/bad-realm-sales-post-sig/",
+            "redirectUris": [
+                "http://localhost:8081/bad-realm-sales-post-sig/*"
+            ],
+            "attributes": {
+                "saml.server.signature": "true",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8081/bad-client-sales-post-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/bad-client-sales-post-sig/",
+            "adminUrl": "http://localhost:8081/bad-client-sales-post-sig/",
+            "redirectUris": [
+                "http://localhost:8081/bad-client-sales-post-sig/*"
+            ],
+            "attributes": {
+                "saml.server.signature": "true",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
+            }
+        },
+        {
+            "name": "http://localhost:8081/sales-post-enc/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/sales-post-enc",
+            "redirectUris": [
+                "http://localhost:8081/sales-post-enc/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-enc/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-enc/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-enc/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-enc/",
+                "saml.server.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA512",
+                "saml.client.signature": "true",
+                "saml.encrypt": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==",
+                "saml.encryption.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
+            }
+        },
+        {
+            "name": "http://localhost:8081/employee-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/employee-sig",
+            "redirectUris": [
+                "http://localhost:8081/employee-sig/*"
+            ],
+            "adminUrl": "http://localhost:8081/employee-sig/",
+            "attributes": {
+                "saml.server.signature": "true",
+                "saml.client.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA1",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
+            }
+        },
+        {
+            "name": "http://localhost:8081/employee/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/employee",
+            "redirectUris": [
+                "http://localhost:8081/employee/*"
+            ],
+            "adminUrl": "http://localhost:8081/employee/",
+            "attributes": {
+                "saml.authnstatement": "true"
+            },
+            "protocolMappers": [
+                {
+                    "name": "email",
+                    "protocol": "saml",
+                    "protocolMapper": "saml-user-property-mapper",
+                    "consentRequired": false,
+                    "config": {
+                        "user.attribute": "email",
+                        "friendly.name": "email",
+                        "attribute.name": "urn:oid:1.2.840.113549.1.9.1",
+                        "attribute.nameformat": "URI Reference"
+                    }
+                },
+                {
+                    "name": "phone",
+                    "protocol": "saml",
+                    "protocolMapper": "saml-user-attribute-mapper",
+                    "consentRequired": false,
+                    "config": {
+                        "user.attribute": "phone",
+                        "attribute.name": "phone",
+                        "attribute.nameformat": "Basic"
+                    }
+                },
+                {
+                    "name": "role-list",
+                    "protocol": "saml",
+                    "protocolMapper": "saml-role-list-mapper",
+                    "consentRequired": false,
+                    "config": {
+                        "attribute.name": "Role",
+                        "attribute.nameformat": "Basic",
+                        "single": "false"
+                    }
+                }
+            ]
+        },
+        {
+            "name": "http://localhost:8081/employee-sig-front/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "frontchannelLogout": true,
+            "baseUrl": "http://localhost:8081/employee-sig-front/",
+            "redirectUris": [
+                "http://localhost:8081/employee-sig-front/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8081/employee-sig-front/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/employee-sig-front/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/employee-sig-front/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/employee-sig-front/",
+                "saml.server.signature": "true",
+                "saml.client.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA1",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
+            }
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "manager",
+                "description": "Have Manager privileges"
+            },
+            {
+                "name": "user",
+                "description": "Have User privileges"
+            }
+        ],
+        "application" : {
+            "http://localhost:8081/employee/" : [
+                {
+                    "name": "employee",
+                    "description": "Have Employee privileges"
+                }
+            ]
+        }
+    }
+}
diff --git a/testsuite/integration/src/test/resources/saml/testsaml.json b/testsuite/integration/src/test/resources/saml/testsaml.json
index 4db2adf..e929c24 100755
--- a/testsuite/integration/src/test/resources/saml/testsaml.json
+++ b/testsuite/integration/src/test/resources/saml/testsaml.json
@@ -69,7 +69,6 @@
                 "saml.signature.algorithm": "RSA_SHA256",
                 "saml.client.signature": "true",
                 "saml.authnstatement": "true",
-                "saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
                 "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
             }
         },
@@ -92,7 +91,6 @@
                 "saml.signature.algorithm": "RSA_SHA256",
                 "saml.client.signature": "true",
                 "saml.authnstatement": "true",
-                "saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
                 "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
             }
         },
@@ -114,7 +112,6 @@
                 "saml.signature.algorithm": "RSA_SHA256",
                 "saml.client.signature": "true",
                 "saml.authnstatement": "true",
-                "saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
                 "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
             }
         },
@@ -139,7 +136,6 @@
                 "saml.signature.algorithm": "RSA_SHA256",
                 "saml.client.signature": "true",
                 "saml.authnstatement": "true",
-                "saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
                 "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
             }
         },
@@ -157,7 +153,6 @@
                 "saml.server.signature": "true",
                 "saml.client.signature": "true",
                 "saml.authnstatement": "true",
-                "saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
                 "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
             }
         },
@@ -175,7 +170,6 @@
                 "saml.server.signature": "true",
                 "saml.client.signature": "true",
                 "saml.authnstatement": "true",
-                "saml.signing.private.key": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
                 "saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
             }
         },
@@ -198,9 +192,7 @@
                 "saml.client.signature": "true",
                 "saml.encrypt": "true",
                 "saml.authnstatement": "true",
-                "saml.signing.private.key": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
                 "saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==",
-                "saml.encryption.private.key": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
                 "saml.encryption.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
             }
         },
@@ -219,7 +211,6 @@
                 "saml.client.signature": "true",
                 "saml.signature.algorithm": "RSA_SHA1",
                 "saml.authnstatement": "true",
-                "saml.signing.private.key": "MIICXQIBAAKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABAoGANU1efgc6ojIvwn7Lsf8GAKN9z2D6uS0T3I9nw1k2CtI+xWhgKAUltEANx5lEfBRYIdYclidRpqrk8DYgzASrDYTHXzqVBJfAk1VrAGpqyRq+TNMLUHkXiTiSDOQ6WqhX93UGMmAgQm1RsLa6+fy1BO/B2y85+Yf2OUylsKS6avECQQDslRDiNFdtEjdvyOL20tQ7+W+eKVxVxKAyQ3gFjIIDizELZt+Jq1Wz6XV9NhK1JFtlVugeD1tlW/+K16fEmDYXAkEAzqKoN/JeGb20rfQldAUWdQbb0jrQAYlgoSU/9fYH9YVJT8vnkfhPBTwIw9H9euf1//lRP/jHltHd5ch4230YyQJBAN3rOkoltPiABPZbpuLGgwS7BwOCYrWlWmurtBLoaTCvyVKbrgXybNL1pBrOtR+rufvGWLeRyja65Gs1vY6BBQMCQQCTsNq/MjJj/522f7yNUl2cw4w2lOa7Um+IflFbAcDqkZu2ty0Kvgns2d4B6INeZ5ECpjaWnMA7YkFRzZnkd2NRAkB8lEY56ScnNigoZkkjtEUd2ejdhZPYuS9SKfv9zHwN+I+DE2vVFZz8GPq/iLcMx13PkZaYaJNQ4FtQY/hRLSn5",
                 "saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
             }
         },
@@ -292,7 +283,6 @@
                 "saml.client.signature": "true",
                 "saml.signature.algorithm": "RSA_SHA1",
                 "saml.authnstatement": "true",
-                "saml.signing.private.key": "MIICXQIBAAKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABAoGANU1efgc6ojIvwn7Lsf8GAKN9z2D6uS0T3I9nw1k2CtI+xWhgKAUltEANx5lEfBRYIdYclidRpqrk8DYgzASrDYTHXzqVBJfAk1VrAGpqyRq+TNMLUHkXiTiSDOQ6WqhX93UGMmAgQm1RsLa6+fy1BO/B2y85+Yf2OUylsKS6avECQQDslRDiNFdtEjdvyOL20tQ7+W+eKVxVxKAyQ3gFjIIDizELZt+Jq1Wz6XV9NhK1JFtlVugeD1tlW/+K16fEmDYXAkEAzqKoN/JeGb20rfQldAUWdQbb0jrQAYlgoSU/9fYH9YVJT8vnkfhPBTwIw9H9euf1//lRP/jHltHd5ch4230YyQJBAN3rOkoltPiABPZbpuLGgwS7BwOCYrWlWmurtBLoaTCvyVKbrgXybNL1pBrOtR+rufvGWLeRyja65Gs1vY6BBQMCQQCTsNq/MjJj/522f7yNUl2cw4w2lOa7Um+IflFbAcDqkZu2ty0Kvgns2d4B6INeZ5ECpjaWnMA7YkFRzZnkd2NRAkB8lEY56ScnNigoZkkjtEUd2ejdhZPYuS9SKfv9zHwN+I+DE2vVFZz8GPq/iLcMx13PkZaYaJNQ4FtQY/hRLSn5",
                 "saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
             }
         }