keycloak-uncached

Changes

Details

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
index 84764e3..956ab86 100755
--- 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
@@ -134,6 +134,8 @@ public class IDP implements Serializable {
     }
 
     private String entityID;
+    private String signatureAlgorithm;
+    private String signatureCanonicalizationMethod;
     private SingleSignOnService singleSignOnService;
     private SingleLogoutService singleLogoutService;
     private List<Key> keys;
@@ -169,4 +171,21 @@ public class IDP implements Serializable {
     public void setKeys(List<Key> keys) {
         this.keys = keys;
     }
+
+    public String getSignatureAlgorithm() {
+        return signatureAlgorithm;
+    }
+
+    public void setSignatureAlgorithm(String signatureAlgorithm) {
+        this.signatureAlgorithm = signatureAlgorithm;
+    }
+
+    public String getSignatureCanonicalizationMethod() {
+        return signatureCanonicalizationMethod;
+    }
+
+    public void setSignatureCanonicalizationMethod(String signatureCanonicalizationMethod) {
+        this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
+    }
+
 }
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
index 0e0542c..fdb8284 100755
--- 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
@@ -39,10 +39,10 @@ public class ConfigXmlConstants {
 
     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 SIGNATURES_REQUIRED_ATTR = "signaturesRequired";
     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";
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
index b72cb41..0421fda 100755
--- 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
@@ -41,10 +41,10 @@ public class DeploymentBuilder {
         deployment.setForceAuthentication(sp.isForceAuthentication());
         deployment.setNameIDPolicyFormat(sp.getNameIDPolicyFormat());
         deployment.setLogoutPage(sp.getLogoutPage());
-        deployment.setSignatureCanonicalizationMethod(sp.getSignatureCanonicalizationMethod());
+        deployment.setSignatureCanonicalizationMethod(sp.getIdp().getSignatureCanonicalizationMethod());
         deployment.setSignatureAlgorithm(SignatureAlgorithm.RSA_SHA256);
-        if (sp.getSignatureAlgorithm() != null) {
-            deployment.setSignatureAlgorithm(SignatureAlgorithm.valueOf(sp.getSignatureAlgorithm()));
+        if (sp.getIdp().getSignatureAlgorithm() != null) {
+            deployment.setSignatureAlgorithm(SignatureAlgorithm.valueOf(sp.getIdp().getSignatureAlgorithm()));
         }
         if (sp.getPrincipalNameMapping() != null) {
             SamlDeployment.PrincipalNamePolicy policy = SamlDeployment.PrincipalNamePolicy.valueOf(sp.getPrincipalNameMapping().getPolicy());
@@ -52,7 +52,6 @@ public class DeploymentBuilder {
             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);
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
index 96485d5..fc08e44 100755
--- 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
@@ -30,6 +30,10 @@ public class IDPXmlParser extends AbstractParser {
 
         }
         idp.setEntityID(entityID);
+
+        boolean signaturesRequired = StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNATURES_REQUIRED_ATTR);
+        idp.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
+        idp.setSignatureAlgorithm(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR));
         while (xmlEventReader.hasNext()) {
             XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
             if (xmlEvent == null)
@@ -47,11 +51,11 @@ public class IDPXmlParser extends AbstractParser {
                 break;
             String tag = StaxParserUtil.getStartElementName(startElement);
             if (tag.equals(ConfigXmlConstants.SINGLE_SIGN_ON_SERVICE_ELEMENT)) {
-                IDP.SingleSignOnService sso = parseSingleSignOnService(xmlEventReader);
+                IDP.SingleSignOnService sso = parseSingleSignOnService(xmlEventReader, signaturesRequired);
                 idp.setSingleSignOnService(sso);
 
             } else if (tag.equals(ConfigXmlConstants.SINGLE_LOGOUT_SERVICE_ELEMENT)) {
-                IDP.SingleLogoutService slo = parseSingleLogoutService(xmlEventReader);
+                IDP.SingleLogoutService slo = parseSingleLogoutService(xmlEventReader, signaturesRequired);
                 idp.setSingleLogoutService(slo);
 
             } else if (tag.equals(ConfigXmlConstants.KEYS_ELEMENT)) {
@@ -66,25 +70,25 @@ public class IDPXmlParser extends AbstractParser {
         return idp;
     }
 
-    protected IDP.SingleLogoutService parseSingleLogoutService(XMLEventReader xmlEventReader) throws ParsingException {
+    protected IDP.SingleLogoutService parseSingleLogoutService(XMLEventReader xmlEventReader, boolean signaturesRequired) 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.setSignRequest(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
+        slo.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
+        slo.setValidateRequestSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR, signaturesRequired));
         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.setSignResponse(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR, signaturesRequired));
         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 {
+    protected IDP.SingleSignOnService parseSingleSignOnService(XMLEventReader xmlEventReader, boolean signaturesRequired) 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.setSignRequest(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
+        sso.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
         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));
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
index 787af69..6fbd8d0 100755
--- 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
@@ -7,6 +7,8 @@ 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.Characters;
 import javax.xml.stream.events.EndElement;
 import javax.xml.stream.events.StartElement;
 import javax.xml.stream.events.XMLEvent;
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
index 089dc78..f010470 100755
--- 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
@@ -37,8 +37,6 @@ public class SPXmlParser extends AbstractParser {
         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.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
-        sp.setSignatureAlgorithm(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR));
         sp.setForceAuthentication(StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.FORCE_AUTHENTICATION_ATTR));
         while (xmlEventReader.hasNext()) {
             XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
@@ -91,7 +89,6 @@ public class SPXmlParser extends AbstractParser {
         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)
@@ -116,21 +113,12 @@ public class SPXmlParser extends AbstractParser {
 
                 }
                 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);
     }
 
 
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
index bd48ba1..fadfe21 100755
--- 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
@@ -41,9 +41,6 @@ public class SP implements Serializable {
     private String nameIDPolicyFormat;
     private PrincipalNameMapping principalNameMapping;
     private Set<String> roleAttributes;
-    private Set<String> roleFriendlyAttributes;
-    private String signatureAlgorithm;
-    private String signatureCanonicalizationMethod;
     private IDP idp;
 
     public String getEntityID() {
@@ -102,14 +99,6 @@ public class SP implements Serializable {
         this.roleAttributes = roleAttributes;
     }
 
-    public Set<String> getRoleFriendlyAttributes() {
-        return roleFriendlyAttributes;
-    }
-
-    public void setRoleFriendlyAttributes(Set<String> roleFriendlyAttributes) {
-        this.roleFriendlyAttributes = roleFriendlyAttributes;
-    }
-
     public IDP getIdp() {
         return idp;
     }
@@ -126,19 +115,4 @@ public class SP implements Serializable {
         this.logoutPage = logoutPage;
     }
 
-    public String getSignatureAlgorithm() {
-        return signatureAlgorithm;
-    }
-
-    public void setSignatureAlgorithm(String signatureAlgorithm) {
-        this.signatureAlgorithm = signatureAlgorithm;
-    }
-
-    public String getSignatureCanonicalizationMethod() {
-        return signatureCanonicalizationMethod;
-    }
-
-    public void setSignatureCanonicalizationMethod(String signatureCanonicalizationMethod) {
-        this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
-    }
 }
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
index 28a4ead..4aa54d6 100755
--- 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
@@ -210,7 +210,6 @@ public class DefaultSamlDeployment implements SamlDeployment {
     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;
@@ -268,12 +267,7 @@ public class DefaultSamlDeployment implements SamlDeployment {
         return roleAttributeNames;
     }
 
-    @Override
-    public Set<String> getRoleAttributeFriendlyNames() {
-        return roleFriendlyAttributeNames;
-    }
-
-    @Override
+   @Override
     public PrincipalNamePolicy getPrincipalNamePolicy() {
         return principalNamePolicy;
     }
@@ -323,10 +317,6 @@ public class DefaultSamlDeployment implements SamlDeployment {
         this.roleAttributeNames = roleAttributeNames;
     }
 
-    public void setRoleFriendlyAttributeNames(Set<String> roleFriendlyAttributeNames) {
-        this.roleFriendlyAttributeNames = roleFriendlyAttributeNames;
-    }
-
     public void setPrincipalNamePolicy(PrincipalNamePolicy principalNamePolicy) {
         this.principalNamePolicy = principalNamePolicy;
     }
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 ae7eb4b..bebb506 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
@@ -354,7 +354,7 @@ public abstract class SamlAuthenticator {
     }
 
     protected boolean isRole(AttributeType attribute) {
-        return deployment.getRoleAttributeNames().contains(attribute.getName()) || deployment.getRoleAttributeFriendlyNames().contains(attribute.getFriendlyName());
+        return (attribute.getName() != null && deployment.getRoleAttributeNames().contains(attribute.getName())) || (attribute.getFriendlyName() != null && deployment.getRoleAttributeNames().contains(attribute.getFriendlyName()));
     }
 
     protected AuthOutcome handleLogoutResponse(SAMLDocumentHolder holder, StatusResponseType responseType, String relayState) {
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 4540b25..681e405 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
@@ -64,7 +64,6 @@ public interface SamlDeployment {
     String getLogoutPage();
 
     Set<String> getRoleAttributeNames();
-    Set<String> getRoleAttributeFriendlyNames();
 
     enum PrincipalNamePolicy {
         FROM_NAME_ID,
diff --git a/saml/client-adapter/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd b/saml/client-adapter/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd
new file mode 100755
index 0000000..b9e0799
--- /dev/null
+++ b/saml/client-adapter/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xs:schema version="1.0"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           xmlns="urn:keycloak:saml:adapter"
+           targetNamespace="urn:keycloak:saml:adapter"
+           elementFormDefault="qualified"
+           attributeFormDefault="unqualified">
+
+    <xs:element name="keycloak-saml-adapter" type="adapter-type"/>
+    <xs:complexType name="adapter-type">
+        <xs:annotation>
+            <xs:documentation>
+                <![CDATA[
+                    The Keycloak SAML Adapter keycloak-saml.xml config file
+                ]]>
+            </xs:documentation>
+        </xs:annotation>
+        <xs:all>
+            <xs:element name="SP" maxOccurs="1" minOccurs="0" type="sp-type"/>
+        </xs:all>
+    </xs:complexType>
+
+    <xs:complexType name="sp-type">
+        <xs:all>
+            <xs:element name="Keys" type="keys-type" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="PrincipalNameMapping" type="principal-name-mapping-type" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="RoleMapping" type="role-mapping-type" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="IDP" type="idp-type" minOccurs="1" maxOccurs="1"/>
+        </xs:all>
+        <xs:attribute name="entityID" type="xs:string" use="required"/>
+        <xs:attribute name="sslPolicy" type="xs:string" use="optional"/>
+        <xs:attribute name="nameIDPolicyFormat" type="xs:string" use="optional"/>
+        <xs:attribute name="logoutPage" type="xs:string" use="optional"/>
+        <xs:attribute name="forceAuthentication" type="xs:boolean" use="optional"/>
+    </xs:complexType>
+
+    <xs:complexType name="keys-type">
+        <xs:sequence>
+            <xs:element name="Key" type="key-type" minOccurs="1" maxOccurs="2"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="key-type">
+        <xs:all>
+            <xs:element name="KeyStore" maxOccurs="1" minOccurs="0" type="key-store-type"/>
+            <xs:element name="PrivateKeyPem" type="xs:string" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="PublicKeyPem" type="xs:string" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="CertificatePem" type="xs:string" minOccurs="0" maxOccurs="1"/>
+        </xs:all>
+        <xs:attribute name="signing" type="xs:boolean" use="optional"/>
+        <xs:attribute name="encryption" type="xs:boolean" use="optional"/>
+    </xs:complexType>
+    <xs:complexType name="key-store-type">
+        <xs:all>
+            <xs:element name="PrivateKey" maxOccurs="1" minOccurs="0" type="private-key-type"/>
+            <xs:element name="Certificate" type="certificate-type" minOccurs="0" maxOccurs="1"/>
+        </xs:all>
+        <xs:attribute name="file" type="xs:string" use="optional"/>
+        <xs:attribute name="resource" type="xs:string" use="optional"/>
+        <xs:attribute name="password" type="xs:string" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="private-key-type">
+        <xs:attribute name="alias" type="xs:string" use="required"/>
+        <xs:attribute name="password" type="xs:string" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="certificate-type">
+        <xs:attribute name="alias" type="xs:string" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="principal-name-mapping-type">
+        <xs:attribute name="policy" type="xs:string" use="required"/>
+        <xs:attribute name="attribute" type="xs:string" use="optional"/>
+    </xs:complexType>
+    <xs:complexType name="role-mapping-type">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="Attribute" maxOccurs="unbounded" minOccurs="0" type="attribute-type"/>
+        </xs:choice>
+    </xs:complexType>
+    <xs:complexType name="attribute-type">
+        <xs:attribute name="name" type="xs:string" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="idp-type">
+        <xs:sequence minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="SingleSignOnService" maxOccurs="1" minOccurs="1" type="sign-on-type"/>
+            <xs:element name="SingleLogoutService" type="logout-type" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="Keys" type="keys-type" minOccurs="0" maxOccurs="1"/>
+        </xs:sequence>
+        <xs:attribute name="entityID" type="xs:string" use="required"/>
+        <xs:attribute name="signaturesRequired" type="xs:boolean" use="required"/>
+        <xs:attribute name="signatureAlgorithm" type="xs:string" use="optional"/>
+        <xs:attribute name="signatureCanonicalizationMethod" type="xs:string" use="optional"/>
+        <xs:attribute name="encryption" type="xs:boolean" use="optional"/>
+    </xs:complexType>
+    <xs:complexType name="sign-on-type">
+        <xs:attribute name="signRequest" type="xs:boolean" use="optional"/>
+        <xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional"/>
+        <xs:attribute name="requestBinding" type="xs:string" use="optional"/>
+        <xs:attribute name="responseBinding" type="xs:string" use="optional"/>
+        <xs:attribute name="bindingUrl" type="xs:string" use="optional"/>
+    </xs:complexType>
+
+    <xs:complexType name="logout-type">
+        <xs:attribute name="signRequest" type="xs:boolean" use="optional"/>
+        <xs:attribute name="signResponse" type="xs:boolean" use="optional"/>
+        <xs:attribute name="validateRequestSignature" type="xs:boolean" use="optional"/>
+        <xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional"/>
+        <xs:attribute name="requestBinding" type="xs:string" use="optional"/>
+        <xs:attribute name="responseBinding" type="xs:string" use="optional"/>
+        <xs:attribute name="postBindingUrl" type="xs:string" use="optional"/>
+        <xs:attribute name="redirectBindingUrl" type="xs:string" use="optional"/>
+    </xs:complexType>
+
+
+
+
+</xs:schema>
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
index c49cdf1..c92fec6 100755
--- 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
@@ -7,7 +7,15 @@ import org.keycloak.adapters.saml.config.Key;
 import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
 import org.keycloak.adapters.saml.config.SP;
 import org.keycloak.adapters.saml.config.parsers.KeycloakSamlAdapterXMLParser;
+import org.keycloak.saml.common.util.StaxParserUtil;
 
+import javax.xml.XMLConstants;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.transform.stax.StAXSource;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
 import java.io.InputStream;
 
 /**
@@ -17,6 +25,37 @@ import java.io.InputStream;
 public class XmlParserTest {
 
     @Test
+    public void testValidation() throws Exception {
+        {
+            InputStream schema = KeycloakSamlAdapterXMLParser.class.getResourceAsStream("/schema/keycloak_saml_adapter_1_6.xsd");
+            InputStream is = getClass().getResourceAsStream("/keycloak-saml.xml");
+            Assert.assertNotNull(is);
+            Assert.assertNotNull(schema);
+            StaxParserUtil.validate(is, schema);
+        }
+        {
+            InputStream sch = KeycloakSamlAdapterXMLParser.class.getResourceAsStream("/schema/keycloak_saml_adapter_1_6.xsd");
+            InputStream doc = getClass().getResourceAsStream("/keycloak-saml2.xml");
+            Assert.assertNotNull(doc);
+            Assert.assertNotNull(sch);
+            try {
+                SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+                Schema schema = factory.newSchema(new StreamSource(sch));
+                Validator validator = schema.newValidator();
+                StreamSource source = new StreamSource(doc);
+                source.setSystemId("/keycloak-saml2.xml");
+                validator.validate(source);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+
+        }
+
+
+    }
+
+    @Test
     public void testXmlParser() throws Exception {
         InputStream is = getClass().getResourceAsStream("/keycloak-saml.xml");
         Assert.assertNotNull(is);
@@ -48,11 +87,11 @@ public class XmlParserTest {
         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.assertEquals("RSA", idp.getSignatureAlgorithm());
+        Assert.assertEquals("canon", idp.getSignatureCanonicalizationMethod());
         Assert.assertTrue(idp.getSingleSignOnService().isSignRequest());
         Assert.assertTrue(idp.getSingleSignOnService().isValidateResponseSignature());
         Assert.assertEquals("post", idp.getSingleSignOnService().getRequestBinding());
diff --git a/saml/client-adapter/core/src/test/resources/keycloak-saml.xml b/saml/client-adapter/core/src/test/resources/keycloak-saml.xml
index 242dc8e..5f88197 100755
--- a/saml/client-adapter/core/src/test/resources/keycloak-saml.xml
+++ b/saml/client-adapter/core/src/test/resources/keycloak-saml.xml
@@ -1,9 +1,7 @@
-<keycloak-saml-adapter>
+<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter">
     <SP entityID="sp"
         sslPolicy="ssl"
         nameIDPolicyFormat="format"
-        signatureAlgorithm=""
-        sgnatureCanonicalizationMethod=""
         forceAuthentication="true">
         <Keys>
             <Key signing="true" >
@@ -24,9 +22,12 @@
         <PrincipalNameMapping policy="policy" attribute="attribute"/>
         <RoleMapping>
             <Attribute name="member"/>
-            <FriendlyAttribute name="memberOf"/>
         </RoleMapping>
-        <IDP entityID="idp">
+        <IDP entityID="idp"
+             signatureAlgorithm="RSA"
+             signatureCanonicalizationMethod="canon"
+             signaturesRequired="true"
+                >
             <SingleSignOnService signRequest="true"
                                  validateResponseSignature="true"
                                  requestBinding="post"
diff --git a/saml/client-adapter/core/src/test/resources/keycloak-saml2.xml b/saml/client-adapter/core/src/test/resources/keycloak-saml2.xml
new file mode 100755
index 0000000..ee6388d
--- /dev/null
+++ b/saml/client-adapter/core/src/test/resources/keycloak-saml2.xml
@@ -0,0 +1,46 @@
+<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter">
+    <SP entityID="sp"
+        sslPolicy="ssl"
+        nameIDPolicyFormat="format"
+        signatureAlgorithm=""
+        signatureCanonicalizationMethod=""
+        forceAuthentication="true">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore file="file" resource="cp" password="pw">
+                    <PrivateKey alias="private alias" password="private pw"/>
+                    <Certificate alias="cert alias"/>
+                </KeyStore>
+            </Key>
+            <Key encryption="true">
+                <PrivateKeyPemmm>
+                    private pem
+                </PrivateKeyPemmm>
+                <PublicKeyPem>
+                    public pem
+                </PublicKeyPem>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="policy" attribute="attribute"/>
+        <RoleMapping>
+            <Attribute name="member"/>
+        </RoleMapping>
+        <IDP entityID="idp"
+             signaturesRequired="true"
+                >
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="post"
+                                 bindingUrl="url"
+                    />
+
+            <Keys>
+                <Key signing="true">
+                    <CertificatePem>
+                        cert pem
+                    </CertificatePem>
+                </Key>
+            </Keys>
+        </IDP>
+    </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/saml/client-adapter/wildfly/wildfly9-subsystem/src/main/resources/subsystem-templates/keycloak-adapter.xml b/saml/client-adapter/wildfly/wildfly9-subsystem/src/main/resources/subsystem-templates/keycloak-adapter.xml
new file mode 100755
index 0000000..8677d31
--- /dev/null
+++ b/saml/client-adapter/wildfly/wildfly9-subsystem/src/main/resources/subsystem-templates/keycloak-adapter.xml
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!--  Template used by WildFly build when directed to include Keycloak subsystem in a configuration. -->
+<config>
+   <extension-module>org.keycloak.keycloak-saml-adapter-subsystem</extension-module>
+   <subsystem xmlns="urn:jboss:domain:keycloak-saml:1.6">
+   </subsystem>
+</config>
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 7941729..1fbec6f 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
@@ -27,13 +27,16 @@ import org.keycloak.saml.common.exceptions.ParsingException;
 import org.keycloak.saml.common.ErrorCodes;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
 
+import javax.xml.XMLConstants;
 import javax.xml.namespace.QName;
 import javax.xml.stream.Location;
 import javax.xml.stream.XMLEventReader;
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.Characters;
 import javax.xml.stream.events.EndElement;
 import javax.xml.stream.events.StartElement;
 import javax.xml.stream.events.XMLEvent;
@@ -41,7 +44,11 @@ import javax.xml.transform.Source;
 import javax.xml.transform.Transformer;
 import javax.xml.transform.dom.DOMResult;
 import javax.xml.transform.stax.StAXSource;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
 import javax.xml.validation.Validator;
+import java.io.IOException;
 import java.io.InputStream;
 
 /**
@@ -54,7 +61,18 @@ public class StaxParserUtil {
 
     private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
 
-    protected static Validator validator = null;
+    public static void validate(InputStream doc, InputStream sch) throws ParsingException {
+        try {
+            XMLEventReader xmlEventReader = StaxParserUtil.getXMLEventReader(doc);
+            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+            Schema schema = factory.newSchema(new StreamSource(sch));
+            Validator validator = schema.newValidator();
+            validator.validate(new StAXSource(xmlEventReader));
+        } catch (Exception e) {
+            throw logger.parserException(e);
+        }
+
+    }
 
     /**
      * Bypass an entire XML element block from startElement to endElement
@@ -76,6 +94,29 @@ public class StaxParserUtil {
     }
 
     /**
+     * Advances reader if character whitespace encountered
+     *
+     * @param xmlEventReader
+     * @param xmlEvent
+     * @return
+     */
+    public static boolean wasWhitespacePeeked(XMLEventReader xmlEventReader, XMLEvent xmlEvent) {
+        if (xmlEvent.isCharacters()) {
+            Characters chars = xmlEvent.asCharacters();
+            String data = chars.getData();
+            if (data == null || data.trim().equals("")) {
+                try {
+                    xmlEventReader.nextEvent();
+                    return true;
+                } catch (XMLStreamException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
      * Given an {@code Attribute}, get its trimmed value
      *
      * @param attribute
@@ -113,11 +154,23 @@ public class StaxParserUtil {
      * @return false if attribute not set
      */
     public static boolean getBooleanAttributeValue(StartElement startElement, String tag) {
+        return getBooleanAttributeValue(startElement, tag, false);
+    }
+
+    /**
+     * 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, boolean defaultValue) {
         String result = null;
         Attribute attr = startElement.getAttributeByName(new QName(tag));
         if (attr != null)
             result = getAttributeValue(attr);
-        if (result == null) return false;
+        if (result == null) return defaultValue;
         return Boolean.valueOf(result);
     }
 
diff --git a/testsuite/integration/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml b/testsuite/integration/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml
index f5b05df..8460a13 100755
--- a/testsuite/integration/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml
+++ b/testsuite/integration/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml
@@ -16,18 +16,13 @@
         <RoleMapping>
             <Attribute name="Role"/>
         </RoleMapping>
-        <IDP entityID="idp">
-            <SingleSignOnService signRequest="true"
-                                 validateResponseSignature="true"
-                                 requestBinding="POST"
+        <IDP entityID="idp"
+             signaturesRequired="true">
+            <SingleSignOnService 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"
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
index 0a907ce..20d9348 100755
--- 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
@@ -16,18 +16,13 @@
         <RoleMapping>
             <Attribute name="Role"/>
         </RoleMapping>
-        <IDP entityID="idp">
-            <SingleSignOnService signRequest="true"
-                                 validateResponseSignature="true"
-                                 requestBinding="POST"
-                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+        <IDP entityID="idp"
+             signaturesRequired="true">
+        <SingleSignOnService 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"