keycloak-uncached

Changes

adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java 88(+0 -88)

adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java 159(+0 -159)

adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java 141(+0 -141)

adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java 177(+0 -177)

Details

diff --git a/adapters/saml/core/pom.xml b/adapters/saml/core/pom.xml
index 5a63c2c..8defcfa 100755
--- a/adapters/saml/core/pom.xml
+++ b/adapters/saml/core/pom.xml
@@ -72,6 +72,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
             <scope>provided</scope>
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java
index 76d7648..a32e122 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java
@@ -27,35 +27,36 @@ import org.keycloak.adapters.cloned.AdapterHttpClientConfig;
  */
 public class IDP implements Serializable {
     public static class SingleSignOnService implements Serializable {
-        private boolean signRequest;
-        private boolean validateResponseSignature;
+        private Boolean signRequest;
+        private Boolean validateResponseSignature;
         private String requestBinding;
         private String responseBinding;
         private String bindingUrl;
         private String assertionConsumerServiceUrl;
-        private boolean validateAssertionSignature;
+        private Boolean validateAssertionSignature;
+        private boolean signaturesRequired = false;
 
         public boolean isSignRequest() {
-            return signRequest;
+            return signRequest == null ? signaturesRequired : signRequest;
         }
 
-        public void setSignRequest(boolean signRequest) {
+        public void setSignRequest(Boolean signRequest) {
             this.signRequest = signRequest;
         }
 
         public boolean isValidateResponseSignature() {
-            return validateResponseSignature;
+            return validateResponseSignature == null ? signaturesRequired : validateResponseSignature;
         }
 
-        public void setValidateResponseSignature(boolean validateResponseSignature) {
+        public void setValidateResponseSignature(Boolean validateResponseSignature) {
             this.validateResponseSignature = validateResponseSignature;
         }
 
         public boolean isValidateAssertionSignature() {
-            return validateAssertionSignature;
+            return validateAssertionSignature == null ? false : validateAssertionSignature;
         }
 
-        public void setValidateAssertionSignature(boolean validateAssertionSignature) {
+        public void setValidateAssertionSignature(Boolean validateAssertionSignature) {
             this.validateAssertionSignature = validateAssertionSignature;
         }
 
@@ -90,47 +91,52 @@ public class IDP implements Serializable {
         public void setAssertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
             this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
         }
+
+        private void setSignaturesRequired(boolean signaturesRequired) {
+            this.signaturesRequired = signaturesRequired;
+        }
     }
 
     public static class SingleLogoutService implements Serializable {
-        private boolean signRequest;
-        private boolean signResponse;
-        private boolean validateRequestSignature;
-        private boolean validateResponseSignature;
+        private Boolean signRequest;
+        private Boolean signResponse;
+        private Boolean validateRequestSignature;
+        private Boolean validateResponseSignature;
         private String requestBinding;
         private String responseBinding;
         private String postBindingUrl;
         private String redirectBindingUrl;
+        private boolean signaturesRequired = false;
 
         public boolean isSignRequest() {
-            return signRequest;
+            return signRequest == null ? signaturesRequired : signRequest;
         }
 
-        public void setSignRequest(boolean signRequest) {
+        public void setSignRequest(Boolean signRequest) {
             this.signRequest = signRequest;
         }
 
         public boolean isSignResponse() {
-            return signResponse;
+            return signResponse == null ? signaturesRequired : signResponse;
         }
 
-        public void setSignResponse(boolean signResponse) {
+        public void setSignResponse(Boolean signResponse) {
             this.signResponse = signResponse;
         }
 
         public boolean isValidateRequestSignature() {
-            return validateRequestSignature;
+            return validateRequestSignature == null ? signaturesRequired : validateRequestSignature;
         }
 
-        public void setValidateRequestSignature(boolean validateRequestSignature) {
+        public void setValidateRequestSignature(Boolean validateRequestSignature) {
             this.validateRequestSignature = validateRequestSignature;
         }
 
         public boolean isValidateResponseSignature() {
-            return validateResponseSignature;
+            return validateResponseSignature == null ? signaturesRequired : validateResponseSignature;
         }
 
-        public void setValidateResponseSignature(boolean validateResponseSignature) {
+        public void setValidateResponseSignature(Boolean validateResponseSignature) {
             this.validateResponseSignature = validateResponseSignature;
         }
 
@@ -165,6 +171,10 @@ public class IDP implements Serializable {
         public void setRedirectBindingUrl(String redirectBindingUrl) {
             this.redirectBindingUrl = redirectBindingUrl;
         }
+
+        private void setSignaturesRequired(boolean signaturesRequired) {
+            this.signaturesRequired = signaturesRequired;
+        }
     }
 
     public static class HttpClientConfig implements AdapterHttpClientConfig {
@@ -258,6 +268,7 @@ public class IDP implements Serializable {
     private SingleLogoutService singleLogoutService;
     private List<Key> keys;
     private AdapterHttpClientConfig httpClientConfig = new HttpClientConfig();
+    private boolean signaturesRequired = false;
 
     public String getEntityID() {
         return entityID;
@@ -273,6 +284,9 @@ public class IDP implements Serializable {
 
     public void setSingleSignOnService(SingleSignOnService singleSignOnService) {
         this.singleSignOnService = singleSignOnService;
+        if (singleSignOnService != null) {
+            singleSignOnService.setSignaturesRequired(signaturesRequired);
+        }
     }
 
     public SingleLogoutService getSingleLogoutService() {
@@ -281,6 +295,9 @@ public class IDP implements Serializable {
 
     public void setSingleLogoutService(SingleLogoutService singleLogoutService) {
         this.singleLogoutService = singleLogoutService;
+        if (singleLogoutService != null) {
+            singleLogoutService.setSignaturesRequired(signaturesRequired);
+        }
     }
 
     public List<Key> getKeys() {
@@ -315,4 +332,12 @@ public class IDP implements Serializable {
         this.httpClientConfig = httpClientConfig;
     }
 
+    public boolean isSignaturesRequired() {
+        return signaturesRequired;
+    }
+
+    public void setSignaturesRequired(boolean signaturesRequired) {
+        this.signaturesRequired = signaturesRequired;
+    }
+
 }
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/Key.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/Key.java
index ebf3b37..5c64ae3 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/Key.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/Key.java
@@ -114,16 +114,16 @@ public class Key implements Serializable {
         return signing;
     }
 
-    public void setSigning(boolean signing) {
-        this.signing = signing;
+    public void setSigning(Boolean signing) {
+        this.signing = signing != null && signing;
     }
 
     public boolean isEncryption() {
         return encryption;
     }
 
-    public void setEncryption(boolean encryption) {
-        this.encryption = encryption;
+    public void setEncryption(Boolean encryption) {
+        this.encryption = encryption != null && encryption;
     }
 
     public KeyStoreConfig getKeystore() {
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/KeycloakSamlAdapter.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/KeycloakSamlAdapter.java
index a103ffc..0cc474a 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/KeycloakSamlAdapter.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/KeycloakSamlAdapter.java
@@ -26,13 +26,14 @@ import java.util.List;
  * @version $Revision: 1 $
  */
 public class KeycloakSamlAdapter implements Serializable {
-    private List<SP> sps = new LinkedList<>();
+    private final List<SP> sps = new LinkedList<>();
 
     public List<SP> getSps() {
         return sps;
     }
 
-    public void setSps(List<SP> sps) {
-        this.sps = sps;
+    public void addSp(SP sp) {
+        sps.add(sp);
     }
+
 }
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/AbstractKeycloakSamlAdapterV1Parser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/AbstractKeycloakSamlAdapterV1Parser.java
new file mode 100644
index 0000000..361c03e
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/AbstractKeycloakSamlAdapterV1Parser.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.saml.common.parsers.AbstractStaxParser;
+
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.parsers.util.QNameEnumLookup;
+import java.util.Collections;
+import java.util.Set;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * 
+ */
+public abstract class AbstractKeycloakSamlAdapterV1Parser<T> extends AbstractStaxParser<T, KeycloakSamlAdapterV1QNames> {
+
+    protected static final QNameEnumLookup<KeycloakSamlAdapterV1QNames> LOOKUP = new QNameEnumLookup(KeycloakSamlAdapterV1QNames.values());
+
+    private static final Set<String> ALTERNATE_NAMESPACES = Collections.singleton(XMLConstants.NULL_NS_URI);
+
+    public AbstractKeycloakSamlAdapterV1Parser(KeycloakSamlAdapterV1QNames expectedStartElement) {
+        super(expectedStartElement.getQName(), KeycloakSamlAdapterV1QNames.UNKNOWN_ELEMENT);
+    }
+
+    @Override
+    protected KeycloakSamlAdapterV1QNames getElementFromName(QName name) {
+        return (ALTERNATE_NAMESPACES.contains(name.getNamespaceURI()))
+          ? LOOKUP.from(new QName(KeycloakSamlAdapterV1QNames.NS_URI, name.getLocalPart()))
+          : LOOKUP.from(name);
+    }
+
+    @Override
+    protected void validateStartElement(StartElement startElement) {
+        QName name = startElement.getName();
+        QName validatedQName = ALTERNATE_NAMESPACES.contains(name.getNamespaceURI())
+          ? new QName(name.getNamespaceURI(), expectedStartElement.getLocalPart())
+          : expectedStartElement;
+        StaxParserUtil.validate(startElement, validatedQName);
+    }
+
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java
index 92254a2..f06a227 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java
@@ -59,7 +59,7 @@ public class DeploymentBuilder {
         idp.setSingleSignOnService(sso);
         idp.setSingleLogoutService(slo);
 
-        KeycloakSamlAdapter adapter = (KeycloakSamlAdapter)(new KeycloakSamlAdapterXMLParser().parse(xml));
+        KeycloakSamlAdapter adapter = (KeycloakSamlAdapter) KeycloakSamlAdapterParser.getInstance().parse(xml);
         SP sp = adapter.getSps().get(0);
         deployment.setConfigured(true);
         deployment.setEntityID(sp.getEntityID());
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/HttpClientParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/HttpClientParser.java
new file mode 100644
index 0000000..b365fd7
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/HttpClientParser.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.IDP.HttpClientConfig;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class HttpClientParser extends AbstractKeycloakSamlAdapterV1Parser<HttpClientConfig> {
+
+    private static final HttpClientParser INSTANCE = new HttpClientParser();
+
+    private HttpClientParser() {
+        super(KeycloakSamlAdapterV1QNames.HTTP_CLIENT);
+    }
+
+    public static HttpClientParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected HttpClientConfig instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        final HttpClientConfig config = new HttpClientConfig();
+
+        final Boolean allowAnyHostname = StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ALLOW_ANY_HOSTNAME);
+        config.setAllowAnyHostname(allowAnyHostname == null ? false : allowAnyHostname);
+        config.setClientKeystore(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_CLIENT_KEYSTORE));
+        config.setClientKeystorePassword(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_CLIENT_KEYSTORE_PASSWORD));
+        final Integer connPoolSize = StaxParserUtil.getIntegerAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_CONNECTION_POOL_SIZE);
+        config.setConnectionPoolSize(connPoolSize == null ? 0 : connPoolSize);
+        final Boolean disableTrustManager = StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_DISABLE_TRUST_MANAGER);
+        config.setDisableTrustManager(disableTrustManager == null ? false : disableTrustManager);
+        config.setProxyUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_PROXY_URL));
+        config.setTruststore(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TRUSTSTORE));
+        config.setTruststorePassword(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TRUSTSTORE_PASSWORD));
+
+        return config;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, HttpClientConfig target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
+    }
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IdpParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IdpParser.java
new file mode 100644
index 0000000..f883658
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IdpParser.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.IDP;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class IdpParser extends AbstractKeycloakSamlAdapterV1Parser<IDP> {
+
+    private static final IdpParser INSTANCE = new IdpParser();
+
+    private IdpParser() {
+        super(KeycloakSamlAdapterV1QNames.IDP);
+    }
+
+    public static IdpParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected IDP instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        final IDP idp = new IDP();
+
+        idp.setEntityID(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ENTITY_ID));
+
+        Boolean signaturesRequired = StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNATURES_REQUIRED);
+        idp.setSignaturesRequired(signaturesRequired == null ? false : signaturesRequired);
+        idp.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNATURE_CANONICALIZATION_METHOD));
+        idp.setSignatureAlgorithm(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNATURE_ALGORITHM));
+
+        return idp;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, IDP target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case HTTP_CLIENT:
+                target.setHttpClientConfig(HttpClientParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case KEYS:
+                target.setKeys(KeysParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case SINGLE_SIGN_ON_SERVICE:
+                target.setSingleSignOnService(SingleSignOnServiceParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case SINGLE_LOGOUT_SERVICE:
+                target.setSingleLogoutService(SingleLogoutServiceParser.getInstance().parse(xmlEventReader));
+                break;
+        }
+    }
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterParser.java
new file mode 100644
index 0000000..2b3bf60
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterParser.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.saml.common.ErrorCodes;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.parsers.AbstractParser;
+import org.keycloak.saml.common.parsers.StaxParser;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import java.util.HashMap;
+import java.util.Map;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public class KeycloakSamlAdapterParser extends AbstractParser {
+
+    private interface ParserFactory {
+        public StaxParser create();
+    }
+    private static final Map<QName, ParserFactory> PARSERS = new HashMap<QName, ParserFactory>();
+
+    // No-namespace variant
+    private static final QName ALTERNATE_KEYCLOAK_SAML_ADAPTER_V1 = new QName(KeycloakSamlAdapterV1QNames.KEYCLOAK_SAML_ADAPTER.getQName().getLocalPart());
+
+    static {
+        PARSERS.put(KeycloakSamlAdapterV1QNames.KEYCLOAK_SAML_ADAPTER.getQName(),   new ParserFactory() { @Override public StaxParser create() { return KeycloakSamlAdapterV1Parser.getInstance(); }});
+        PARSERS.put(ALTERNATE_KEYCLOAK_SAML_ADAPTER_V1,                             new ParserFactory() { @Override public StaxParser create() { return KeycloakSamlAdapterV1Parser.getInstance(); }});
+    }
+
+    private static final KeycloakSamlAdapterParser INSTANCE = new KeycloakSamlAdapterParser();
+
+    public static KeycloakSamlAdapterParser getInstance() {
+        return INSTANCE;
+    }
+
+    protected KeycloakSamlAdapterParser() {
+    }
+
+    /**
+     * @see {@link org.keycloak.saml.common.parsers.ParserNamespaceSupport#parse(XMLEventReader)}
+     */
+    @Override
+    public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
+        while (xmlEventReader.hasNext()) {
+            XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
+
+            if (xmlEvent instanceof StartElement) {
+                StartElement startElement = (StartElement) xmlEvent;
+                final QName name = startElement.getName();
+
+                ParserFactory pf = PARSERS.get(name);
+                if (pf == null) {
+                    throw logger.parserException(new RuntimeException(ErrorCodes.UNKNOWN_START_ELEMENT + name + "::location="
+                            + startElement.getLocation()));
+                }
+
+                return pf.create().parse(xmlEventReader);
+            }
+
+            StaxParserUtil.getNextEvent(xmlEventReader);
+        }
+
+        throw new RuntimeException(ErrorCodes.FAILED_PARSING + "SAML Parsing has failed");
+    }
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterV1Parser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterV1Parser.java
new file mode 100755
index 0000000..72d35f9
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterV1Parser.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakSamlAdapterV1Parser extends AbstractKeycloakSamlAdapterV1Parser<KeycloakSamlAdapter> {
+
+    private static final KeycloakSamlAdapterV1Parser INSTANCE = new KeycloakSamlAdapterV1Parser();
+
+    private KeycloakSamlAdapterV1Parser() {
+        super(KeycloakSamlAdapterV1QNames.KEYCLOAK_SAML_ADAPTER);
+    }
+
+    public static KeycloakSamlAdapterV1Parser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected KeycloakSamlAdapter instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        return new KeycloakSamlAdapter();
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, KeycloakSamlAdapter target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case SP:
+                target.addSp(SpParser.getInstance().parse(xmlEventReader));
+                break;
+
+            default:
+                // Ignore unknown tags
+                StaxParserUtil.bypassElementBlock(xmlEventReader);
+        }
+    }
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterV1QNames.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterV1QNames.java
new file mode 100644
index 0000000..73e4a71
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterV1QNames.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.saml.processing.core.parsers.util.HasQName;
+import javax.xml.namespace.QName;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public enum KeycloakSamlAdapterV1QNames implements HasQName {
+
+    ATTRIBUTE("Attribute"),
+    CERTIFICATE("Certificate"),
+    CERTIFICATE_PEM("CertificatePem"),
+    HTTP_CLIENT("HttpClient"),
+    IDP("IDP"),
+    KEY("Key"),
+    KEYCLOAK_SAML_ADAPTER("keycloak-saml-adapter"),
+    KEYS("Keys"),
+    KEY_STORE("KeyStore"),
+    PRINCIPAL_NAME_MAPPING("PrincipalNameMapping"),
+    PRIVATE_KEY("PrivateKey"),
+    PRIVATE_KEY_PEM("PrivateKeyPem"),
+    PUBLIC_KEY_PEM("PublicKeyPem"),
+    ROLE_IDENTIFIERS("RoleIdentifiers"),
+    SINGLE_LOGOUT_SERVICE("SingleLogoutService"),
+    SINGLE_SIGN_ON_SERVICE("SingleSignOnService"),
+    SP("SP"),
+
+    ATTR_ALIAS(null, "alias"),
+    ATTR_ALLOW_ANY_HOSTNAME(null, "allowAnyHostname"),
+    ATTR_ASSERTION_CONSUMER_SERVICE_URL(null, "assertionConsumerServiceUrl"),
+    ATTR_ATTRIBUTE(null, "attribute"),
+    ATTR_AUTODETECT_BEARER_ONLY(null, "autodetectBearerOnly"),
+    ATTR_BINDING_URL(null, "bindingUrl"),
+    ATTR_CLIENT_KEYSTORE(null, "clientKeystore"),
+    ATTR_CLIENT_KEYSTORE_PASSWORD(null, "clientKeystorePassword"),
+    ATTR_CONNECTION_POOL_SIZE(null, "connectionPoolSize"),
+    ATTR_DISABLE_TRUST_MANAGER(null, "disableTrustManager"),
+    ATTR_ENCRYPTION(null, "encryption"),
+    ATTR_ENTITY_ID(null, "entityID"),
+    ATTR_FILE(null, "file"),
+    ATTR_FORCE_AUTHENTICATION(null, "forceAuthentication"),
+    ATTR_IS_PASSIVE(null, "isPassive"),
+    ATTR_LOGOUT_PAGE(null, "logoutPage"),
+    ATTR_NAME(null, "name"),
+    ATTR_NAME_ID_POLICY_FORMAT(null, "nameIDPolicyFormat"),
+    ATTR_PASSWORD(null, "password"),
+    ATTR_POLICY(null, "policy"),
+    ATTR_POST_BINDING_URL(null, "postBindingUrl"),
+    ATTR_PROXY_URL(null, "proxyUrl"),
+    ATTR_REDIRECT_BINDING_URL(null, "redirectBindingUrl"),
+    ATTR_REQUEST_BINDING(null, "requestBinding"),
+    ATTR_RESOURCE(null, "resource"),
+    ATTR_RESPONSE_BINDING(null, "responseBinding"),
+    ATTR_SIGNATURES_REQUIRED(null, "signaturesRequired"),
+    ATTR_SIGNATURE_ALGORITHM(null, "signatureAlgorithm"),
+    ATTR_SIGNATURE_CANONICALIZATION_METHOD(null, "signatureCanonicalizationMethod"),
+    ATTR_SIGNING(null, "signing"),
+    ATTR_SIGN_REQUEST(null, "signRequest"),
+    ATTR_SIGN_RESPONSE(null, "signResponse"),
+    ATTR_SSL_POLICY(null, "sslPolicy"),
+    ATTR_TRUSTSTORE(null, "truststore"),
+    ATTR_TRUSTSTORE_PASSWORD(null, "truststorePassword"),
+    ATTR_TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN(null, "turnOffChangeSessionIdOnLogin"),
+    ATTR_TYPE(null, "type"),
+    ATTR_VALIDATE_ASSERTION_SIGNATURE(null, "validateAssertionSignature"),
+    ATTR_VALIDATE_REQUEST_SIGNATURE(null, "validateRequestSignature"),
+    ATTR_VALIDATE_RESPONSE_SIGNATURE(null, "validateResponseSignature"),
+
+    UNKNOWN_ELEMENT("")
+    ;
+
+    public static final String NS_URI = "urn:keycloak:saml:adapter";
+
+    private final QName qName;
+
+    private KeycloakSamlAdapterV1QNames(String localName) {
+        this(NS_URI, localName);
+    }
+
+    private KeycloakSamlAdapterV1QNames(HasQName source) {
+        this.qName = source.getQName();
+    }
+
+    private KeycloakSamlAdapterV1QNames(String nsUri, String localName) {
+        this.qName = new QName(nsUri == null ? null : nsUri, localName);
+    }
+
+    @Override
+    public QName getQName() {
+        return qName;
+    }
+
+    public QName getQName(String prefix) {
+        return new QName(this.qName.getNamespaceURI(), this.qName.getLocalPart(), prefix);
+    }
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyParser.java
new file mode 100644
index 0000000..d6b59f5
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyParser.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.Key;
+import org.keycloak.common.util.StringPropertyReplacer;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeyParser extends AbstractKeycloakSamlAdapterV1Parser<Key> {
+
+    private static final KeyParser INSTANCE = new KeyParser();
+
+    private KeyParser() {
+        super(KeycloakSamlAdapterV1QNames.KEY);
+    }
+
+    public static KeyParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected Key instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        Key key = new Key();
+        key.setSigning(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNING));
+        key.setEncryption(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ENCRYPTION));
+        return key;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, Key target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
+        String value;
+        switch (element) {
+            case KEY_STORE:
+                target.setKeystore(KeyStoreParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case CERTIFICATE_PEM:
+                StaxParserUtil.advance(xmlEventReader);
+                value = StaxParserUtil.getElementText(xmlEventReader);
+                target.setCertificatePem(StringPropertyReplacer.replaceProperties(value));
+                break;
+
+            case PUBLIC_KEY_PEM:
+                StaxParserUtil.advance(xmlEventReader);
+                value = StaxParserUtil.getElementText(xmlEventReader);
+                target.setPublicKeyPem(StringPropertyReplacer.replaceProperties(value));
+                break;
+
+            case PRIVATE_KEY_PEM:
+                StaxParserUtil.advance(xmlEventReader);
+                value = StaxParserUtil.getElementText(xmlEventReader);
+                target.setPrivateKeyPem(StringPropertyReplacer.replaceProperties(value));
+                break;
+        }
+    }
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyStoreParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyStoreParser.java
new file mode 100644
index 0000000..9cdfaf4
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyStoreParser.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.Key;
+import org.keycloak.adapters.saml.config.Key.KeyStoreConfig;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeyStoreParser extends AbstractKeycloakSamlAdapterV1Parser<KeyStoreConfig> {
+
+    private static final KeyStoreParser INSTANCE = new KeyStoreParser();
+
+    private KeyStoreParser() {
+        super(KeycloakSamlAdapterV1QNames.KEY_STORE);
+    }
+
+    public static KeyStoreParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected KeyStoreConfig instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        final KeyStoreConfig keyStore = new Key.KeyStoreConfig();
+        keyStore.setType(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TYPE));
+        keyStore.setAlias(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ALIAS));
+        keyStore.setFile(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_FILE));
+        keyStore.setResource(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_RESOURCE));
+        keyStore.setPassword(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_PASSWORD));
+
+        if (keyStore.getFile() == null && keyStore.getResource() == null) {
+            throw new ParsingException("KeyStore element must have the url or classpath attribute set");
+        }
+
+        return keyStore;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, KeyStoreConfig target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case CERTIFICATE:
+                target.setCertificateAlias(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_ALIAS));
+                break;
+
+            case PRIVATE_KEY:
+                target.setPrivateKeyAlias(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_ALIAS));
+                target.setPrivateKeyPassword(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_PASSWORD));
+                break;
+        }
+    }
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/PrincipalNameMappingParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/PrincipalNameMappingParser.java
new file mode 100644
index 0000000..7438382
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/PrincipalNameMappingParser.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.SP;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class PrincipalNameMappingParser extends AbstractKeycloakSamlAdapterV1Parser<SP.PrincipalNameMapping> {
+
+    private static final PrincipalNameMappingParser INSTANCE = new PrincipalNameMappingParser();
+
+    private PrincipalNameMappingParser() {
+        super(KeycloakSamlAdapterV1QNames.PRINCIPAL_NAME_MAPPING);
+    }
+
+    public static PrincipalNameMappingParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected SP.PrincipalNameMapping instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        final SP.PrincipalNameMapping mapping = new SP.PrincipalNameMapping();
+
+        mapping.setPolicy(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_POLICY));
+        mapping.setAttributeName(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ATTRIBUTE));
+
+        return mapping;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, SP.PrincipalNameMapping target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
+    }
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SingleLogoutServiceParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SingleLogoutServiceParser.java
new file mode 100644
index 0000000..7340058
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SingleLogoutServiceParser.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.IDP;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SingleLogoutServiceParser extends AbstractKeycloakSamlAdapterV1Parser<IDP.SingleLogoutService> {
+
+    private static final SingleLogoutServiceParser INSTANCE = new SingleLogoutServiceParser();
+
+    private SingleLogoutServiceParser() {
+        super(KeycloakSamlAdapterV1QNames.SINGLE_LOGOUT_SERVICE);
+    }
+
+    public static SingleLogoutServiceParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected IDP.SingleLogoutService instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        final IDP.SingleLogoutService slo = new IDP.SingleLogoutService();
+
+        slo.setSignRequest(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGN_REQUEST));
+        slo.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_VALIDATE_RESPONSE_SIGNATURE));
+        slo.setValidateRequestSignature(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_VALIDATE_REQUEST_SIGNATURE));
+        slo.setRequestBinding(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_REQUEST_BINDING));
+        slo.setResponseBinding(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_RESPONSE_BINDING));
+        slo.setSignResponse(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGN_RESPONSE));
+        slo.setPostBindingUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_POST_BINDING_URL));
+        slo.setRedirectBindingUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_REDIRECT_BINDING_URL));
+
+        return slo;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, IDP.SingleLogoutService target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
+    }
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SingleSignOnServiceParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SingleSignOnServiceParser.java
new file mode 100644
index 0000000..52306c3
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SingleSignOnServiceParser.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.IDP;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SingleSignOnServiceParser extends AbstractKeycloakSamlAdapterV1Parser<IDP.SingleSignOnService> {
+
+    private static final SingleSignOnServiceParser INSTANCE = new SingleSignOnServiceParser();
+
+    private SingleSignOnServiceParser() {
+        super(KeycloakSamlAdapterV1QNames.SINGLE_SIGN_ON_SERVICE);
+    }
+
+    public static SingleSignOnServiceParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected IDP.SingleSignOnService instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        final IDP.SingleSignOnService sso = new IDP.SingleSignOnService();
+
+        sso.setSignRequest(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGN_REQUEST));
+        sso.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_VALIDATE_RESPONSE_SIGNATURE));
+        sso.setValidateAssertionSignature(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_VALIDATE_ASSERTION_SIGNATURE));
+        sso.setRequestBinding(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_REQUEST_BINDING));
+        sso.setResponseBinding(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_RESPONSE_BINDING));
+        sso.setBindingUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_BINDING_URL));
+        sso.setAssertionConsumerServiceUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ASSERTION_CONSUMER_SERVICE_URL));
+
+        return sso;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, IDP.SingleSignOnService target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
+    }
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SpParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SpParser.java
new file mode 100644
index 0000000..eac4db8
--- /dev/null
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SpParser.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.config.parsers;
+
+import org.keycloak.adapters.saml.config.SP;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SpParser extends AbstractKeycloakSamlAdapterV1Parser<SP> {
+
+    private static final SpParser INSTANCE = new SpParser();
+
+    private SpParser() {
+        super(KeycloakSamlAdapterV1QNames.SP);
+    }
+
+    public static SpParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected SP instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        final SP sp = new SP();
+
+        sp.setEntityID(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ENTITY_ID));
+
+        sp.setSslPolicy(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SSL_POLICY));
+        sp.setLogoutPage(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_LOGOUT_PAGE));
+        sp.setNameIDPolicyFormat(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_NAME_ID_POLICY_FORMAT));
+        sp.setForceAuthentication(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_FORCE_AUTHENTICATION));
+        sp.setIsPassive(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_IS_PASSIVE));
+        sp.setAutodetectBearerOnly(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_AUTODETECT_BEARER_ONLY));
+        sp.setTurnOffChangeSessionIdOnLogin(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN));
+
+        return sp;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, SP target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case KEYS:
+                target.setKeys(KeysParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case PRINCIPAL_NAME_MAPPING:
+                target.setPrincipalNameMapping(PrincipalNameMappingParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case ROLE_IDENTIFIERS:
+                target.setRoleAttributes(RoleMappingParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case IDP:
+                target.setIdp(IdpParser.getInstance().parse(xmlEventReader));
+                break;
+        }
+    }
+}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/SP.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/SP.java
index 071b170..9b1ba35 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/SP.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/SP.java
@@ -80,24 +80,24 @@ public class SP implements Serializable {
         return forceAuthentication;
     }
 
-    public void setForceAuthentication(boolean forceAuthentication) {
-        this.forceAuthentication = forceAuthentication;
+    public void setForceAuthentication(Boolean forceAuthentication) {
+        this.forceAuthentication = forceAuthentication != null && forceAuthentication;
     }
 
     public boolean isIsPassive() {
         return isPassive;
     }
 
-    public void setIsPassive(boolean isPassive) {
-        this.isPassive = isPassive;
+    public void setIsPassive(Boolean isPassive) {
+        this.isPassive = isPassive != null && isPassive;
     }
 
     public boolean isTurnOffChangeSessionIdOnLogin() {
         return turnOffChangeSessionIdOnLogin;
     }
 
-    public void setTurnOffChangeSessionIdOnLogin(boolean turnOffChangeSessionIdOnLogin) {
-        this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin;
+    public void setTurnOffChangeSessionIdOnLogin(Boolean turnOffChangeSessionIdOnLogin) {
+        this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin != null && turnOffChangeSessionIdOnLogin;
     }
 
     public List<Key> getKeys() {
@@ -152,7 +152,7 @@ public class SP implements Serializable {
         return autodetectBearerOnly;
     }
 
-    public void setAutodetectBearerOnly(boolean autodetectBearerOnly) {
-        this.autodetectBearerOnly = autodetectBearerOnly;
+    public void setAutodetectBearerOnly(Boolean autodetectBearerOnly) {
+        this.autodetectBearerOnly = autodetectBearerOnly != null && autodetectBearerOnly;
     }
 }
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/descriptor/parsers/SamlDescriptorIDPKeysExtractor.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/descriptor/parsers/SamlDescriptorIDPKeysExtractor.java
index b8d5d66..cedad34 100644
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/descriptor/parsers/SamlDescriptorIDPKeysExtractor.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/descriptor/parsers/SamlDescriptorIDPKeysExtractor.java
@@ -35,6 +35,7 @@ import org.keycloak.saml.common.constants.JBossSAMLConstants;
 import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
 import org.keycloak.saml.common.exceptions.ParsingException;
 import org.keycloak.saml.common.util.DocumentUtil;
+import org.keycloak.saml.processing.core.parsers.saml.xmldsig.XmlDSigQNames;
 import org.keycloak.saml.processing.core.util.NamespaceContext;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -88,7 +89,7 @@ public class SamlDescriptorIDPKeysExtractor {
     }
 
     private KeyInfo processKeyDescriptor(Element keyDescriptor) throws MarshalException {
-        NodeList childNodes = keyDescriptor.getElementsByTagNameNS(JBossSAMLURIConstants.XMLDSIG_NSURI.get(), JBossSAMLConstants.KEY_INFO.get());
+        NodeList childNodes = keyDescriptor.getElementsByTagNameNS(JBossSAMLURIConstants.XMLDSIG_NSURI.get(), XmlDSigQNames.KEY_INFO.getQName().getLocalPart());
 
         if (childNodes.getLength() == 0) {
             return null;
diff --git a/adapters/saml/core/src/test/java/org/keycloak/adapters/cloned/HttpAdapterUtilsTest.java b/adapters/saml/core/src/test/java/org/keycloak/adapters/cloned/HttpAdapterUtilsTest.java
index 2c03ef8..8676a02 100644
--- a/adapters/saml/core/src/test/java/org/keycloak/adapters/cloned/HttpAdapterUtilsTest.java
+++ b/adapters/saml/core/src/test/java/org/keycloak/adapters/cloned/HttpAdapterUtilsTest.java
@@ -14,7 +14,7 @@ import javax.xml.crypto.dsig.keyinfo.X509Data;
 import static org.hamcrest.CoreMatchers.*;
 import org.junit.Test;
 import static org.junit.Assert.*;
-import org.keycloak.adapters.saml.config.parsers.ConfigXmlConstants;
+import org.keycloak.adapters.saml.config.parsers.KeycloakSamlAdapterV1QNames;
 import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.dom.saml.v2.metadata.KeyTypes;
 import org.keycloak.saml.common.exceptions.ParsingException;
@@ -41,15 +41,15 @@ public class HttpAdapterUtilsTest {
 
         assertThat(res, notNullValue());
         assertThat(res.keySet(), hasItems(KeyTypes.SIGNING.value()));
-        assertThat(res.get(ConfigXmlConstants.SIGNING_ATTR), notNullValue());
-        assertThat(res.get(ConfigXmlConstants.SIGNING_ATTR).size(), equalTo(2));
+        assertThat(res.get(KeycloakSamlAdapterV1QNames.ATTR_SIGNING.getQName().getLocalPart()), notNullValue());
+        assertThat(res.get(KeycloakSamlAdapterV1QNames.ATTR_SIGNING.getQName().getLocalPart()).size(), equalTo(2));
 
         KeyInfo ki;
         KeyName keyName;
         X509Data x509data;
         X509Certificate x509certificate;
 
-        ki = res.get(ConfigXmlConstants.SIGNING_ATTR).get(0);
+        ki = res.get(KeycloakSamlAdapterV1QNames.ATTR_SIGNING.getQName().getLocalPart()).get(0);
         assertThat(ki.getContent().size(), equalTo(2));
         assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(X509Data.class)));
         assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(KeyName.class)));
@@ -63,7 +63,7 @@ public class HttpAdapterUtilsTest {
         assertThat(x509certificate, notNullValue());
         assertThat(x509certificate.getSigAlgName(), equalTo("SHA256withRSA"));
 
-        ki = res.get(ConfigXmlConstants.SIGNING_ATTR).get(1);
+        ki = res.get(KeycloakSamlAdapterV1QNames.ATTR_SIGNING.getQName().getLocalPart()).get(1);
         assertThat(ki.getContent().size(), equalTo(2));
         assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(X509Data.class)));
         assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(KeyName.class)));
diff --git a/adapters/saml/core/src/test/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterXMLParserTest.java b/adapters/saml/core/src/test/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterXMLParserTest.java
index 88a96cb..1a28743 100755
--- a/adapters/saml/core/src/test/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterXMLParserTest.java
+++ b/adapters/saml/core/src/test/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterXMLParserTest.java
@@ -30,6 +30,8 @@ import java.io.InputStream;
 import org.junit.Rule;
 import org.junit.rules.ExpectedException;
 import org.keycloak.saml.common.exceptions.ParsingException;
+import java.io.IOException;
+import org.hamcrest.Matchers;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -67,7 +69,7 @@ public class KeycloakSamlAdapterXMLParserTest {
 
     @Test
     public void testValidationKeyInvalid() throws Exception {
-        InputStream schemaIs = KeycloakSamlAdapterXMLParser.class.getResourceAsStream(CURRENT_XSD_LOCATION);
+        InputStream schemaIs = KeycloakSamlAdapterV1Parser.class.getResourceAsStream(CURRENT_XSD_LOCATION);
         InputStream is = getClass().getResourceAsStream("keycloak-saml-invalid.xml");
         assertNotNull(is);
         assertNotNull(schemaIs);
@@ -77,12 +79,14 @@ public class KeycloakSamlAdapterXMLParserTest {
     }
 
     @Test
-    public void testXmlParser() throws Exception {
-        InputStream is = getClass().getResourceAsStream("keycloak-saml.xml");
-        assertNotNull(is);
-        KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
+    public void testParseSimpleFileNoNamespace() throws Exception {
+        KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-no-namespace.xml", KeycloakSamlAdapter.class);
+    }
+
+    @Test
+    public void testXmlParserBaseFile() throws Exception {
+        KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml.xml", KeycloakSamlAdapter.class);
 
-        KeycloakSamlAdapter config = (KeycloakSamlAdapter)parser.parse(is);
         assertNotNull(config);
         assertEquals(1, config.getSps().size());
         SP sp = config.getSps().get(0);
@@ -121,7 +125,7 @@ public class KeycloakSamlAdapterXMLParserTest {
         assertEquals("POST", idp.getSingleSignOnService().getRequestBinding());
         assertEquals("url", idp.getSingleSignOnService().getBindingUrl());
 
-        assertTrue(idp.getSingleLogoutService().isSignRequest());
+        assertFalse(idp.getSingleLogoutService().isSignRequest());
         assertTrue(idp.getSingleLogoutService().isSignResponse());
         assertTrue(idp.getSingleLogoutService().isValidateRequestSignature());
         assertTrue(idp.getSingleLogoutService().isValidateResponseSignature());
@@ -135,14 +139,17 @@ public class KeycloakSamlAdapterXMLParserTest {
         assertEquals("cert pem", idp.getKeys().get(0).getCertificatePem());
     }
 
+    private <T> T parseKeycloakSamlAdapterConfig(String fileName, Class<T> targetClass) throws ParsingException, IOException {
+        try (InputStream is = getClass().getResourceAsStream(fileName)) {
+            KeycloakSamlAdapterParser parser = KeycloakSamlAdapterParser.getInstance();
+            return targetClass.cast(parser.parse(is));
+        }
+    }
+
 
     @Test
     public void testXmlParserMultipleSigningKeys() throws Exception {
-        InputStream is = getClass().getResourceAsStream("keycloak-saml-multiple-signing-keys.xml");
-        assertNotNull(is);
-        KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
-
-        KeycloakSamlAdapter config = (KeycloakSamlAdapter) parser.parse(is);
+        KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-multiple-signing-keys.xml", KeycloakSamlAdapter.class);
         assertNotNull(config);
         assertEquals(1, config.getSps().size());
         SP sp = config.getSps().get(0);
@@ -158,11 +165,7 @@ public class KeycloakSamlAdapterXMLParserTest {
 
     @Test
     public void testXmlParserHttpClientSettings() throws Exception {
-        InputStream is = getClass().getResourceAsStream("keycloak-saml-wth-http-client-settings.xml");
-        assertNotNull(is);
-        KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
-
-        KeycloakSamlAdapter config = (KeycloakSamlAdapter) parser.parse(is);
+        KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-wth-http-client-settings.xml", KeycloakSamlAdapter.class);
         assertNotNull(config);
         assertEquals(1, config.getSps().size());
         SP sp = config.getSps().get(0);
@@ -178,4 +181,66 @@ public class KeycloakSamlAdapterXMLParserTest {
         assertThat(idp.getHttpClientConfig().isAllowAnyHostname(), is(true));
         assertThat(idp.getHttpClientConfig().isDisableTrustManager(), is(true));
     }
+
+    @Test
+    public void testXmlParserSystemPropertiesNoPropertiesSet() throws Exception {
+        KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-properties.xml", KeycloakSamlAdapter.class);
+        assertNotNull(config);
+        assertThat(config.getSps(), Matchers.contains(instanceOf(SP.class)));
+        SP sp = config.getSps().get(0);
+        IDP idp = sp.getIdp();
+
+        assertThat(sp.getEntityID(), is("sp"));
+        assertThat(sp.getSslPolicy(), is("${keycloak-saml-properties.sslPolicy}"));
+
+        assertThat(idp.isSignaturesRequired(), is(false));
+
+        assertThat(idp.getSingleLogoutService().isSignRequest(), is(true));
+        assertThat(idp.getSingleLogoutService().isSignResponse(), is(false));
+
+        assertThat(idp.getSingleSignOnService().isSignRequest(), is(true));
+        assertThat(idp.getSingleSignOnService().isValidateResponseSignature(), is(true));
+
+        // These should take default from IDP.signaturesRequired
+        assertThat(idp.getSingleLogoutService().isValidateRequestSignature(), is(false));
+        assertThat(idp.getSingleLogoutService().isValidateResponseSignature(), is(false));
+
+        assertThat(idp.getSingleSignOnService().isValidateAssertionSignature(), is(false));
+    }
+
+    @Test
+    public void testXmlParserSystemPropertiesWithPropertiesSet() throws Exception {
+        try {
+            System.setProperty("keycloak-saml-properties.entityID", "meid");
+            System.setProperty("keycloak-saml-properties.sslPolicy", "INTERNAL");
+            System.setProperty("keycloak-saml-properties.signaturesRequired", "true");
+
+            KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-properties.xml", KeycloakSamlAdapter.class);
+            assertNotNull(config);
+            assertThat(config.getSps(), Matchers.contains(instanceOf(SP.class)));
+            SP sp = config.getSps().get(0);
+            IDP idp = sp.getIdp();
+
+            assertThat(sp.getEntityID(), is("meid"));
+            assertThat(sp.getSslPolicy(), is("INTERNAL"));
+            assertThat(idp.isSignaturesRequired(), is(true));
+
+            assertThat(idp.getSingleLogoutService().isSignRequest(), is(true));
+            assertThat(idp.getSingleLogoutService().isSignResponse(), is(false));
+
+            assertThat(idp.getSingleSignOnService().isSignRequest(), is(true));
+            assertThat(idp.getSingleSignOnService().isValidateResponseSignature(), is(true));
+
+            // These should take default from IDP.signaturesRequired
+            assertThat(idp.getSingleLogoutService().isValidateRequestSignature(), is(true));
+            assertThat(idp.getSingleLogoutService().isValidateResponseSignature(), is(true));
+
+            // This is false by default
+            assertThat(idp.getSingleSignOnService().isValidateAssertionSignature(), is(false));
+        } finally {
+            System.clearProperty("keycloak-saml-properties.entityID");
+            System.clearProperty("keycloak-saml-properties.sslPolicy");
+            System.clearProperty("keycloak-saml-properties.signaturesRequired");
+        }
+    }
 }
diff --git a/adapters/saml/core/src/test/resources/org/keycloak/adapters/saml/config/parsers/keycloak-saml.xml b/adapters/saml/core/src/test/resources/org/keycloak/adapters/saml/config/parsers/keycloak-saml.xml
index 31f62e5..e59d8f8 100755
--- a/adapters/saml/core/src/test/resources/org/keycloak/adapters/saml/config/parsers/keycloak-saml.xml
+++ b/adapters/saml/core/src/test/resources/org/keycloak/adapters/saml/config/parsers/keycloak-saml.xml
@@ -57,7 +57,7 @@
             <SingleLogoutService
                     validateRequestSignature="true"
                     validateResponseSignature="true"
-                    signRequest="true"
+                    signRequest="false"
                     signResponse="true"
                     requestBinding="REDIRECT"
                     responseBinding="POST"
diff --git a/adapters/saml/core/src/test/resources/org/keycloak/adapters/saml/config/parsers/keycloak-saml-no-namespace.xml b/adapters/saml/core/src/test/resources/org/keycloak/adapters/saml/config/parsers/keycloak-saml-no-namespace.xml
new file mode 100644
index 0000000..87aea81
--- /dev/null
+++ b/adapters/saml/core/src/test/resources/org/keycloak/adapters/saml/config/parsers/keycloak-saml-no-namespace.xml
@@ -0,0 +1,74 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="${keycloak-saml-properties.entityID:sp}"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="format"
+        forceAuthentication="true"
+        isPassive="true">
+        <Keys>
+            <Key signing="true">
+                <KeyStore file="file" resource="cp" password="pw">
+                    <PrivateKey alias="private alias" password="private pw"/>
+                    <Certificate alias="cert alias"/>
+                </KeyStore>
+            </Key>
+            <Key encryption="true">
+                <PrivateKeyPem>
+                    private pem
+                </PrivateKeyPem>
+                <PublicKeyPem>
+                    public pem
+                </PublicKeyPem>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_ATTRIBUTE" attribute="attribute"/>
+        <RoleIdentifiers>
+            <Attribute name="member"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp"
+             signatureAlgorithm="RSA_SHA256"
+             signatureCanonicalizationMethod="canon"
+             signaturesRequired="true"
+                >
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="POST"
+                                 bindingUrl="url"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="REDIRECT"
+                    responseBinding="POST"
+                    postBindingUrl="posturl"
+                    redirectBindingUrl="redirecturl"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <CertificatePem>
+                        cert pem
+                    </CertificatePem>
+                </Key>
+            </Keys>
+        </IDP>
+    </SP>
+</keycloak-saml-adapter>
diff --git a/adapters/saml/core/src/test/resources/org/keycloak/adapters/saml/config/parsers/keycloak-saml-properties.xml b/adapters/saml/core/src/test/resources/org/keycloak/adapters/saml/config/parsers/keycloak-saml-properties.xml
new file mode 100644
index 0000000..a54bf36
--- /dev/null
+++ b/adapters/saml/core/src/test/resources/org/keycloak/adapters/saml/config/parsers/keycloak-saml-properties.xml
@@ -0,0 +1,74 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter"
+                       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                       xsi:schemaLocation="urn:keycloak:saml:adapter http://www.keycloak.org/schema/keycloak_saml_adapter_1_9.xsd">
+    <SP entityID="${keycloak-saml-properties.entityID:sp}"
+        sslPolicy="${keycloak-saml-properties.sslPolicy}"
+        nameIDPolicyFormat="format"
+        forceAuthentication="true"
+        isPassive="true">
+        <Keys>
+            <Key signing="true">
+                <KeyStore file="file" resource="cp" password="pw">
+                    <PrivateKey alias="private alias" password="private pw"/>
+                    <Certificate alias="cert alias"/>
+                </KeyStore>
+            </Key>
+            <Key encryption="true">
+                <PrivateKeyPem>
+                    private pem
+                </PrivateKeyPem>
+                <PublicKeyPem>
+                    public pem
+                </PublicKeyPem>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_ATTRIBUTE" attribute="attribute"/>
+        <RoleIdentifiers>
+            <Attribute name="member"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp"
+             signatureAlgorithm="RSA_SHA256"
+             signatureCanonicalizationMethod="canon"
+             signaturesRequired="${keycloak-saml-properties.signaturesRequired:false}"
+                >
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="POST"
+                                 bindingUrl="url"
+                    />
+
+            <SingleLogoutService
+                    signRequest="true"
+                    signResponse="false"
+                    requestBinding="REDIRECT"
+                    responseBinding="POST"
+                    postBindingUrl="posturl"
+                    redirectBindingUrl="redirecturl"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <CertificatePem>
+                        cert pem
+                    </CertificatePem>
+                </Key>
+            </Keys>
+        </IDP>
+    </SP>
+</keycloak-saml-adapter>
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractStaxParser.java b/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractStaxParser.java
index 5d1dbdd..6d84a81 100644
--- a/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractStaxParser.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractStaxParser.java
@@ -37,7 +37,7 @@ import javax.xml.stream.events.XMLEvent;
 public abstract class AbstractStaxParser<T, E> implements StaxParser {
 
     protected static final PicketLinkLogger LOGGER = PicketLinkLoggerFactory.getLogger();
-    private final QName expectedStartElement;
+    protected final QName expectedStartElement;
     private final E unknownElement;
 
     public AbstractStaxParser(QName expectedStartElement, E unknownElement) {
@@ -51,7 +51,8 @@ public abstract class AbstractStaxParser<T, E> implements StaxParser {
 
         // Get the start element and validate it is the expected one
         StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-        StaxParserUtil.validate(startElement, expectedStartElement);
+        final QName actualQName = startElement.getName();
+        validateStartElement(startElement);
         T target = instantiateElement(xmlEventReader, startElement);
 
         // STATE: Start element has been read.
@@ -76,7 +77,7 @@ public abstract class AbstractStaxParser<T, E> implements StaxParser {
                 }
 
                 // If end element corresponding to this start element, stop processing.
-                if (Objects.equals(qName, expectedStartElement)) {
+                if (Objects.equals(qName, actualQName)) {
                     // consume the end element and finish parsing of this tag
                     StaxParserUtil.advance(xmlEventReader);
                     break;
@@ -105,13 +106,21 @@ public abstract class AbstractStaxParser<T, E> implements StaxParser {
 
             // In case of recursive nesting the same element, the corresponding end element MUST be handled
             // in the {@code processSubElement} method and MUST NOT be consumed here.
-            if (Objects.equals(expectedStartElement, currentSubelement) || isUnknownElement(token)) {
+            if (Objects.equals(actualQName, currentSubelement) || isUnknownElement(token)) {
                 currentSubelement = null;
             }
         }
         return target;
     }
 
+    /**
+     * Validates that the given startElement has the expected properties (namely {@link QName} matches the expected one).
+     * @param startElement
+     * @return
+     */
+    protected void validateStartElement(StartElement startElement) {
+        StaxParserUtil.validate(startElement, expectedStartElement);
+    }
 
     protected boolean isUnknownElement(E token) {
         return token == null || Objects.equals(token, unknownElement);
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java b/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java
index 1fc338c..4f8a9a8 100755
--- a/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java
@@ -16,6 +16,7 @@
  */
 package org.keycloak.saml.common.util;
 
+import org.keycloak.common.util.StringPropertyReplacer;
 import org.keycloak.saml.common.ErrorCodes;
 import org.keycloak.saml.common.PicketLinkLogger;
 import org.keycloak.saml.common.PicketLinkLoggerFactory;
@@ -190,6 +191,23 @@ public class StaxParserUtil {
     }
 
     /**
+     * Given an {@code Attribute}, get its trimmed value, replacing every occurrence of ${..} by corresponding system property value
+     *
+     * @param attribute
+     *
+     * @return
+     */
+    public static String getAttributeValueRP(Attribute attribute) {
+        if (attribute == null) {
+            return null;
+        }
+
+        final String value = attribute.getValue();
+
+        return value == null ? null : trim(StringPropertyReplacer.replaceProperties(value));
+    }
+
+    /**
      * Get the Attribute value
      *
      * @param startElement
@@ -215,6 +233,21 @@ public class StaxParserUtil {
     }
 
     /**
+     * Get the Attribute value, replacing every occurrence of ${..} by corresponding system property value
+     *
+     * @param startElement
+     * @param tag localpart of the qname of the attribute
+     *
+     * @see StringPropertyReplacer#replaceProperties(java.lang.String)
+     *
+     * @return
+     */
+    public static String getAttributeValueRP(StartElement startElement, HasQName attrName) {
+        final String value = getAttributeValue(startElement, attrName.getQName());
+        return value == null ? null : StringPropertyReplacer.replaceProperties(value);
+    }
+
+    /**
      * Get the Attribute value
      *
      * @param startElement
@@ -270,6 +303,20 @@ public class StaxParserUtil {
     }
 
     /**
+     * Get the Attribute value, replacing every occurrence of ${..} by corresponding system property value
+     *
+     * @param startElement
+     * @param tag localpart of the qname of the attribute
+     *
+     * @return
+     */
+    public static Integer getIntegerAttributeValueRP(StartElement startElement, HasQName attrName) {
+        Attribute attr = startElement.getAttributeByName(attrName.getQName());
+        String value = getAttributeValueRP(attr);
+        return value == null ? null : Integer.valueOf(value);
+    }
+
+    /**
      * Get the Attribute value
      *
      * @param startElement
@@ -284,6 +331,20 @@ public class StaxParserUtil {
     }
 
     /**
+     * Get the Attribute value, replacing every occurrence of ${..} by corresponding system property value
+     *
+     * @param startElement
+     * @param tag localpart of the qname of the attribute
+     *
+     * @return
+     */
+    public static Boolean getBooleanAttributeValueRP(StartElement startElement, HasQName attrName) {
+        Attribute attr = startElement.getAttributeByName(attrName.getQName());
+        String value = getAttributeValueRP(attr);
+        return value == null ? null : Boolean.valueOf(value);
+    }
+
+    /**
      * Get the Attribute value
      *
      * @param startElement
@@ -322,6 +383,14 @@ public class StaxParserUtil {
         return StaxParserUtil.getAttributeValue(attr);
     }
 
+    public static String getRequiredAttributeValueRP(StartElement startElement, HasQName attrName) throws ParsingException {
+        final QName qName = attrName.getQName();
+        Attribute attr = startElement.getAttributeByName(qName);
+        if (attr == null)
+            throw logger.parserRequiredAttribute(qName.getLocalPart());
+        return StaxParserUtil.getAttributeValueRP(attr);
+    }
+
     private static final String JDK_TRANSFORMER_PROPERTY = "picketlink.jdk.transformer";
 
     /**
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/QNameEnumLookup.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/QNameEnumLookup.java
index 9a585f4..3a92903 100644
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/QNameEnumLookup.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/QNameEnumLookup.java
@@ -53,6 +53,11 @@ public class QNameEnumLookup<E extends Enum<E> & HasQName> {
         this.qNameConstants = Collections.unmodifiableMap(q);
     }
 
+    /**
+     * Looks up the given {@code name} and returns the corresponding constant.
+     * @param name
+     * @return
+     */
     public E from(QName name) {
         E c = qNameConstants.get(name);
         if (c == null) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
index ba8aac3..21af1ce 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
@@ -1204,7 +1204,7 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
         Client client = ClientBuilder.newClient();
 
         // Do not redirect client to login page if it's an XHR
-        WebTarget target = client.target(salesPostAutodetectServletPage.toString());
+        WebTarget target = client.target(salesPostAutodetectServletPage.toString() + "/");
         Response response = target.request().header("X-Requested-With", "XMLHttpRequest").get();
         Assert.assertEquals(401, response.getStatus());
         response.close();