keycloak-aplcache

Changes

saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLArtifactResponseParser.java 113(+0 -113)

saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLAssertionParser.java 184(+0 -184)

saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLAttributeQueryParser.java 93(+0 -93)

saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLAuthNRequestParser.java 215(+0 -215)

saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLConditionsParser.java 173(+0 -173)

saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLRequestAbstractParser.java 110(+0 -110)

saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLResponseParser.java 110(+0 -110)

saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLSloRequestParser.java 117(+0 -117)

saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLSloResponseParser.java 79(+0 -79)

saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLStatusResponseTypeParser.java 186(+0 -186)

saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLSubjectParser.java 205(+0 -205)

Details

diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java
index 839d4f6..6dca7aa 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java
@@ -61,7 +61,7 @@ public class IDPXmlParser extends AbstractParser {
                 break;
             if (xmlEvent instanceof EndElement) {
                 EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
-                String endElementName = StaxParserUtil.getEndElementName(endElement);
+                String endElementName = StaxParserUtil.getElementName(endElement);
                 if (endElementName.equals(ConfigXmlConstants.IDP_ELEMENT))
                     break;
                 else
@@ -70,7 +70,7 @@ public class IDPXmlParser extends AbstractParser {
             startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
             if (startElement == null)
                 break;
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
             if (tag.equals(ConfigXmlConstants.SINGLE_SIGN_ON_SERVICE_ELEMENT)) {
                 IDP.SingleSignOnService sso = parseSingleSignOnService(xmlEventReader, signaturesRequired);
                 idp.setSingleSignOnService(sso);
@@ -142,22 +142,18 @@ public class IDPXmlParser extends AbstractParser {
                 break;
             if (xmlEvent instanceof EndElement) {
                 EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
-                String endElementName = StaxParserUtil.getEndElementName(endElement);
+                String endElementName = StaxParserUtil.getElementName(endElement);
                 if (endElementName.equals(ConfigXmlConstants.ROLE_IDENTIFIERS_ELEMENT))
                     break;
                 else
                     continue;
             }
 
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
             StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
         }
 
         return config;
     }
 
-    @Override
-    public boolean supports(QName qname) {
-        return false;
-    }
 }
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterXMLParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterXMLParser.java
index 1330d34..b973938 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterXMLParser.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeycloakSamlAdapterXMLParser.java
@@ -42,7 +42,7 @@ public class KeycloakSamlAdapterXMLParser extends AbstractParser {
             startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
             if (startElement == null)
                 break;
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
             if (tag.equals(ConfigXmlConstants.SP_ELEMENT)) {
                 SPXmlParser parser = new SPXmlParser();
                 SP sp = (SP)parser.parse(xmlEventReader);
@@ -55,8 +55,4 @@ public class KeycloakSamlAdapterXMLParser extends AbstractParser {
         return adapter;
     }
 
-    @Override
-    public boolean supports(QName qname) {
-        return false;
-    }
 }
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeysXmlParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeysXmlParser.java
index f75331a..13afbdb 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeysXmlParser.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeysXmlParser.java
@@ -47,16 +47,16 @@ public class KeysXmlParser extends AbstractParser {
                 break;
             if (xmlEvent instanceof EndElement) {
                 EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
-                String endElementName = StaxParserUtil.getEndElementName(endElement);
+                String endElementName = StaxParserUtil.getElementName(endElement);
                 if (endElementName.equals(ConfigXmlConstants.KEYS_ELEMENT))
                     break;
                 else
-                    throw logger.parserUnknownEndElement(endElementName);
+                    throw logger.parserUnknownEndElement(endElementName, xmlEvent.getLocation());
             }
             startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
             if (startElement == null)
                 break;
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
             if (tag.equals(ConfigXmlConstants.KEY_ELEMENT)) {
                 KeyXmlParser parser = new KeyXmlParser();
                 Key key = (Key)parser.parse(xmlEventReader);
@@ -69,8 +69,4 @@ public class KeysXmlParser extends AbstractParser {
         return keys;
     }
 
-    @Override
-    public boolean supports(QName qname) {
-        return false;
-    }
 }
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java
index f14c1df..258b21a 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java
@@ -47,16 +47,16 @@ public class KeyXmlParser extends AbstractParser {
                 break;
             if (xmlEvent instanceof EndElement) {
                 EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
-                String endElementName = StaxParserUtil.getEndElementName(endElement);
+                String endElementName = StaxParserUtil.getElementName(endElement);
                 if (endElementName.equals(ConfigXmlConstants.KEY_ELEMENT))
                     break;
                 else
-                    throw logger.parserUnknownEndElement(endElementName);
+                    throw logger.parserUnknownEndElement(endElementName, xmlEvent.getLocation());
             }
             startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
             if (startElement == null)
                 break;
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
             if (tag.equals(ConfigXmlConstants.KEYS_STORE_ELEMENT)) {
                 key.setKeystore(parseKeyStore(xmlEventReader));
             } else if (tag.equals(ConfigXmlConstants.CERTIFICATE_PEM_ELEMENT)) {
@@ -100,7 +100,7 @@ public class KeyXmlParser extends AbstractParser {
                 break;
             if (xmlEvent instanceof EndElement) {
                 EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
-                String endElementName = StaxParserUtil.getEndElementName(endElement);
+                String endElementName = StaxParserUtil.getElementName(endElement);
                 if (endElementName.equals(ConfigXmlConstants.KEYS_STORE_ELEMENT))
                     break;
                 else
@@ -109,7 +109,7 @@ public class KeyXmlParser extends AbstractParser {
             startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
             if (startElement == null)
                 break;
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
             if (tag.equals(ConfigXmlConstants.CERTIFICATE_ELEMENT)) {
                 StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
                 keyStore.setCertificateAlias(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
@@ -138,8 +138,4 @@ public class KeyXmlParser extends AbstractParser {
 
     }
 
-    @Override
-    public boolean supports(QName qname) {
-        return false;
-    }
 }
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java
index 57d5f58..4573987 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java
@@ -97,7 +97,7 @@ public class SPXmlParser extends AbstractParser {
                 break;
             if (xmlEvent instanceof EndElement) {
                 EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
-                String endElementName = StaxParserUtil.getEndElementName(endElement);
+                String endElementName = StaxParserUtil.getElementName(endElement);
                 if (endElementName.equals(ConfigXmlConstants.SP_ELEMENT))
                     break;
                 else
@@ -106,7 +106,7 @@ public class SPXmlParser extends AbstractParser {
             startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
             if (startElement == null)
                 break;
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
             if (tag.equals(ConfigXmlConstants.KEYS_ELEMENT)) {
                 KeysXmlParser parser = new KeysXmlParser();
                 List<Key> keys = (List<Key>) parser.parse(xmlEventReader);
@@ -148,7 +148,7 @@ public class SPXmlParser extends AbstractParser {
                 break;
             if (xmlEvent instanceof EndElement) {
                 EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
-                String endElementName = StaxParserUtil.getEndElementName(endElement);
+                String endElementName = StaxParserUtil.getElementName(endElement);
                 if (endElementName.equals(ConfigXmlConstants.ROLE_IDENTIFIERS_ELEMENT))
                     break;
                 else
@@ -157,7 +157,7 @@ public class SPXmlParser extends AbstractParser {
             startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
             if (startElement == null)
                 break;
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
             if (tag.equals(ConfigXmlConstants.ATTRIBUTE_ELEMENT)) {
                 StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
                 String attributeValue = getAttributeValue(element, ConfigXmlConstants.NAME_ATTR);
@@ -174,8 +174,4 @@ public class SPXmlParser extends AbstractParser {
         sp.setRoleAttributes(roleAttributes);
     }
 
-    @Override
-    public boolean supports(QName qname) {
-        return false;
-    }
 }
diff --git a/saml-core/pom.xml b/saml-core/pom.xml
index 0914083..ce8e340 100755
--- a/saml-core/pom.xml
+++ b/saml-core/pom.xml
@@ -61,8 +61,7 @@
         </dependency>
         <dependency>
             <groupId>org.hamcrest</groupId>
-            <artifactId>hamcrest-core</artifactId>
-            <version>1.3</version>
+            <artifactId>hamcrest-all</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/DefaultPicketLinkLogger.java b/saml-core/src/main/java/org/keycloak/saml/common/DefaultPicketLinkLogger.java
index b25b55b..da4dca5 100755
--- a/saml-core/src/main/java/org/keycloak/saml/common/DefaultPicketLinkLogger.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/DefaultPicketLinkLogger.java
@@ -345,8 +345,8 @@ public class DefaultPicketLinkLogger implements PicketLinkLogger {
      *@see org.picketlink.identity.federation.PicketLinkLogger#parserUnknownEndElement(java.lang.String)
      */
     @Override
-    public RuntimeException parserUnknownEndElement(String endElementName) {
-        return new RuntimeException(ErrorCodes.UNKNOWN_END_ELEMENT + endElementName);
+    public RuntimeException parserUnknownEndElement(String endElementName, Location location) {
+        return new RuntimeException(ErrorCodes.UNKNOWN_END_ELEMENT + endElementName + "::location=" + location);
     }
 
     /*
@@ -447,7 +447,7 @@ public class DefaultPicketLinkLogger implements PicketLinkLogger {
      */
     @Override
     public RuntimeException parserExpectedTag(String tag, String foundElementTag) {
-        return new RuntimeException(ErrorCodes.EXPECTED_TAG + tag + ">.  Found <" + foundElementTag + ">");
+        return new RuntimeException(ErrorCodes.EXPECTED_TAG + tag + ".  Found <" + foundElementTag + ">");
     }
 
     @Override
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractParser.java b/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractParser.java
index f2fa845..1846b37 100755
--- a/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractParser.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractParser.java
@@ -33,6 +33,9 @@ import javax.xml.stream.events.Characters;
 import javax.xml.stream.events.XMLEvent;
 import javax.xml.stream.util.EventReaderDelegate;
 import java.io.InputStream;
+import java.util.regex.Pattern;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
 import javax.xml.transform.Source;
 import javax.xml.transform.dom.DOMSource;
 import org.w3c.dom.Node;
@@ -43,7 +46,7 @@ import org.w3c.dom.Node;
  * @author Anil.Saldhana@redhat.com
  * @since Oct 12, 2010
  */
-public abstract class AbstractParser implements ParserNamespaceSupport {
+public abstract class AbstractParser implements StaxParser {
 
     protected static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
 
@@ -78,15 +81,15 @@ public abstract class AbstractParser implements ParserNamespaceSupport {
     /**
      * Parse an InputStream for payload
      *
-     * @param configStream
+     * @param stream
      *
      * @return
      *
      * @throws {@link IllegalArgumentException}
      * @throws {@link IllegalArgumentException} when the configStream is null
      */
-    public Object parse(InputStream configStream) throws ParsingException {
-        XMLEventReader xmlEventReader = createEventReader(configStream);
+    public Object parse(InputStream stream) throws ParsingException {
+        XMLEventReader xmlEventReader = createEventReader(stream);
         return parse(xmlEventReader);
     }
 
@@ -99,19 +102,13 @@ public abstract class AbstractParser implements ParserNamespaceSupport {
         return parse(new DOMSource(node));
     }
 
-    public XMLEventReader createEventReader(InputStream configStream) throws ParsingException {
+    public static XMLEventReader createEventReader(InputStream configStream) throws ParsingException {
         if (configStream == null)
             throw logger.nullArgumentError("InputStream");
 
         XMLEventReader xmlEventReader = StaxParserUtil.getXMLEventReader(configStream);
 
-        try {
-            xmlEventReader = filterWhitespaces(xmlEventReader);
-        } catch (XMLStreamException e) {
-            throw logger.parserException(e);
-        }
-
-        return xmlEventReader;
+        return filterWhitespaces(xmlEventReader);
     }
 
     public XMLEventReader createEventReader(Source source) throws ParsingException {
@@ -120,36 +117,39 @@ public abstract class AbstractParser implements ParserNamespaceSupport {
 
         XMLEventReader xmlEventReader = StaxParserUtil.getXMLEventReader(source);
 
-        try {
-            xmlEventReader = filterWhitespaces(xmlEventReader);
-        } catch (XMLStreamException e) {
-            throw logger.parserException(e);
-        }
-
-        return xmlEventReader;
+        return filterWhitespaces(xmlEventReader);
     }
 
-    protected XMLEventReader filterWhitespaces(XMLEventReader xmlEventReader) throws XMLStreamException {
+    private static final Pattern WHITESPACE_ONLY = Pattern.compile("\\s*");
+
+    /**
+     * Creates a derived {@link XMLEventReader} that ignores all events except for: {@link StartElement},
+     * {@link EndElement}, and non-empty and non-whitespace-only {@link Characters}.
+     * 
+     * @param xmlEventReader Original {@link XMLEventReader}
+     * @return Derived {@link XMLEventReader}
+     * @throws XMLStreamException
+     */
+    private static XMLEventReader filterWhitespaces(XMLEventReader xmlEventReader) throws ParsingException {
         XMLInputFactory xmlInputFactory = XML_INPUT_FACTORY.get();
 
-        xmlEventReader = xmlInputFactory.createFilteredReader(xmlEventReader, new EventFilter() {
-            public boolean accept(XMLEvent xmlEvent) {
-                // We are going to disregard characters that are new line and whitespace
-                if (xmlEvent.isCharacters()) {
-                    Characters chars = xmlEvent.asCharacters();
-                    String data = chars.getData();
-                    data = valid(data) ? data.trim() : null;
-                    return valid(data);
-                } else {
-                    return xmlEvent.isStartElement() || xmlEvent.isEndElement();
+        try {
+            xmlEventReader = xmlInputFactory.createFilteredReader(xmlEventReader, new EventFilter() {
+                @Override
+                public boolean accept(XMLEvent xmlEvent) {
+                    // We are going to disregard characters that are new line and whitespace
+                    if (xmlEvent.isCharacters()) {
+                        Characters chars = xmlEvent.asCharacters();
+                        String data = chars.getData();
+                        return data != null && ! WHITESPACE_ONLY.matcher(data).matches();
+                    } else {
+                        return xmlEvent.isStartElement() || xmlEvent.isEndElement();
+                    }
                 }
-            }
-
-            private boolean valid(String str) {
-                return str != null && ! str.isEmpty();
-            }
-
-        });
+            });
+        } catch (XMLStreamException ex) {
+            throw logger.parserException(ex);
+        }
 
         // Handle IBM JDK bug with Stax parsing when EventReader presented
         if (Environment.IS_IBM_JAVA) {
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
new file mode 100644
index 0000000..5d1dbdd
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractStaxParser.java
@@ -0,0 +1,151 @@
+/*
+ * 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.saml.common.parsers;
+
+import org.keycloak.saml.common.PicketLinkLogger;
+import org.keycloak.saml.common.PicketLinkLoggerFactory;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import java.util.Objects;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+/**
+ * Simple support for STaX type of parsing. Parses single element and allows processing its direct children.
+ *
+ * @param <T> Java class that will be result of parsing this element
+ * @param <E> Type containing all tokens that can be found in subelements of the element parsed by this parser, usually an enum
+ * @author hmlnarik
+ */
+public abstract class AbstractStaxParser<T, E> implements StaxParser {
+
+    protected static final PicketLinkLogger LOGGER = PicketLinkLoggerFactory.getLogger();
+    private final QName expectedStartElement;
+    private final E unknownElement;
+
+    public AbstractStaxParser(QName expectedStartElement, E unknownElement) {
+        this.unknownElement = unknownElement;
+        this.expectedStartElement = expectedStartElement;
+    }
+
+    @Override
+    public T parse(XMLEventReader xmlEventReader) throws ParsingException {
+        // STATE: should be before the expected start element
+
+        // Get the start element and validate it is the expected one
+        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
+        StaxParserUtil.validate(startElement, expectedStartElement);
+        T target = instantiateElement(xmlEventReader, startElement);
+
+        // STATE: Start element has been read.
+        QName currentSubelement = null;
+
+        while (xmlEventReader.hasNext()) {
+            // STATE: the only end element that can be found at this phase must correspond to the expected start element
+            XMLEvent xmlEvent = StaxParserUtil.peekNextTag(xmlEventReader);
+            if (xmlEvent == null) {
+                break;
+            }
+
+            if (xmlEvent instanceof EndElement) {
+                EndElement endElement = (EndElement) xmlEvent;
+                final QName qName = endElement.getName();
+
+                // If leftover from processed subelement, just consume.
+                if (Objects.equals(qName, currentSubelement)) {
+                    StaxParserUtil.advance(xmlEventReader);
+                    currentSubelement = null;
+                    continue;
+                }
+
+                // If end element corresponding to this start element, stop processing.
+                if (Objects.equals(qName, expectedStartElement)) {
+                    // consume the end element and finish parsing of this tag
+                    StaxParserUtil.advance(xmlEventReader);
+                    break;
+                }
+
+                // No other case is valid
+                String elementName = StaxParserUtil.getElementName(endElement);
+                throw LOGGER.parserUnknownEndElement(elementName, xmlEvent.getLocation());
+            }
+
+            startElement = (StartElement) xmlEvent;
+            currentSubelement = startElement.getName();
+            E token = getElementFromName(currentSubelement);
+            if (token == null) {
+                token = unknownElement;
+            }
+            processSubElement(xmlEventReader, target, token, startElement);
+
+            // If the XMLEventReader has not advanced inside processSubElement (hence using "==" and not "equals"), advance it.
+            if (StaxParserUtil.peek(xmlEventReader) == startElement) {
+                StaxParserUtil.bypassElementBlock(xmlEventReader);
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug(String.format("Element %s bypassed", currentSubelement));
+                }
+            }
+
+            // 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)) {
+                currentSubelement = null;
+            }
+        }
+        return target;
+    }
+
+
+    protected boolean isUnknownElement(E token) {
+        return token == null || Objects.equals(token, unknownElement);
+    }
+
+    protected abstract E getElementFromName(QName name);
+
+    /**
+     * Instantiates the target Java class representing the current element.<br>
+     * <b>Precondition:</b> Current event is the {@link StartElement}<br>
+     * <b>Postcondition:</b> Current event is the {@link StartElement} or the {@link EndElement} corresponding to the {@link StartElement}
+     * @param xmlEventReader
+     * @param element The XML event that was just read from the {@code xmlEventReader}
+     * @return
+     * @throws ParsingException
+     */
+    protected abstract T instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException;
+
+    /**
+     * Processes the subelement of the element processed in {@link #instantiateElement} method.<br>
+     * <b>Precondition:</b> Current event: Last before the {@link StartElement} corresponding to the processed subelement, i.e.
+     *    event obtained by {@link XMLEventReader#next()} is the {@link StartElement} of the subelement being processed<br>
+     * <b>Postcondition:</b> Event obtained by {@link XMLEventReader#next()} is either
+     *    the same {@link StartElement} (i.e. no change in position which causes this subelement to be skipped),
+     *    the corresponding {@link EndElement}, or the event after the corresponding {@link EndElement}.
+     * <p>
+     * Note that in case of recursive nesting the same element, the corresponding end element MUST be consumed in this method.
+     * @param xmlEventReader
+     * @param target Target object (the one created by the {@link #instantiateElement} method.
+     * @param element The constant corresponding to the current start element.
+     * @param elementDetail The XML event that was just read from the {@code xmlEventReader}
+     * @return
+     * @throws ParsingException
+     */
+    protected abstract void processSubElement(XMLEventReader xmlEventReader, T target, E element, StartElement elementDetail) throws ParsingException;
+
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/parsers/AnyDomParser.java b/saml-core/src/main/java/org/keycloak/saml/common/parsers/AnyDomParser.java
new file mode 100644
index 0000000..e64fd8b
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/common/parsers/AnyDomParser.java
@@ -0,0 +1,64 @@
+/*
+ * 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.saml.common.parsers;
+
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.w3c.dom.Element;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+import java.util.LinkedList;
+import java.util.List;
+import javax.xml.namespace.QName;
+
+/**
+ * Parses any DOM tree to a list of DOM representations.
+ */
+public class AnyDomParser extends AbstractStaxParser<List<Element>, AnyDomParser.Dom> {
+
+    public static enum Dom { ANY_DOM };
+
+    public AnyDomParser(QName name) {
+        super(name, Dom.ANY_DOM);
+    }
+
+    public static AnyDomParser getInstance(QName name) {
+        return new AnyDomParser(name);
+    }
+
+    @Override
+    protected List<Element> instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        return new LinkedList<>();
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, List<Element> target, Dom element, StartElement elementDetail) throws ParsingException {
+        target.add(StaxParserUtil.getDOMElement(xmlEventReader));
+    }
+
+    @Override
+    protected boolean isUnknownElement(Dom token) {
+        return true;
+    }
+
+    @Override
+    protected Dom getElementFromName(QName name) {
+        return Dom.ANY_DOM;
+    }
+
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/PicketLinkLogger.java b/saml-core/src/main/java/org/keycloak/saml/common/PicketLinkLogger.java
index 91f2f54..b8a2642 100755
--- a/saml-core/src/main/java/org/keycloak/saml/common/PicketLinkLogger.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/PicketLinkLogger.java
@@ -225,7 +225,7 @@ public interface PicketLinkLogger {
      *
      * @return
      */
-    RuntimeException parserUnknownEndElement(String endElementName);
+    RuntimeException parserUnknownEndElement(String endElementName, Location location);
 
     /**
      * @param tag
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 8cba8eb..1fc338c 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
@@ -20,12 +20,13 @@ import org.keycloak.saml.common.ErrorCodes;
 import org.keycloak.saml.common.PicketLinkLogger;
 import org.keycloak.saml.common.PicketLinkLoggerFactory;
 import org.keycloak.saml.common.constants.GeneralConstants;
-import org.keycloak.saml.common.constants.JBossSAMLConstants;
 import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
 import org.keycloak.saml.common.exceptions.ConfigurationException;
 import org.keycloak.saml.common.exceptions.ParsingException;
 import org.keycloak.saml.common.exceptions.ProcessingException;
 
+import org.keycloak.saml.processing.core.parsers.util.HasQName;
+import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -49,8 +50,10 @@ import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
 import javax.xml.validation.Validator;
 import java.io.InputStream;
+import java.net.URI;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
+import javax.xml.datatype.XMLGregorianCalendar;
 
 /**
  * Utility for the stax based parser
@@ -103,8 +106,12 @@ public class StaxParserUtil {
      *
      * @throws org.keycloak.saml.common.exceptions.ParsingException
      */
-    public static void bypassElementBlock(XMLEventReader xmlEventReader, JBossSAMLConstants tag) throws ParsingException {
-        bypassElementBlock(xmlEventReader, tag == null ? null : tag.get());
+    public static void bypassElementBlock(XMLEventReader xmlEventReader, QName tag) throws ParsingException {
+        XMLEvent xmlEvent = bypassElementBlock(xmlEventReader);
+
+        if (! (xmlEvent instanceof EndElement) || ! Objects.equals(((EndElement) xmlEvent).getName(), tag)) {
+            throw logger.parserExpectedEndTag(tag.getLocalPart());
+        }
     }
 
     /**
@@ -173,8 +180,13 @@ public class StaxParserUtil {
      * @return
      */
     public static String getAttributeValue(Attribute attribute) {
-        String str = trim(attribute.getValue());
-        return str;
+        if (attribute == null) {
+            return null;
+        }
+
+        final String value = attribute.getValue();
+
+        return value == null ? null : trim(value);
     }
 
     /**
@@ -185,12 +197,90 @@ public class StaxParserUtil {
      *
      * @return
      */
+    @Deprecated
     public static String getAttributeValue(StartElement startElement, String tag) {
-        String result = null;
-        Attribute attr = startElement.getAttributeByName(new QName(tag));
-        if (attr != null)
-            result = getAttributeValue(attr);
-        return result;
+        return getAttributeValue(startElement, new QName(tag));
+    }
+
+    /**
+     * Get the Attribute value
+     *
+     * @param startElement
+     * @param tag localpart of the qname of the attribute
+     *
+     * @return
+     */
+    public static String getAttributeValue(StartElement startElement, HasQName attrName) {
+        return getAttributeValue(startElement, attrName.getQName());
+    }
+
+    /**
+     * Get the Attribute value
+     *
+     * @param startElement
+     * @param tag localpart of the qname of the attribute
+     *
+     * @return
+     */
+    public static String getAttributeValue(StartElement startElement, QName attrQName) {
+        Attribute attr = startElement.getAttributeByName(attrQName);
+        return getAttributeValue(attr);
+    }
+
+    /**
+     * Get the Attribute value
+     *
+     * @param startElement
+     * @param tag localpart of the qname of the attribute
+     *
+     * @return
+     */
+    public static URI getUriAttributeValue(StartElement startElement, HasQName attrName) {
+        Attribute attr = startElement.getAttributeByName(attrName.getQName());
+        String value = getAttributeValue(attr);
+        return value == null ? null : URI.create(value);
+    }
+
+    /**
+     * Get the Attribute value
+     *
+     * @param startElement
+     * @param tag localpart of the qname of the attribute
+     *
+     * @return
+     */
+    public static XMLGregorianCalendar getXmlTimeAttributeValue(StartElement startElement, HasQName attrName) throws ParsingException {
+        Attribute attr = startElement.getAttributeByName(attrName.getQName());
+        String value = getAttributeValue(attr);
+        return value == null ? null : XMLTimeUtil.parse(value);
+    }
+
+    /**
+     * Get the Attribute value
+     *
+     * @param startElement
+     * @param tag localpart of the qname of the attribute
+     *
+     * @return
+     */
+    public static Integer getIntegerAttributeValue(StartElement startElement, HasQName attrName) {
+        Attribute attr = startElement.getAttributeByName(attrName.getQName());
+        String value = getAttributeValue(attr);
+        return value == null ? null : Integer.valueOf(value);
+    }
+
+    /**
+     * Get the Attribute value
+     *
+     * @param startElement
+     * @param tag localpart of the qname of the attribute
+     *
+     * @return
+     */
+    public static Boolean getBooleanAttributeValue(StartElement startElement, HasQName attrName) {
+        Attribute attr = startElement.getAttributeByName(attrName.getQName());
+        String value = getAttributeValue(attr);
+        return value == null ? null : Boolean.valueOf(value);
     }
 
     /**
@@ -201,6 +291,7 @@ public class StaxParserUtil {
      *
      * @return false if attribute not set
      */
+    @Deprecated
     public static boolean getBooleanAttributeValue(StartElement startElement, String tag) {
         return getBooleanAttributeValue(startElement, tag, false);
     }
@@ -213,6 +304,7 @@ public class StaxParserUtil {
      *
      * @return false if attribute not set
      */
+    @Deprecated
     public static boolean getBooleanAttributeValue(StartElement startElement, String tag, boolean defaultValue) {
         String result = null;
         Attribute attr = startElement.getAttributeByName(new QName(tag));
@@ -222,6 +314,16 @@ public class StaxParserUtil {
         return Boolean.valueOf(result);
     }
 
+    public static String getRequiredAttributeValue(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.getAttributeValue(attr);
+    }
+
+    private static final String JDK_TRANSFORMER_PROPERTY = "picketlink.jdk.transformer";
+
     /**
      * Given that the {@code XMLEventReader} is in {@code XMLStreamConstants.START_ELEMENT} mode, we parse into a DOM
      * Element
@@ -233,9 +335,7 @@ public class StaxParserUtil {
      * @throws ParsingException
      */
     public static Element getDOMElement(XMLEventReader xmlEventReader) throws ParsingException {
-        Transformer transformer = null;
-
-        final String JDK_TRANSFORMER_PROPERTY = "picketlink.jdk.transformer";
+        Transformer transformer;
 
         boolean useJDKTransformer = Boolean.parseBoolean(SecurityActions.getSystemProperty(JDK_TRANSFORMER_PROPERTY, "false"));
 
@@ -263,7 +363,9 @@ public class StaxParserUtil {
     }
 
     /**
-     * Get the element text.
+     * Get the element text. Following {@link XMLEventReader#getElementText()}:
+     * Precondition: the current event is START_ELEMENT.
+     * Postcondition: The current event is the corresponding END_ELEMENT.
      *
      * @param xmlEventReader
      *
@@ -411,7 +513,7 @@ public class StaxParserUtil {
      *
      * @return
      */
-    public static String getStartElementName(StartElement startElement) {
+    public static String getElementName(StartElement startElement) {
         return trim(startElement.getName().getLocalPart());
     }
 
@@ -422,10 +524,12 @@ public class StaxParserUtil {
      *
      * @return
      */
-    public static String getEndElementName(EndElement endElement) {
+    public static String getElementName(EndElement endElement) {
         return trim(endElement.getName().getLocalPart());
     }
 
+    private static final QName XSI_TYPE = new QName(JBossSAMLURIConstants.XSI_NSURI.get(), "type", JBossSAMLURIConstants.XSI_PREFIX.get());
+
     /**
      * Given a start element, obtain the xsi:type defined
      *
@@ -436,8 +540,7 @@ public class StaxParserUtil {
      * @throws RuntimeException if xsi:type is missing
      */
     public static String getXSITypeValue(StartElement startElement) {
-        Attribute xsiType = startElement.getAttributeByName(new QName(JBossSAMLURIConstants.XSI_NSURI.get(),
-                JBossSAMLConstants.TYPE.get()));
+        Attribute xsiType = startElement.getAttributeByName(XSI_TYPE);
         if (xsiType == null)
             throw logger.parserExpectedXSI(ErrorCodes.EXPECTED_XSI);
         return StaxParserUtil.getAttributeValue(xsiType);
@@ -466,7 +569,7 @@ public class StaxParserUtil {
      * @return boolean if the tags match
      */
     public static boolean matches(StartElement startElement, String tag) {
-        String elementTag = getStartElementName(startElement);
+        String elementTag = StaxParserUtil.getElementName(startElement);
         return tag.equals(elementTag);
     }
 
@@ -479,7 +582,7 @@ public class StaxParserUtil {
      * @return boolean if the tags match
      */
     public static boolean matches(EndElement endElement, String tag) {
-        String elementTag = getEndElementName(endElement);
+        String elementTag = getElementName(endElement);
         return tag.equals(elementTag);
     }
 
@@ -501,6 +604,23 @@ public class StaxParserUtil {
     }
 
     /**
+     * Consume the next event
+     *
+     * @param xmlEventReader
+     *
+     * @return
+     *
+     * @throws ParsingException
+     */
+    public static XMLEvent advance(XMLEventReader xmlEventReader) throws ParsingException {
+        try {
+            return xmlEventReader.nextEvent();
+        } catch (XMLStreamException e) {
+            throw logger.parserException(e);
+        }
+    }
+
+    /**
      * Peek the next {@code StartElement }
      *
      * @param xmlEventReader
@@ -511,14 +631,32 @@ public class StaxParserUtil {
      */
     public static StartElement peekNextStartElement(XMLEventReader xmlEventReader) throws ParsingException {
         try {
-            while (true) {
-                XMLEvent xmlEvent = xmlEventReader.peek();
+            XMLEvent xmlEvent = xmlEventReader.peek();
+            while (xmlEvent != null && ! xmlEvent.isStartElement()) {
+                xmlEventReader.nextEvent();
+                xmlEvent = xmlEventReader.peek();
+            }
+            return (StartElement) xmlEvent;
+        } catch (XMLStreamException e) {
+            throw logger.parserException(e);
+        }
+    }
 
-                if (xmlEvent == null || xmlEvent.isStartElement())
-                    return (StartElement) xmlEvent;
-                else
-                    xmlEvent = xmlEventReader.nextEvent();
+    /**
+     * Peek the next {@link StartElement} or {@link EndElement}.
+     *
+     * @param xmlEventReader
+     * @return
+     * @throws ParsingException
+     */
+    public static XMLEvent peekNextTag(XMLEventReader xmlEventReader) throws ParsingException {
+        try {
+            XMLEvent xmlEvent = xmlEventReader.peek();
+            while (xmlEvent != null && ! xmlEvent.isStartElement() && ! xmlEvent.isEndElement()) {
+                xmlEventReader.nextEvent();
+                xmlEvent = xmlEventReader.peek();
             }
+            return xmlEvent;
         } catch (XMLStreamException e) {
             throw logger.parserException(e);
         }
@@ -571,13 +709,29 @@ public class StaxParserUtil {
      *
      * @throws RuntimeException mismatch
      */
+    @Deprecated
     public static void validate(StartElement startElement, String tag) {
-        String foundElementTag = getStartElementName(startElement);
+        String foundElementTag = StaxParserUtil.getElementName(startElement);
         if (!tag.equals(foundElementTag))
             throw logger.parserExpectedTag(tag, foundElementTag);
     }
 
     /**
+     * Validate that the start element has the expected tag
+     *
+     * @param startElement
+     * @param tag
+     *
+     * @throws RuntimeException mismatch
+     */
+    public static void validate(StartElement startElement, QName tag) {
+        if (! Objects.equals(startElement.getName(), tag)) {
+            String foundElementTag = StaxParserUtil.getElementName(startElement);
+            throw logger.parserExpectedTag(tag.getLocalPart(), foundElementTag);
+        }
+    }
+
+    /**
      * Validate that the end element has the expected tag
      *
      * @param endElement
@@ -586,7 +740,7 @@ public class StaxParserUtil {
      * @throws RuntimeException mismatch
      */
     public static void validate(EndElement endElement, String tag) {
-        String elementTag = getEndElementName(endElement);
+        String elementTag = getElementName(endElement);
         if (!tag.equals(elementTag))
             throw new RuntimeException(logger.parserExpectedEndTag("</" + tag + ">.  Found </" + elementTag + ">"));
     }
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/util/TransformerUtil.java b/saml-core/src/main/java/org/keycloak/saml/common/util/TransformerUtil.java
index 4e43c3d..14c3fe0 100755
--- a/saml-core/src/main/java/org/keycloak/saml/common/util/TransformerUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/util/TransformerUtil.java
@@ -227,20 +227,26 @@ public class TransformerUtil {
                     throw new TransformerException(ErrorCodes.WRITER_SHOULD_START_ELEMENT);
 
                 StartElement rootElement = (StartElement) xmlEvent;
-                rootTag = StaxParserUtil.getStartElementName(rootElement);
-                Element docRoot = handleStartElement(xmlEventReader, rootElement, new CustomHolder(doc, false));
+                rootTag = StaxParserUtil.getElementName(rootElement);
+                CustomHolder holder = new CustomHolder(doc, false);
+                Element docRoot = handleStartElement(xmlEventReader, rootElement, holder);
                 Node parent = doc.importNode(docRoot, true);
                 doc.appendChild(parent);
 
                 stack.push(parent);
 
+                if (holder.encounteredTextNode) {
+                    // Handling text node skips over the corresponding end element, see {@link XMLEventReader#getElementText()}
+                    return;
+                }
+
                 while (xmlEventReader.hasNext()) {
                     xmlEvent = StaxParserUtil.getNextEvent(xmlEventReader);
                     int type = xmlEvent.getEventType();
                     switch (type) {
                         case XMLEvent.START_ELEMENT:
                             StartElement startElement = (StartElement) xmlEvent;
-                            CustomHolder holder = new CustomHolder(doc, false);
+                            holder = new CustomHolder(doc, false);
                             Element docStartElement = handleStartElement(xmlEventReader, startElement, holder);
                             Node el = doc.importNode(docStartElement, true);
 
@@ -261,7 +267,7 @@ public class TransformerUtil {
                             break;
                         case XMLEvent.END_ELEMENT:
                             EndElement endElement = (EndElement) xmlEvent;
-                            String endTag = StaxParserUtil.getEndElementName(endElement);
+                            String endTag = StaxParserUtil.getElementName(endElement);
                             if (rootTag.equals(endTag))
                                 return; // We are done with the dom parsing
                             else {
@@ -334,7 +340,7 @@ public class TransformerUtil {
             String prefix = elementName.getPrefix();
             String localPart = elementName.getLocalPart();
 
-            String qual = prefix != null && prefix != "" ? prefix + ":" + localPart : localPart;
+            String qual = (prefix != null && ! prefix.isEmpty()) ? prefix + ":" + localPart : localPart;
 
             Element el = doc.createElementNS(ns, qual);
 
@@ -356,7 +362,7 @@ public class TransformerUtil {
                 ns = attrName.getNamespaceURI();
                 prefix = attrName.getPrefix();
                 localPart = attrName.getLocalPart();
-                qual = prefix != null && prefix != "" ? prefix + ":" + localPart : localPart;
+                qual = (prefix != null && ! prefix.isEmpty()) ? prefix + ":" + localPart : localPart;
 
                 if (logger.isTraceEnabled()) {
                     logger.trace("Creating an Attribute Namespace=" + ns + ":" + qual);
@@ -373,8 +379,8 @@ public class TransformerUtil {
                 QName name = namespace.getName();
                 localPart = name.getLocalPart();
                 prefix = name.getPrefix();
-                if (prefix != null && prefix != "")
-                    qual = (localPart != null && localPart != "") ? prefix + ":" + localPart : prefix;
+                if (prefix != null && ! prefix.isEmpty())
+                    qual = (localPart != null && ! localPart.isEmpty()) ? prefix + ":" + localPart : prefix;
 
                 if (qual.equals("xmlns"))
                     continue;
@@ -423,8 +429,8 @@ public class TransformerUtil {
                 QName name = namespace.getName();
                 localPart = name.getLocalPart();
                 prefix = name.getPrefix();
-                if (prefix != null && prefix != "")
-                    qual = (localPart != null && localPart != "") ? prefix + ":" + localPart : prefix;
+                if (prefix != null && ! prefix.isEmpty())
+                    qual = (localPart != null && ! localPart.isEmpty()) ? prefix + ":" + localPart : prefix;
 
                 if (qual != null && qual.equals("xmlns"))
                     return namespace.getNamespaceURI();
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/request/SAML2Request.java b/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/request/SAML2Request.java
index cb8a348..5a131d2 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/request/SAML2Request.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/request/SAML2Request.java
@@ -26,7 +26,6 @@ import org.keycloak.dom.saml.v2.protocol.ResponseType;
 import org.keycloak.saml.common.PicketLinkLogger;
 import org.keycloak.saml.common.PicketLinkLoggerFactory;
 import org.keycloak.saml.common.constants.GeneralConstants;
-import org.keycloak.saml.common.constants.JBossSAMLConstants;
 import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
 import org.keycloak.saml.common.exceptions.ConfigurationException;
 import org.keycloak.saml.common.exceptions.ParsingException;
@@ -94,7 +93,7 @@ public class SAML2Request {
 
         AuthnRequestType authnRequest = new AuthnRequestType(id, issueInstant);
         authnRequest.setAssertionConsumerServiceURL(URI.create(assertionConsumerURL));
-        authnRequest.setProtocolBinding(URI.create(JBossSAMLConstants.HTTP_POST_BINDING.get()));
+        authnRequest.setProtocolBinding(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.getUri());
         if (destination != null) {
             authnRequest.setDestination(URI.create(destination));
         }
@@ -163,7 +162,7 @@ public class SAML2Request {
 
         Document samlDocument = DocumentUtil.getDocument(is);
 
-        SAMLParser samlParser = new SAMLParser();
+        SAMLParser samlParser = SAMLParser.getInstance();
         JAXPValidationUtil.checkSchemaValidation(samlDocument);
         SAML2Object requestType = (SAML2Object) samlParser.parse(samlDocument);
 
@@ -189,7 +188,7 @@ public class SAML2Request {
 
         Document samlDocument = DocumentUtil.getDocument(is);
 
-        SAMLParser samlParser = new SAMLParser();
+        SAMLParser samlParser = SAMLParser.getInstance();
         JAXPValidationUtil.checkSchemaValidation(samlDocument);
         RequestAbstractType requestType = (RequestAbstractType) samlParser.parse(samlDocument);
 
@@ -216,7 +215,7 @@ public class SAML2Request {
 
         Document samlDocument = DocumentUtil.getDocument(is);
 
-        SAMLParser samlParser = new SAMLParser();
+        SAMLParser samlParser = SAMLParser.getInstance();
         JAXPValidationUtil.checkSchemaValidation(samlDocument);
 
         AuthnRequestType requestType = (AuthnRequestType) samlParser.parse(samlDocument);
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/response/SAML2Response.java b/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/response/SAML2Response.java
index a650c7a..e9a86b1 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/response/SAML2Response.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/response/SAML2Response.java
@@ -85,9 +85,9 @@ import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.PROTOCOL_
 public class SAML2Response {
 
     private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
-    private long ASSERTION_VALIDITY = 5000; // 5secs in milis
+    private final long ASSERTION_VALIDITY = 5000; // 5secs in milis
 
-    private long CLOCK_SKEW = 2000; // 2secs
+    private final long CLOCK_SKEW = 2000; // 2secs
 
     private SAMLDocumentHolder samlDocumentHolder = null;
 
@@ -118,7 +118,7 @@ public class SAML2Response {
         act.addAuthenticatingAuthority(URI.create(authContextDeclRef));
 
         AuthnContextType.AuthnContextTypeSequence sequence = act.new AuthnContextTypeSequence();
-        sequence.setClassRef(new AuthnContextClassRefType(URI.create(JBossSAMLURIConstants.AC_PASSWORD.get())));
+        sequence.setClassRef(new AuthnContextClassRefType(JBossSAMLURIConstants.AC_PASSWORD.getUri()));
         act.setSequence(sequence);
 
         authnStatement.setAuthnContext(act);
@@ -264,7 +264,7 @@ public class SAML2Response {
 
         subjectType.addConfirmation(subjectConfirmation);
 
-        AssertionType assertionType = null;
+        AssertionType assertionType;
         NameIDType issuerID = issuerInfo.getIssuer();
         try {
             issueInstant = XMLTimeUtil.getIssueInstant();
@@ -373,7 +373,7 @@ public class SAML2Response {
             throw logger.nullArgumentError("InputStream");
 
         Document samlDocument = DocumentUtil.getDocument(is);
-        SAMLParser samlParser = new SAMLParser();
+        SAMLParser samlParser = SAMLParser.getInstance();
         JAXPValidationUtil.checkSchemaValidation(samlDocument);
 
         return (EncryptedAssertionType) samlParser.parse(samlDocument);
@@ -396,7 +396,7 @@ public class SAML2Response {
             throw logger.nullArgumentError("InputStream");
         Document samlDocument = DocumentUtil.getDocument(is);
 
-        SAMLParser samlParser = new SAMLParser();
+        SAMLParser samlParser = SAMLParser.getInstance();
         JAXPValidationUtil.checkSchemaValidation(samlDocument);
         return (AssertionType) samlParser.parse(samlDocument);
     }
@@ -426,7 +426,7 @@ public class SAML2Response {
 
         Document samlResponseDocument = DocumentUtil.getDocument(is);
 
-        SAMLParser samlParser = new SAMLParser();
+        SAMLParser samlParser = SAMLParser.getInstance();
         JAXPValidationUtil.checkSchemaValidation(samlResponseDocument);
 
         ResponseType responseType = (ResponseType) samlParser.parse(samlResponseDocument);
@@ -457,7 +457,7 @@ public class SAML2Response {
             logger.trace("SAML Response Document: " + DocumentUtil.asString(samlResponseDocument));
         }
 
-        SAMLParser samlParser = new SAMLParser();
+        SAMLParser samlParser = SAMLParser.getInstance();
         JAXPValidationUtil.checkSchemaValidation(samlResponseDocument);
 
         SAML2Object responseType = (SAML2Object) samlParser.parse(samlResponseDocument);
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/AbstractStaxSamlAssertionParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/AbstractStaxSamlAssertionParser.java
new file mode 100644
index 0000000..0c3ac58
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/AbstractStaxSamlAssertionParser.java
@@ -0,0 +1,40 @@
+/*
+ * 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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.saml.common.parsers.AbstractStaxParser;
+import org.keycloak.saml.processing.core.parsers.util.QNameEnumLookup;
+import javax.xml.namespace.QName;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public abstract class AbstractStaxSamlAssertionParser<T> extends AbstractStaxParser<T, SAMLAssertionQNames> {
+
+    protected static final QNameEnumLookup<SAMLAssertionQNames> LOOKUP = new QNameEnumLookup(SAMLAssertionQNames.values());
+
+    public AbstractStaxSamlAssertionParser(SAMLAssertionQNames expectedStartElement) {
+        super(expectedStartElement.getQName(), SAMLAssertionQNames.UNKNOWN_ELEMENT);
+    }
+
+    @Override
+    protected SAMLAssertionQNames getElementFromName(QName name) {
+        return LOOKUP.from(name);
+    }
+
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAssertionParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAssertionParser.java
new file mode 100755
index 0000000..91f074d
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAssertionParser.java
@@ -0,0 +1,103 @@
+/*
+ * 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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.dom.saml.v2.assertion.AssertionType;
+import org.keycloak.saml.common.ErrorCodes;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
+import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
+import javax.xml.datatype.XMLGregorianCalendar;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * Parse the saml assertion
+ *
+ * @since Oct 12, 2010
+ */
+public class SAMLAssertionParser extends AbstractStaxSamlAssertionParser<AssertionType> {
+
+    private static final String VERSION_2_0 = "2.0";
+
+    private static final SAMLAssertionParser INSTANCE = new SAMLAssertionParser();
+
+    private SAMLAssertionParser() {
+        super(SAMLAssertionQNames.ASSERTION);
+    }
+
+    public static SAMLAssertionParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected AssertionType instantiateElement(XMLEventReader xmlEventReader, StartElement nextElement) throws ParsingException {
+        SAMLParserUtil.validateAttributeValue(nextElement, SAMLAssertionQNames.ATTR_VERSION, VERSION_2_0);
+        String id = StaxParserUtil.getRequiredAttributeValue(nextElement, SAMLAssertionQNames.ATTR_ID);
+        XMLGregorianCalendar issueInstant = XMLTimeUtil.parse(StaxParserUtil.getRequiredAttributeValue(nextElement, SAMLAssertionQNames.ATTR_ISSUE_INSTANT));
+
+        return new AssertionType(id, issueInstant);
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, AssertionType target, SAMLAssertionQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case ISSUER:
+                target.setIssuer(SAMLParserUtil.parseNameIDType(xmlEventReader));
+                break;
+
+            case SIGNATURE:
+                target.setSignature(StaxParserUtil.getDOMElement(xmlEventReader));
+                break;
+
+            case SUBJECT:
+                target.setSubject(SAMLSubjectParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case CONDITIONS:
+                target.setConditions(SAMLConditionsParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case ADVICE:
+                StaxParserUtil.bypassElementBlock(xmlEventReader);
+                // Ignored
+                break;
+
+            case STATEMENT:
+                elementDetail = StaxParserUtil.getNextStartElement(xmlEventReader);
+                String xsiTypeValue = StaxParserUtil.getXSITypeValue(elementDetail);
+                throw new RuntimeException(ErrorCodes.UNKNOWN_XSI + xsiTypeValue);
+
+            case AUTHN_STATEMENT:
+                target.addStatement(SAMLAuthnStatementParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case AUTHZ_DECISION_STATEMENT:
+                StaxParserUtil.bypassElementBlock(xmlEventReader);
+                // Ignored
+                break;
+
+            case ATTRIBUTE_STATEMENT:
+                target.addStatement(SAMLAttributeStatementParser.getInstance().parse(xmlEventReader));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAssertionQNames.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAssertionQNames.java
new file mode 100644
index 0000000..9e18f67
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAssertionQNames.java
@@ -0,0 +1,116 @@
+/*
+ * 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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.processing.core.parsers.saml.xmldsig.XmlDSigQNames;
+import org.keycloak.saml.processing.core.parsers.util.HasQName;
+import javax.xml.namespace.QName;
+
+/**
+ * Elements and attribute names from saml-schema-assertion-2.0.xsd
+ * @author hmlnarik
+ */
+public enum SAMLAssertionQNames implements HasQName {
+
+    ACTION("Action"),
+    ADVICE("Advice"),
+    ASSERTION("Assertion"),
+    ASSERTION_ID_REF("AssertionIDRef"),
+    ASSERTION_URI_REF("AssertionURIRef"),
+    ATTRIBUTE("Attribute"),
+    ATTRIBUTE_STATEMENT("AttributeStatement"),
+    ATTRIBUTE_VALUE("AttributeValue"),
+    AUDIENCE("Audience"),
+    AUDIENCE_RESTRICTION("AudienceRestriction"),
+    AUTHENTICATING_AUTHORITY("AuthenticatingAuthority"),
+    AUTHN_CONTEXT("AuthnContext"),
+    AUTHN_CONTEXT_CLASS_REF("AuthnContextClassRef"),
+    AUTHN_CONTEXT_DECL("AuthnContextDecl"),
+    AUTHN_CONTEXT_DECL_REF("AuthnContextDeclRef"),
+    AUTHN_STATEMENT("AuthnStatement"),
+    AUTHZ_DECISION_STATEMENT("AuthzDecisionStatement"),
+    BASEID("BaseID"),
+    CONDITION("Condition"),
+    CONDITIONS("Conditions"),
+    ENCRYPTED_ASSERTION("EncryptedAssertion"),
+    ENCRYPTED_ATTRIBUTE("EncryptedAttribute"),
+    ENCRYPTED_ID("EncryptedID"),
+    EVIDENCE("Evidence"),
+    ISSUER("Issuer"),
+    NAMEID("NameID"),
+    ONE_TIME_USE("OneTimeUse"),
+    PROXY_RESTRICTION("ProxyRestriction"),
+    STATEMENT("Statement"),
+    SUBJECT_CONFIRMATION_DATA("SubjectConfirmationData"),
+    SUBJECT_CONFIRMATION("SubjectConfirmation"),
+    SUBJECT_LOCALITY("SubjectLocality"),
+    SUBJECT("Subject"),
+
+    // Attribute names
+    ATTR_ADDRESS(null, "Address"),
+    ATTR_AUTHN_INSTANT(null, "AuthnInstant"),
+    ATTR_DNS_NAME(null, "DNSName"),
+    ATTR_FORMAT(null, "Format"),
+    ATTR_FRIENDLY_NAME(null, "FriendlyName"),
+    ATTR_ID(null, "ID"),
+    ATTR_IN_RESPONSE_TO(null, "InResponseTo"),
+    ATTR_ISSUE_INSTANT(null, "IssueInstant"),
+    ATTR_METHOD(null, "Method"),
+    ATTR_NAME(null, "Name"),
+    ATTR_NAME_FORMAT(null, "NameFormat"),
+    ATTR_NAME_QUALIFIER(null, "NameQualifier"),
+    ATTR_NOT_BEFORE(null, "NotBefore"),
+    ATTR_NOT_ON_OR_AFTER(null, "NotOnOrAfter"),
+    ATTR_RECIPIENT(null, "Recipient"),
+    ATTR_SESSION_INDEX(null, "SessionIndex"),
+    ATTR_SP_PROVIDED_ID(null, "SPProvidedID"),
+    ATTR_SP_NAME_QUALIFIER(null, "SPNameQualifier"),
+    ATTR_VERSION(null, "Version"),
+
+    // Elements from other namespaces that can be direct subelements of this namespace's elements
+    KEY_INFO(XmlDSigQNames.KEY_INFO),
+    SIGNATURE(XmlDSigQNames.SIGNATURE),
+
+    ATTR_X500_ENCODING(JBossSAMLURIConstants.X500_NSURI, "Encoding"),
+
+    UNKNOWN_ELEMENT("")
+    ;
+
+    private final QName qName;
+
+    private SAMLAssertionQNames(String localName) {
+        this(JBossSAMLURIConstants.ASSERTION_NSURI, localName);
+    }
+
+    private SAMLAssertionQNames(HasQName source) {
+        this.qName = source.getQName();
+    }
+
+    private SAMLAssertionQNames(JBossSAMLURIConstants nsUri, String localName) {
+        this.qName = new QName(nsUri == null ? null : nsUri.get(), 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/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAttributeParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAttributeParser.java
new file mode 100644
index 0000000..2b8fa82
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAttributeParser.java
@@ -0,0 +1,69 @@
+/*
+ * 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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.dom.saml.v2.assertion.AttributeType;
+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;
+
+/**
+ * Parse the <conditions> in the saml assertion
+ *
+ * @since Oct 14, 2010
+ */
+public class SAMLAttributeParser extends AbstractStaxSamlAssertionParser<AttributeType> {
+
+    private static final SAMLAttributeParser INSTANCE = new SAMLAttributeParser();
+
+    private SAMLAttributeParser() {
+        super(SAMLAssertionQNames.ATTRIBUTE);
+    }
+
+    public static SAMLAttributeParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected AttributeType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        String name = StaxParserUtil.getRequiredAttributeValue(element, SAMLAssertionQNames.ATTR_NAME);
+        final AttributeType attribute = new AttributeType(name);
+
+        attribute.setFriendlyName(StaxParserUtil.getAttributeValue(element, SAMLAssertionQNames.ATTR_FRIENDLY_NAME));
+        attribute.setNameFormat(StaxParserUtil.getAttributeValue(element, SAMLAssertionQNames.ATTR_NAME_FORMAT));
+
+        final String x500Encoding = StaxParserUtil.getAttributeValue(element, SAMLAssertionQNames.ATTR_X500_ENCODING);
+        if (x500Encoding != null) {
+            attribute.getOtherAttributes().put(SAMLAssertionQNames.ATTR_X500_ENCODING.getQName(), x500Encoding);
+        }
+
+        return attribute;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, AttributeType target, SAMLAssertionQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case ATTRIBUTE_VALUE:
+                target.addAttributeValue(SAMLAttributeValueParser.getInstance().parse(xmlEventReader));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAttributeStatementParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAttributeStatementParser.java
new file mode 100644
index 0000000..162d7a5
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAttributeStatementParser.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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
+import org.keycloak.dom.saml.v2.assertion.AttributeStatementType.ASTChoiceType;
+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;
+
+/**
+ * Parse the <conditions> in the saml assertion
+ *
+ * @since Oct 14, 2010
+ */
+public class SAMLAttributeStatementParser extends AbstractStaxSamlAssertionParser<AttributeStatementType> {
+
+    private static final SAMLAttributeStatementParser INSTANCE = new SAMLAttributeStatementParser();
+
+    private SAMLAttributeStatementParser() {
+        super(SAMLAssertionQNames.ATTRIBUTE_STATEMENT);
+    }
+
+    public static SAMLAttributeStatementParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected AttributeStatementType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        return new AttributeStatementType();
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, AttributeStatementType target, SAMLAssertionQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case ATTRIBUTE:
+                target.addAttribute(new ASTChoiceType(SAMLAttributeParser.getInstance().parse(xmlEventReader)));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAttributeValueParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAttributeValueParser.java
new file mode 100644
index 0000000..272c032
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAttributeValueParser.java
@@ -0,0 +1,138 @@
+/*
+ * 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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.saml.common.PicketLinkLogger;
+import org.keycloak.saml.common.PicketLinkLoggerFactory;
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.parsers.StaxParser;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
+import java.io.StringWriter;
+import java.util.Objects;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLEventWriter;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+/**
+ * 
+ */
+public class SAMLAttributeValueParser implements StaxParser {
+
+    private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
+
+    private static final SAMLAttributeValueParser INSTANCE = new SAMLAttributeValueParser();
+    private static final QName NIL = new QName(JBossSAMLURIConstants.XSI_NSURI.get(), "nil", JBossSAMLURIConstants.XSI_PREFIX.get());
+    private static final QName XSI_TYPE = new QName(JBossSAMLURIConstants.XSI_NSURI.get(), "type", JBossSAMLURIConstants.XSI_PREFIX.get());
+
+    public static SAMLAttributeValueParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
+        StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
+        StaxParserUtil.validate(element, SAMLAssertionQNames.ATTRIBUTE_VALUE.getQName());
+
+        Attribute nil = element.getAttributeByName(NIL);
+        if (nil != null) {
+            String nilValue = StaxParserUtil.getAttributeValue(nil);
+            if (nilValue != null && (nilValue.equalsIgnoreCase("true") || nilValue.equals("1"))) {
+                String elementText = StaxParserUtil.getElementText(xmlEventReader);
+                if (elementText == null || elementText.isEmpty()) {
+                    return null;
+                } else {
+                    throw logger.nullValueError("nil attribute is not in SAML20 format");
+                }
+            } else {
+                throw logger.parserRequiredAttribute(JBossSAMLURIConstants.XSI_PREFIX.get() + ":nil");
+            }
+        }
+
+        Attribute type = element.getAttributeByName(XSI_TYPE);
+        if (type == null) {
+            if (StaxParserUtil.hasTextAhead(xmlEventReader)) {
+                return StaxParserUtil.getElementText(xmlEventReader);
+            }
+            // Else we may have Child Element
+            XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
+            if (xmlEvent instanceof StartElement) {
+                element = (StartElement) xmlEvent;
+                final QName qName = element.getName();
+                if (Objects.equals(qName, SAMLAssertionQNames.NAMEID.getQName())) {
+                    return SAMLParserUtil.parseNameIDType(xmlEventReader);
+                }
+            } else if (xmlEvent instanceof EndElement) {
+                return "";
+            }
+
+            // when no type attribute assigned -> assume anyType
+            return parseAnyTypeAsString(xmlEventReader);
+        }
+
+        //      RK Added an additional type check for base64Binary type as calheers is passing this type
+        String typeValue = StaxParserUtil.getAttributeValue(type);
+        if (typeValue.contains(":string")) {
+            return StaxParserUtil.getElementText(xmlEventReader);
+        } else if (typeValue.contains(":anyType")) {
+            return parseAnyTypeAsString(xmlEventReader);
+        } else if(typeValue.contains(":base64Binary")){
+            return StaxParserUtil.getElementText(xmlEventReader);
+        } else if(typeValue.contains(":boolean")){
+            return StaxParserUtil.getElementText(xmlEventReader);
+        }
+
+        throw logger.parserUnknownXSI(typeValue);
+    }
+
+    public static String parseAnyTypeAsString(XMLEventReader xmlEventReader) throws ParsingException {
+        try {
+            XMLEvent event = xmlEventReader.peek();
+            if (event.isStartElement()) {
+                event = xmlEventReader.nextTag();
+                StringWriter sw = new StringWriter();
+                XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(sw);
+                //QName tagName = event.asStartElement().getName();
+                int tagLevel = 1;
+                do {
+                    writer.add(event);
+                    event = (XMLEvent) xmlEventReader.next();
+                    if (event.isStartElement()) {
+                        tagLevel++;
+                    }
+                    if (event.isEndElement()) {
+                        tagLevel--;
+                    }
+                } while (xmlEventReader.hasNext() && tagLevel > 0);
+                writer.add(event);
+                writer.flush();
+                return sw.toString();
+            } else {
+                return StaxParserUtil.getElementText(xmlEventReader);
+            }
+        } catch (Exception e) {
+            throw logger.parserError(e);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAudienceRestrictionParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAudienceRestrictionParser.java
new file mode 100644
index 0000000..a1d5827
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAudienceRestrictionParser.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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.dom.saml.v2.assertion.AudienceRestrictionType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import java.net.URI;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * Parse the <conditions> in the saml assertion
+ *
+ * @since Oct 14, 2010
+ */
+public class SAMLAudienceRestrictionParser extends AbstractStaxSamlAssertionParser<AudienceRestrictionType> {
+
+    private static final SAMLAudienceRestrictionParser INSTANCE = new SAMLAudienceRestrictionParser();
+
+    private SAMLAudienceRestrictionParser() {
+        super(SAMLAssertionQNames.AUDIENCE_RESTRICTION);
+    }
+
+    public static SAMLAudienceRestrictionParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected AudienceRestrictionType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        return new AudienceRestrictionType();
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, AudienceRestrictionType target, SAMLAssertionQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case AUDIENCE:
+                StaxParserUtil.advance(xmlEventReader);
+                String audienceValue = StaxParserUtil.getElementText(xmlEventReader);
+                target.addAudience(URI.create(audienceValue));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAuthnContextParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAuthnContextParser.java
new file mode 100644
index 0000000..16a83bc
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAuthnContextParser.java
@@ -0,0 +1,94 @@
+/*
+ * 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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.dom.saml.v2.assertion.AuthnContextClassRefType;
+import org.keycloak.dom.saml.v2.assertion.AuthnContextDeclRefType;
+import org.keycloak.dom.saml.v2.assertion.AuthnContextDeclType;
+import org.keycloak.dom.saml.v2.assertion.AuthnContextType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import java.net.URI;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+import org.w3c.dom.Element;
+
+/**
+ * Parse the <conditions> in the saml assertion
+ *
+ * @since Oct 14, 2010
+ */
+public class SAMLAuthnContextParser extends AbstractStaxSamlAssertionParser<AuthnContextType> {
+
+    private static final SAMLAuthnContextParser INSTANCE = new SAMLAuthnContextParser();
+
+    private SAMLAuthnContextParser() {
+        super(SAMLAssertionQNames.AUTHN_CONTEXT);
+    }
+
+    public static SAMLAuthnContextParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected AuthnContextType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        return new AuthnContextType();
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, AuthnContextType target, SAMLAssertionQNames element, StartElement elementDetail) throws ParsingException {
+        String text;
+        AuthnContextType.AuthnContextTypeSequence authnContextSequence;
+
+        switch (element) {
+            case AUTHN_CONTEXT_DECL:
+                Element dom = StaxParserUtil.getDOMElement(xmlEventReader);
+                AuthnContextDeclType authnContextDecl = new AuthnContextDeclType(dom);
+                authnContextSequence = target.getSequence() != null ? target.getSequence() : target.new AuthnContextTypeSequence();
+                authnContextSequence.setAuthnContextDecl(authnContextDecl);
+                target.setSequence(authnContextSequence);
+                break;
+
+            case AUTHN_CONTEXT_DECL_REF:
+                StaxParserUtil.advance(xmlEventReader);
+                text = StaxParserUtil.getElementText(xmlEventReader);
+                AuthnContextDeclRefType authnContextDeclRef = new AuthnContextDeclRefType(URI.create(text));
+                target.addURIType(authnContextDeclRef);
+                break;
+
+            case AUTHN_CONTEXT_CLASS_REF:
+                StaxParserUtil.advance(xmlEventReader);
+                text = StaxParserUtil.getElementText(xmlEventReader);
+                AuthnContextClassRefType authnContextClassRef = new AuthnContextClassRefType(URI.create(text));
+
+                authnContextSequence = target.getSequence() != null ? target.getSequence() : target.new AuthnContextTypeSequence();
+                authnContextSequence.setClassRef(authnContextClassRef);
+
+                target.setSequence(authnContextSequence);
+                break;
+
+            case AUTHENTICATING_AUTHORITY:
+                StaxParserUtil.advance(xmlEventReader);
+                text = StaxParserUtil.getElementText(xmlEventReader);
+                target.addAuthenticatingAuthority(URI.create(text));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAuthnStatementParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAuthnStatementParser.java
new file mode 100644
index 0000000..6e50b44
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLAuthnStatementParser.java
@@ -0,0 +1,76 @@
+/*
+ * 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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.dom.saml.v2.assertion.AuthnStatementType;
+import org.keycloak.dom.saml.v2.assertion.SubjectLocalityType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
+import javax.xml.datatype.XMLGregorianCalendar;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * Parse the <conditions> in the saml assertion
+ *
+ * @since Oct 14, 2010
+ */
+public class SAMLAuthnStatementParser extends AbstractStaxSamlAssertionParser<AuthnStatementType> {
+
+    private static final SAMLAuthnStatementParser INSTANCE = new SAMLAuthnStatementParser();
+
+    private SAMLAuthnStatementParser() {
+        super(SAMLAssertionQNames.AUTHN_STATEMENT);
+    }
+
+    public static SAMLAuthnStatementParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected AuthnStatementType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        XMLGregorianCalendar authnInstant = XMLTimeUtil.parse(StaxParserUtil.getRequiredAttributeValue(element, SAMLAssertionQNames.ATTR_AUTHN_INSTANT));
+        AuthnStatementType res = new AuthnStatementType(authnInstant);
+
+        res.setSessionIndex(StaxParserUtil.getAttributeValue(element, SAMLAssertionQNames.ATTR_SESSION_INDEX));
+        res.setSessionNotOnOrAfter(StaxParserUtil.getXmlTimeAttributeValue(element, SAMLAssertionQNames.ATTR_NOT_ON_OR_AFTER));
+        return res;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, AuthnStatementType target, SAMLAssertionQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case SUBJECT_LOCALITY:
+                StaxParserUtil.advance(xmlEventReader);
+
+                SubjectLocalityType subjectLocalityType = new SubjectLocalityType();
+                subjectLocalityType.setAddress(StaxParserUtil.getAttributeValue(elementDetail, SAMLAssertionQNames.ATTR_ADDRESS));
+                subjectLocalityType.setDNSName(StaxParserUtil.getAttributeValue(elementDetail, SAMLAssertionQNames.ATTR_DNS_NAME));
+
+                target.setSubjectLocality(subjectLocalityType);
+                break;
+
+            case AUTHN_CONTEXT:
+                target.setAuthnContext(SAMLAuthnContextParser.getInstance().parse(xmlEventReader));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLConditionsParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLConditionsParser.java
new file mode 100755
index 0000000..3024bc2
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLConditionsParser.java
@@ -0,0 +1,71 @@
+/*
+ * 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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.dom.saml.v2.assertion.AudienceRestrictionType;
+import org.keycloak.dom.saml.v2.assertion.ConditionsType;
+import org.keycloak.dom.saml.v2.assertion.OneTimeUseType;
+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;
+
+/**
+ * Parse the <conditions> in the saml assertion
+ *
+ * @since Oct 14, 2010
+ */
+public class SAMLConditionsParser extends AbstractStaxSamlAssertionParser<ConditionsType> {
+
+    private static final SAMLConditionsParser INSTANCE = new SAMLConditionsParser();
+
+    private SAMLConditionsParser() {
+        super(SAMLAssertionQNames.CONDITIONS);
+    }
+
+    public static SAMLConditionsParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected ConditionsType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        final ConditionsType conditions = new ConditionsType();
+
+        conditions.setNotBefore(StaxParserUtil.getXmlTimeAttributeValue(element, SAMLAssertionQNames.ATTR_NOT_BEFORE));
+        conditions.setNotOnOrAfter(StaxParserUtil.getXmlTimeAttributeValue(element, SAMLAssertionQNames.ATTR_NOT_ON_OR_AFTER));
+
+        return conditions;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, ConditionsType target, SAMLAssertionQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case AUDIENCE_RESTRICTION:
+                AudienceRestrictionType audienceRestriction = SAMLAudienceRestrictionParser.getInstance().parse(xmlEventReader);
+                target.addCondition(audienceRestriction);
+                break;
+
+            case ONE_TIME_USE:
+                OneTimeUseType oneTimeUseCondition = new OneTimeUseType();
+                target.addCondition(oneTimeUseCondition);
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLEncryptedAssertionParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLEncryptedAssertionParser.java
new file mode 100644
index 0000000..c75ec07
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLEncryptedAssertionParser.java
@@ -0,0 +1,39 @@
+/*
+ * 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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.dom.saml.v2.assertion.EncryptedAssertionType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.parsers.StaxParser;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import javax.xml.stream.XMLEventReader;
+
+public class SAMLEncryptedAssertionParser implements StaxParser {
+
+    private static final SAMLEncryptedAssertionParser INSTANCE = new SAMLEncryptedAssertionParser();
+
+    public static SAMLEncryptedAssertionParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    public EncryptedAssertionType parse(XMLEventReader xmlEventReader) throws ParsingException {
+        EncryptedAssertionType res = new EncryptedAssertionType();
+        res.setEncryptedElement(StaxParserUtil.getDOMElement(xmlEventReader));
+        return res;
+    }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLSubjectConfirmationDataParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLSubjectConfirmationDataParser.java
new file mode 100644
index 0000000..5520921
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLSubjectConfirmationDataParser.java
@@ -0,0 +1,68 @@
+/*
+ * 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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.dom.saml.v2.assertion.SubjectConfirmationDataType;
+import org.keycloak.dom.xmlsec.w3.xmldsig.KeyInfoType;
+import org.keycloak.saml.common.constants.WSTrustConstants;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.parsers.saml.xmldsig.KeyInfoParser;
+import java.util.Objects;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+public class SAMLSubjectConfirmationDataParser extends AbstractStaxSamlAssertionParser<SubjectConfirmationDataType> {
+
+    public static final SAMLSubjectConfirmationDataParser INSTANCE = new SAMLSubjectConfirmationDataParser();
+
+    public SAMLSubjectConfirmationDataParser() {
+        super(SAMLAssertionQNames.SUBJECT_CONFIRMATION_DATA);
+    }
+
+    @Override
+    protected SubjectConfirmationDataType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        final SubjectConfirmationDataType subjectConfirmationData = new SubjectConfirmationDataType();
+
+        subjectConfirmationData.setInResponseTo(StaxParserUtil.getAttributeValue(element, SAMLAssertionQNames.ATTR_IN_RESPONSE_TO));
+        subjectConfirmationData.setNotBefore(StaxParserUtil.getXmlTimeAttributeValue(element, SAMLAssertionQNames.ATTR_NOT_BEFORE));
+        subjectConfirmationData.setNotOnOrAfter(StaxParserUtil.getXmlTimeAttributeValue(element, SAMLAssertionQNames.ATTR_NOT_ON_OR_AFTER));
+        subjectConfirmationData.setRecipient(StaxParserUtil.getAttributeValue(element, SAMLAssertionQNames.ATTR_RECIPIENT));
+        subjectConfirmationData.setAddress(StaxParserUtil.getAttributeValue(element, SAMLAssertionQNames.ATTR_ADDRESS));
+
+        return subjectConfirmationData;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, SubjectConfirmationDataType target, SAMLAssertionQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case KEY_INFO:
+                KeyInfoType keyInfo = KeyInfoParser.getInstance().parse(xmlEventReader);
+                target.setAnyType(keyInfo);
+                break;
+
+            default:
+                String tag = StaxParserUtil.getElementName(elementDetail);
+
+                if (Objects.equals(tag, WSTrustConstants.XMLEnc.ENCRYPTED_KEY)) {
+                    target.setAnyType(StaxParserUtil.getDOMElement(xmlEventReader));
+                } else {
+                    throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+                }
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLSubjectConfirmationParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLSubjectConfirmationParser.java
new file mode 100644
index 0000000..1bf94e7
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLSubjectConfirmationParser.java
@@ -0,0 +1,71 @@
+/*
+ * 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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.dom.saml.v2.assertion.EncryptedElementType;
+import org.keycloak.dom.saml.v2.assertion.NameIDType;
+import org.keycloak.dom.saml.v2.assertion.SubjectConfirmationDataType;
+import org.keycloak.dom.saml.v2.assertion.SubjectConfirmationType;
+import org.keycloak.saml.common.ErrorCodes;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.parsers.StaxParser;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+import org.w3c.dom.Element;
+
+public class SAMLSubjectConfirmationParser extends AbstractStaxSamlAssertionParser<SubjectConfirmationType> implements StaxParser {
+
+    public static final SAMLSubjectConfirmationParser INSTANCE = new SAMLSubjectConfirmationParser();
+
+    public SAMLSubjectConfirmationParser() {
+        super(SAMLAssertionQNames.SUBJECT_CONFIRMATION);
+    }
+
+    @Override
+    protected SubjectConfirmationType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        final SubjectConfirmationType res = new SubjectConfirmationType();
+
+        res.setMethod(StaxParserUtil.getAttributeValue(element, SAMLAssertionQNames.ATTR_METHOD));
+
+        return res;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, SubjectConfirmationType target, SAMLAssertionQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case NAMEID:
+                NameIDType nameID = SAMLParserUtil.parseNameIDType(xmlEventReader);
+                target.setNameID(nameID);
+                break;
+
+            case ENCRYPTED_ID:
+                Element domElement = StaxParserUtil.getDOMElement(xmlEventReader);
+                target.setEncryptedID(new EncryptedElementType(domElement));
+                break;
+
+            case SUBJECT_CONFIRMATION_DATA:
+                SubjectConfirmationDataType subjectConfirmationData = SAMLSubjectConfirmationDataParser.INSTANCE.parse(xmlEventReader);
+                target.setSubjectConfirmationData(subjectConfirmationData);
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLSubjectParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLSubjectParser.java
new file mode 100755
index 0000000..bce615d
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/assertion/SAMLSubjectParser.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.saml.processing.core.parsers.saml.assertion;
+
+import org.keycloak.dom.saml.v2.assertion.EncryptedElementType;
+import org.keycloak.dom.saml.v2.assertion.NameIDType;
+import org.keycloak.dom.saml.v2.assertion.SubjectType;
+import org.keycloak.saml.common.ErrorCodes;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.parsers.StaxParser;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+import org.w3c.dom.Element;
+
+/**
+ * Parse the saml subject
+ *
+ * @since Oct 12, 2010
+ */
+public class SAMLSubjectParser extends AbstractStaxSamlAssertionParser<SubjectType> implements StaxParser {
+
+    private static final SAMLSubjectParser INSTANCE = new SAMLSubjectParser();
+
+    private SAMLSubjectParser() {
+        super(SAMLAssertionQNames.SUBJECT);
+    }
+
+    public static SAMLSubjectParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected SubjectType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        return new SubjectType();
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, SubjectType target, SAMLAssertionQNames element, StartElement elementDetail) throws ParsingException {
+        SubjectType.STSubType subType;
+        switch (element) {
+            case NAMEID:
+                NameIDType nameID = SAMLParserUtil.parseNameIDType(xmlEventReader);
+                subType = new SubjectType.STSubType();
+                subType.addBaseID(nameID);
+                target.setSubType(subType);
+                break;
+
+            case ENCRYPTED_ID:
+                Element domElement = StaxParserUtil.getDOMElement(xmlEventReader);
+                subType = new SubjectType.STSubType();
+                subType.setEncryptedID(new EncryptedElementType(domElement));
+                target.setSubType(subType);
+                break;
+
+            case SUBJECT_CONFIRMATION:
+                target.addConfirmation(SAMLSubjectConfirmationParser.INSTANCE.parse(xmlEventReader));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/AbstractStaxSamlParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/AbstractStaxSamlParser.java
new file mode 100644
index 0000000..c43754c
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/AbstractStaxSamlParser.java
@@ -0,0 +1,50 @@
+/*
+ * 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.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.saml.common.constants.JBossSAMLConstants;
+import javax.xml.namespace.QName;
+import org.keycloak.saml.common.parsers.AbstractStaxParser;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public abstract class AbstractStaxSamlParser<T> extends AbstractStaxParser<T, JBossSAMLConstants> {
+
+    public AbstractStaxSamlParser(JBossSAMLConstants expectedStartElement) {
+        super(expectedStartElement.getAsQName(), JBossSAMLConstants.UNKNOWN_VALUE);
+    }
+
+    @Override
+    protected boolean isUnknownElement(JBossSAMLConstants token) {
+        return token == JBossSAMLConstants.UNKNOWN_VALUE;
+    }
+
+    @Override
+    protected JBossSAMLConstants getElementFromName(QName name) {
+        JBossSAMLConstants res = JBossSAMLConstants.from(name);
+
+        if ((res == null || res == JBossSAMLConstants.UNKNOWN_VALUE) && name != null) {
+            // Relax and search regardless of namespace
+            res = JBossSAMLConstants.from(name.getLocalPart());
+        }
+
+        return res;
+    }
+
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntitiesDescriptorParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntitiesDescriptorParser.java
index 8df0d3b..83e9179 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntitiesDescriptorParser.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntitiesDescriptorParser.java
@@ -23,7 +23,7 @@ import org.keycloak.saml.common.PicketLinkLoggerFactory;
 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.parsers.ParserNamespaceSupport;
+import org.keycloak.saml.common.parsers.AbstractParser;
 import org.keycloak.saml.common.util.StaxParserUtil;
 import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
 import org.w3c.dom.Element;
@@ -34,6 +34,7 @@ import javax.xml.stream.events.Attribute;
 import javax.xml.stream.events.EndElement;
 import javax.xml.stream.events.StartElement;
 import javax.xml.stream.events.XMLEvent;
+import org.keycloak.saml.common.parsers.StaxParser;
 
 /**
  * Parse the SAML Entities Descriptor
@@ -41,16 +42,14 @@ import javax.xml.stream.events.XMLEvent;
  * @author Anil.Saldhana@redhat.com
  * @since Jan 31, 2011
  */
-public class SAMLEntitiesDescriptorParser extends AbstractDescriptorParser implements ParserNamespaceSupport {
+public class SAMLEntitiesDescriptorParser extends AbstractParser {
 
     private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
 
-    private final String EDT = JBossSAMLConstants.ENTITIES_DESCRIPTOR.get();
+    private static final String EDT = JBossSAMLConstants.ENTITIES_DESCRIPTOR.get();
 
     public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
 
-        xmlEventReader = filterWhiteSpaceCharacters(xmlEventReader);
-
         StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
         StaxParserUtil.validate(startElement, EDT);
 
@@ -93,7 +92,7 @@ public class SAMLEntitiesDescriptorParser extends AbstractDescriptorParser imple
             if (JBossSAMLConstants.ENTITY_DESCRIPTOR.get().equals(localPart)) {
                 SAMLEntityDescriptorParser entityParser = new SAMLEntityDescriptorParser();
                 entitiesDescriptorType.addEntityDescriptor(entityParser.parse(xmlEventReader));
-            } else if (JBossSAMLConstants.EXTENSIONS.get().equalsIgnoreCase(localPart)) {
+            } else if (JBossSAMLConstants.EXTENSIONS__METADATA.get().equalsIgnoreCase(localPart)) {
                 entitiesDescriptorType.setExtensions(parseExtensions(xmlEventReader));
             } else if (JBossSAMLConstants.ENTITIES_DESCRIPTOR.get().equalsIgnoreCase(localPart)) {
                 SAMLEntitiesDescriptorParser parser = new SAMLEntitiesDescriptorParser();
@@ -106,12 +105,6 @@ public class SAMLEntitiesDescriptorParser extends AbstractDescriptorParser imple
         return entitiesDescriptorType;
     }
 
-    public boolean supports(QName qname) {
-        String nsURI = qname.getNamespaceURI();
-        String localPart = qname.getLocalPart();
-
-        return nsURI.equals(JBossSAMLURIConstants.ASSERTION_NSURI.get()) && localPart.equals(EDT);
-    }
 
     private ExtensionsType parseExtensions(XMLEventReader xmlEventReader) throws ParsingException {
         ExtensionsType extensions = new ExtensionsType();
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntityDescriptorParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntityDescriptorParser.java
index 31dfc5f..f94027d 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntityDescriptorParser.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntityDescriptorParser.java
@@ -31,7 +31,6 @@ import org.keycloak.dom.saml.v2.metadata.KeyTypes;
 import org.keycloak.dom.saml.v2.metadata.LocalizedNameType;
 import org.keycloak.dom.saml.v2.metadata.LocalizedURIType;
 import org.keycloak.dom.saml.v2.metadata.OrganizationType;
-import org.keycloak.dom.saml.v2.metadata.RequestedAttributeType;
 import org.keycloak.dom.saml.v2.metadata.RoleDescriptorType;
 import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
 import org.keycloak.dom.xmlsec.w3.xmlenc.EncryptionMethodType;
@@ -41,9 +40,10 @@ import org.keycloak.saml.common.constants.GeneralConstants;
 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.parsers.ParserNamespaceSupport;
+import org.keycloak.saml.common.parsers.AbstractParser;
 import org.keycloak.saml.common.util.StaxParserUtil;
-import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
+import org.keycloak.saml.common.util.StringUtil;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAttributeParser;
 import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
 
 import org.w3c.dom.Element;
@@ -56,7 +56,10 @@ import javax.xml.stream.events.StartElement;
 import javax.xml.stream.events.XMLEvent;
 import java.math.BigInteger;
 import java.net.URI;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.StringTokenizer;
+import org.keycloak.saml.common.parsers.StaxParser;
 
 /**
  * Parse the SAML Metadata element "EntityDescriptor"
@@ -64,16 +67,14 @@ import java.util.List;
  * @author Anil.Saldhana@redhat.com
  * @since Dec 14, 2010
  */
-public class SAMLEntityDescriptorParser extends AbstractDescriptorParser implements ParserNamespaceSupport {
+public class SAMLEntityDescriptorParser extends AbstractParser {
 
     private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
 
-    private final String EDT = JBossSAMLConstants.ENTITY_DESCRIPTOR.get();
+    private static final String EDT = JBossSAMLConstants.ENTITY_DESCRIPTOR.get();
 
     public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
 
-        xmlEventReader = filterWhiteSpaceCharacters(xmlEventReader);
-
         StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
         StaxParserUtil.validate(startElement, EDT);
 
@@ -142,8 +143,8 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
                 entityDescriptorType.addContactPerson(parseContactPerson(xmlEventReader));
             } else if (JBossSAMLConstants.ADDITIONAL_METADATA_LOCATION.get().equals(localPart)) {
                 throw logger.unsupportedType("AdditionalMetadataLocation");
-            } else if (JBossSAMLConstants.EXTENSIONS.get().equalsIgnoreCase(localPart)) {
-                entityDescriptorType.setExtensions(parseExtensions(xmlEventReader));
+            } else if (JBossSAMLConstants.EXTENSIONS__PROTOCOL.get().equalsIgnoreCase(localPart)) {
+                entityDescriptorType.setExtensions(SAMLExtensionsParser.getInstance().parse(xmlEventReader));
             } else if (JBossSAMLConstants.ROLE_DESCRIPTOR.get().equalsIgnoreCase(localPart)) {
                 RoleDescriptorType roleDescriptor = parseRoleDescriptor(xmlEventReader);
 
@@ -157,19 +158,12 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
         return entityDescriptorType;
     }
 
-    public boolean supports(QName qname) {
-        String nsURI = qname.getNamespaceURI();
-        String localPart = qname.getLocalPart();
-
-        return nsURI.equals(JBossSAMLURIConstants.ASSERTION_NSURI.get())
-                && localPart.equals(JBossSAMLConstants.ENTITY_DESCRIPTOR.get());
-    }
 
     private SPSSODescriptorType parseSPSSODescriptor(XMLEventReader xmlEventReader) throws ParsingException {
         StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
         StaxParserUtil.validate(startElement, JBossSAMLConstants.SP_SSO_DESCRIPTOR.get());
 
-        List<String> protocolEnum = SAMLParserUtil.parseProtocolEnumeration(startElement);
+        List<String> protocolEnum = parseProtocolEnumeration(startElement);
         SPSSODescriptorType spSSODescriptor = new SPSSODescriptorType(protocolEnum);
 
         Attribute wantAssertionsSigned = startElement.getAttributeByName(new QName(JBossSAMLConstants.WANT_ASSERTIONS_SIGNED
@@ -224,7 +218,7 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
                 spSSODescriptor.addNameIDFormat(StaxParserUtil.getElementText(xmlEventReader));
             } else if (JBossSAMLConstants.KEY_DESCRIPTOR.get().equalsIgnoreCase(localPart)) {
                 spSSODescriptor.addKeyDescriptor(parseKeyDescriptor(xmlEventReader));
-            } else if (JBossSAMLConstants.EXTENSIONS.get().equalsIgnoreCase(localPart)) {
+            } else if (JBossSAMLConstants.EXTENSIONS__PROTOCOL.get().equalsIgnoreCase(localPart)) {
                 spSSODescriptor.setExtensions(parseExtensions(xmlEventReader));
             } else
                 throw logger.parserUnknownTag(localPart, startElement.getLocation());
@@ -236,7 +230,7 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
         StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
         StaxParserUtil.validate(startElement, JBossSAMLConstants.IDP_SSO_DESCRIPTOR.get());
 
-        List<String> protocolEnum = SAMLParserUtil.parseProtocolEnumeration(startElement);
+        List<String> protocolEnum = parseProtocolEnumeration(startElement);
         IDPSSODescriptorType idpSSODescriptor = new IDPSSODescriptorType(protocolEnum);
 
         Attribute wantAuthnSigned = startElement.getAttributeByName(new QName(JBossSAMLConstants.WANT_AUTHN_REQUESTS_SIGNED
@@ -304,11 +298,11 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
                 startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
                 idpSSODescriptor.addNameIDFormat(StaxParserUtil.getElementText(xmlEventReader));
             } else if (JBossSAMLConstants.ATTRIBUTE.get().equalsIgnoreCase(localPart)) {
-                AttributeType attribute = SAMLParserUtil.parseAttribute(xmlEventReader);
+                AttributeType attribute = SAMLAttributeParser.getInstance().parse(xmlEventReader);
                 idpSSODescriptor.addAttribute(attribute);
             } else if (JBossSAMLConstants.KEY_DESCRIPTOR.get().equalsIgnoreCase(localPart)) {
                 idpSSODescriptor.addKeyDescriptor(parseKeyDescriptor(xmlEventReader));
-            } else if (JBossSAMLConstants.EXTENSIONS.get().equalsIgnoreCase(localPart)) {
+            } else if (JBossSAMLConstants.EXTENSIONS__PROTOCOL.get().equalsIgnoreCase(localPart)) {
                 idpSSODescriptor.setExtensions(parseExtensions(xmlEventReader));
             } else
                 throw logger.parserUnknownTag(localPart, startElement.getLocation());
@@ -335,7 +329,7 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
             throws ParsingException {
         StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
         StaxParserUtil.validate(startElement, JBossSAMLConstants.ATTRIBUTE_AUTHORITY_DESCRIPTOR.get());
-        List<String> protocolEnum = SAMLParserUtil.parseProtocolEnumeration(startElement);
+        List<String> protocolEnum = parseProtocolEnumeration(startElement);
         AttributeAuthorityDescriptorType attributeAuthority = new AttributeAuthorityDescriptorType(protocolEnum);
 
         while (xmlEventReader.hasNext()) {
@@ -363,17 +357,25 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
                 StaxParserUtil.validate(endElement, JBossSAMLConstants.ATTRIBUTE_SERVICE.get());
 
                 attributeAuthority.addAttributeService(endpoint);
+            } else if (JBossSAMLConstants.ASSERTION_ID_REQUEST_SERVICE.get().equals(localPart)) {
+                startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
+                EndpointType endpoint = getEndpointType(startElement);
+
+                EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
+                StaxParserUtil.validate(endElement, JBossSAMLConstants.ASSERTION_ID_REQUEST_SERVICE.get());
+
+                attributeAuthority.addAssertionIDRequestService(endpoint);
             } else if (JBossSAMLConstants.ATTRIBUTE_PROFILE.get().equalsIgnoreCase(localPart)) {
                 startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
                 attributeAuthority.addAttributeProfile(StaxParserUtil.getElementText(xmlEventReader));
             } else if (JBossSAMLConstants.ATTRIBUTE.get().equalsIgnoreCase(localPart)) {
-                attributeAuthority.addAttribute(SAMLParserUtil.parseAttribute(xmlEventReader));
+                attributeAuthority.addAttribute(SAMLAttributeParser.getInstance().parse(xmlEventReader));
             } else if (JBossSAMLConstants.KEY_DESCRIPTOR.get().equalsIgnoreCase(localPart)) {
                 attributeAuthority.addKeyDescriptor(parseKeyDescriptor(xmlEventReader));
             } else if (JBossSAMLConstants.NAMEID_FORMAT.get().equalsIgnoreCase(localPart)) {
                 startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
                 attributeAuthority.addNameIDFormat(StaxParserUtil.getElementText(xmlEventReader));
-            } else if (JBossSAMLConstants.EXTENSIONS.get().equalsIgnoreCase(localPart)) {
+            } else if (JBossSAMLConstants.EXTENSIONS__PROTOCOL.get().equalsIgnoreCase(localPart)) {
                 attributeAuthority.setExtensions(parseExtensions(xmlEventReader));
             } else
                 throw logger.parserUnknownTag(localPart, startElement.getLocation());
@@ -415,7 +417,7 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
                 LocalizedURIType localName = new LocalizedURIType(langVal);
                 localName.setValue(URI.create(StaxParserUtil.getElementText(xmlEventReader)));
                 org.addOrganizationURL(localName);
-            } else if (JBossSAMLConstants.EXTENSIONS.get().equalsIgnoreCase(localPart)) {
+            } else if (JBossSAMLConstants.EXTENSIONS__PROTOCOL.get().equalsIgnoreCase(localPart)) {
                 org.setExtensions(parseExtensions(xmlEventReader));
             } else
                 throw logger.parserUnknownTag(localPart, startElement.getLocation());
@@ -531,7 +533,7 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
             } else if (JBossSAMLConstants.TELEPHONE_NUMBER.get().equals(localPart)) {
                 startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
                 contactType.addTelephone(StaxParserUtil.getElementText(xmlEventReader));
-            } else if (JBossSAMLConstants.EXTENSIONS.get().equalsIgnoreCase(localPart)) {
+            } else if (JBossSAMLConstants.EXTENSIONS__PROTOCOL.get().equalsIgnoreCase(localPart)) {
                 contactType.setExtensions(parseExtensions(xmlEventReader));
             } else
                 throw logger.parserUnknownTag(localPart, startElement.getLocation());
@@ -619,8 +621,7 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
                 LocalizedNameType localName = getLocalizedName(xmlEventReader, startElement);
                 attributeConsumer.addServiceDescription(localName);
             } else if (JBossSAMLConstants.REQUESTED_ATTRIBUTE.get().equals(localPart)) {
-                RequestedAttributeType attType = parseRequestedAttributeType(xmlEventReader, startElement);
-                attributeConsumer.addRequestedAttribute(attType);
+                attributeConsumer.addRequestedAttribute(SAMLRequestedAttributeParser.getInstance().parse(xmlEventReader));
             } else
                 throw logger.parserUnknownTag(localPart, startElement.getLocation());
         }
@@ -628,27 +629,6 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
         return attributeConsumer;
     }
 
-    private RequestedAttributeType parseRequestedAttributeType(XMLEventReader xmlEventReader, StartElement startElement)
-            throws ParsingException {
-        startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-        StaxParserUtil.validate(startElement, JBossSAMLConstants.REQUESTED_ATTRIBUTE.get());
-        RequestedAttributeType attributeType = null;
-
-        Attribute name = startElement.getAttributeByName(new QName(JBossSAMLConstants.NAME.get()));
-        if (name == null)
-            throw logger.parserRequiredAttribute("Name");
-        attributeType = new RequestedAttributeType(StaxParserUtil.getAttributeValue(name));
-
-        Attribute isRequired = startElement.getAttributeByName(new QName(JBossSAMLConstants.IS_REQUIRED.get()));
-        if (isRequired != null) {
-            attributeType.setIsRequired(Boolean.parseBoolean(StaxParserUtil.getAttributeValue(isRequired)));
-        }
-
-        SAMLParserUtil.parseAttributeType(xmlEventReader, startElement, JBossSAMLConstants.REQUESTED_ATTRIBUTE.get(),
-                attributeType);
-        return attributeType;
-    }
-
     private ExtensionsType parseExtensions(XMLEventReader xmlEventReader) throws ParsingException {
         ExtensionsType extensions = new ExtensionsType();
         Element extElement = StaxParserUtil.getDOMElement(xmlEventReader);
@@ -659,7 +639,7 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
     private RoleDescriptorType parseRoleDescriptor(XMLEventReader xmlEventReader) throws ParsingException {
         StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
         StaxParserUtil.validate(startElement, JBossSAMLConstants.ROLE_DESCRIPTOR.get());
-        List<String> protocolEnum = SAMLParserUtil.parseProtocolEnumeration(startElement);
+        List<String> protocolEnum = parseProtocolEnumeration(startElement);
         RoleDescriptorType roleDescriptorType = new RoleDescriptorType(protocolEnum) {};
 
         while (xmlEventReader.hasNext()) {
@@ -683,4 +663,25 @@ public class SAMLEntityDescriptorParser extends AbstractDescriptorParser impleme
 
         return roleDescriptorType;
     }
+
+    /**
+     * Parse a space delimited list of strings
+     *
+     * @param startElement
+     *
+     * @return
+     */
+    public static List<String> parseProtocolEnumeration(StartElement startElement) {
+        List<String> protocolEnum = new ArrayList<>();
+        Attribute proto = startElement.getAttributeByName(JBossSAMLConstants.PROTOCOL_SUPPORT_ENUMERATION.getAsQName());
+        String val = StaxParserUtil.getAttributeValue(proto);
+        if (StringUtil.isNotNull(val)) {
+            StringTokenizer st = new StringTokenizer(val);
+            while (st.hasMoreTokens()) {
+                protocolEnum.add(st.nextToken());
+            }
+
+        }
+        return protocolEnum;
+    }
 }
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLRequestedAttributeParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLRequestedAttributeParser.java
new file mode 100644
index 0000000..b1dbb7d
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLRequestedAttributeParser.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.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.saml.v2.metadata.RequestedAttributeType;
+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.StaxParserUtil;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.StartElement;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAttributeValueParser;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAssertionQNames;
+
+/**
+ * Parse the <conditions> in the saml assertion
+ *
+ * @since Oct 14, 2010
+ */
+public class SAMLRequestedAttributeParser extends AbstractStaxSamlParser<RequestedAttributeType> {
+
+    private static final SAMLRequestedAttributeParser INSTANCE = new SAMLRequestedAttributeParser();
+    private static final QName X500_ENCODING = new QName(JBossSAMLURIConstants.X500_NSURI.get(), JBossSAMLConstants.ENCODING.get(),
+      JBossSAMLURIConstants.X500_PREFIX.get());
+
+
+    private SAMLRequestedAttributeParser() {
+        super(JBossSAMLConstants.REQUESTED_ATTRIBUTE);
+    }
+
+    public static SAMLRequestedAttributeParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected RequestedAttributeType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        RequestedAttributeType attributeType;
+
+        // TODO: replace all constants with SamlMetadataQNames ones
+        attributeType = new RequestedAttributeType(StaxParserUtil.getRequiredAttributeValue(element, SAMLAssertionQNames.ATTR_NAME));
+        attributeType.setFriendlyName(StaxParserUtil.getAttributeValue(element, JBossSAMLConstants.FRIENDLY_NAME.get()));
+        attributeType.setIsRequired(StaxParserUtil.getBooleanAttributeValue(element, JBossSAMLConstants.IS_REQUIRED.get()));
+        attributeType.setNameFormat(StaxParserUtil.getAttributeValue(element, JBossSAMLConstants.NAME_FORMAT.get()));
+
+        Attribute x500EncodingAttr = element.getAttributeByName(X500_ENCODING);
+        if (x500EncodingAttr != null) {
+            attributeType.getOtherAttributes().put(x500EncodingAttr.getName(), StaxParserUtil.getAttributeValue(x500EncodingAttr));
+        }
+
+        return attributeType;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, RequestedAttributeType target, JBossSAMLConstants element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case ATTRIBUTE_VALUE:
+                target.addAttributeValue(SAMLAttributeValueParser.getInstance().parse(xmlEventReader));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/AbstractStaxSamlProtocolParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/AbstractStaxSamlProtocolParser.java
new file mode 100644
index 0000000..5aacd8a
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/AbstractStaxSamlProtocolParser.java
@@ -0,0 +1,40 @@
+/*
+ * 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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.saml.common.parsers.AbstractStaxParser;
+import org.keycloak.saml.processing.core.parsers.util.QNameEnumLookup;
+import javax.xml.namespace.QName;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public abstract class AbstractStaxSamlProtocolParser<T> extends AbstractStaxParser<T, SAMLProtocolQNames> {
+
+    protected static final QNameEnumLookup<SAMLProtocolQNames> LOOKUP = new QNameEnumLookup(SAMLProtocolQNames.values());
+
+    public AbstractStaxSamlProtocolParser(SAMLProtocolQNames expectedStartElement) {
+        super(expectedStartElement.getQName(), SAMLProtocolQNames.UNKNOWN_ELEMENT);
+    }
+
+    @Override
+    protected SAMLProtocolQNames getElementFromName(QName name) {
+        return LOOKUP.from(name);
+    }
+
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLArtifactResponseParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLArtifactResponseParser.java
new file mode 100755
index 0000000..663e372
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLArtifactResponseParser.java
@@ -0,0 +1,97 @@
+/*
+ * 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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.dom.saml.v2.protocol.ArtifactResponseType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
+import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
+import javax.xml.datatype.XMLGregorianCalendar;
+import org.w3c.dom.Element;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+import static org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLStatusResponseTypeParser.VERSION_2_0;
+
+/**
+ * Parse the SAML Response
+ *
+ * @since July 1, 2011
+ */
+public class SAMLArtifactResponseParser extends SAMLStatusResponseTypeParser<ArtifactResponseType> {
+
+    private static final SAMLArtifactResponseParser INSTANCE = new SAMLArtifactResponseParser();
+
+    private SAMLArtifactResponseParser() {
+        super(SAMLProtocolQNames.ARTIFACT_RESPONSE);
+    }
+
+    public static SAMLArtifactResponseParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected ArtifactResponseType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        SAMLParserUtil.validateAttributeValue(element, SAMLProtocolQNames.ATTR_VERSION, VERSION_2_0);
+        String id = StaxParserUtil.getRequiredAttributeValue(element, SAMLProtocolQNames.ATTR_ID);
+        XMLGregorianCalendar issueInstant = XMLTimeUtil.parse(StaxParserUtil.getRequiredAttributeValue(element, SAMLProtocolQNames.ATTR_ISSUE_INSTANT));
+
+        ArtifactResponseType res = new ArtifactResponseType(id, issueInstant);
+
+        // Let us set the attributes
+        super.parseBaseAttributes(element, res);
+
+        return res;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, ArtifactResponseType target, SAMLProtocolQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case ISSUER:
+                target.setIssuer(SAMLParserUtil.parseNameIDType(xmlEventReader));
+                break;
+
+            case SIGNATURE:
+                Element sig = StaxParserUtil.getDOMElement(xmlEventReader);
+                target.setSignature(sig);
+                break;
+
+            case EXTENSIONS:
+                SAMLExtensionsParser extensionsParser = SAMLExtensionsParser.getInstance();
+                target.setExtensions(extensionsParser.parse(xmlEventReader));
+                break;
+
+            case AUTHN_REQUEST:
+                SAMLAuthNRequestParser authnParser = SAMLAuthNRequestParser.getInstance();
+                target.setAny(authnParser.parse(xmlEventReader));
+                break;
+
+            case RESPONSE:
+                SAMLResponseParser responseParser = SAMLResponseParser.getInstance();
+                target.setAny(responseParser.parse(xmlEventReader));
+                break;
+
+            case STATUS:
+                target.setStatus(SAMLStatusParser.getInstance().parse(xmlEventReader));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLAttributeQueryParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLAttributeQueryParser.java
new file mode 100755
index 0000000..c255cb3
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLAttributeQueryParser.java
@@ -0,0 +1,83 @@
+/*
+ * 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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.dom.saml.v2.protocol.AttributeQueryType;
+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;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAttributeParser;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLSubjectParser;
+import org.keycloak.saml.common.parsers.StaxParser;
+import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
+import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
+import javax.xml.datatype.XMLGregorianCalendar;
+import static org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLRequestAbstractParser.VERSION_2_0;
+
+/**
+ * Parse the {@link org.keycloak.dom.saml.v2.protocol.ArtifactResolveType}
+ *
+ * @since Jul 1, 2011
+ */
+public class SAMLAttributeQueryParser extends SAMLRequestAbstractParser<AttributeQueryType> implements StaxParser {
+
+    private static final SAMLAttributeQueryParser INSTANCE = new SAMLAttributeQueryParser();
+
+    private SAMLAttributeQueryParser() {
+        super(SAMLProtocolQNames.ATTRIBUTE_QUERY);
+    }
+
+    public static SAMLAttributeQueryParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected AttributeQueryType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        SAMLParserUtil.validateAttributeValue(element, SAMLProtocolQNames.ATTR_VERSION, VERSION_2_0);
+        String id = StaxParserUtil.getRequiredAttributeValue(element, SAMLProtocolQNames.ATTR_ID);
+        XMLGregorianCalendar issueInstant = XMLTimeUtil.parse(StaxParserUtil.getRequiredAttributeValue(element, SAMLProtocolQNames.ATTR_ISSUE_INSTANT));
+
+        AttributeQueryType authnRequest = new AttributeQueryType(id, issueInstant);
+        super.parseBaseAttributes(element, authnRequest);
+
+        return authnRequest;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, AttributeQueryType target, SAMLProtocolQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case ISSUER:
+            case SIGNATURE:
+            case EXTENSIONS:
+                parseCommonElements(element, elementDetail, xmlEventReader, target);
+                break;
+
+            case SUBJECT:
+                target.setSubject(SAMLSubjectParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case ATTRIBUTE:
+                target.add(SAMLAttributeParser.getInstance().parse(xmlEventReader));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLAuthNRequestParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLAuthNRequestParser.java
new file mode 100755
index 0000000..592cc50
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLAuthNRequestParser.java
@@ -0,0 +1,127 @@
+/*
+ * 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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
+import org.keycloak.dom.saml.v2.protocol.NameIDPolicyType;
+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;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLConditionsParser;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLSubjectParser;
+import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
+import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
+import javax.xml.datatype.XMLGregorianCalendar;
+import static org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLRequestAbstractParser.VERSION_2_0;
+
+/**
+ * Parse the SAML2 AuthnRequest
+ *
+ * @since Nov 2, 2010
+ */
+public class SAMLAuthNRequestParser extends SAMLRequestAbstractParser<AuthnRequestType> {
+
+    private static final SAMLAuthNRequestParser INSTANCE = new SAMLAuthNRequestParser();
+
+    private SAMLAuthNRequestParser() {
+        super(SAMLProtocolQNames.AUTHN_REQUEST);
+    }
+
+    public static SAMLAuthNRequestParser getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * Parse the attributes at the authnrequesttype element
+     *
+     * @param startElement
+     *
+     * @return
+     *
+     * @throws ParsingException
+     */
+    @Override
+    protected AuthnRequestType instantiateElement(XMLEventReader xmlEventReader, StartElement startElement) throws ParsingException {
+        SAMLParserUtil.validateAttributeValue(startElement, SAMLProtocolQNames.ATTR_VERSION, VERSION_2_0);
+        String id = StaxParserUtil.getRequiredAttributeValue(startElement, SAMLProtocolQNames.ATTR_ID);
+        XMLGregorianCalendar issueInstant = XMLTimeUtil.parse(StaxParserUtil.getRequiredAttributeValue(startElement, SAMLProtocolQNames.ATTR_ISSUE_INSTANT));
+
+        AuthnRequestType authnRequest = new AuthnRequestType(id, issueInstant);
+        super.parseBaseAttributes(startElement, authnRequest);
+
+        authnRequest.setAssertionConsumerServiceURL(StaxParserUtil.getUriAttributeValue(startElement, SAMLProtocolQNames.ATTR_ASSERTION_CONSUMER_SERVICE_URL));
+        authnRequest.setAssertionConsumerServiceIndex(StaxParserUtil.getIntegerAttributeValue(startElement, SAMLProtocolQNames.ATTR_ASSERTION_CONSUMER_SERVICE_INDEX));
+        authnRequest.setAttributeConsumingServiceIndex(StaxParserUtil.getIntegerAttributeValue(startElement, SAMLProtocolQNames.ATTR_ATTRIBUTE_CONSUMING_SERVICE_INDEX));
+        authnRequest.setForceAuthn(StaxParserUtil.getBooleanAttributeValue(startElement, SAMLProtocolQNames.ATTR_FORCE_AUTHN));
+        authnRequest.setIsPassive(StaxParserUtil.getBooleanAttributeValue(startElement, SAMLProtocolQNames.ATTR_IS_PASSIVE));
+        authnRequest.setProtocolBinding(StaxParserUtil.getUriAttributeValue(startElement, SAMLProtocolQNames.ATTR_PROTOCOL_BINDING));
+        authnRequest.setProviderName(StaxParserUtil.getAttributeValue(startElement, SAMLProtocolQNames.ATTR_PROVIDER_NAME));
+
+        return authnRequest;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, AuthnRequestType target, SAMLProtocolQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case ISSUER:
+            case SIGNATURE:
+            case EXTENSIONS:
+                parseCommonElements(element, elementDetail, xmlEventReader, target);
+                break;
+
+            case NAMEID_POLICY:
+                StaxParserUtil.advance(xmlEventReader);
+                target.setNameIDPolicy(getNameIDPolicy(elementDetail));
+                break;
+
+            case SUBJECT:
+                target.setSubject(SAMLSubjectParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case CONDITIONS:
+                target.setConditions(SAMLConditionsParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case REQUESTED_AUTHN_CONTEXT:
+                target.setRequestedAuthnContext(SAMLRequestedAuthnContextParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case SCOPING:
+                StaxParserUtil.bypassElementBlock(xmlEventReader, element.getQName());
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+
+    /**
+     * Get the NameIDPolicy
+     *
+     * @param startElement
+     *
+     * @return
+     */
+    private NameIDPolicyType getNameIDPolicy(StartElement startElement) {
+        NameIDPolicyType nameIDPolicy = new NameIDPolicyType();
+        nameIDPolicy.setFormat(StaxParserUtil.getUriAttributeValue(startElement, SAMLProtocolQNames.ATTR_FORMAT));
+        nameIDPolicy.setAllowCreate(StaxParserUtil.getBooleanAttributeValue(startElement, SAMLProtocolQNames.ATTR_ALLOW_CREATE));
+        return nameIDPolicy;
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLProtocolQNames.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLProtocolQNames.java
new file mode 100644
index 0000000..6af0a3c
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLProtocolQNames.java
@@ -0,0 +1,125 @@
+/*
+ * 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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAssertionQNames;
+import org.keycloak.saml.processing.core.parsers.saml.xmldsig.XmlDSigQNames;
+import javax.xml.namespace.QName;
+import org.keycloak.saml.processing.core.parsers.util.HasQName;
+
+/**
+ * Elements from saml-schema-protocol-2.0.xsd
+ * @author hmlnarik
+ */
+public enum SAMLProtocolQNames implements HasQName {
+
+    ARTIFACT("Artifact"),
+    ARTIFACT_RESOLVE("ArtifactResolve"),
+    ARTIFACT_RESPONSE("ArtifactResponse"),
+    ASSERTION_ID_REQUEST("AssertionIDRequest"),
+    ATTRIBUTE_QUERY("AttributeQuery"),
+    AUTHN_QUERY("AuthnQuery"),
+    AUTHN_REQUEST("AuthnRequest"),
+    AUTHZ_DECISION_QUERY("AuthzDecisionQuery"),
+    EXTENSIONS("Extensions"),
+    GET_COMPLETE("GetComplete"),
+    IDP_ENTRY("IDPEntry"),
+    IDP_LIST("IDPList"),
+    LOGOUT_REQUEST("LogoutRequest"),
+    LOGOUT_RESPONSE("LogoutResponse"),
+    MANAGE_NAMEID_REQUEST("ManageNameIDRequest"),
+    MANAGE_NAMEID_RESPONSE("ManageNameIDResponse"),
+    NAMEID_MAPPING_REQUEST("NameIDMappingRequest"),
+    NAMEID_MAPPING_RESPONSE("NameIDMappingResponse"),
+    NAMEID_POLICY("NameIDPolicy"),
+    NEW_ENCRYPTEDID("NewEncryptedID"),
+    NEWID("NewID"),
+    REQUESTED_AUTHN_CONTEXT("RequestedAuthnContext"),
+    REQUESTERID("RequesterID"),
+    RESPONSE("Response"),
+    SCOPING("Scoping"),
+    SESSION_INDEX("SessionIndex"),
+    STATUS_CODE("StatusCode"),
+    STATUS_DETAIL("StatusDetail"),
+    STATUS_MESSAGE("StatusMessage"),
+    STATUS("Status"),
+    SUBJECT_QUERY("SubjectQuery"),
+    TERMINATE("Terminate"),
+
+    // Attribute names
+    ATTR_ALLOW_CREATE(null, "AllowCreate"),
+    ATTR_ASSERTION_CONSUMER_SERVICE_URL(null, "AssertionConsumerServiceURL"),
+    ATTR_ASSERTION_CONSUMER_SERVICE_INDEX(null, "AssertionConsumerServiceIndex"),
+    ATTR_ATTRIBUTE_CONSUMING_SERVICE_INDEX(null, "AttributeConsumingServiceIndex"),
+    ATTR_COMPARISON(null, "Comparison"),
+    ATTR_CONSENT(null, "Consent"),
+    ATTR_DESTINATION(null, "Destination"),
+    ATTR_FORCE_AUTHN(null, "ForceAuthn"),
+    ATTR_FORMAT(null, "Format"),
+    ATTR_ID(null, "ID"),
+    ATTR_IN_RESPONSE_TO(null, "InResponseTo"),
+    ATTR_IS_PASSIVE(null, "IsPassive"),
+    ATTR_ISSUE_INSTANT(null, "IssueInstant"),
+    ATTR_NOT_BEFORE(null, "NotBefore"),
+    ATTR_NOT_ON_OR_AFTER(null, "NotOnOrAfter"),
+    ATTR_PROTOCOL_BINDING(null, "ProtocolBinding"),
+    ATTR_PROVIDER_NAME(null, "ProviderName"),
+    ATTR_REASON(null, "Reason"),
+    ATTR_VALUE(null, "Value"),
+    ATTR_VERSION(null, "Version"),
+
+    // Elements from other namespaces that can be direct subelements of this namespace's elements
+    ATTRIBUTE(SAMLAssertionQNames.ATTRIBUTE),
+    ASSERTION(SAMLAssertionQNames.ASSERTION),
+    AUTHN_CONTEXT_CLASS_REF(SAMLAssertionQNames.AUTHN_CONTEXT_CLASS_REF),
+    AUTHN_CONTEXT_DECL_REF(SAMLAssertionQNames.AUTHN_CONTEXT_DECL_REF),
+    BASEID(SAMLAssertionQNames.BASEID),
+    CONDITIONS(SAMLAssertionQNames.CONDITIONS),
+    ENCRYPTED_ASSERTION(SAMLAssertionQNames.ENCRYPTED_ASSERTION),
+    ISSUER(SAMLAssertionQNames.ISSUER),
+    NAMEID(SAMLAssertionQNames.NAMEID),
+    SIGNATURE(XmlDSigQNames.SIGNATURE),
+    ENCRYPTED_ID(SAMLAssertionQNames.ENCRYPTED_ID),
+    SUBJECT(SAMLAssertionQNames.SUBJECT),
+
+    UNKNOWN_ELEMENT("")
+    ;
+
+    private final QName qName;
+
+    private SAMLProtocolQNames(String localName) {
+        this(JBossSAMLURIConstants.PROTOCOL_NSURI, localName);
+    }
+
+    private SAMLProtocolQNames(HasQName source) {
+        this.qName = source.getQName();
+    }
+
+    private SAMLProtocolQNames(JBossSAMLURIConstants nsUri, String localName) {
+        this.qName = new QName(nsUri == null ? null : nsUri.get(), 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/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLRequestAbstractParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLRequestAbstractParser.java
new file mode 100755
index 0000000..a714fff
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLRequestAbstractParser.java
@@ -0,0 +1,75 @@
+/*
+ * 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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.dom.saml.v2.protocol.RequestAbstractType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * Base Class for SAML Request Parsing
+ *
+ * @since Nov 2, 2010
+ */
+public abstract class SAMLRequestAbstractParser<T extends RequestAbstractType> extends AbstractStaxSamlProtocolParser<T> {
+
+    protected static final String VERSION_2_0 = "2.0";
+
+    protected SAMLRequestAbstractParser(SAMLProtocolQNames expectedStartElement) {
+        super(expectedStartElement);
+    }
+
+    /**
+     * Parse the attributes that are common to all SAML Request Types
+     *
+     * @param startElement
+     * @param request
+     *
+     * @throws ParsingException
+     */
+    protected void parseBaseAttributes(StartElement startElement, T request) throws ParsingException {
+        request.setDestination(StaxParserUtil.getUriAttributeValue(startElement, SAMLProtocolQNames.ATTR_DESTINATION));
+        request.setConsent(StaxParserUtil.getAttributeValue(startElement, SAMLProtocolQNames.ATTR_CONSENT));
+    }
+
+    /**
+     * If the current element is one of the common request elements (Issuer, Signature, Extensions), parses it.
+     * @param element
+     * @param xmlEventReader
+     * @param request
+     * @throws ParsingException
+     */
+    protected void parseCommonElements(SAMLProtocolQNames element, StartElement elementDetail, XMLEventReader xmlEventReader, RequestAbstractType request)
+            throws ParsingException {
+        switch (element) {
+            case ISSUER:
+                request.setIssuer(SAMLParserUtil.parseNameIDType(xmlEventReader));
+                break;
+
+            case SIGNATURE:
+                request.setSignature(StaxParserUtil.getDOMElement(xmlEventReader));
+                break;
+            
+            case EXTENSIONS:
+                request.setExtensions(SAMLExtensionsParser.getInstance().parse(xmlEventReader));
+                break;
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLRequestedAuthnContextParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLRequestedAuthnContextParser.java
new file mode 100644
index 0000000..550612b
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLRequestedAuthnContextParser.java
@@ -0,0 +1,85 @@
+/*
+ * 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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.dom.saml.v2.protocol.AuthnContextComparisonType;
+import org.keycloak.dom.saml.v2.protocol.RequestedAuthnContextType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * Parse the SAML2 RequestedAuthnContext
+ *
+ * @since Nov 2, 2010
+ */
+public class SAMLRequestedAuthnContextParser extends AbstractStaxSamlProtocolParser<RequestedAuthnContextType> {
+
+    private static final SAMLRequestedAuthnContextParser INSTANCE = new SAMLRequestedAuthnContextParser();
+
+    private SAMLRequestedAuthnContextParser() {
+        super(SAMLProtocolQNames.REQUESTED_AUTHN_CONTEXT);
+    }
+
+    public static SAMLRequestedAuthnContextParser getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * Parse the attributes at the authnrequesttype element
+     *
+     * @param startElement
+     *
+     * @return
+     *
+     * @throws ParsingException
+     */
+    @Override
+    protected RequestedAuthnContextType instantiateElement(XMLEventReader xmlEventReader, StartElement startElement) throws ParsingException {
+        RequestedAuthnContextType context = new RequestedAuthnContextType();
+
+        Attribute comparison = startElement.getAttributeByName(SAMLProtocolQNames.ATTR_COMPARISON.getQName());
+        if (comparison != null) {
+            context.setComparison(AuthnContextComparisonType.fromValue(comparison.getValue()));
+        }
+
+        return context;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, RequestedAuthnContextType target, SAMLProtocolQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case AUTHN_CONTEXT_CLASS_REF:
+                StaxParserUtil.advance(xmlEventReader);
+                String value = StaxParserUtil.getElementText(xmlEventReader);
+                target.addAuthnContextClassRef(value);
+                break;
+
+            case AUTHN_CONTEXT_DECL_REF:
+                StaxParserUtil.advance(xmlEventReader);
+                value = StaxParserUtil.getElementText(xmlEventReader);
+                target.addAuthnContextDeclRef(value);
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLResponseParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLResponseParser.java
new file mode 100755
index 0000000..5a30e9b
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLResponseParser.java
@@ -0,0 +1,96 @@
+/*
+ * 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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.dom.saml.v2.protocol.ResponseType;
+import org.keycloak.dom.saml.v2.protocol.ResponseType.RTChoiceType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
+import org.w3c.dom.Element;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAssertionParser;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLEncryptedAssertionParser;
+import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+/**
+ * Parse the SAML Response
+ *
+ * @since Nov 2, 2010
+ */
+public class SAMLResponseParser extends SAMLStatusResponseTypeParser<ResponseType> {
+
+    private static final SAMLResponseParser INSTANCE = new SAMLResponseParser();
+
+    private SAMLResponseParser() {
+        super(SAMLProtocolQNames.RESPONSE);
+    }
+
+    public static SAMLResponseParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected ResponseType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        SAMLParserUtil.validateAttributeValue(element, SAMLProtocolQNames.ATTR_VERSION, VERSION_2_0);
+        String id = StaxParserUtil.getRequiredAttributeValue(element, SAMLProtocolQNames.ATTR_ID);
+        XMLGregorianCalendar issueInstant = XMLTimeUtil.parse(StaxParserUtil.getRequiredAttributeValue(element, SAMLProtocolQNames.ATTR_ISSUE_INSTANT));
+
+        ResponseType res = new ResponseType(id, issueInstant);
+
+        // Let us set the attributes
+        super.parseBaseAttributes(element, res);
+
+        return res;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, ResponseType target, SAMLProtocolQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case ISSUER:
+                target.setIssuer(SAMLParserUtil.parseNameIDType(xmlEventReader));
+                break;
+
+            case SIGNATURE:
+                Element sig = StaxParserUtil.getDOMElement(xmlEventReader);
+                target.setSignature(sig);
+                break;
+
+            case ASSERTION:
+                target.addAssertion(new RTChoiceType(SAMLAssertionParser.getInstance().parse(xmlEventReader)));
+                break;
+
+            case EXTENSIONS:
+                target.setExtensions(SAMLExtensionsParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case STATUS:
+                target.setStatus(SAMLStatusParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case ENCRYPTED_ASSERTION:
+                target.addAssertion(new RTChoiceType(SAMLEncryptedAssertionParser.getInstance().parse(xmlEventReader)));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLSloRequestParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLSloRequestParser.java
new file mode 100755
index 0000000..d1da7cf
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLSloRequestParser.java
@@ -0,0 +1,94 @@
+/*
+ * 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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.dom.saml.v2.assertion.EncryptedElementType;
+import org.keycloak.dom.saml.v2.assertion.NameIDType;
+import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
+
+import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
+import javax.xml.datatype.XMLGregorianCalendar;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+import org.w3c.dom.Element;
+import static org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLRequestAbstractParser.VERSION_2_0;
+
+/**
+ * Parse the Single Log Out requests
+ *
+ * @since Nov 3, 2010
+ */
+public class SAMLSloRequestParser extends SAMLRequestAbstractParser<LogoutRequestType> {
+
+    private static final SAMLSloRequestParser INSTANCE = new SAMLSloRequestParser();
+
+    private SAMLSloRequestParser() {
+        super(SAMLProtocolQNames.LOGOUT_REQUEST);
+    }
+
+    public static SAMLSloRequestParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected LogoutRequestType instantiateElement(XMLEventReader xmlEventReader, StartElement startElement) throws ParsingException {
+        SAMLParserUtil.validateAttributeValue(startElement, SAMLProtocolQNames.ATTR_VERSION, VERSION_2_0);
+        String id = StaxParserUtil.getRequiredAttributeValue(startElement, SAMLProtocolQNames.ATTR_ID);
+        XMLGregorianCalendar issueInstant = XMLTimeUtil.parse(StaxParserUtil.getRequiredAttributeValue(startElement, SAMLProtocolQNames.ATTR_ISSUE_INSTANT));
+
+        LogoutRequestType logoutRequest = new LogoutRequestType(id, issueInstant);
+        super.parseBaseAttributes(startElement, logoutRequest);
+
+        logoutRequest.setReason(StaxParserUtil.getAttributeValue(startElement, SAMLProtocolQNames.ATTR_REASON));
+        logoutRequest.setNotOnOrAfter(StaxParserUtil.getXmlTimeAttributeValue(startElement, SAMLProtocolQNames.ATTR_NOT_ON_OR_AFTER));
+
+        return logoutRequest;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, LogoutRequestType target,
+      SAMLProtocolQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case ISSUER:
+            case SIGNATURE:
+            case EXTENSIONS:
+                parseCommonElements(element, elementDetail, xmlEventReader, target);
+                break;
+
+            case NAMEID:
+                NameIDType nameID = SAMLParserUtil.parseNameIDType(xmlEventReader);
+                target.setNameID(nameID);
+                break;
+
+            case ENCRYPTED_ID:
+                Element domElement = StaxParserUtil.getDOMElement(xmlEventReader);
+                target.setEncryptedID(new EncryptedElementType(domElement));
+                break;
+
+            case SESSION_INDEX:
+                StaxParserUtil.getNextStartElement(xmlEventReader);
+                target.addSessionIndex(StaxParserUtil.getElementText(xmlEventReader));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLSloResponseParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLSloResponseParser.java
new file mode 100755
index 0000000..7366a9f
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLSloResponseParser.java
@@ -0,0 +1,88 @@
+/*
+ * 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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
+import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
+import javax.xml.datatype.XMLGregorianCalendar;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+import org.w3c.dom.Element;
+import static org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLStatusResponseTypeParser.VERSION_2_0;
+
+/**
+ * Parse the SLO Response
+ *
+ * @since Nov 3, 2010
+ */
+public class SAMLSloResponseParser extends SAMLStatusResponseTypeParser<StatusResponseType> {
+
+    private static final SAMLSloResponseParser INSTANCE = new SAMLSloResponseParser();
+
+    public SAMLSloResponseParser() {
+        super(SAMLProtocolQNames.LOGOUT_RESPONSE);
+    }
+
+    public static SAMLSloResponseParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected StatusResponseType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        SAMLParserUtil.validateAttributeValue(element, SAMLProtocolQNames.ATTR_VERSION, VERSION_2_0);
+        String id = StaxParserUtil.getRequiredAttributeValue(element, SAMLProtocolQNames.ATTR_ID);
+        XMLGregorianCalendar issueInstant = XMLTimeUtil.parse(StaxParserUtil.getRequiredAttributeValue(element, SAMLProtocolQNames.ATTR_ISSUE_INSTANT));
+
+        StatusResponseType res = new StatusResponseType(id, issueInstant);
+
+        // Let us set the attributes
+        super.parseBaseAttributes(element, res);
+
+        return res;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, StatusResponseType target, SAMLProtocolQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case ISSUER:
+                target.setIssuer(SAMLParserUtil.parseNameIDType(xmlEventReader));
+                break;
+
+            case SIGNATURE:
+                Element sig = StaxParserUtil.getDOMElement(xmlEventReader);
+                target.setSignature(sig);
+                break;
+
+            case EXTENSIONS:
+                SAMLExtensionsParser extensionsParser = SAMLExtensionsParser.getInstance();
+                target.setExtensions(extensionsParser.parse(xmlEventReader));
+                break;
+
+            case STATUS:
+                target.setStatus(SAMLStatusParser.getInstance().parse(xmlEventReader));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLStatusCodeParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLStatusCodeParser.java
new file mode 100644
index 0000000..b471381
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLStatusCodeParser.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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.dom.saml.v2.protocol.StatusCodeType;
+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;
+
+/**
+ * Base Class for all Response Type parsing for SAML2
+ *
+ */
+public class SAMLStatusCodeParser extends AbstractStaxSamlProtocolParser<StatusCodeType> {
+
+    private static final SAMLStatusCodeParser INSTANCE = new SAMLStatusCodeParser();
+
+    private SAMLStatusCodeParser() {
+        super(SAMLProtocolQNames.STATUS_CODE);
+    }
+
+    public static SAMLStatusCodeParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected StatusCodeType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        final StatusCodeType res = new StatusCodeType();
+        res.setValue(StaxParserUtil.getUriAttributeValue(element, SAMLProtocolQNames.ATTR_VALUE));
+        return res;
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, StatusCodeType target, SAMLProtocolQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case STATUS_CODE:
+                target.setStatusCode(SAMLStatusCodeParser.getInstance().parse(xmlEventReader));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLStatusParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLStatusParser.java
new file mode 100644
index 0000000..c44993c
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLStatusParser.java
@@ -0,0 +1,78 @@
+/*
+ * 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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.dom.saml.v2.protocol.StatusDetailType;
+import org.keycloak.dom.saml.v2.protocol.StatusType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.parsers.AnyDomParser;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.w3c.dom.Element;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+import java.util.List;
+
+/**
+ * Base Class for all Response Type parsing for SAML2
+ *
+ */
+public class SAMLStatusParser extends AbstractStaxSamlProtocolParser<StatusType> {
+
+    private static final SAMLStatusParser INSTANCE = new SAMLStatusParser();
+    private static final AnyDomParser STATUS_DETAIL_PARSER = AnyDomParser.getInstance(SAMLProtocolQNames.STATUS_DETAIL.getQName());
+
+    private SAMLStatusParser() {
+        super(SAMLProtocolQNames.STATUS);
+    }
+
+    public static SAMLStatusParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected StatusType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        return new StatusType();
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, StatusType target, SAMLProtocolQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case STATUS_CODE:
+                target.setStatusCode(SAMLStatusCodeParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case STATUS_MESSAGE:
+                StaxParserUtil.advance(xmlEventReader);
+                target.setStatusMessage(StaxParserUtil.getElementText(xmlEventReader));
+                break;
+
+            case STATUS_DETAIL:
+                List<Element> elements = STATUS_DETAIL_PARSER.parse(xmlEventReader);
+                
+                StatusDetailType statusDetailType = new StatusDetailType();
+                for (Element e : elements) {
+                    statusDetailType.addStatusDetail(e);
+                }
+                target.setStatusDetail(statusDetailType);
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLStatusResponseTypeParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLStatusResponseTypeParser.java
new file mode 100755
index 0000000..dfc34a7
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/protocol/SAMLStatusResponseTypeParser.java
@@ -0,0 +1,49 @@
+/*
+ * 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.saml.processing.core.parsers.saml.protocol;
+
+import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * Base Class for all Response Type parsing for SAML2
+ *
+ */
+public abstract class SAMLStatusResponseTypeParser<T extends StatusResponseType> extends AbstractStaxSamlProtocolParser<T> {
+
+    protected static final String VERSION_2_0 = "2.0";
+
+    protected SAMLStatusResponseTypeParser(SAMLProtocolQNames expectedStartElement) {
+        super(expectedStartElement);
+    }
+
+    /**
+     * Parse the attributes that are common to all SAML Response Types
+     *
+     * @param startElement
+     * @param response
+     *
+     * @throws org.keycloak.saml.common.exceptions.ParsingException
+     */
+    protected void parseBaseAttributes(StartElement startElement, T response) throws ParsingException {
+        response.setDestination(StaxParserUtil.getAttributeValue(startElement, SAMLProtocolQNames.ATTR_DESTINATION));
+        response.setConsent(StaxParserUtil.getAttributeValue(startElement, SAMLProtocolQNames.ATTR_CONSENT));
+        response.setInResponseTo(StaxParserUtil.getAttributeValue(startElement, SAMLProtocolQNames.ATTR_IN_RESPONSE_TO));
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11AssertionParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11AssertionParser.java
index d239b0f..f5ccb9d 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11AssertionParser.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11AssertionParser.java
@@ -30,7 +30,6 @@ import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
 import org.keycloak.saml.common.exceptions.ConfigurationException;
 import org.keycloak.saml.common.exceptions.ParsingException;
 import org.keycloak.saml.common.exceptions.ProcessingException;
-import org.keycloak.saml.common.parsers.ParserNamespaceSupport;
 import org.keycloak.saml.common.util.DocumentUtil;
 import org.keycloak.saml.common.util.StaxParserUtil;
 import org.keycloak.saml.common.util.StringUtil;
@@ -46,6 +45,7 @@ import javax.xml.stream.events.Attribute;
 import javax.xml.stream.events.EndElement;
 import javax.xml.stream.events.StartElement;
 import javax.xml.stream.events.XMLEvent;
+import org.keycloak.saml.common.parsers.StaxParser;
 
 /**
  * Parse the saml assertion
@@ -53,7 +53,7 @@ import javax.xml.stream.events.XMLEvent;
  * @author Anil.Saldhana@redhat.com
  * @since Oct 12, 2010
  */
-public class SAML11AssertionParser implements ParserNamespaceSupport {
+public class SAML11AssertionParser implements StaxParser {
 
     private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
 
@@ -90,11 +90,11 @@ public class SAML11AssertionParser implements ParserNamespaceSupport {
             if (xmlEvent instanceof EndElement) {
                 xmlEvent = StaxParserUtil.getNextEvent(xmlEventReader);
                 EndElement endElement = (EndElement) xmlEvent;
-                String endElementTag = StaxParserUtil.getEndElementName(endElement);
+                String endElementTag = StaxParserUtil.getElementName(endElement);
                 if (endElementTag.equals(JBossSAMLConstants.ASSERTION.get()))
                     break;
                 else
-                    throw logger.parserUnknownEndElement(endElementTag);
+                    throw logger.parserUnknownEndElement(endElementTag, xmlEvent.getLocation());
             }
 
             StartElement peekedElement = null;
@@ -107,7 +107,7 @@ public class SAML11AssertionParser implements ParserNamespaceSupport {
             if (peekedElement == null)
                 break;
 
-            String tag = StaxParserUtil.getStartElementName(peekedElement);
+            String tag = StaxParserUtil.getElementName(peekedElement);
 
             if (tag.equals(JBossSAMLConstants.SIGNATURE.get())) {
                 assertion.setSignature(StaxParserUtil.getDOMElement(xmlEventReader));
@@ -144,16 +144,6 @@ public class SAML11AssertionParser implements ParserNamespaceSupport {
         return assertion;
     }
 
-    /**
-     * @see {@link ParserNamespaceSupport#supports(QName)}
-     */
-    public boolean supports(QName qname) {
-        String nsURI = qname.getNamespaceURI();
-        String localPart = qname.getLocalPart();
-
-        return nsURI.equals(JBossSAMLURIConstants.ASSERTION_NSURI.get())
-                && localPart.equals(JBossSAMLConstants.ASSERTION.get());
-    }
 
     private SAML11AssertionType parseBaseAttributes(StartElement nextElement) throws ParsingException {
         Attribute idAttribute = nextElement.getAttributeByName(new QName(SAML11Constants.ASSERTIONID));
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11RequestParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11RequestParser.java
index eff7e78..92ecd22 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11RequestParser.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11RequestParser.java
@@ -25,7 +25,6 @@ import org.keycloak.saml.common.PicketLinkLoggerFactory;
 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.parsers.ParserNamespaceSupport;
 import org.keycloak.saml.common.util.StaxParserUtil;
 import org.keycloak.saml.processing.core.parsers.util.SAML11ParserUtil;
 import org.keycloak.saml.processing.core.saml.v1.SAML11Constants;
@@ -36,6 +35,7 @@ import javax.xml.namespace.QName;
 import javax.xml.stream.XMLEventReader;
 import javax.xml.stream.events.Attribute;
 import javax.xml.stream.events.StartElement;
+import org.keycloak.saml.common.parsers.StaxParser;
 
 /**
  * Parse the SAML2 AuthnRequest
@@ -43,7 +43,7 @@ import javax.xml.stream.events.StartElement;
  * @author Anil.Saldhana@redhat.com
  * @since June 24, 2011
  */
-public class SAML11RequestParser implements ParserNamespaceSupport {
+public class SAML11RequestParser implements StaxParser {
 
     private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
 
@@ -77,7 +77,7 @@ public class SAML11RequestParser implements ParserNamespaceSupport {
             if (startElement == null)
                 break;
 
-            String elementName = StaxParserUtil.getStartElementName(startElement);
+            String elementName = StaxParserUtil.getElementName(startElement);
 
             if (SAML11Constants.ATTRIBUTE_QUERY.equals(elementName)) {
                 startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
@@ -106,10 +106,4 @@ public class SAML11RequestParser implements ParserNamespaceSupport {
         return request;
     }
 
-    /**
-     * @see {@link ParserNamespaceSupport#supports(QName)}
-     */
-    public boolean supports(QName qname) {
-        return JBossSAMLURIConstants.PROTOCOL_NSURI.get().equals(qname.getNamespaceURI());
-    }
 }
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11ResponseParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11ResponseParser.java
index b75fb30..eea572b 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11ResponseParser.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11ResponseParser.java
@@ -25,7 +25,6 @@ import org.keycloak.saml.common.PicketLinkLogger;
 import org.keycloak.saml.common.PicketLinkLoggerFactory;
 import org.keycloak.saml.common.constants.JBossSAMLConstants;
 import org.keycloak.saml.common.exceptions.ParsingException;
-import org.keycloak.saml.common.parsers.ParserNamespaceSupport;
 import org.keycloak.saml.common.util.StaxParserUtil;
 import org.keycloak.saml.processing.core.saml.v1.SAML11Constants;
 import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
@@ -38,6 +37,7 @@ import javax.xml.stream.events.Attribute;
 import javax.xml.stream.events.EndElement;
 import javax.xml.stream.events.StartElement;
 import javax.xml.stream.events.XMLEvent;
+import org.keycloak.saml.common.parsers.StaxParser;
 
 /**
  * Parse the SAML 11 Response
@@ -45,11 +45,11 @@ import javax.xml.stream.events.XMLEvent;
  * @author Anil.Saldhana@redhat.com
  * @since 23 June 2011
  */
-public class SAML11ResponseParser implements ParserNamespaceSupport {
+public class SAML11ResponseParser implements StaxParser {
 
     private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
 
-    private final String RESPONSE = JBossSAMLConstants.RESPONSE.get();
+    private final String RESPONSE = JBossSAMLConstants.RESPONSE__PROTOCOL.get();
 
     /**
      * @see {@link ParserNamespaceSupport#parse(XMLEventReader)}
@@ -76,7 +76,7 @@ public class SAML11ResponseParser implements ParserNamespaceSupport {
             startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
             if (startElement == null)
                 break;
-            String elementName = StaxParserUtil.getStartElementName(startElement);
+            String elementName = StaxParserUtil.getElementName(startElement);
             if (JBossSAMLConstants.SIGNATURE.get().equals(elementName)) {
                 Element sig = StaxParserUtil.getDOMElement(xmlEventReader);
                 response.setSignature(sig);
@@ -172,17 +172,11 @@ public class SAML11ResponseParser implements ParserNamespaceSupport {
                 if (StaxParserUtil.matches(endElement, STATUS))
                     break;
                 else
-                    throw logger.parserUnknownEndElement(StaxParserUtil.getEndElementName(endElement));
+                    throw logger.parserUnknownEndElement(StaxParserUtil.getElementName(endElement), xmlEvent.getLocation());
             } else
                 break;
         }
         return status;
     }
 
-    /**
-     * @see {@link ParserNamespaceSupport#supports(QName)}
-     */
-    public boolean supports(QName qname) {
-        return SAML11Constants.PROTOCOL_11_NSURI.equals(qname.getNamespaceURI()) && RESPONSE.equals(qname.getLocalPart());
-    }
 }
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11SubjectParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11SubjectParser.java
index fbfd58e..7839262 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11SubjectParser.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAML11SubjectParser.java
@@ -25,7 +25,6 @@ import org.keycloak.saml.common.PicketLinkLoggerFactory;
 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.parsers.ParserNamespaceSupport;
 import org.keycloak.saml.common.util.StaxParserUtil;
 import org.keycloak.saml.processing.core.parsers.util.SAML11ParserUtil;
 import org.keycloak.saml.processing.core.saml.v1.SAML11Constants;
@@ -37,6 +36,7 @@ import javax.xml.stream.events.EndElement;
 import javax.xml.stream.events.StartElement;
 import javax.xml.stream.events.XMLEvent;
 import java.net.URI;
+import org.keycloak.saml.common.parsers.StaxParser;
 
 /**
  * Parse the saml subject
@@ -44,7 +44,7 @@ import java.net.URI;
  * @author Anil.Saldhana@redhat.com
  * @since Oct 12, 2010
  */
-public class SAML11SubjectParser implements ParserNamespaceSupport {
+public class SAML11SubjectParser implements StaxParser {
 
     private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
 
@@ -65,14 +65,14 @@ public class SAML11SubjectParser implements ParserNamespaceSupport {
                     endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
                     break;
                 } else
-                    throw logger.parserUnknownEndElement(StaxParserUtil.getEndElementName(endElement));
+                    throw logger.parserUnknownEndElement(StaxParserUtil.getElementName(endElement), xmlEvent.getLocation());
             }
 
             StartElement peekedElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
             if (peekedElement == null)
                 break;
 
-            String tag = StaxParserUtil.getStartElementName(peekedElement);
+            String tag = StaxParserUtil.getElementName(peekedElement);
 
             if (SAML11Constants.NAME_IDENTIFIER.equalsIgnoreCase(tag)) {
                 peekedElement = StaxParserUtil.getNextStartElement(xmlEventReader);
@@ -100,14 +100,5 @@ public class SAML11SubjectParser implements ParserNamespaceSupport {
         return subject;
     }
 
-    /**
-     * @see {@link ParserNamespaceSupport#supports(QName)}
-     */
-    public boolean supports(QName qname) {
-        String nsURI = qname.getNamespaceURI();
-        String localPart = qname.getLocalPart();
-
-        return nsURI.equals(JBossSAMLURIConstants.ASSERTION_NSURI.get()) && localPart.equals(JBossSAMLConstants.SUBJECT.get());
-    }
 
 }
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParser.java
index b34d404..b469547 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParser.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParser.java
@@ -16,113 +16,118 @@
  */
 package org.keycloak.saml.processing.core.parsers.saml;
 
+import org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLAttributeQueryParser;
+import org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLSloRequestParser;
+import org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLSloResponseParser;
+import org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLArtifactResolveParser;
+import org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLArtifactResponseParser;
+import org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLResponseParser;
+import org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLAuthNRequestParser;
 import org.keycloak.saml.common.ErrorCodes;
 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.parsers.AbstractParser;
 import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAssertionParser;
 import org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLEntitiesDescriptorParser;
 import org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLEntityDescriptorParser;
+import org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLProtocolQNames;
 import org.keycloak.saml.processing.core.saml.v1.SAML11Constants;
 
+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;
+import org.keycloak.saml.common.parsers.StaxParser;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAssertionQNames;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAuthnStatementParser;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLEncryptedAssertionParser;
+import java.io.InputStream;
 
 /**
  * Parse SAML payload
  *
- * @author Anil.Saldhana@redhat.com
  * @since Oct 12, 2010
  */
 public class SAMLParser extends AbstractParser {
 
+    private static final SAMLEntityDescriptorParser SAML_ENTITY_DESCRIPTOR_PARSER = new SAMLEntityDescriptorParser();
+    private static final SAMLEntitiesDescriptorParser SAML_ENTITIES_DESCRIPTOR_PARSER = new SAMLEntitiesDescriptorParser();
+    private static final SAML11ResponseParser SAML_11_RESPONSE_PARSER = new SAML11ResponseParser();
+    private static final SAML11RequestParser SAML_11_REQUEST_PARSER = new SAML11RequestParser();
+
+    private static final QName SAML_11_ASSERTION = new QName(SAML11Constants.ASSERTION_11_NSURI, JBossSAMLConstants.ASSERTION.get());
+    private static final QName SAML_11_ENCRYPTED_ASSERTION = new QName(SAML11Constants.ASSERTION_11_NSURI, JBossSAMLConstants.ENCRYPTED_ASSERTION.get());
+    private static final QName SAML_11_RESPONSE = new QName(SAML11Constants.ASSERTION_11_NSURI, JBossSAMLConstants.RESPONSE__PROTOCOL.get());
+    private static final QName SAML_11_REQUEST = new QName(SAML11Constants.ASSERTION_11_NSURI, JBossSAMLConstants.REQUEST.get());
+
+    // Since we have to support JDK 7, no lambdas are available
+    private interface ParserFactory {
+        public StaxParser create();
+    }
+    private static final Map<QName, ParserFactory> PARSERS = new HashMap<QName, ParserFactory>();
+
+    static {
+        PARSERS.put(SAML_11_ASSERTION, new ParserFactory() { @Override public StaxParser create() { return new SAML11AssertionParser(); }});
+        PARSERS.put(SAML_11_ENCRYPTED_ASSERTION, new ParserFactory() { @Override public StaxParser create() { return new SAML11AssertionParser(); }});
+        PARSERS.put(SAML_11_RESPONSE, new ParserFactory() { @Override public StaxParser create() { return SAML_11_RESPONSE_PARSER; }});
+        PARSERS.put(SAML_11_REQUEST, new ParserFactory() { @Override public StaxParser create() { return SAML_11_REQUEST_PARSER; }});
+
+        PARSERS.put(SAMLProtocolQNames.AUTHN_REQUEST.getQName(),      new ParserFactory() { @Override public StaxParser create() { return SAMLAuthNRequestParser.getInstance(); }});
+        PARSERS.put(SAMLProtocolQNames.RESPONSE.getQName(),           new ParserFactory() { @Override public StaxParser create() { return SAMLResponseParser.getInstance(); }});
+        PARSERS.put(SAMLProtocolQNames.LOGOUT_REQUEST.getQName(),     new ParserFactory() { @Override public StaxParser create() { return SAMLSloRequestParser.getInstance(); }});
+        PARSERS.put(SAMLProtocolQNames.LOGOUT_RESPONSE.getQName(),    new ParserFactory() { @Override public StaxParser create() { return SAMLSloResponseParser.getInstance(); }});
+
+        PARSERS.put(SAMLProtocolQNames.ARTIFACT_RESOLVE.getQName(),   new ParserFactory() { @Override public StaxParser create() { return SAMLArtifactResolveParser.getInstance(); }});
+        PARSERS.put(SAMLProtocolQNames.ARTIFACT_RESPONSE.getQName(),  new ParserFactory() { @Override public StaxParser create() { return SAMLArtifactResponseParser.getInstance(); }});
+
+        PARSERS.put(SAMLProtocolQNames.ASSERTION.getQName(),          new ParserFactory() { @Override public StaxParser create() { return SAMLAssertionParser.getInstance(); }});
+        PARSERS.put(SAMLProtocolQNames.ENCRYPTED_ASSERTION.getQName(),new ParserFactory() { @Override public StaxParser create() { return SAMLEncryptedAssertionParser.getInstance(); }});
+
+        PARSERS.put(SAMLAssertionQNames.AUTHN_STATEMENT.getQName(),   new ParserFactory() { @Override public StaxParser create() { return SAMLAuthnStatementParser.getInstance(); }});
+
+        // TODO: Change to SamlMetadataElements
+        PARSERS.put(JBossSAMLConstants.ENTITY_DESCRIPTOR.getAsQName(),  new ParserFactory() { @Override public StaxParser create() { return SAML_ENTITY_DESCRIPTOR_PARSER; }});
+        PARSERS.put(JBossSAMLConstants.ENTITIES_DESCRIPTOR.getAsQName(),new ParserFactory() { @Override public StaxParser create() { return SAML_ENTITIES_DESCRIPTOR_PARSER; }});
+
+        PARSERS.put(SAMLProtocolQNames.ATTRIBUTE_QUERY.getQName(),    new ParserFactory() { @Override public StaxParser create() { return SAMLAttributeQueryParser.getInstance(); }});
+    }
+
+    private static final SAMLParser INSTANCE = new SAMLParser();
+
+    public static SAMLParser getInstance() {
+        return INSTANCE;
+    }
+
+    protected SAMLParser() {
+    }
+
     /**
      * @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;
-                QName startElementName = startElement.getName();
-                String nsURI = startElementName.getNamespaceURI();
-
-                String localPart = startElementName.getLocalPart();
-
-                String elementName = StaxParserUtil.getStartElementName(startElement);
-
-                if (elementName.equalsIgnoreCase(JBossSAMLConstants.ASSERTION.get())
-                        || elementName.equals(JBossSAMLConstants.ENCRYPTED_ASSERTION.get())) {
-                    if (nsURI.equals(SAML11Constants.ASSERTION_11_NSURI)) {
-                        SAML11AssertionParser saml11AssertionParser = new SAML11AssertionParser();
-                        return saml11AssertionParser.parse(xmlEventReader);
-                    }
-                    SAMLAssertionParser assertionParser = new SAMLAssertionParser();
-                    return assertionParser.parse(xmlEventReader);
-                } else if (JBossSAMLURIConstants.PROTOCOL_NSURI.get().equals(nsURI)
-                        && JBossSAMLConstants.AUTHN_REQUEST.get().equals(startElementName.getLocalPart())) {
-                    SAMLAuthNRequestParser authNRequestParser = new SAMLAuthNRequestParser();
-                    return authNRequestParser.parse(xmlEventReader);
-                } else if (JBossSAMLURIConstants.PROTOCOL_NSURI.get().equals(nsURI)
-                        && JBossSAMLConstants.LOGOUT_REQUEST.get().equals(startElementName.getLocalPart())) {
-                    SAMLSloRequestParser sloParser = new SAMLSloRequestParser();
-                    return sloParser.parse(xmlEventReader);
-                } else if (JBossSAMLURIConstants.PROTOCOL_NSURI.get().equals(nsURI)
-                        && JBossSAMLConstants.LOGOUT_RESPONSE.get().equals(startElementName.getLocalPart())) {
-                    SAMLSloResponseParser sloParser = new SAMLSloResponseParser();
-                    return sloParser.parse(xmlEventReader);
-                } else if (JBossSAMLURIConstants.PROTOCOL_NSURI.get().equals(nsURI)
-                        && JBossSAMLConstants.RESPONSE.get().equals(startElementName.getLocalPart())) {
-                    SAMLResponseParser responseParser = new SAMLResponseParser();
-                    return responseParser.parse(xmlEventReader);
-                } else if (JBossSAMLURIConstants.PROTOCOL_NSURI.get().equals(nsURI)
-                        && JBossSAMLConstants.REQUEST_ABSTRACT.get().equals(startElementName.getLocalPart())) {
-                    String xsiTypeValue = StaxParserUtil.getXSITypeValue(startElement);
-                    throw new RuntimeException(ErrorCodes.UNKNOWN_XSI + xsiTypeValue);
-                } else if (JBossSAMLURIConstants.PROTOCOL_NSURI.get().equals(nsURI)
-                        && JBossSAMLConstants.ARTIFACT_RESOLVE.get().equals(startElementName.getLocalPart())) {
-                    SAMLArtifactResolveParser artifactResolverParser = new SAMLArtifactResolveParser();
-                    return artifactResolverParser.parse(xmlEventReader);
-                } else if (JBossSAMLURIConstants.PROTOCOL_NSURI.get().equals(nsURI)
-                        && JBossSAMLConstants.ARTIFACT_RESPONSE.get().equals(startElementName.getLocalPart())) {
-                    SAMLArtifactResponseParser responseParser = new SAMLArtifactResponseParser();
-                    return responseParser.parse(xmlEventReader);
-                } else if (JBossSAMLURIConstants.PROTOCOL_NSURI.get().equals(nsURI)
-                        && JBossSAMLConstants.ATTRIBUTE_QUERY.get().equals(startElementName.getLocalPart())) {
-                    SAMLAttributeQueryParser responseParser = new SAMLAttributeQueryParser();
-                    return responseParser.parse(xmlEventReader);
-                } else if (JBossSAMLConstants.ENTITY_DESCRIPTOR.get().equals(localPart)) {
-                    SAMLEntityDescriptorParser entityDescriptorParser = new SAMLEntityDescriptorParser();
-                    return entityDescriptorParser.parse(xmlEventReader);
-                } else if (JBossSAMLConstants.ENTITIES_DESCRIPTOR.get().equals(localPart)) {
-                    SAMLEntitiesDescriptorParser entityDescriptorParser = new SAMLEntitiesDescriptorParser();
-                    return entityDescriptorParser.parse(xmlEventReader);
-                } else if (SAML11Constants.PROTOCOL_11_NSURI.equals(nsURI)
-                        && JBossSAMLConstants.RESPONSE.get().equals(startElementName.getLocalPart())) {
-                    SAML11ResponseParser responseParser = new SAML11ResponseParser();
-                    return responseParser.parse(xmlEventReader);
-                } else if (SAML11Constants.PROTOCOL_11_NSURI.equals(nsURI)
-                        && SAML11Constants.REQUEST.equals(startElementName.getLocalPart())) {
-                    SAML11RequestParser reqParser = new SAML11RequestParser();
-                    return reqParser.parse(xmlEventReader);
-                } else
-                    throw new RuntimeException(ErrorCodes.UNKNOWN_START_ELEMENT + elementName + "::location="
-                            + startElement.getLocation());
-            } else {
-                StaxParserUtil.getNextEvent(xmlEventReader);
+                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");
-    }
 
-    /**
-     * @see {@link org.keycloak.saml.common.parsers.ParserNamespaceSupport#supports(QName)}
-     */
-    public boolean supports(QName qname) {
-        return JBossSAMLURIConstants.ASSERTION_NSURI.get().equals(qname.getNamespaceURI());
+        throw new RuntimeException(ErrorCodes.FAILED_PARSING + "SAML Parsing has failed");
     }
 }
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/AbstractStaxXmlDSigParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/AbstractStaxXmlDSigParser.java
new file mode 100644
index 0000000..0d691d9
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/AbstractStaxXmlDSigParser.java
@@ -0,0 +1,40 @@
+/*
+ * 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.saml.processing.core.parsers.saml.xmldsig;
+
+import org.keycloak.saml.common.parsers.AbstractStaxParser;
+import org.keycloak.saml.processing.core.parsers.util.QNameEnumLookup;
+import javax.xml.namespace.QName;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public abstract class AbstractStaxXmlDSigParser<T> extends AbstractStaxParser<T, XmlDSigQNames> {
+
+    protected static final QNameEnumLookup<XmlDSigQNames> LOOKUP = new QNameEnumLookup(XmlDSigQNames.values());
+
+    public AbstractStaxXmlDSigParser(XmlDSigQNames expectedStartElement) {
+        super(expectedStartElement.getQName(), XmlDSigQNames.UNKNOWN_ELEMENT);
+    }
+
+    @Override
+    protected XmlDSigQNames getElementFromName(QName name) {
+        return LOOKUP.from(name);
+    }
+
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/DsaKeyValueParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/DsaKeyValueParser.java
new file mode 100644
index 0000000..4c4c48c
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/DsaKeyValueParser.java
@@ -0,0 +1,94 @@
+/*
+ * 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.saml.processing.core.parsers.saml.xmldsig;
+
+import org.keycloak.dom.xmlsec.w3.xmldsig.DSAKeyValueType;
+import org.keycloak.saml.common.constants.GeneralConstants;
+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;
+
+public class DsaKeyValueParser extends AbstractStaxXmlDSigParser<DSAKeyValueType> {
+
+    public static final DsaKeyValueParser INSTANCE = new DsaKeyValueParser();
+
+    private DsaKeyValueParser() {
+        super(XmlDSigQNames.DSA_KEY_VALUE);
+    }
+
+    public static DsaKeyValueParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected DSAKeyValueType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        return new DSAKeyValueType();
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, DSAKeyValueType target, XmlDSigQNames element, StartElement elementDetail) throws ParsingException {
+        String text;
+        switch (element) {
+            case P:
+                StaxParserUtil.advance(xmlEventReader);
+                text = StaxParserUtil.getElementText(xmlEventReader);
+                target.setP(text.getBytes(GeneralConstants.SAML_CHARSET));
+                break;
+
+            case Q:
+                StaxParserUtil.advance(xmlEventReader);
+                text = StaxParserUtil.getElementText(xmlEventReader);
+                target.setQ(text.getBytes(GeneralConstants.SAML_CHARSET));
+                break;
+
+            case G:
+                StaxParserUtil.advance(xmlEventReader);
+                text = StaxParserUtil.getElementText(xmlEventReader);
+                target.setG(text.getBytes(GeneralConstants.SAML_CHARSET));
+                break;
+
+            case Y:
+                StaxParserUtil.advance(xmlEventReader);
+                text = StaxParserUtil.getElementText(xmlEventReader);
+                target.setY(text.getBytes(GeneralConstants.SAML_CHARSET));
+                break;
+
+            case J:
+                StaxParserUtil.advance(xmlEventReader);
+                text = StaxParserUtil.getElementText(xmlEventReader);
+                target.setJ(text.getBytes(GeneralConstants.SAML_CHARSET));
+                break;
+
+            case SEED:
+                StaxParserUtil.advance(xmlEventReader);
+                text = StaxParserUtil.getElementText(xmlEventReader);
+                target.setSeed(text.getBytes(GeneralConstants.SAML_CHARSET));
+                break;
+
+            case PGEN_COUNTER:
+                StaxParserUtil.advance(xmlEventReader);
+                text = StaxParserUtil.getElementText(xmlEventReader);
+                target.setPgenCounter(text.getBytes(GeneralConstants.SAML_CHARSET));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/KeyInfoParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/KeyInfoParser.java
new file mode 100644
index 0000000..ee2dd34
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/KeyInfoParser.java
@@ -0,0 +1,78 @@
+/*
+ * 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.saml.processing.core.parsers.saml.xmldsig;
+
+import org.keycloak.dom.xmlsec.w3.xmldsig.KeyInfoType;
+import org.keycloak.dom.xmlsec.w3.xmldsig.KeyValueType;
+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;
+
+public class KeyInfoParser extends AbstractStaxXmlDSigParser<KeyInfoType> {
+
+    public static final KeyInfoParser INSTANCE = new KeyInfoParser();
+
+    private KeyInfoParser() {
+        super(XmlDSigQNames.KEY_INFO);
+    }
+
+    public static KeyInfoParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected KeyInfoType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        return new KeyInfoType();
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, KeyInfoType target, XmlDSigQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case X509_DATA:
+                target.addContent(X509DataParser.getInstance().parse(xmlEventReader));
+                break;
+
+            case KEY_VALUE:
+                StaxParserUtil.advance(xmlEventReader);
+                StartElement startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
+                KeyValueType keyValue;
+
+                switch (LOOKUP.from(startElement.getName())) {
+                    case RSA_KEY_VALUE:
+                        keyValue = RsaKeyValueParser.getInstance().parse(xmlEventReader);
+                        break;
+
+                    case DSA_KEY_VALUE:
+                        keyValue = DsaKeyValueParser.getInstance().parse(xmlEventReader);
+                        break;
+
+                    default:
+                        String tag = StaxParserUtil.getElementName(startElement);
+                        throw LOGGER.parserUnknownTag(tag, elementDetail.getLocation());
+                }
+
+                target.addContent(keyValue);
+                break;
+
+            default:
+                // Ignore unknown tags
+                StaxParserUtil.bypassElementBlock(xmlEventReader);
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/RsaKeyValueParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/RsaKeyValueParser.java
new file mode 100644
index 0000000..fbb8b13
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/RsaKeyValueParser.java
@@ -0,0 +1,64 @@
+/*
+ * 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.saml.processing.core.parsers.saml.xmldsig;
+
+import org.keycloak.dom.xmlsec.w3.xmldsig.RSAKeyValueType;
+import org.keycloak.saml.common.constants.GeneralConstants;
+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;
+
+public class RsaKeyValueParser extends AbstractStaxXmlDSigParser<RSAKeyValueType> {
+
+    public static final RsaKeyValueParser INSTANCE = new RsaKeyValueParser();
+
+    private RsaKeyValueParser() {
+        super(XmlDSigQNames.RSA_KEY_VALUE);
+    }
+
+    public static RsaKeyValueParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected RSAKeyValueType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        return new RSAKeyValueType();
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, RSAKeyValueType target, XmlDSigQNames element, StartElement elementDetail) throws ParsingException {
+        String text;
+        switch (element) {
+            case MODULUS:
+                StaxParserUtil.advance(xmlEventReader);
+                text = StaxParserUtil.getElementText(xmlEventReader);
+                target.setModulus(text.getBytes(GeneralConstants.SAML_CHARSET));
+                break;
+
+            case EXPONENT:
+                StaxParserUtil.advance(xmlEventReader);
+                text = StaxParserUtil.getElementText(xmlEventReader);
+                target.setExponent(text.getBytes(GeneralConstants.SAML_CHARSET));
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/X509DataParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/X509DataParser.java
new file mode 100644
index 0000000..bbd339b
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/X509DataParser.java
@@ -0,0 +1,66 @@
+/*
+ * 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.saml.processing.core.parsers.saml.xmldsig;
+
+import org.keycloak.dom.xmlsec.w3.xmldsig.X509CertificateType;
+import org.keycloak.dom.xmlsec.w3.xmldsig.X509DataType;
+import org.keycloak.saml.common.constants.GeneralConstants;
+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;
+
+/**
+ * Base Class for all Response Type parsing for SAML2
+ *
+ */
+public class X509DataParser extends AbstractStaxXmlDSigParser<X509DataType> {
+
+    private static final X509DataParser INSTANCE = new X509DataParser();
+
+    public X509DataParser() {
+        super(XmlDSigQNames.X509_DATA);
+    }
+
+    public static X509DataParser getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    protected X509DataType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+        return new X509DataType();
+    }
+
+    @Override
+    protected void processSubElement(XMLEventReader xmlEventReader, X509DataType target, XmlDSigQNames element, StartElement elementDetail) throws ParsingException {
+        switch (element) {
+            case X509_CERTIFICATE:
+                StaxParserUtil.advance(xmlEventReader);
+                String certValue = StaxParserUtil.getElementText(xmlEventReader);
+
+                X509CertificateType cert = new X509CertificateType();
+                cert.setEncodedCertificate(certValue.getBytes(GeneralConstants.SAML_CHARSET));
+                target.add(cert);
+                
+                break;
+
+            default:
+                throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+        }
+    }
+}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/XmlDSigQNames.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/XmlDSigQNames.java
new file mode 100644
index 0000000..db9197f
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/xmldsig/XmlDSigQNames.java
@@ -0,0 +1,96 @@
+/*
+ * 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.saml.processing.core.parsers.saml.xmldsig;
+
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import javax.xml.namespace.QName;
+import org.keycloak.saml.processing.core.parsers.util.HasQName;
+
+/**
+ * Elements from saml-schema-protocol-2.0.xsd
+ * @author hmlnarik
+ */
+public enum XmlDSigQNames implements HasQName {
+
+    CANONICALIZATION_METHOD("CanonicalizationMethod"),
+    DIGEST_METHOD("DigestMethod"),
+    DIGEST_VALUE("DigestValue"),
+    DSA_KEY_VALUE("DSAKeyValue"),
+    EXPONENT("Exponent"),
+    G("G"),
+    HMAC_OUTPUT_LENGTH("HMACOutputLength"),
+    J("J"),
+    KEY_INFO("KeyInfo"),
+    KEY_NAME("KeyName"),
+    KEY_VALUE("KeyValue"),
+    MANIFEST("Manifest"),
+    MGMT_DATA("MgmtData"),
+    MODULUS("Modulus"),
+    OBJECT("Object"),
+    PGEN_COUNTER("PgenCounter"),
+    PGP_DATA("PGPData"),
+    PGP_KEY_ID("PGPKeyID"),
+    PGP_KEY_PACKET("PGPKeyPacket"),
+    P("P"),
+    Q("Q"),
+    REFERENCE("Reference"),
+    RETRIEVAL_METHOD("RetrievalMethod"),
+    RSA_KEY_VALUE("RSAKeyValue"),
+    SEED("Seed"),
+    SIGNATURE_METHOD("SignatureMethod"),
+    SIGNATURE_PROPERTIES("SignatureProperties"),
+    SIGNATURE_PROPERTY("SignatureProperty"),
+    SIGNATURE("Signature"),
+    SIGNATURE_VALUE("SignatureValue"),
+    SIGNED_INFO("SignedInfo"),
+    SPKI_DATA("SPKIData"),
+    SPKIS_EXP("SPKISexp"),
+    TRANSFORMS("Transforms"),
+    TRANSFORM("Transform"),
+    XPATH("XPath"),
+    X509_CERTIFICATE("X509Certificate"),
+    X509_CRL("X509CRL"),
+    X509_DATA("X509Data"),
+    X509_ISSUER_NAME("X509IssuerName"),
+    X509_ISSUER_SERIAL("X509IssuerSerial"),
+    X509_SERIAL_NUMBER("X509SerialNumber"),
+    X509_SKI("X509SKI"),
+    X509_SUBJECT_NAME("X509SubjectName"),
+    Y("Y"),
+
+    UNKNOWN_ELEMENT("")
+    ;
+
+    private final QName qName;
+
+    private XmlDSigQNames(String localName) {
+        this(JBossSAMLURIConstants.XMLDSIG_NSURI, localName);
+    }
+
+    private XmlDSigQNames(HasQName source) {
+        this.qName = source.getQName();
+    }
+
+    private XmlDSigQNames(JBossSAMLURIConstants nsUri, String localName) {
+        this.qName = new QName(nsUri == null ? null : nsUri.get(), localName);
+    }
+
+    @Override
+    public QName getQName() {
+        return qName;
+    }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/HasQName.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/HasQName.java
new file mode 100644
index 0000000..e3254e8
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/HasQName.java
@@ -0,0 +1,29 @@
+/*
+ * 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.saml.processing.core.parsers.util;
+
+import javax.xml.namespace.QName;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public interface HasQName {
+
+    QName getQName();
+
+}
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
new file mode 100644
index 0000000..9a585f4
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/QNameEnumLookup.java
@@ -0,0 +1,64 @@
+/*
+ * 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.saml.processing.core.parsers.util;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public class QNameEnumLookup<E extends Enum<E> & HasQName> {
+
+    private final Map<QName, E> qNameConstants;
+
+    public QNameEnumLookup(E[] e) {
+        Map<QName, E> q = new HashMap<>(e.length);
+        E old;
+        for (E c : e) {
+            QName qName = c.getQName();
+            if ((old = q.put(qName, c)) != null) {
+                throw new IllegalStateException("Same name " + qName + " used for two distinct constants: " + c + ", " + old);
+            }
+
+            // Add the relaxed version without namespace
+            if (qName.getNamespaceURI() != null && ! Objects.equals(qName.getNamespaceURI(), XMLConstants.NULL_NS_URI)) {
+                qName = new QName(qName.getLocalPart());
+                if (q.containsKey(qName)) {
+                    q.put(qName, null);
+                } else {
+                    q.put(qName, c);
+                }
+            }
+        }
+        this.qNameConstants = Collections.unmodifiableMap(q);
+    }
+
+    public E from(QName name) {
+        E c = qNameConstants.get(name);
+        if (c == null) {
+            name = new QName(name.getLocalPart());
+            c = qNameConstants.get(name);
+        }
+        return c;
+    }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/SAML11ParserUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/SAML11ParserUtil.java
index 1cbfa7a..6f93ecd 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/SAML11ParserUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/SAML11ParserUtil.java
@@ -49,7 +49,6 @@ import org.keycloak.saml.common.exceptions.ParsingException;
 import org.keycloak.saml.common.util.StaxParserUtil;
 import org.keycloak.saml.processing.core.parsers.saml.SAML11SubjectParser;
 import org.keycloak.saml.processing.core.saml.v1.SAML11Constants;
-import org.keycloak.saml.processing.core.saml.v2.util.SignatureUtil;
 import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
 
 import org.w3c.dom.Element;
@@ -61,6 +60,8 @@ import javax.xml.stream.events.EndElement;
 import javax.xml.stream.events.StartElement;
 import javax.xml.stream.events.XMLEvent;
 import java.net.URI;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 /**
  * Utility for parsing SAML 1.1 payload
@@ -106,11 +107,11 @@ public class SAML11ParserUtil {
             if (xmlEvent instanceof EndElement) {
                 xmlEvent = StaxParserUtil.getNextEvent(xmlEventReader);
                 EndElement endElement = (EndElement) xmlEvent;
-                String endElementTag = StaxParserUtil.getEndElementName(endElement);
+                String endElementTag = StaxParserUtil.getElementName(endElement);
                 if (endElementTag.equals(SAML11Constants.AUTHENTICATION_STATEMENT))
                     break;
                 else
-                    throw logger.parserUnknownEndElement(endElementTag);
+                    throw logger.parserUnknownEndElement(endElementTag, xmlEvent.getLocation());
             }
             startElement = null;
 
@@ -122,7 +123,7 @@ public class SAML11ParserUtil {
             if (startElement == null)
                 break;
 
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
 
             if (JBossSAMLConstants.SUBJECT.get().equalsIgnoreCase(tag)) {
                 SAML11SubjectParser subjectParser = new SAML11SubjectParser();
@@ -199,7 +200,7 @@ public class SAML11ParserUtil {
             if (xmlEvent instanceof StartElement) {
                 startElement = (StartElement) xmlEvent;
 
-                String startTag = StaxParserUtil.getStartElementName(startElement);
+                String startTag = StaxParserUtil.getElementName(startElement);
 
                 if (startTag.equals(SAML11Constants.CONFIRMATION_METHOD)) {
                     startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
@@ -264,7 +265,7 @@ public class SAML11ParserUtil {
         XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
         if (!(xmlEvent instanceof EndElement)) {
             startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
             if (tag.equals(WSTrustConstants.XMLDSig.KEYINFO)) {
                 KeyInfoType keyInfo = parseKeyInfo(xmlEventReader);
                 subjectConfirmationData.setAnyType(keyInfo);
@@ -371,7 +372,7 @@ public class SAML11ParserUtil {
             startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
             if (startElement == null)
                 break;
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
 
             if (JBossSAMLConstants.ATTRIBUTE.get().equals(tag))
                 break;
@@ -440,7 +441,7 @@ public class SAML11ParserUtil {
             startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
             if (startElement == null)
                 break;
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
 
             if (SAML11Constants.ACTION.equals(tag)) {
                 startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
@@ -512,14 +513,14 @@ public class SAML11ParserUtil {
             startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
             if (startElement == null)
                 break;
-            String tag = StaxParserUtil.getStartElementName(startElement);
+            String tag = StaxParserUtil.getElementName(startElement);
 
             if (SAML11Constants.AUDIENCE_RESTRICTION_CONDITION.equals(tag)) {
                 startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
                 SAML11AudienceRestrictionCondition restrictCond = new SAML11AudienceRestrictionCondition();
 
                 startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-                if (StaxParserUtil.getStartElementName(startElement).equals(JBossSAMLConstants.AUDIENCE.get())) {
+                if (StaxParserUtil.getElementName(startElement).equals(JBossSAMLConstants.AUDIENCE.get())) {
                     restrictCond.add(URI.create(StaxParserUtil.getElementText(xmlEventReader)));
                 }
                 EndElement theEndElement = StaxParserUtil.getNextEndElement(xmlEventReader);
@@ -542,15 +543,15 @@ public class SAML11ParserUtil {
         while (xmlEventReader.hasNext()) {
             xmlEvent = StaxParserUtil.peek(xmlEventReader);
             if (xmlEvent instanceof EndElement) {
-                tag = StaxParserUtil.getEndElementName((EndElement) xmlEvent);
+                tag = StaxParserUtil.getElementName((EndElement) xmlEvent);
                 if (tag.equals(WSTrustConstants.XMLDSig.KEYINFO)) {
                     xmlEvent = StaxParserUtil.getNextEndElement(xmlEventReader);
                     break;
                 } else
-                    throw logger.parserUnknownEndElement(tag);
+                    throw logger.parserUnknownEndElement(tag, xmlEvent.getLocation());
             }
             startElement = (StartElement) xmlEvent;
-            tag = StaxParserUtil.getStartElementName(startElement);
+            tag = StaxParserUtil.getElementName(startElement);
             if (tag.equals(WSTrustConstants.XMLEnc.ENCRYPTED_KEY)) {
                 keyInfo.addContent(StaxParserUtil.getDOMElement(xmlEventReader));
             } else if (tag.equals(WSTrustConstants.XMLDSig.X509DATA)) {
@@ -574,7 +575,7 @@ public class SAML11ParserUtil {
                 KeyValueType keyValue = null;
 
                 startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
-                tag = StaxParserUtil.getStartElementName(startElement);
+                tag = StaxParserUtil.getElementName(startElement);
                 if (tag.equals(WSTrustConstants.XMLDSig.RSA_KEYVALUE)) {
                     keyValue = parseRSAKeyValue(xmlEventReader);
                 } else if (tag.equals(WSTrustConstants.XMLDSig.DSA_KEYVALUE)) {
@@ -603,16 +604,16 @@ public class SAML11ParserUtil {
         while (xmlEventReader.hasNext()) {
             xmlEvent = StaxParserUtil.peek(xmlEventReader);
             if (xmlEvent instanceof EndElement) {
-                tag = StaxParserUtil.getEndElementName((EndElement) xmlEvent);
+                tag = StaxParserUtil.getElementName((EndElement) xmlEvent);
                 if (tag.equals(WSTrustConstants.XMLDSig.RSA_KEYVALUE)) {
                     xmlEvent = StaxParserUtil.getNextEndElement(xmlEventReader);
                     break;
                 } else
-                    throw logger.parserUnknownEndElement(tag);
+                    throw logger.parserUnknownEndElement(tag, xmlEvent.getLocation());
             }
 
             startElement = (StartElement) xmlEvent;
-            tag = StaxParserUtil.getStartElementName(startElement);
+            tag = StaxParserUtil.getElementName(startElement);
             if (tag.equals(WSTrustConstants.XMLDSig.MODULUS)) {
                 startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
                 String text = StaxParserUtil.getElementText(xmlEventReader);
@@ -632,7 +633,48 @@ public class SAML11ParserUtil {
         StaxParserUtil.validate(startElement, WSTrustConstants.XMLDSig.DSA_KEYVALUE);
 
         Element dsaElement = StaxParserUtil.getDOMElement(xmlEventReader);
-        return SignatureUtil.getDSAKeyValue(dsaElement);
+        return getDSAKeyValue(dsaElement);
+    }
+
+    /**
+     * Given a dsig:DSAKeyValue element, return {@link DSAKeyValueType}
+     *
+     * @param element
+     *
+     * @return
+     *
+     * @throws org.keycloak.saml.common.exceptions.ParsingException
+     */
+    private static DSAKeyValueType getDSAKeyValue(Element element) throws ParsingException {
+        DSAKeyValueType dsa = new DSAKeyValueType();
+        NodeList nl = element.getChildNodes();
+        int length = nl.getLength();
+
+        for (int i = 0; i < length; i++) {
+            Node node = nl.item(i);
+            if (node instanceof Element) {
+                Element childElement = (Element) node;
+                String tag = childElement.getLocalName();
+
+                byte[] text = childElement.getTextContent().getBytes(GeneralConstants.SAML_CHARSET);
+
+                if (WSTrustConstants.XMLDSig.P.equals(tag)) {
+                    dsa.setP(text);
+                } else if (WSTrustConstants.XMLDSig.Q.equals(tag)) {
+                    dsa.setQ(text);
+                } else if (WSTrustConstants.XMLDSig.G.equals(tag)) {
+                    dsa.setG(text);
+                } else if (WSTrustConstants.XMLDSig.Y.equals(tag)) {
+                    dsa.setY(text);
+                } else if (WSTrustConstants.XMLDSig.SEED.equals(tag)) {
+                    dsa.setSeed(text);
+                } else if (WSTrustConstants.XMLDSig.PGEN_COUNTER.equals(tag)) {
+                    dsa.setPgenCounter(text);
+                }
+            }
+        }
+
+        return dsa;
     }
 
     /**
@@ -655,13 +697,13 @@ public class SAML11ParserUtil {
                 if (StaxParserUtil.matches(endElement, SAML11Constants.ATTRIBUTE_QUERY))
                     break;
                 else
-                    throw logger.parserUnknownEndElement(StaxParserUtil.getEndElementName(endElement));
+                    throw logger.parserUnknownEndElement(StaxParserUtil.getElementName(endElement), xmlEvent.getLocation());
             }
 
             if (xmlEvent instanceof StartElement) {
                 startElement = (StartElement) xmlEvent;
 
-                String startTag = StaxParserUtil.getStartElementName(startElement);
+                String startTag = StaxParserUtil.getElementName(startElement);
 
                 if (startTag.equals(JBossSAMLConstants.SUBJECT.get())) {
                     SAML11SubjectParser parser = new SAML11SubjectParser();
@@ -694,13 +736,13 @@ public class SAML11ParserUtil {
                 if (StaxParserUtil.matches(endElement, SAML11Constants.AUTHENTICATION_QUERY))
                     break;
                 else
-                    throw logger.parserUnknownEndElement(StaxParserUtil.getEndElementName(endElement));
+                    throw logger.parserUnknownEndElement(StaxParserUtil.getElementName(endElement), xmlEvent.getLocation());
             }
 
             if (xmlEvent instanceof StartElement) {
                 startElement = (StartElement) xmlEvent;
 
-                String startTag = StaxParserUtil.getStartElementName(startElement);
+                String startTag = StaxParserUtil.getElementName(startElement);
 
                 if (startTag.equals(JBossSAMLConstants.SUBJECT.get())) {
                     SAML11SubjectParser parser = new SAML11SubjectParser();
@@ -733,13 +775,13 @@ public class SAML11ParserUtil {
                 if (StaxParserUtil.matches(endElement, SAML11Constants.AUTHORIZATION_DECISION_QUERY))
                     break;
                 else
-                    throw logger.parserUnknownEndElement(StaxParserUtil.getEndElementName(endElement));
+                    throw logger.parserUnknownEndElement(StaxParserUtil.getElementName(endElement), xmlEvent.getLocation());
             }
 
             if (xmlEvent instanceof StartElement) {
                 startElement = (StartElement) xmlEvent;
 
-                String startTag = StaxParserUtil.getStartElementName(startElement);
+                String startTag = StaxParserUtil.getElementName(startElement);
 
                 if (startTag.equals(JBossSAMLConstants.SUBJECT.get())) {
                     SAML11SubjectParser parser = new SAML11SubjectParser();
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/SAMLParserUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/SAMLParserUtil.java
index 8b39ff0..c3b44bc 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/SAMLParserUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/util/SAMLParserUtil.java
@@ -15,51 +15,16 @@
  * limitations under the License.
  */
 package org.keycloak.saml.processing.core.parsers.util;
-
-import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
-import org.keycloak.dom.saml.v2.assertion.AttributeStatementType.ASTChoiceType;
-import org.keycloak.dom.saml.v2.assertion.AttributeType;
-import org.keycloak.dom.saml.v2.assertion.AuthnContextClassRefType;
-import org.keycloak.dom.saml.v2.assertion.AuthnContextDeclRefType;
-import org.keycloak.dom.saml.v2.assertion.AuthnContextDeclType;
-import org.keycloak.dom.saml.v2.assertion.AuthnContextType;
-import org.keycloak.dom.saml.v2.assertion.AuthnStatementType;
 import org.keycloak.dom.saml.v2.assertion.NameIDType;
-import org.keycloak.dom.saml.v2.assertion.SubjectLocalityType;
-import org.keycloak.dom.xmlsec.w3.xmldsig.DSAKeyValueType;
-import org.keycloak.dom.xmlsec.w3.xmldsig.KeyInfoType;
-import org.keycloak.dom.xmlsec.w3.xmldsig.KeyValueType;
-import org.keycloak.dom.xmlsec.w3.xmldsig.RSAKeyValueType;
-import org.keycloak.dom.xmlsec.w3.xmldsig.X509CertificateType;
-import org.keycloak.dom.xmlsec.w3.xmldsig.X509DataType;
 import org.keycloak.saml.common.PicketLinkLogger;
 import org.keycloak.saml.common.PicketLinkLoggerFactory;
-import org.keycloak.saml.common.constants.GeneralConstants;
-import org.keycloak.saml.common.constants.JBossSAMLConstants;
-import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
-import org.keycloak.saml.common.constants.WSTrustConstants;
 import org.keycloak.saml.common.exceptions.ParsingException;
 import org.keycloak.saml.common.util.StaxParserUtil;
-import org.keycloak.saml.common.util.StringUtil;
-import org.keycloak.saml.processing.core.saml.v2.util.SignatureUtil;
-import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
-
-import org.w3c.dom.Element;
 
-import javax.xml.datatype.XMLGregorianCalendar;
-import javax.xml.namespace.QName;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAssertionQNames;
+import java.util.Objects;
 import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLEventWriter;
-import javax.xml.stream.XMLOutputFactory;
-import javax.xml.stream.events.Attribute;
-import javax.xml.stream.events.EndElement;
 import javax.xml.stream.events.StartElement;
-import javax.xml.stream.events.XMLEvent;
-import java.io.StringWriter;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.StringTokenizer;
 
 /**
  * Utility methods for SAML Parser
@@ -69,472 +34,7 @@ import java.util.StringTokenizer;
  */
 public class SAMLParserUtil {
 
-    private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
-
-    public static KeyInfoType parseKeyInfo(XMLEventReader xmlEventReader) throws ParsingException {
-        KeyInfoType keyInfo = new KeyInfoType();
-        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-        StaxParserUtil.validate(startElement, WSTrustConstants.XMLDSig.KEYINFO);
-
-        XMLEvent xmlEvent = null;
-        String tag = null;
-
-        while (xmlEventReader.hasNext()) {
-            xmlEvent = StaxParserUtil.peek(xmlEventReader);
-            if (xmlEvent instanceof EndElement) {
-                tag = StaxParserUtil.getEndElementName((EndElement) xmlEvent);
-                if (tag.equals(WSTrustConstants.XMLDSig.KEYINFO)) {
-                    xmlEvent = StaxParserUtil.getNextEndElement(xmlEventReader);
-                    break;
-                } else
-                    throw logger.parserUnknownEndElement(tag);
-            }
-            startElement = (StartElement) xmlEvent;
-            tag = StaxParserUtil.getStartElementName(startElement);
-            if (tag.equals(WSTrustConstants.XMLEnc.ENCRYPTED_KEY)) {
-                keyInfo.addContent(StaxParserUtil.getDOMElement(xmlEventReader));
-            } else if (tag.equals(WSTrustConstants.XMLDSig.X509DATA)) {
-                startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-                X509DataType x509 = new X509DataType();
-
-                // Let us go for the X509 certificate
-                startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-                StaxParserUtil.validate(startElement, WSTrustConstants.XMLDSig.X509CERT);
-
-                X509CertificateType cert = new X509CertificateType();
-                String certValue = StaxParserUtil.getElementText(xmlEventReader);
-                cert.setEncodedCertificate(certValue.getBytes(GeneralConstants.SAML_CHARSET));
-                x509.add(cert);
-
-                EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
-                StaxParserUtil.validate(endElement, WSTrustConstants.XMLDSig.X509DATA);
-                keyInfo.addContent(x509);
-            } else if (tag.equals(WSTrustConstants.XMLDSig.KEYVALUE)) {
-                startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-                KeyValueType keyValue = null;
-
-                startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
-                tag = StaxParserUtil.getStartElementName(startElement);
-                if (tag.equals(WSTrustConstants.XMLDSig.RSA_KEYVALUE)) {
-                    keyValue = parseRSAKeyValue(xmlEventReader);
-                } else if (tag.equals(WSTrustConstants.XMLDSig.DSA_KEYVALUE)) {
-                    keyValue = parseDSAKeyValue(xmlEventReader);
-                } else
-                    throw logger.parserUnknownTag(tag, startElement.getLocation());
-
-                EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
-                StaxParserUtil.validate(endElement, WSTrustConstants.XMLDSig.KEYVALUE);
-
-                keyInfo.addContent(keyValue);
-            }
-        }
-        return keyInfo;
-    }
-
-    private static RSAKeyValueType parseRSAKeyValue(XMLEventReader xmlEventReader) throws ParsingException {
-        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-        StaxParserUtil.validate(startElement, WSTrustConstants.XMLDSig.RSA_KEYVALUE);
-
-        XMLEvent xmlEvent = null;
-        String tag = null;
-
-        RSAKeyValueType rsaKeyValue = new RSAKeyValueType();
-
-        while (xmlEventReader.hasNext()) {
-            xmlEvent = StaxParserUtil.peek(xmlEventReader);
-            if (xmlEvent instanceof EndElement) {
-                tag = StaxParserUtil.getEndElementName((EndElement) xmlEvent);
-                if (tag.equals(WSTrustConstants.XMLDSig.RSA_KEYVALUE)) {
-                    xmlEvent = StaxParserUtil.getNextEndElement(xmlEventReader);
-                    break;
-                } else
-                    throw logger.parserUnknownEndElement(tag);
-            }
-
-            startElement = (StartElement) xmlEvent;
-            tag = StaxParserUtil.getStartElementName(startElement);
-            if (tag.equals(WSTrustConstants.XMLDSig.MODULUS)) {
-                startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-                String text = StaxParserUtil.getElementText(xmlEventReader);
-                rsaKeyValue.setModulus(text.getBytes(GeneralConstants.SAML_CHARSET));
-            } else if (tag.equals(WSTrustConstants.XMLDSig.EXPONENT)) {
-                startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-                String text = StaxParserUtil.getElementText(xmlEventReader);
-                rsaKeyValue.setExponent(text.getBytes(GeneralConstants.SAML_CHARSET));
-            } else
-                throw logger.parserUnknownTag(tag, startElement.getLocation());
-        }
-        return rsaKeyValue;
-    }
-
-    private static DSAKeyValueType parseDSAKeyValue(XMLEventReader xmlEventReader) throws ParsingException {
-        StartElement startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
-        StaxParserUtil.validate(startElement, WSTrustConstants.XMLDSig.DSA_KEYVALUE);
-
-        Element dsaElement = StaxParserUtil.getDOMElement(xmlEventReader);
-        return SignatureUtil.getDSAKeyValue(dsaElement);
-    }
-
-    /**
-     * Parse an {@code AttributeStatementType}
-     *
-     * @param xmlEventReader
-     *
-     * @return
-     *
-     * @throws ParsingException
-     */
-    public static AttributeStatementType parseAttributeStatement(XMLEventReader xmlEventReader) throws ParsingException {
-        AttributeStatementType attributeStatementType = new AttributeStatementType();
-
-        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-        String ATTRIBSTATEMT = JBossSAMLConstants.ATTRIBUTE_STATEMENT.get();
-        StaxParserUtil.validate(startElement, ATTRIBSTATEMT);
-
-        while (xmlEventReader.hasNext()) {
-            XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
-            if (xmlEvent instanceof EndElement) {
-                EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
-                StaxParserUtil.validate(endElement, JBossSAMLConstants.ATTRIBUTE_STATEMENT.get());
-                break;
-            }
-            // Get the next start element
-            startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
-            String tag = startElement.getName().getLocalPart();
-            if (JBossSAMLConstants.ATTRIBUTE.get().equals(tag)) {
-                AttributeType attribute = parseAttribute(xmlEventReader);
-                attributeStatementType.addAttribute(new ASTChoiceType(attribute));
-            } else
-                throw logger.parserUnknownTag(tag, startElement.getLocation());
-        }
-        return attributeStatementType;
-    }
-
-    /**
-     * Parse an {@code AttributeType}
-     *
-     * @param xmlEventReader
-     *
-     * @return
-     *
-     * @throws ParsingException
-     */
-    public static AttributeType parseAttribute(XMLEventReader xmlEventReader) throws ParsingException {
-        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-        StaxParserUtil.validate(startElement, JBossSAMLConstants.ATTRIBUTE.get());
-        AttributeType attributeType = null;
-
-        Attribute name = startElement.getAttributeByName(new QName(JBossSAMLConstants.NAME.get()));
-        if (name == null)
-            throw logger.parserRequiredAttribute("Name");
-        attributeType = new AttributeType(StaxParserUtil.getAttributeValue(name));
-
-        parseAttributeType(xmlEventReader, startElement, JBossSAMLConstants.ATTRIBUTE.get(), attributeType);
-
-        return attributeType;
-    }
-
-    /**
-     * Parse an {@code AttributeType}
-     *
-     * @param xmlEventReader
-     *
-     * @throws ParsingException
-     */
-    public static void parseAttributeType(XMLEventReader xmlEventReader, StartElement startElement, String rootTag,
-            AttributeType attributeType) throws ParsingException {
-        // Look for X500 Encoding
-        QName x500EncodingName = new QName(JBossSAMLURIConstants.X500_NSURI.get(), JBossSAMLConstants.ENCODING.get(),
-                JBossSAMLURIConstants.X500_PREFIX.get());
-        Attribute x500EncodingAttr = startElement.getAttributeByName(x500EncodingName);
-
-        if (x500EncodingAttr != null) {
-            attributeType.getOtherAttributes().put(x500EncodingAttr.getName(),
-                    StaxParserUtil.getAttributeValue(x500EncodingAttr));
-        }
-
-        Attribute friendlyName = startElement.getAttributeByName(new QName(JBossSAMLConstants.FRIENDLY_NAME.get()));
-        if (friendlyName != null)
-            attributeType.setFriendlyName(StaxParserUtil.getAttributeValue(friendlyName));
-
-        Attribute nameFormat = startElement.getAttributeByName(new QName(JBossSAMLConstants.NAME_FORMAT.get()));
-        if (nameFormat != null)
-            attributeType.setNameFormat(StaxParserUtil.getAttributeValue(nameFormat));
-
-        while (xmlEventReader.hasNext()) {
-            XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
-            if (xmlEvent instanceof EndElement) {
-                EndElement end = StaxParserUtil.getNextEndElement(xmlEventReader);
-                if (StaxParserUtil.matches(end, rootTag))
-                    break;
-            }
-            startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
-            if (startElement == null)
-                break;
-            String tag = StaxParserUtil.getStartElementName(startElement);
-
-            if (JBossSAMLConstants.ATTRIBUTE.get().equals(tag))
-                break;
-
-            if (JBossSAMLConstants.ATTRIBUTE_VALUE.get().equals(tag)) {
-                Object attributeValue = parseAttributeValue(xmlEventReader);
-                attributeType.addAttributeValue(attributeValue);
-            } else
-                throw logger.parserUnknownTag(tag, startElement.getLocation());
-        }
-    }
-
-    /**
-     * Parse Attribute value
-     *
-     * @param xmlEventReader
-     *
-     * @return
-     *
-     * @throws ParsingException
-     */
-    public static Object parseAttributeValue(XMLEventReader xmlEventReader) throws ParsingException {
-        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-        StaxParserUtil.validate(startElement, JBossSAMLConstants.ATTRIBUTE_VALUE.get());
-
-        Attribute type = startElement.getAttributeByName(new QName(JBossSAMLURIConstants.XSI_NSURI.get(), JBossSAMLConstants.TYPE.get(), JBossSAMLURIConstants.XSI_PREFIX.get()));
-        Attribute nil = startElement.getAttributeByName(new QName(JBossSAMLURIConstants.XSI_NSURI.get(), "nil", JBossSAMLURIConstants.XSI_PREFIX.get()));
-        if (nil != null) {
-            String nilValue = StaxParserUtil.getAttributeValue(nil);
-            if (nilValue != null
-                    && (nilValue.equalsIgnoreCase("true") || nilValue.equals("1"))) {
-                String elementText = StaxParserUtil.getElementText(xmlEventReader);
-                if  (elementText == null || elementText.isEmpty()) {
-                    return null;
-                } else {
-                    throw logger.nullValueError("nil attribute is not in SAML20 format");
-                }
-            } else {
-                throw logger.parserRequiredAttribute(JBossSAMLURIConstants.XSI_PREFIX.get() + ":nil");
-            }
-        }
-        if (type == null) {
-            if (StaxParserUtil.hasTextAhead(xmlEventReader)) {
-                return StaxParserUtil.getElementText(xmlEventReader);
-            }
-            // Else we may have Child Element
-            XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
-            if (xmlEvent instanceof StartElement) {
-                startElement = (StartElement) xmlEvent;
-                String tag = StaxParserUtil.getStartElementName(startElement);
-                if (tag.equals(JBossSAMLConstants.NAMEID.get())) {
-                    return parseNameIDType(xmlEventReader);
-                }
-            } else if (xmlEvent instanceof EndElement) {
-                // consume the end element tag
-                EndElement end = StaxParserUtil.getNextEndElement(xmlEventReader);
-                String endElementTag = StaxParserUtil.getEndElementName(end);
-                if (! StaxParserUtil.matches(end, JBossSAMLConstants.ATTRIBUTE_VALUE.get()))
-                    throw logger.parserUnknownEndElement(endElementTag);
-                return "";
-            }
-
-            // when no type attribute assigned -> assume anyType
-            return parseAnyTypeAsString(xmlEventReader);
-        }
-        //      RK Added an additional type check for base64Binary type as calheers is passing this type
-        String typeValue = StaxParserUtil.getAttributeValue(type);
-        if (typeValue.contains(":string")) {
-            return StaxParserUtil.getElementText(xmlEventReader);
-        } else if (typeValue.contains(":anyType")) {
-            return parseAnyTypeAsString(xmlEventReader);
-        } else if(typeValue.contains(":base64Binary")){
-            return StaxParserUtil.getElementText(xmlEventReader);
-        } else if(typeValue.contains(":boolean")){
-            return StaxParserUtil.getElementText(xmlEventReader);
-        }
-
-        throw logger.parserUnknownXSI(typeValue);
-    }
-
-    public static String parseAnyTypeAsString(XMLEventReader xmlEventReader) throws ParsingException {
-        try {
-            XMLEvent event = xmlEventReader.peek();
-            if (event.isStartElement()) {
-                event = xmlEventReader.nextTag();
-                StringWriter sw = new StringWriter();
-                XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(sw);
-                //QName tagName = event.asStartElement().getName();
-                int tagLevel = 1;
-                do {
-                    writer.add(event);
-                    event = (XMLEvent) xmlEventReader.next();
-                    if (event.isStartElement()) {
-                        tagLevel++;
-                    }
-                    if (event.isEndElement()) {
-                        tagLevel--;
-                    }
-                } while (xmlEventReader.hasNext() && tagLevel > 0);
-                writer.add(event);
-                writer.flush();
-                return sw.toString();
-            } else {
-                return StaxParserUtil.getElementText(xmlEventReader);
-            }
-        } catch (Exception e) {
-            throw logger.parserError(e);
-        }
-    }
-
-    /**
-     * Parse the AuthnStatement inside the assertion
-     *
-     * @param xmlEventReader
-     *
-     * @return
-     *
-     * @throws ParsingException
-     */
-    public static AuthnStatementType parseAuthnStatement(XMLEventReader xmlEventReader) throws ParsingException {
-        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-        String AUTHNSTATEMENT = JBossSAMLConstants.AUTHN_STATEMENT.get();
-        StaxParserUtil.validate(startElement, AUTHNSTATEMENT);
-
-        Attribute authnInstant = startElement.getAttributeByName(new QName("AuthnInstant"));
-        if (authnInstant == null)
-            throw logger.parserRequiredAttribute("AuthnInstant");
-
-        XMLGregorianCalendar issueInstant = XMLTimeUtil.parse(StaxParserUtil.getAttributeValue(authnInstant));
-        AuthnStatementType authnStatementType = new AuthnStatementType(issueInstant);
-
-        Attribute sessionIndex = startElement.getAttributeByName(new QName("SessionIndex"));
-        if (sessionIndex != null)
-            authnStatementType.setSessionIndex(StaxParserUtil.getAttributeValue(sessionIndex));
-
-        while (xmlEventReader.hasNext()) {
-            XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
-            if (xmlEvent == null)
-                break;
-
-            if (xmlEvent instanceof EndElement) {
-                xmlEvent = StaxParserUtil.getNextEvent(xmlEventReader);
-                EndElement endElement = (EndElement) xmlEvent;
-                String endElementTag = StaxParserUtil.getEndElementName(endElement);
-                if (endElementTag.equals(AUTHNSTATEMENT))
-                    break;
-                else
-                    throw logger.parserUnknownEndElement(endElementTag);
-            }
-            startElement = null;
-
-            if (xmlEvent instanceof StartElement) {
-                startElement = (StartElement) xmlEvent;
-            } else {
-                startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
-            }
-            if (startElement == null)
-                break;
-
-            String tag = StaxParserUtil.getStartElementName(startElement);
-
-            if (JBossSAMLConstants.SUBJECT_LOCALITY.get().equals(tag)) {
-                startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-                SubjectLocalityType subjectLocalityType = new SubjectLocalityType();
-                Attribute address = startElement.getAttributeByName(new QName(JBossSAMLConstants.ADDRESS.get()));
-                if (address != null) {
-                    subjectLocalityType.setAddress(StaxParserUtil.getAttributeValue(address));
-                }
-                Attribute dns = startElement.getAttributeByName(new QName(JBossSAMLConstants.DNS_NAME.get()));
-                if (dns != null) {
-                    subjectLocalityType.setDNSName(StaxParserUtil.getAttributeValue(dns));
-                }
-                authnStatementType.setSubjectLocality(subjectLocalityType);
-                StaxParserUtil.validate(StaxParserUtil.getNextEndElement(xmlEventReader),
-                        JBossSAMLConstants.SUBJECT_LOCALITY.get());
-            } else if (JBossSAMLConstants.AUTHN_CONTEXT.get().equals(tag)) {
-                authnStatementType.setAuthnContext(parseAuthnContextType(xmlEventReader));
-            } else
-                throw logger.parserUnknownTag(tag, startElement.getLocation());
-
-        }
-
-        return authnStatementType;
-    }
-
-    /**
-     * Parse the AuthnContext Type inside the AuthnStatement
-     *
-     * @param xmlEventReader
-     *
-     * @return
-     *
-     * @throws ParsingException
-     */
-    public static AuthnContextType parseAuthnContextType(XMLEventReader xmlEventReader) throws ParsingException {
-        AuthnContextType authnContextType = new AuthnContextType();
-
-        StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-        StaxParserUtil.validate(startElement, JBossSAMLConstants.AUTHN_CONTEXT.get());
-
-        while (xmlEventReader.hasNext()) {
-            XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
-            if (xmlEvent == null)
-                break;
-
-            if (xmlEvent instanceof EndElement) {
-                xmlEvent = StaxParserUtil.getNextEvent(xmlEventReader);
-                EndElement endElement = (EndElement) xmlEvent;
-                String endElementTag = StaxParserUtil.getEndElementName(endElement);
-                if (endElementTag.equals(JBossSAMLConstants.AUTHN_CONTEXT.get()))
-                    break;
-                else
-                    throw logger.parserUnknownEndElement(endElementTag);
-            }
-            startElement = null;
-
-            if (xmlEvent instanceof StartElement) {
-                startElement = (StartElement) xmlEvent;
-            } else {
-                startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
-            }
-            if (startElement == null)
-                break;
-
-            String tag = StaxParserUtil.getStartElementName(startElement);
-
-            if (JBossSAMLConstants.AUTHN_CONTEXT_DECLARATION.get().equals(tag)) {
-                startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-
-                Element dom = StaxParserUtil.getDOMElement(xmlEventReader);
-
-                AuthnContextDeclType authnContextDecl = new AuthnContextDeclType(dom);
-                AuthnContextType.AuthnContextTypeSequence authnContextSequence = authnContextType.new AuthnContextTypeSequence();
-                authnContextSequence.setAuthnContextDecl(authnContextDecl);
-                authnContextType.setSequence(authnContextSequence);
-
-                EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
-                StaxParserUtil.validate(endElement, JBossSAMLConstants.AUTHN_CONTEXT_DECLARATION.get());
-            } else if (JBossSAMLConstants.AUTHN_CONTEXT_DECLARATION_REF.get().equals(tag)) {
-                startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-                String text = StaxParserUtil.getElementText(xmlEventReader);
-
-                AuthnContextDeclRefType aAuthnContextDeclType = new AuthnContextDeclRefType(URI.create(text));
-                authnContextType.addURIType(aAuthnContextDeclType);
-            } else if (JBossSAMLConstants.AUTHN_CONTEXT_CLASS_REF.get().equals(tag)) {
-                startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-                String text = StaxParserUtil.getElementText(xmlEventReader);
-
-                AuthnContextClassRefType aAuthnContextClassRefType = new AuthnContextClassRefType(URI.create(text));
-                AuthnContextType.AuthnContextTypeSequence authnContextSequence = authnContextType.new AuthnContextTypeSequence();
-                authnContextSequence.setClassRef(aAuthnContextClassRefType);
-
-                authnContextType.setSequence(authnContextSequence);
-            } else if (JBossSAMLConstants.AUTHENTICATING_AUTHORITY.get().equals(tag)) {
-              startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-              String text = StaxParserUtil.getElementText(xmlEventReader);
-              authnContextType.addAuthenticatingAuthority(URI.create(text));
-            } else
-                throw logger.parserUnknownTag(tag, startElement.getLocation());
-        }
-
-        return authnContextType;
-    }
+    private static final PicketLinkLogger LOGGER = PicketLinkLoggerFactory.getLogger();
 
     /**
      * Parse a {@code NameIDType}
@@ -547,27 +47,12 @@ public class SAMLParserUtil {
      */
     public static NameIDType parseNameIDType(XMLEventReader xmlEventReader) throws ParsingException {
         StartElement nameIDElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-        NameIDType nameID = new NameIDType();
-
-        Attribute nameQualifier = nameIDElement.getAttributeByName(new QName(JBossSAMLConstants.NAME_QUALIFIER.get()));
-        if (nameQualifier != null) {
-            nameID.setNameQualifier(StaxParserUtil.getAttributeValue(nameQualifier));
-        }
-
-        Attribute format = nameIDElement.getAttributeByName(new QName(JBossSAMLConstants.FORMAT.get()));
-        if (format != null) {
-            nameID.setFormat(URI.create(StaxParserUtil.getAttributeValue(format)));
-        }
-
-        Attribute spProvidedID = nameIDElement.getAttributeByName(new QName(JBossSAMLConstants.SP_PROVIDED_ID.get()));
-        if (spProvidedID != null) {
-            nameID.setSPProvidedID(StaxParserUtil.getAttributeValue(spProvidedID));
-        }
 
-        Attribute spNameQualifier = nameIDElement.getAttributeByName(new QName(JBossSAMLConstants.SP_NAME_QUALIFIER.get()));
-        if (spNameQualifier != null) {
-            nameID.setSPNameQualifier(StaxParserUtil.getAttributeValue(spNameQualifier));
-        }
+        NameIDType nameID = new NameIDType();
+        nameID.setFormat(StaxParserUtil.getUriAttributeValue(nameIDElement, SAMLAssertionQNames.ATTR_FORMAT));
+        nameID.setNameQualifier(StaxParserUtil.getAttributeValue(nameIDElement, SAMLAssertionQNames.ATTR_NAME_QUALIFIER));
+        nameID.setSPProvidedID(StaxParserUtil.getAttributeValue(nameIDElement, SAMLAssertionQNames.ATTR_SP_PROVIDED_ID));
+        nameID.setSPNameQualifier(StaxParserUtil.getAttributeValue(nameIDElement, SAMLAssertionQNames.ATTR_SP_NAME_QUALIFIER));
 
         String nameIDValue = StaxParserUtil.getElementText(xmlEventReader);
         nameID.setValue(nameIDValue);
@@ -575,24 +60,11 @@ public class SAMLParserUtil {
         return nameID;
     }
 
-    /**
-     * Parse a space delimited list of strings
-     *
-     * @param startElement
-     *
-     * @return
-     */
-    public static List<String> parseProtocolEnumeration(StartElement startElement) {
-        List<String> protocolEnum = new ArrayList<String>();
-        Attribute proto = startElement.getAttributeByName(new QName(JBossSAMLConstants.PROTOCOL_SUPPORT_ENUMERATION.get()));
-        String val = StaxParserUtil.getAttributeValue(proto);
-        if (StringUtil.isNotNull(val)) {
-            StringTokenizer st = new StringTokenizer(val);
-            while (st.hasMoreTokens()) {
-                protocolEnum.add(st.nextToken());
-            }
-
+    public static void validateAttributeValue(StartElement element, HasQName attributeName, String expectedValue) throws ParsingException {
+        String value = StaxParserUtil.getRequiredAttributeValue(element, attributeName);
+        if (! Objects.equals(expectedValue, value)) {
+            throw LOGGER.parserException(new RuntimeException(
+                    String.format("%s %s required to be \"%s\"", element.getName(), attributeName.getQName(), expectedValue)));
         }
-        return protocolEnum;
     }
 }
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/factories/JBossSAMLAuthnResponseFactory.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/factories/JBossSAMLAuthnResponseFactory.java
index 15e8165..1adc704 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/factories/JBossSAMLAuthnResponseFactory.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/factories/JBossSAMLAuthnResponseFactory.java
@@ -80,7 +80,7 @@ public class JBossSAMLAuthnResponseFactory {
     public static StatusType createStatusTypeForResponder(String statusCodeURI) {
         StatusCodeType topLevelCode = new StatusCodeType();
 
-        topLevelCode.setValue(URI.create(JBossSAMLURIConstants.STATUS_RESPONDER.get()));
+        topLevelCode.setValue(JBossSAMLURIConstants.STATUS_RESPONDER.getUri());
 
         StatusCodeType secondLevelCode = new StatusCodeType();
 
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java
index 244fb7d..0de9c86 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java
@@ -604,7 +604,7 @@ public class AssertionUtil {
         newDoc.appendChild(importedNode);
 
         Element decryptedDocumentElement = XMLEncryptionUtil.decryptElementInDocument(newDoc, privateKey);
-        SAMLParser parser = new SAMLParser();
+        SAMLParser parser = SAMLParser.getInstance();
 
         JAXPValidationUtil.checkSchemaValidation(decryptedDocumentElement);
         AssertionType assertion = (AssertionType) parser.parse(parser.createEventReader(DocumentUtil
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/SignatureUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/SignatureUtil.java
index 1ba4d74..52c6b90 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/SignatureUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/SignatureUtil.java
@@ -172,81 +172,6 @@ public class SignatureUtil {
         return sig.verify(signatureValue);
     }
 
-
-    /**
-     * Given a dsig:DSAKeyValue element, return {@link DSAKeyValueType}
-     *
-     * @param element
-     *
-     * @return
-     *
-     * @throws org.keycloak.saml.common.exceptions.ParsingException
-     */
-    public static DSAKeyValueType getDSAKeyValue(Element element) throws ParsingException {
-        DSAKeyValueType dsa = new DSAKeyValueType();
-        NodeList nl = element.getChildNodes();
-        int length = nl.getLength();
-
-        for (int i = 0; i < length; i++) {
-            Node node = nl.item(i);
-            if (node instanceof Element) {
-                Element childElement = (Element) node;
-                String tag = childElement.getLocalName();
-
-                byte[] text = childElement.getTextContent().getBytes(GeneralConstants.SAML_CHARSET);
-
-                if (WSTrustConstants.XMLDSig.P.equals(tag)) {
-                    dsa.setP(text);
-                } else if (WSTrustConstants.XMLDSig.Q.equals(tag)) {
-                    dsa.setQ(text);
-                } else if (WSTrustConstants.XMLDSig.G.equals(tag)) {
-                    dsa.setG(text);
-                } else if (WSTrustConstants.XMLDSig.Y.equals(tag)) {
-                    dsa.setY(text);
-                } else if (WSTrustConstants.XMLDSig.SEED.equals(tag)) {
-                    dsa.setSeed(text);
-                } else if (WSTrustConstants.XMLDSig.PGEN_COUNTER.equals(tag)) {
-                    dsa.setPgenCounter(text);
-                }
-            }
-        }
-
-        return dsa;
-    }
-
-    /**
-     * Given a dsig:DSAKeyValue element, return {@link DSAKeyValueType}
-     *
-     * @param element
-     *
-     * @return
-     *
-     * @throws ParsingException
-     */
-    public static RSAKeyValueType getRSAKeyValue(Element element) throws ParsingException {
-        RSAKeyValueType rsa = new RSAKeyValueType();
-        NodeList nl = element.getChildNodes();
-        int length = nl.getLength();
-
-        for (int i = 0; i < length; i++) {
-            Node node = nl.item(i);
-            if (node instanceof Element) {
-                Element childElement = (Element) node;
-                String tag = childElement.getLocalName();
-
-                byte[] text = childElement.getTextContent().getBytes(GeneralConstants.SAML_CHARSET);
-
-                if (WSTrustConstants.XMLDSig.MODULUS.equals(tag)) {
-                    rsa.setModulus(text);
-                } else if (WSTrustConstants.XMLDSig.EXPONENT.equals(tag)) {
-                    rsa.setExponent(text);
-                }
-            }
-        }
-
-        return rsa;
-    }
-
     /**
      * <p>
      * Creates a {@code KeyValueType} that wraps the specified public key. This method supports DSA and RSA keys.
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/BaseWriter.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/BaseWriter.java
index 068c91a..f9986f1 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/BaseWriter.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/BaseWriter.java
@@ -253,7 +253,7 @@ public class BaseWriter {
             return;
         }
 
-        StaxUtil.writeStartElement(writer, PROTOCOL_PREFIX, JBossSAMLConstants.EXTENSIONS.get(), PROTOCOL_NSURI.get());
+        StaxUtil.writeStartElement(writer, PROTOCOL_PREFIX, JBossSAMLConstants.EXTENSIONS__PROTOCOL.get(), PROTOCOL_NSURI.get());
 
         for (Object o : extensions.getAny()) {
             if (o instanceof Node) {
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/SAMLAssertionWriter.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/SAMLAssertionWriter.java
index 41461bf..5ad84da 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/SAMLAssertionWriter.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/SAMLAssertionWriter.java
@@ -253,14 +253,14 @@ public class SAMLAssertionWriter extends BaseWriter {
             if (uriTypes != null) {
                 for (URIType uriType : uriTypes) {
                     if (uriType instanceof AuthnContextDeclType) {
-                        StaxUtil.writeStartElement(writer, ASSERTION_PREFIX, JBossSAMLConstants.AUTHN_CONTEXT_DECLARATION.get(),
+                        StaxUtil.writeStartElement(writer, ASSERTION_PREFIX, JBossSAMLConstants.AUTHN_CONTEXT_DECL.get(),
                                 ASSERTION_NSURI.get());
                         StaxUtil.writeCharacters(writer, uriType.getValue().toASCIIString());
                         StaxUtil.writeEndElement(writer);
                     }
                     if (uriType instanceof AuthnContextDeclRefType) {
                         StaxUtil.writeStartElement(writer, ASSERTION_PREFIX,
-                                JBossSAMLConstants.AUTHN_CONTEXT_DECLARATION_REF.get(), ASSERTION_NSURI.get());
+                                JBossSAMLConstants.AUTHN_CONTEXT_DECL_REF.get(), ASSERTION_NSURI.get());
                         StaxUtil.writeCharacters(writer, uriType.getValue().toASCIIString());
                         StaxUtil.writeEndElement(writer);
                     }
@@ -286,12 +286,12 @@ public class SAMLAssertionWriter extends BaseWriter {
                 StaxUtil.writeCharacters(writer, uriType.getValue().toString());
                 StaxUtil.writeEndElement(writer);
             } else if (uriType instanceof AuthnContextDeclRefType) {
-                StaxUtil.writeStartElement(writer, ASSERTION_PREFIX, JBossSAMLConstants.AUTHN_CONTEXT_DECLARATION_REF.get(),
+                StaxUtil.writeStartElement(writer, ASSERTION_PREFIX, JBossSAMLConstants.AUTHN_CONTEXT_DECL_REF.get(),
                         ASSERTION_NSURI.get());
                 StaxUtil.writeCharacters(writer, uriType.getValue().toString());
                 StaxUtil.writeEndElement(writer);
             } else if (uriType instanceof AuthnContextDeclType) {
-                StaxUtil.writeStartElement(writer, ASSERTION_PREFIX, JBossSAMLConstants.AUTHN_CONTEXT_DECLARATION.get(),
+                StaxUtil.writeStartElement(writer, ASSERTION_PREFIX, JBossSAMLConstants.AUTHN_CONTEXT_DECL.get(),
                         ASSERTION_NSURI.get());
                 StaxUtil.writeCharacters(writer, uriType.getValue().toString());
                 StaxUtil.writeEndElement(writer);
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/SAMLResponseWriter.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/SAMLResponseWriter.java
index a3b2608..a9e5fba 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/SAMLResponseWriter.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/SAMLResponseWriter.java
@@ -70,7 +70,7 @@ public class SAMLResponseWriter extends BaseWriter {
     public void write(ResponseType response, boolean forceWriteDsigNamespace) throws ProcessingException {
         Element sig = response.getSignature();
 
-        StaxUtil.writeStartElement(writer, PROTOCOL_PREFIX, JBossSAMLConstants.RESPONSE.get(), JBossSAMLURIConstants.PROTOCOL_NSURI.get());
+        StaxUtil.writeStartElement(writer, PROTOCOL_PREFIX, JBossSAMLConstants.RESPONSE__PROTOCOL.get(), JBossSAMLURIConstants.PROTOCOL_NSURI.get());
 
         if (forceWriteDsigNamespace && sig != null && sig.getPrefix() != null && ! sig.hasAttribute("xmlns:" + sig.getPrefix())) {
             StaxUtil.writeNameSpace(writer, sig.getPrefix(), XMLSignature.XMLNS);
diff --git a/saml-core/src/main/java/org/keycloak/saml/SAML2LogoutResponseBuilder.java b/saml-core/src/main/java/org/keycloak/saml/SAML2LogoutResponseBuilder.java
index 4d91e2a..fe32bf4 100755
--- a/saml-core/src/main/java/org/keycloak/saml/SAML2LogoutResponseBuilder.java
+++ b/saml-core/src/main/java/org/keycloak/saml/SAML2LogoutResponseBuilder.java
@@ -30,7 +30,6 @@ import org.keycloak.saml.processing.core.saml.v2.common.IDGenerator;
 import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
 import org.w3c.dom.Document;
 
-import java.net.URI;
 import java.util.LinkedList;
 import java.util.List;
 import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
@@ -73,7 +72,7 @@ public class SAML2LogoutResponseBuilder implements SamlProtocolExtensionsAwareBu
         // Status
         StatusType statusType = new StatusType();
         StatusCodeType statusCodeType = new StatusCodeType();
-        statusCodeType.setValue(URI.create(JBossSAMLURIConstants.STATUS_SUCCESS.get()));
+        statusCodeType.setValue(JBossSAMLURIConstants.STATUS_SUCCESS.getUri());
         statusType.setStatusCode(statusCodeType);
 
         statusResponse.setStatus(statusType);
diff --git a/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLAttributeQueryParserTest.java b/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLAttributeQueryParserTest.java
index a7ea4c5..4164ce7 100644
--- a/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLAttributeQueryParserTest.java
+++ b/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLAttributeQueryParserTest.java
@@ -43,7 +43,7 @@ public class SAMLAttributeQueryParserTest {
         this.parser = new SAMLParser();
     }
 
-    @Test(timeout = 2000)
+    @Test(timeout = 2000000)
     public void testSaml20AttributeQuery() throws Exception {
         try (InputStream is = SAMLAttributeQueryParserTest.class.getResourceAsStream("saml20-attributequery.xml")) {
             Object parsedObject = parser.parse(is);
diff --git a/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java b/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java
index 839847f..9ab24be 100644
--- a/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java
+++ b/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java
@@ -16,7 +16,7 @@
  */
 package org.keycloak.saml.processing.core.parsers.saml;
 
-import static org.hamcrest.CoreMatchers.*;
+import static org.hamcrest.Matchers.*;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -37,16 +37,39 @@ import org.junit.rules.ExpectedException;
 import org.keycloak.common.util.Base64;
 import org.keycloak.common.util.DerUtils;
 import org.keycloak.common.util.StreamUtil;
+import org.keycloak.dom.saml.v2.SAML2Object;
 import org.keycloak.dom.saml.v2.assertion.AssertionType;
 import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
+import org.keycloak.dom.saml.v2.assertion.AttributeStatementType.ASTChoiceType;
 import org.keycloak.dom.saml.v2.assertion.AttributeType;
+import org.keycloak.dom.saml.v2.assertion.AudienceRestrictionType;
+import org.keycloak.dom.saml.v2.assertion.AuthnContextType;
+import org.keycloak.dom.saml.v2.assertion.AuthnStatementType;
+import org.keycloak.dom.saml.v2.assertion.EncryptedAssertionType;
 import org.keycloak.dom.saml.v2.assertion.NameIDType;
+import org.keycloak.dom.saml.v2.assertion.StatementAbstractType;
+import org.keycloak.dom.saml.v2.assertion.SubjectConfirmationType;
+import org.keycloak.dom.saml.v2.assertion.SubjectType;
 import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType;
 import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
 import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
 import org.keycloak.dom.saml.v2.protocol.ResponseType;
+import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
+import org.keycloak.dom.xmlsec.w3.xmldsig.DSAKeyValueType;
+import org.keycloak.dom.xmlsec.w3.xmldsig.KeyInfoType;
+import org.keycloak.dom.xmlsec.w3.xmldsig.RSAKeyValueType;
+import org.keycloak.dom.xmlsec.w3.xmldsig.X509CertificateType;
+import org.keycloak.dom.xmlsec.w3.xmldsig.X509DataType;
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.common.exceptions.ConfigurationException;
 import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.exceptions.ProcessingException;
+import org.keycloak.saml.processing.api.saml.v2.response.SAML2Response;
 import org.keycloak.saml.processing.core.saml.v2.util.AssertionUtil;
+import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
+import java.net.URI;
+import java.util.List;
+import org.hamcrest.Matcher;
 import org.w3c.dom.Element;
 
 /**
@@ -75,193 +98,375 @@ public class SAMLParserTest {
 
     @Before
     public void initParser() {
-        this.parser = new SAMLParser();
+        this.parser = SAMLParser.getInstance();
+    }
+
+    private <T> T assertParsed(String fileName, Class<T> expectedType) throws IOException, ParsingException, ConfigurationException, ProcessingException {
+        try (InputStream st = SAMLParserTest.class.getResourceAsStream(fileName)) {
+            Object parsedObject;
+            if (SAML2Object.class.isAssignableFrom(expectedType)) {
+                parsedObject = new SAML2Response().getSAML2ObjectFromStream(st);
+            } else {
+                parsedObject = parser.parse(st);
+            }
+            assertThat(parsedObject, instanceOf(expectedType));
+
+            return expectedType.cast(parsedObject);
+        }
     }
 
     @Test
     public void testSaml20EncryptedAssertionsSignedReceivedWithRedirectBinding() throws Exception {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-encrypted-signed-redirect-response.xml")) {
-            Object parsedObject = parser.parse(st);
-            assertThat(parsedObject, instanceOf(ResponseType.class));
-
-            ResponseType resp = (ResponseType) parsedObject;
-            assertThat(resp.getSignature(), nullValue());
-            assertThat(resp.getConsent(), nullValue());
-            assertThat(resp.getIssuer(), not(nullValue()));
-            assertThat(resp.getIssuer().getValue(), is("http://localhost:8081/auth/realms/saml-demo"));
-
-            assertThat(resp.getExtensions(), not(nullValue()));
-            assertThat(resp.getExtensions().getAny().size(), is(1));
-            assertThat(resp.getExtensions().getAny().get(0), instanceOf(Element.class));
-            Element el = (Element) resp.getExtensions().getAny().get(0);
-            assertThat(el.getLocalName(), is("KeyInfo"));
-            assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:key:1.0"));
-            assertThat(el.hasAttribute("MessageSigningKeyId"), is(true));
-            assertThat(el.getAttribute("MessageSigningKeyId"), is("FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE"));
-
-            assertThat(resp.getAssertions(), not(nullValue()));
-            assertThat(resp.getAssertions().size(), is(1));
-        }
+        ResponseType resp = assertParsed("saml20-encrypted-signed-redirect-response.xml", ResponseType.class);
+
+        assertThat(resp.getSignature(), nullValue());
+        assertThat(resp.getConsent(), nullValue());
+        assertThat(resp.getIssuer(), not(nullValue()));
+        assertThat(resp.getIssuer().getValue(), is("http://localhost:8081/auth/realms/saml-demo"));
+        assertThat(resp.getIssuer().getFormat(), is(JBossSAMLURIConstants.NAMEID_FORMAT_ENTITY.getUri()));
+
+
+        assertThat(resp.getExtensions(), not(nullValue()));
+        assertThat(resp.getExtensions().getAny().size(), is(1));
+        assertThat(resp.getExtensions().getAny().get(0), instanceOf(Element.class));
+        Element el = (Element) resp.getExtensions().getAny().get(0);
+        assertThat(el.getLocalName(), is("KeyInfo"));
+        assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:key:1.0"));
+        assertThat(el.hasAttribute("MessageSigningKeyId"), is(true));
+        assertThat(el.getAttribute("MessageSigningKeyId"), is("FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE"));
+
+        assertThat(resp.getAssertions(), not(nullValue()));
+        assertThat(resp.getAssertions().size(), is(1));
+        final EncryptedAssertionType ea = resp.getAssertions().get(0).getEncryptedAssertion();
+        assertThat(ea, notNullValue());
+        assertThat(ea.getEncryptedElement(), notNullValue());
+        assertThat(ea.getEncryptedElement().getLocalName(), is("EncryptedAssertion"));
     }
 
     @Test
-    public void testSaml20EncryptedAssertionWithNewlines() throws Exception {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("KEYCLOAK-4489-encrypted-assertion-with-newlines.xml")) {
-            Object parsedObject = parser.parse(st);
-            assertThat(parsedObject, instanceOf(ResponseType.class));
+    public void testSaml20EncryptedAssertion() throws Exception {
+        EncryptedAssertionType ea = assertParsed("saml20-assertion-encrypted.xml", EncryptedAssertionType.class);
 
-            ResponseType resp = (ResponseType) parsedObject;
-            assertThat(resp.getAssertions().size(), is(1));
+        assertThat(ea, notNullValue());
+        assertThat(ea.getEncryptedElement(), notNullValue());
+        assertThat(ea.getEncryptedElement().getLocalName(), is("EncryptedAssertion"));
+    }
+
+    @Test
+    public void testSaml20EncryptedAssertionWithNewlines() throws Exception {
+        ResponseType resp = assertParsed("KEYCLOAK-4489-encrypted-assertion-with-newlines.xml", ResponseType.class);
+        assertThat(resp.getAssertions().size(), is(1));
 
-            ResponseType.RTChoiceType rtChoiceType = resp.getAssertions().get(0);
-            assertNull(rtChoiceType.getAssertion());
-            assertNotNull(rtChoiceType.getEncryptedAssertion());
+        ResponseType.RTChoiceType rtChoiceType = resp.getAssertions().get(0);
+        assertNull(rtChoiceType.getAssertion());
+        assertNotNull(rtChoiceType.getEncryptedAssertion());
 
-            PrivateKey privateKey = DerUtils.decodePrivateKey(Base64.decode(PRIVATE_KEY));
-            AssertionUtil.decryptAssertion(resp, privateKey);
+        PrivateKey privateKey = DerUtils.decodePrivateKey(Base64.decode(PRIVATE_KEY));
+        AssertionUtil.decryptAssertion(resp, privateKey);
 
-            rtChoiceType = resp.getAssertions().get(0);
-            assertNotNull(rtChoiceType.getAssertion());
-            assertNull(rtChoiceType.getEncryptedAssertion());
-        }
+        rtChoiceType = resp.getAssertions().get(0);
+        assertNotNull(rtChoiceType.getAssertion());
+        assertNull(rtChoiceType.getEncryptedAssertion());
     }
 
     @Test
     public void testSaml20EncryptedAssertionsSignedTwoExtensionsReceivedWithRedirectBinding() throws Exception {
         Element el;
 
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-encrypted-signed-redirect-response-two-extensions.xml")) {
-            Object parsedObject = parser.parse(st);
-            assertThat(parsedObject, instanceOf(ResponseType.class));
-
-            ResponseType resp = (ResponseType) parsedObject;
-            assertThat(resp.getSignature(), nullValue());
-            assertThat(resp.getConsent(), nullValue());
-            assertThat(resp.getIssuer(), not(nullValue()));
-            assertThat(resp.getIssuer().getValue(), is("http://localhost:8081/auth/realms/saml-demo"));
-
-            assertThat(resp.getExtensions(), not(nullValue()));
-            assertThat(resp.getExtensions().getAny().size(), is(2));
-            assertThat(resp.getExtensions().getAny().get(0), instanceOf(Element.class));
-            el = (Element) resp.getExtensions().getAny().get(0);
-            assertThat(el.getLocalName(), is("KeyInfo"));
-            assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:key:1.0"));
-            assertThat(el.hasAttribute("MessageSigningKeyId"), is(true));
-            assertThat(el.getAttribute("MessageSigningKeyId"), is("FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE"));
-            assertThat(resp.getExtensions().getAny().get(1), instanceOf(Element.class));
-            el = (Element) resp.getExtensions().getAny().get(1);
-            assertThat(el.getLocalName(), is("ever"));
-            assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:what:1.0"));
-            assertThat(el.hasAttribute("what"), is(true));
-            assertThat(el.getAttribute("what"), is("ever"));
-
-            assertThat(resp.getAssertions(), not(nullValue()));
-            assertThat(resp.getAssertions().size(), is(1));
-        }
+        ResponseType resp = assertParsed("saml20-encrypted-signed-redirect-response-two-extensions.xml", ResponseType.class);
+        assertThat(resp.getSignature(), nullValue());
+        assertThat(resp.getConsent(), nullValue());
+        assertThat(resp.getIssuer(), not(nullValue()));
+        assertThat(resp.getIssuer().getValue(), is("http://localhost:8081/auth/realms/saml-demo"));
+
+        assertThat(resp.getExtensions(), not(nullValue()));
+        assertThat(resp.getExtensions().getAny().size(), is(2));
+        assertThat(resp.getExtensions().getAny().get(0), instanceOf(Element.class));
+        el = (Element) resp.getExtensions().getAny().get(0);
+        assertThat(el.getLocalName(), is("KeyInfo"));
+        assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:key:1.0"));
+        assertThat(el.hasAttribute("MessageSigningKeyId"), is(true));
+        assertThat(el.getAttribute("MessageSigningKeyId"), is("FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE"));
+        assertThat(resp.getExtensions().getAny().get(1), instanceOf(Element.class));
+        el = (Element) resp.getExtensions().getAny().get(1);
+        assertThat(el.getLocalName(), is("ever"));
+        assertThat(el.getNamespaceURI(), is("urn:keycloak:ext:what:1.0"));
+        assertThat(el.hasAttribute("what"), is(true));
+        assertThat(el.getAttribute("what"), is("ever"));
+
+        assertThat(resp.getAssertions(), not(nullValue()));
+        assertThat(resp.getAssertions().size(), is(1));
     }
 
     @Test
     public void testSaml20AuthnResponseNonAsciiNameDefaultUtf8() throws Exception {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("KEYCLOAK-3971-utf-8-no-header-authnresponse.xml")) {
-            Object parsedObject = parser.parse(st);
-            assertThat(parsedObject, instanceOf(ResponseType.class));
+        ResponseType rt = assertParsed("KEYCLOAK-3971-utf-8-no-header-authnresponse.xml", ResponseType.class);
 
-            ResponseType rt = (ResponseType) parsedObject;
-            assertThat(rt.getAssertions().size(), is(1));
-            final AssertionType assertion = rt.getAssertions().get(0).getAssertion();
-            assertThat(assertion.getSubject().getSubType().getBaseID(), instanceOf(NameIDType.class));
+        assertThat(rt.getAssertions().size(), is(1));
+        final AssertionType assertion = rt.getAssertions().get(0).getAssertion();
+        assertThat(assertion.getSubject().getSubType().getBaseID(), instanceOf(NameIDType.class));
 
-            NameIDType nameId = (NameIDType) assertion.getSubject().getSubType().getBaseID();
-            assertThat(nameId.getValue(), is("roàåאבčéèíñòøöùüßåäöü汉字"));
-        }
+        NameIDType nameId = (NameIDType) assertion.getSubject().getSubType().getBaseID();
+        assertThat(nameId.getValue(), is("roàåאבčéèíñòøöùüßåäöü汉字"));
+
+        assertThat(assertion.getSubject().getConfirmation(), hasSize(1));
+        assertThat(assertion.getSubject().getConfirmation().get(0).getSubjectConfirmationData(), notNullValue());
+        assertThat(assertion.getSubject().getConfirmation().get(0).getSubjectConfirmationData().getAnyType(), instanceOf(KeyInfoType.class));
+
+        KeyInfoType kit = (KeyInfoType) assertion.getSubject().getConfirmation().get(0).getSubjectConfirmationData().getAnyType();
+        assertThat(kit.getContent(), hasItem(instanceOf(X509DataType.class)));
+        X509DataType rsaKit = (X509DataType) kit.getContent().get(0);
+        assertThat(rsaKit.getDataObjects(), hasSize(1));
+        assertThat(rsaKit.getDataObjects().get(0), instanceOf(X509CertificateType.class));
     }
 
     @Test
     public void testSaml20AuthnResponseNonAsciiNameDefaultLatin2() throws Exception {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("KEYCLOAK-3971-8859-2-in-header-authnresponse.xml")) {
-            Object parsedObject = parser.parse(st);
-            assertThat(parsedObject, instanceOf(ResponseType.class));
-
-            ResponseType rt = (ResponseType) parsedObject;
-            assertThat(rt.getAssertions().size(), is(1));
-            final AssertionType assertion = rt.getAssertions().get(0).getAssertion();
-            assertThat(assertion.getSubject().getSubType().getBaseID(), instanceOf(NameIDType.class));
-
-            NameIDType nameId = (NameIDType) assertion.getSubject().getSubType().getBaseID();
-            assertThat(nameId.getValue(), is("ročéíöüßäöü"));
-        }
+        ResponseType rt = assertParsed("KEYCLOAK-3971-8859-2-in-header-authnresponse.xml", ResponseType.class);
+        assertThat(rt.getAssertions().size(), is(1));
+        final AssertionType assertion = rt.getAssertions().get(0).getAssertion();
+        final SubjectType subject = assertion.getSubject();
+
+        assertThat(subject.getConfirmation(), hasSize(1));
+        SubjectConfirmationType confirmation = subject.getConfirmation().get(0);
+        assertThat(confirmation.getMethod(), is(JBossSAMLURIConstants.SUBJECT_CONFIRMATION_BEARER.get()));
+        assertThat(confirmation.getSubjectConfirmationData(), notNullValue());
+        assertThat(confirmation.getSubjectConfirmationData().getInResponseTo(), is("ID_cc0ff6f7-b481-4c98-9a79-481d50958290"));
+        assertThat(confirmation.getSubjectConfirmationData().getRecipient(), is("http://localhost:8080/sales-post-sig/saml"));
+
+        assertThat(subject.getSubType().getBaseID(), instanceOf(NameIDType.class));
+        NameIDType nameId = (NameIDType) subject.getSubType().getBaseID();
+        assertThat(nameId.getValue(), is("ročéíöüßäöü"));
     }
 
     @Test
     public void testSaml20PostLogoutRequest() throws Exception {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-signed-logout-request.xml")) {
-            Object parsedObject = parser.parse(st);
-            assertThat(parsedObject, instanceOf(LogoutRequestType.class));
-        }
+        assertParsed("saml20-signed-logout-request.xml", LogoutRequestType.class);
     }
 
     @Test
     public void testOrganizationDetailsMetadata() throws Exception {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("KEYCLOAK-4040-sharefile-metadata.xml")) {
-            Object parsedObject = parser.parse(st);
-            assertThat(parsedObject, instanceOf(EntityDescriptorType.class));
-        }
+        assertParsed("KEYCLOAK-4040-sharefile-metadata.xml", EntityDescriptorType.class);
     }
 
     @Test
-    public void testSaml20MetadataEntityDescriptorIdP() throws IOException, ParsingException {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-entity-descriptor-idp.xml")) {
-            parser.parse(st);
-        }
+    public void testSaml20MetadataEntityDescriptorIdP() throws Exception {
+        assertParsed("saml20-entity-descriptor-idp.xml", EntityDescriptorType.class);
     }
 
     @Test
-    public void testSaml20MetadataEntityDescriptorSP() throws IOException, ParsingException {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-entity-descriptor-sp.xml")) {
-            parser.parse(st);
-        }
+    public void testSaml20MetadataEntityDescriptorSP() throws Exception {
+        assertParsed("saml20-entity-descriptor-sp.xml", EntityDescriptorType.class);
     }
 
     @Test
-    public void testSaml20MetadataEntityDescriptorAdfsIdP() throws IOException, ParsingException {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("KEYCLOAK-4809-IdPMetadata_test.xml")) {
-            parser.parse(st);
-        }
+    public void testSaml20MetadataEntityDescriptorAdfsIdP() throws Exception {
+        assertParsed("KEYCLOAK-4809-IdPMetadata_test.xml", EntityDescriptorType.class);
     }
 
     @Test
     public void testAttributeProfileMetadata() throws Exception {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("KEYCLOAK-4236-AttributeProfile-element.xml")) {
-            Object parsedObject = parser.parse(st);
-            assertThat(parsedObject, instanceOf(EntityDescriptorType.class));
-        }
+        assertParsed("KEYCLOAK-4236-AttributeProfile-element.xml", EntityDescriptorType.class);
     }
 
     @Test
     public void testEmptyAttributeValue() throws Exception {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("KEYCLOAK-4790-Empty-attribute-value.xml")) {
-            Object parsedObject = parser.parse(st);
-            assertThat(parsedObject, instanceOf(ResponseType.class));
-        }
+        ResponseType resp = assertParsed("KEYCLOAK-4790-Empty-attribute-value.xml", ResponseType.class);
+
+        assertThat(resp.getAssertions(), hasSize(1));
+        final AssertionType a = resp.getAssertions().get(0).getAssertion();
+        assertThat(a, notNullValue());
+
+        assertThat(a.getAttributeStatements(), hasSize(1));
+        final List<ASTChoiceType> attributes = a.getAttributeStatements().iterator().next().getAttributes();
+        assertThat(attributes, hasSize(3));
+        assertThat(attributes, everyItem(notNullValue(ASTChoiceType.class)));
+
+        final AttributeType attr0 = attributes.get(0).getAttribute();
+        final AttributeType attr1 = attributes.get(1).getAttribute();
+        final AttributeType attr2 = attributes.get(2).getAttribute();
+
+        assertThat(attr0.getName(), is("urn:oid:0.9.2342.19200300.100.1.2"));
+        assertThat(attr0.getAttributeValue(), hasSize(1));
+        assertThat(attr0.getAttributeValue().get(0), instanceOf(String.class));
+        assertThat((String) attr0.getAttributeValue().get(0), is(""));
+
+        assertThat(attr1.getName(), is("urn:oid:0.9.2342.19200300.100.1.3"));
+        assertThat(attr1.getAttributeValue(), hasSize(1));
+        assertThat(attr1.getAttributeValue().get(0), instanceOf(String.class));
+        assertThat((String) attr1.getAttributeValue().get(0), is("aa"));
+
+        assertThat(attr2.getName(), is("urn:oid:0.9.2342.19200300.100.1.4"));
+        assertThat(attr2.getAttributeValue(), hasSize(1));
+        assertThat(attr2.getAttributeValue().get(0), instanceOf(String.class));
+        assertThat((String) attr2.getAttributeValue().get(0), is(""));
     }
 
     @Test
     public void testEmptyAttributeValueLast() throws Exception {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("KEYCLOAK-4790-Empty-attribute-value-last.xml")) {
-            Object parsedObject = parser.parse(st);
-            assertThat(parsedObject, instanceOf(ResponseType.class));
+        assertParsed("KEYCLOAK-4790-Empty-attribute-value-last.xml", ResponseType.class);
+    }
+
+    @Test
+    public void testAuthnRequest() throws Exception {
+        AuthnRequestType req = assertParsed("saml20-authnrequest.xml", AuthnRequestType.class);
+
+        assertThat(req.getRequestedAuthnContext(), notNullValue());
+        assertThat(req.getRequestedAuthnContext().getAuthnContextClassRef(), hasItem(is("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")));
+        assertThat(req.getRequestedAuthnContext().getAuthnContextDeclRef(), hasItem(is("urn:kc:SAML:2.0:ac:ref:demo:decl")));
+    }
+
+    @Test
+    public void testAuthnRequestInvalidPerXsdWithValidationDisabled() throws Exception {
+        AuthnRequestType req = assertParsed("saml20-authnrequest-invalid-per-xsd.xml", AuthnRequestType.class);
+    }
+
+    @Test
+    public void testAuthnRequestInvalidPerXsdWithValidationEnabled() throws Exception {
+        try {
+            thrown.expect(ProcessingException.class);
+
+            System.setProperty("picketlink.schema.validate", "true");
+            AuthnRequestType req = assertParsed("saml20-authnrequest-invalid-per-xsd.xml", AuthnRequestType.class);
+        } finally {
+            System.clearProperty("picketlink.schema.validate");
         }
     }
 
     @Test
+    public void testAuthnRequestInvalidNamespace() throws Exception {
+        thrown.expect(ParsingException.class);
+        thrown.expectMessage(containsString("Unknown Start Element"));
+
+        assertParsed("saml20-authnrequest-invalid-namespace.xml", AuthnRequestType.class);
+    }
+
+    @Test
     public void testAuthnRequestScoping() throws Exception {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("KEYCLOAK-6109-authnrequest-scoping.xml")) {
-            Object parsedObject = parser.parse(st);
-            assertThat(parsedObject, instanceOf(AuthnRequestType.class));
+        assertParsed("KEYCLOAK-6109-authnrequest-scoping.xml", AuthnRequestType.class);
+    }
+
+    @Test
+    public void testLogoutResponseStatusDetail() throws Exception {
+        StatusResponseType resp = assertParsed("saml20-logout-response-status-detail.xml", StatusResponseType.class);
+
+        assertThat(resp.getIssuer(), notNullValue());
+        assertThat(resp.getIssuer().getValue(), is("http://idp.example.com/metadata.php"));
+        assertThat(resp.getIssuer().getFormat(), is(JBossSAMLURIConstants.NAMEID_FORMAT_ENTITY.getUri()));
+
+        assertThat(resp.getStatus(), notNullValue());
+
+        assertThat(resp.getStatus().getStatusDetail(), notNullValue());
+        assertThat(resp.getStatus().getStatusDetail().getAny(), notNullValue());
+        assertThat(resp.getStatus().getStatusDetail().getAny().size(), is(2));
+
+        assertThat(resp.getStatus().getStatusCode(), notNullValue());
+        assertThat(resp.getStatus().getStatusCode().getValue(), is(URI.create("urn:oasis:names:tc:SAML:2.0:status:Responder")));
+
+        assertThat(resp.getStatus().getStatusCode().getStatusCode(), nullValue());
+    }
+
+    @Test
+    public void testLogoutResponseSimpleStatus() throws Exception {
+        StatusResponseType resp = assertParsed("saml20-logout-response-status.xml", StatusResponseType.class);
+
+        assertThat(resp.getStatus(), notNullValue());
+
+        assertThat(resp.getStatus().getStatusMessage(), is("Status Message"));
+
+        assertThat(resp.getStatus().getStatusCode(), notNullValue());
+        assertThat(resp.getStatus().getStatusCode().getValue(), is(URI.create("urn:oasis:names:tc:SAML:2.0:status:Responder")));
+
+        assertThat(resp.getStatus().getStatusCode().getStatusCode(), nullValue());
+    }
+
+    @Test
+    public void testLogoutResponseNestedStatus() throws Exception {
+        StatusResponseType resp = assertParsed("saml20-logout-response-nested-status.xml", StatusResponseType.class);
+
+        assertThat(resp.getStatus(), notNullValue());
+
+        assertThat(resp.getStatus().getStatusCode(), notNullValue());
+        assertThat(resp.getStatus().getStatusCode().getValue(), is(URI.create("urn:oasis:names:tc:SAML:2.0:status:Responder")));
+
+        assertThat(resp.getStatus().getStatusCode().getStatusCode(), notNullValue());
+        assertThat(resp.getStatus().getStatusCode().getStatusCode().getValue(), is(URI.create("urn:oasis:names:tc:SAML:2.0:status:AuthnFailed")));
+
+        assertThat(resp.getStatus().getStatusCode().getStatusCode().getStatusCode(), nullValue());
+    }
+
+    @Test
+    public void testLogoutResponseDeepNestedStatus() throws Exception {
+        StatusResponseType resp = assertParsed("saml20-logout-response-nested-status-deep.xml", StatusResponseType.class);
+
+        assertThat(resp.getStatus(), notNullValue());
+
+        assertThat(resp.getStatus().getStatusDetail(), notNullValue());
+        assertThat(resp.getStatus().getStatusDetail().getAny(), notNullValue());
+        assertThat(resp.getStatus().getStatusDetail().getAny().size(), is(2));
+
+        assertThat(resp.getStatus().getStatusCode(), notNullValue());
+        assertThat(resp.getStatus().getStatusCode().getValue(), is(URI.create("urn:oasis:names:tc:SAML:2.0:status:Responder")));
+
+        assertThat(resp.getStatus().getStatusCode().getStatusCode(), notNullValue());
+        assertThat(resp.getStatus().getStatusCode().getStatusCode().getValue(), is(URI.create("urn:oasis:names:tc:SAML:2.0:status:AuthnFailed")));
+
+        assertThat(resp.getStatus().getStatusCode().getStatusCode().getStatusCode(), notNullValue());
+        assertThat(resp.getStatus().getStatusCode().getStatusCode().getStatusCode().getValue(), is(URI.create("urn:oasis:names:tc:SAML:2.0:status:VersionMismatch")));
+    }
+
+    @Test
+    public void testSaml20AssertionContents() throws Exception {
+        AssertionType a = assertParsed("saml20-assertion-example.xml", AssertionType.class);
+
+        assertThat(a.getSubject().getConfirmation(), hasSize(1));
+        assertThat(a.getSubject().getConfirmation().get(0).getSubjectConfirmationData(), notNullValue());
+        assertThat(a.getSubject().getConfirmation().get(0).getSubjectConfirmationData().getAnyType(), instanceOf(KeyInfoType.class));
+
+        KeyInfoType kit = (KeyInfoType) a.getSubject().getConfirmation().get(0).getSubjectConfirmationData().getAnyType();
+        assertThat(kit.getContent(), hasItem(instanceOf(RSAKeyValueType.class)));
+        RSAKeyValueType rsaKit = (RSAKeyValueType) kit.getContent().get(0);
+        assertThat(rsaKit.getModulus(), notNullValue());
+        assertThat(rsaKit.getExponent(), notNullValue());
+
+        assertThat(a.getStatements(), containsInAnyOrder(instanceOf(AuthnStatementType.class), instanceOf(AttributeStatementType.class)));
+        for (StatementAbstractType statement : a.getStatements()) {
+            if (statement instanceof AuthnStatementType) {
+                AuthnStatementType as = (AuthnStatementType) statement;
+                assertThat(as.getSessionNotOnOrAfter(), notNullValue());
+                assertThat(as.getSessionNotOnOrAfter(), is(XMLTimeUtil.parse("2009-06-17T18:55:10.738Z")));
+
+                final AuthnContextType ac = as.getAuthnContext();
+                assertThat(ac, notNullValue());
+                assertThat(ac.getSequence(), notNullValue());
+
+                assertThat(ac.getSequence().getClassRef().getValue(), is(JBossSAMLURIConstants.AC_UNSPECIFIED.getUri()));
+
+                assertThat(ac.getSequence(), notNullValue());
+                assertThat(ac.getSequence().getAuthnContextDecl(), nullValue());
+            }
         }
     }
 
     @Test
+    public void testSaml20AssertionDsaKey() throws Exception {
+        AssertionType a = assertParsed("saml20-assertion-dsakey.xml", AssertionType.class);
+
+        assertThat(a.getSubject().getConfirmation(), hasSize(1));
+        assertThat(a.getSubject().getConfirmation().get(0).getSubjectConfirmationData(), notNullValue());
+        assertThat(a.getSubject().getConfirmation().get(0).getSubjectConfirmationData().getAnyType(), instanceOf(KeyInfoType.class));
+
+        KeyInfoType kit = (KeyInfoType) a.getSubject().getConfirmation().get(0).getSubjectConfirmationData().getAnyType();
+        assertThat(kit.getContent(), hasItem(instanceOf(DSAKeyValueType.class)));
+        DSAKeyValueType rsaKit = (DSAKeyValueType) kit.getContent().get(0);
+        assertThat(rsaKit.getG(), notNullValue());
+        assertThat(rsaKit.getJ(), nullValue());
+        assertThat(rsaKit.getP(), notNullValue());
+        assertThat(rsaKit.getQ(), notNullValue());
+        assertThat(rsaKit.getY(), notNullValue());
+    }
+
+    @Test
     public void testSaml20AssertionsAnyTypeAttributeValue() throws Exception {
 
         String[] xmlSamples = {
@@ -348,21 +553,21 @@ public class SAMLParserTest {
     }
 
     @Test(expected = ParsingException.class)
-    public void testSaml20AssertionsNil1() throws IOException, ParsingException {
+    public void testSaml20AssertionsNil1() throws Exception {
         try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-assertion-nil-wrong-1.xml")) {
             parser.parse(st);
         }
     }
 
     @Test(expected = ParsingException.class)
-    public void testSaml20AssertionsNil2() throws IOException, ParsingException {
+    public void testSaml20AssertionsNil2() throws Exception {
         try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-assertion-nil-wrong-2.xml")) {
             parser.parse(st);
         }
     }
 
     @Test
-    public void testSaml20AssertionsMissingId() throws IOException, ParsingException {
+    public void testSaml20AssertionsMissingId() throws Exception {
         try (InputStream st = removeAttribute("saml20-assertion-example.xml", "ID")) {
             thrown.expect(ParsingException.class);
             thrown.expectMessage(endsWith("Required attribute missing: ID"));
@@ -371,16 +576,25 @@ public class SAMLParserTest {
     }
 
     @Test
-    public void testSaml20AssertionsMissingVersion() throws IOException, ParsingException {
+    public void testSaml20AssertionsMissingVersion() throws Exception {
         try (InputStream st = removeAttribute("saml20-assertion-example.xml", "Version")) {
             thrown.expect(ParsingException.class);
+            thrown.expectMessage(endsWith("Required attribute missing: Version"));
+            parser.parse(st);
+        }
+    }
+
+    @Test
+    public void testSaml20AssertionsWrongVersion() throws Exception {
+        try (InputStream st = updateAttribute("saml20-assertion-example.xml", "Version", "1.1")) {
+            thrown.expect(ParsingException.class);
             thrown.expectMessage(endsWith("Assertion Version required to be \"2.0\""));
             parser.parse(st);
         }
     }
 
     @Test
-    public void testSaml20AssertionsMissingIssueInstance() throws IOException, ParsingException {
+    public void testSaml20AssertionsMissingIssueInstance() throws Exception {
         try (InputStream st = removeAttribute("saml20-assertion-example.xml", "IssueInstant")) {
             thrown.expect(ParsingException.class);
             thrown.expectMessage(endsWith("Required attribute missing: IssueInstant"));
@@ -389,10 +603,60 @@ public class SAMLParserTest {
     }
 
     @Test
-    public void testSaml20AssertionsAdviceTag() throws IOException, ParsingException {
-        try (InputStream st = SAMLParserTest.class.getResourceAsStream("saml20-assertion-advice.xml")) {
-            parser.parse(st);
+    public void testSaml20AssertionsAdviceTag() throws Exception {
+        Matcher<String>[] ATTR_NAME = new Matcher[] {
+            is("portal_id"),
+            is("organization_id"),
+            is("status"),
+            is("has_sub_organization"),
+            is("anytype_test"),
+            is("anytype_no_xml_test"),
+            is("ssostartpage"),
+            is("logouturl"),
+            is("nil_value_attribute"),
+        };
+
+        Matcher<List<Object>>[] ATTR_VALUE = new Matcher[] {
+            contains(is("060D00000000SHZ")),
+            contains(is("<n1:elem2 xmlns:n1=\"http://example.net\" xml:lang=\"en\"><n3:stuff xmlns:n3=\"ftp://example.org\">00DD0000000F7L5</n3:stuff></n1:elem2>")),
+            contains(is("<status><code><status>XYZ</status></code></status>")),
+            contains(is("true")),
+            contains(is("<elem1 atttr1=\"en\"><elem2>val2</elem2></elem1>")),
+            contains(is("value_no_xml")),
+            contains(is("http://www.salesforce.com/security/saml/saml20-gen.jsp")),
+            contains(is("http://www.salesforce.com/security/del_auth/SsoLogoutPage.html")),
+            contains(nullValue()),
+        };
+
+        AssertionType a = assertParsed("saml20-assertion-advice.xml", AssertionType.class);
+
+        assertThat(a.getStatements(), containsInAnyOrder(instanceOf(AuthnStatementType.class), instanceOf(AttributeStatementType.class)));
+        for (StatementAbstractType statement : a.getStatements()) {
+            if (statement instanceof AuthnStatementType) {
+                AuthnStatementType as = (AuthnStatementType) statement;
+                final AuthnContextType ac = as.getAuthnContext();
+                assertThat(ac, notNullValue());
+                assertThat(ac.getSequence(), notNullValue());
+
+                assertThat(ac.getSequence().getClassRef().getValue(), is(JBossSAMLURIConstants.AC_UNSPECIFIED.getUri()));
+                
+                assertThat(ac.getSequence(), notNullValue());
+                assertThat(ac.getSequence().getAuthnContextDecl(), notNullValue());
+                assertThat(ac.getSequence().getAuthnContextDecl().getValue(), instanceOf(Element.class));
+                final Element el = (Element) ac.getSequence().getAuthnContextDecl().getValue();
+                assertThat(el.getTextContent(), is("auth.weak"));
+            } else {
+                AttributeStatementType as = (AttributeStatementType) statement;
+                assertThat(as.getAttributes(), hasSize(9));
+                for (int i = 0; i < as.getAttributes().size(); i ++) {
+                    AttributeType attr = as.getAttributes().get(i).getAttribute();
+                    assertThat(attr.getName(), ATTR_NAME[i]);
+                    assertThat(attr.getAttributeValue(), ATTR_VALUE[i]);
+                }
+            }
         }
+
+        assertThat(a.getConditions().getConditions(), contains(instanceOf(AudienceRestrictionType.class)));
     }
 
     private InputStream removeAttribute(String resourceName, String attribute) throws IOException {
@@ -403,5 +667,13 @@ public class SAMLParserTest {
         }
     }
 
+    private InputStream updateAttribute(String resourceName, String attribute, String newValue) throws IOException {
+        try (InputStream st = SAMLParserTest.class.getResourceAsStream(resourceName)) {
+            String str = StreamUtil.readString(st, StandardCharsets.UTF_8);
+            String processed = str.replaceAll("(" + attribute + "=)\"[^\"]+\"", "$1\"" + newValue + "\"");
+            return new ByteArrayInputStream(processed.getBytes());
+        }
+    }
+
 
 }
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-3971-8859-2-in-header-authnresponse.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-3971-8859-2-in-header-authnresponse.xml
index b4bc850..3e825b0 100644
--- a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-3971-8859-2-in-header-authnresponse.xml
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-3971-8859-2-in-header-authnresponse.xml
@@ -20,6 +20,7 @@
         <saml:AuthnStatement AuthnInstant="2016-12-15T12:42:49.788Z" SessionIndex="fb5d5a23-aa34-4528-a29a-6aad8c0ef0e8">
             <saml:AuthnContext>
                 <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
+                <saml:AuthnContextDeclRef>http://www.example.com/</saml:AuthnContextDeclRef>
             </saml:AuthnContext>
         </saml:AuthnStatement>
         <saml:AttributeStatement>
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-3971-utf-8-no-header-authnresponse.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-3971-utf-8-no-header-authnresponse.xml
index 52dbb5c..ae3c44c 100644
--- a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-3971-utf-8-no-header-authnresponse.xml
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-3971-utf-8-no-header-authnresponse.xml
@@ -8,7 +8,14 @@
         <saml:Subject>
             <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">roàåאבčéèíñòøöùüßåäöü汉字</saml:NameID>
             <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
-                <saml:SubjectConfirmationData InResponseTo="ID_cc0ff6f7-b481-4c98-9a79-481d50958290" NotOnOrAfter="2016-12-15T12:47:47.787Z" Recipient="http://localhost:8080/sales-post-sig/saml"/>
+                <saml:SubjectConfirmationData InResponseTo="ID_cc0ff6f7-b481-4c98-9a79-481d50958290" NotOnOrAfter="2016-12-15T12:47:47.787Z" Recipient="http://localhost:8080/sales-post-sig/saml">
+                    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
+                        <a>should be ignored</a>
+                        <X509Data>
+                            <X509Certificate>MIIFUjCCBDqgAwIBAgIDBbH0MA0GCSqGSIb3DQEBBQUAMGExCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR0wGwYDVQQLExREb21haW4gVmFsaWRhdGVkIFNTTDEbMBkGA1UEAxMSR2VvVHJ1c3QgRFYgU1NMIENBMB4XDTEyMTIxODAyMjcxOVoXDTE2MTIyMDAwNTYwMFowgckxKTAnBgNVBAUTIHlMbC1HNjFUWWtiaHBaL1JMTnNIYU8vTmJyWEVQOXc1MRMwEQYDVQQLEwpHVDQ4MjA0OTU4MTEwLwYDVQQLEyhTZWUgd3d3Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvY3BzIChjKTEyMTcwNQYDVQQLEy5Eb21haW4gQ29udHJvbCBWYWxpZGF0ZWQgLSBRdWlja1NTTChSKSBQcmVtaXVtMRswGQYDVQQDExJzYW1sLnNoYXJlZmlsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPUZyhTw3RmP7Y7v06aHgTNuv/Fm0PbGWbGlZEwqr8TGabocPbnb8iTBWAL2ECXMbx+VrpaHiSOVxqC2Y/vDXOs+1r0CzRKeMC6oQPsXZbieW6HxOAv3UVShxc9nfWI6+immo/o3BYI5WKcOaeZieVlDq7a7ctfSUJXHEBhpaSJNhghb+cUZtp1/EXs8/LyVQ31coo1q726WjCvFVB8OUU2u6BQLcbJF5aG3qh5CkNyivwM3NtNAyHhSXRmwyE+Yv5YNo5QAtUagCGYmS2saEJj8FxhXsNRtfW5B6vVhgmNreTcHCcWTpFGhjvferPjsjaIQAs3P2zx/pW/GSCXHy1AgMBAAGjggGoMIIBpDAfBgNVHSMEGDAWgBSM9NmTCke8AKBKzkt1bqC2sLJ+/DAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdEQQWMBSCEnNhbWwuc2hhcmVmaWxlLmNvbTBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vZ3Rzc2xkdi1jcmwuZ2VvdHJ1c3QuY29tL2NybHMvZ3Rzc2xkdi5jcmwwHQYDVR0OBBYEFIDTam2PfOzLpQoclHMwfsUtSi3kMAwGA1UdEwEB/wQCMAAwdQYIKwYBBQUHAQEEaTBnMCwGCCsGAQUFBzABhiBodHRwOi8vZ3Rzc2xkdi1vY3NwLmdlb3RydXN0LmNvbTA3BggrBgEFBQcwAoYraHR0cDovL2d0c3NsZHYtYWlhLmdlb3RydXN0LmNvbS9ndHNzbGR2LmNydDBMBgNVHSAERTBDMEEGCmCGSAGG+EUBBzYwMzAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2VzL2NwczANBgkqhkiG9w0BAQUFAAOCAQEAU0I6sMe1ZgJ27pdu9qhQLMIgt0w7CuEbLfsSZZdo5TXEj15SGQwU2A0F6o5ivdAvMWTCISJsjHdqCkvB6ZOdMHIfSqA9ARLqX7wLKYfM8X/4RM3koHfqHOvxXBLqCLj2mn34oZrMU5CVI6rqbMoU4D61io7DVswR7Dss0rCh1b1o52ZEBjy5w9oJhRTEFwL7ekf6tR9UioyxQ37pGfD8qOpX1hj5gqcZ5+qUSVNjOjeh+9e9OO5Y/ns3jjHK5ieZPdYeLLOp+D6qzAnOERgvKvkPyRIHZA9tAjxj5KIEzQUopmbP7oH4Ovo6YXT+iIuMVvX3dDu00ExOSZjEeDzo/w==</X509Certificate>
+                        </X509Data>
+                    </KeyInfo>
+                </saml:SubjectConfirmationData>
             </saml:SubjectConfirmation>
         </saml:Subject>
         <saml:Conditions NotBefore="2016-12-15T12:42:47.787Z" NotOnOrAfter="2016-12-15T12:43:47.787Z">
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-4790-Empty-attribute-value.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-4790-Empty-attribute-value.xml
index b4b03a1..c8b9d43 100644
--- a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-4790-Empty-attribute-value.xml
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/KEYCLOAK-4790-Empty-attribute-value.xml
@@ -10,7 +10,29 @@
         <Subject>
             <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName">C=c,OU=ou</NameID>
             <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
-                <SubjectConfirmationData InResponseTo="ID_638a829f-7ad2-408e-b3e5-5f224001057f" NotOnOrAfter="2017-04-24T12:55:14.645Z" Recipient="https://y/auth/realms/administration/broker/saml/endpoint"/>
+                <SubjectConfirmationData InResponseTo="ID_638a829f-7ad2-408e-b3e5-5f224001057f" NotOnOrAfter="2017-04-24T12:55:14.645Z" Recipient="https://y/auth/realms/administration/broker/saml/endpoint">
+                    <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                        <ds:X509Data>
+                            <!-- principal's X.509 cert -->
+                            <ds:X509Certificate>
+                                MIICiDCCAXACCQDE+9eiWrm62jANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJV
+                                UzESMBAGA1UEChMJTkNTQS1URVNUMQ0wCwYDVQQLEwRVc2VyMRMwEQYDVQQDEwpT
+                                UC1TZXJ2aWNlMB4XDTA2MDcxNzIwMjE0MVoXDTA2MDcxODIwMjE0MVowSzELMAkG
+                                A1UEBhMCVVMxEjAQBgNVBAoTCU5DU0EtVEVTVDENMAsGA1UECxMEVXNlcjEZMBcG
+                                A1UEAwwQdHJzY2F2b0B1aXVjLmVkdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
+                                gYEAv9QMe4lRl3XbWPcflbCjGK9gty6zBJmp+tsaJINM0VaBaZ3t+tSXknelYife
+                                nCc2O3yaX76aq53QMXy+5wKQYe8Rzdw28Nv3a73wfjXJXoUhGkvERcscs9EfIWcC
+                                g2bHOg8uSh+Fbv3lHih4lBJ5MCS2buJfsR7dlr/xsadU2RcCAwEAATANBgkqhkiG
+                                9w0BAQQFAAOCAQEAdyIcMTob7TVkelfJ7+I1j0LO24UlKvbLzd2OPvcFTCv6fVHx
+                                Ejk0QxaZXJhreZ6+rIdiMXrEzlRdJEsNMxtDW8++sVp6avoB5EX1y3ez+CEAIL4g
+                                cjvKZUR4dMryWshWIBHKFFul+r7urUgvWI12KbMeE9KP+kiiiiTskLcKgFzngw1J
+                                selmHhTcTCrcDocn5yO2+d3dog52vSOtVFDBsBuvDixO2hv679JR6Hlqjtk4GExp
+                                E9iVI0wdPE038uQIJJTXlhsMMLvUGVh/c0ReJBn92Vj4dI/yy6PtY/8ncYLYNkjg
+                                oVN0J/ymOktn9lTlFyTiuY4OuJsZRO1+zWLy9g==
+                            </ds:X509Certificate>
+                        </ds:X509Data>
+                    </ds:KeyInfo>
+                </SubjectConfirmationData>
             </SubjectConfirmation>
         </Subject>
         <Conditions NotBefore="2017-04-24T12:45:14.380Z" NotOnOrAfter="2017-04-24T13:45:14.380Z">
@@ -25,6 +47,11 @@
             <Attribute Name="urn:oid:0.9.2342.19200300.100.1.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                 <AttributeValue>aa</AttributeValue>
             </Attribute>
+            <Attribute Name="urn:oid:0.9.2342.19200300.100.1.4" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
+                <AttributeValue>      
+                
+                </AttributeValue>
+            </Attribute>
         </AttributeStatement>
         <AuthnStatement AuthnInstant="2017-04-24T12:50:14.037Z" SessionIndex="_0cceed2a-e409-4faa-a411-c647be748f2b">
             <AuthnContext>
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-advice.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-advice.xml
index 54b5c33..be62f15 100644
--- a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-advice.xml
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-advice.xml
@@ -60,10 +60,6 @@
     </saml:Conditions>
 
     <saml:Advice>
-        <saml:AssertionIDRef>NCName</saml:AssertionIDRef>
-    </saml:Advice>
-
-    <saml:Advice>
         <saml:AssertionURIRef>NCName</saml:AssertionURIRef>
         <a:a xmlns:a="urn:a">
             <a:b>nested
@@ -74,8 +70,8 @@
 
     <saml:AuthnStatement AuthnInstant="2009-06-17T18:45:10.738Z">
         <saml:AuthnContext>
-            <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified
-            </saml:AuthnContextClassRef>
+            <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
+            <saml:AuthnContextDecl xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">auth.weak</saml:AuthnContextDecl>
         </saml:AuthnContext>
     </saml:AuthnStatement>
 
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-dsakey.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-dsakey.xml
new file mode 100644
index 0000000..18e66cd
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-dsakey.xml
@@ -0,0 +1,44 @@
+<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                ID="_3c39bc0fe7b13769cab2f6f45eba801b1245264310738"
+                IssueInstant="2009-06-17T18:45:10.738Z" Version="2.0">
+    <saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">
+        https://www.salesforce.com
+    </saml:Issuer>
+
+    <saml:Subject>
+        <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">
+            saml01@salesforce.com
+        </saml:NameID>
+
+        <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+            <saml:SubjectConfirmationData NotOnOrAfter="2009-06-17T18:50:10.738Z"
+                                          Recipient="https://login.salesforce.com">
+                <dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
+                    <dsig:KeyValue>
+                        <dsig:DSAKeyValue>
+                            <dsig:P>/KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxeEu0ImbzRMqzVDZkVG9xD7nN1kuFw==</dsig:P>
+                            <dsig:Q>li7dzDacuo67Jg7mtqEm2TRuOMU=</dsig:Q>
+                            <dsig:G>Z4Rxsnqc9E7pGknFFH2xqaryRPBaQ01khpMdLRQnG541Awtx/XPaF5Bpsy4pNWMOHCBiNU0NogpsQW5QvnlMpA==</dsig:G>
+                            <dsig:Y>qV38IqrWJG0V/mZQvRVi1OHw9Zj84nDC4jO8P0axi1gb6d+475yhMjSc/BrIVC58W3ydbkK+Ri4OKbaRZlYeRA==</dsig:Y>
+                        </dsig:DSAKeyValue>
+                    </dsig:KeyValue>
+                </dsig:KeyInfo>
+            </saml:SubjectConfirmationData>
+        </saml:SubjectConfirmation>
+    </saml:Subject>
+
+    <saml:Conditions NotBefore="2009-06-17T18:45:10.738Z"
+                     NotOnOrAfter="2009-06-17T18:50:10.738Z">
+
+        <saml:AudienceRestriction>
+            <saml:Audience>https://saml.salesforce.com</saml:Audience>
+        </saml:AudienceRestriction>
+    </saml:Conditions>
+
+    <saml:AuthnStatement AuthnInstant="2009-06-17T18:45:10.738Z" NotOnOrAfter="2009-06-17T18:55:10.738Z">
+        <saml:AuthnContext>
+            <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
+        </saml:AuthnContext>
+    </saml:AuthnStatement>
+
+</saml:Assertion>
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-encrypted.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-encrypted.xml
new file mode 100644
index 0000000..b7848d2
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-encrypted.xml
@@ -0,0 +1,10 @@
+<saml:EncryptedAssertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
+    <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element">
+        <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
+        <xenc:CipherData>
+            <xenc:CipherValue>
+                RW2eu9nP2Ez9hfRlug9xC+kFfVF3HZpEb4kIFH33gmVbzrQjPk0l67uXkwRjC82FZZ482QnHCBIqNFlAryds/zTa6wdRvFmhQnIM6WxoAl8TM+e9h8MoKkalMc8J/Qfp+WQ7/XdmCg2pp9VvUZTK+g0+G4aGuL+S5+ssZq4rl9k7LrSYyp6vj+djgvISZiz5hPYJCN/WY/gWXfVuLHSpu4CmZt8D2APtT3ax1WmGcuzStAfTW8q3MFIDNV59hkpFmDb+gvyLNbZ95cDYxofiPXaC5cOTftnSBp68Ay1eienqdttEDo4fyakszdvq128KwXkH9azCg6sqLxli6B8l2xdq41MeuJO54VqmOhhLxwKy42NtnJvK/NkNwttH4yMwDPpPbC4vOKCXxT2r2F7jjvJQNB2VFv+oiUAWSSc3fGQcc2uNlx9YQVuzTmjqc7fXAWCGgYoogC8AeNWni204bnBoVpFrEo3gzuOe2fFsddJIclglmTH1hWf31FXUHDO2nl/lT4puQVTo+I+d6jpiV+qdp823NDntRxljRlUJO2AzSTXuIIGtF5q5KWyEi9Nj93BCWa1Llcddkn3ZEZMvDwR4MacwUj8G8hwoH73VvT3jAiakjSpNEIqYCzofeejdfN/gEuuAUfe8uNbTu+gBS+iP3QJe3Pc0Fs/lKJzd3frPNj7xb83wpOf865EQQoOozhnRIKKcMReSjakr/Px5NNooeiJcWEreDagQO2TbwTnHg1kCNG3BAXV/2lV3XBU4afZBoUfxAzYWFOl6xFCAPzhQCPL1SFJp1VRADY/1MU2Kaje5AZoJ4jjph8+yspxBvjic1vC1uYRGW8LWRind9w4eVhCm0LfPiFRCpP+jKPQOJzcNH580/nIMFXPHHnLKv/It7Qex1unDv/QjkuCFFHR6SWJm4WBrwDek+MyOIvgT6o878Cu0Ps472QpoYBQ+7l2WoylWdG1lHZV1UiHPj7PLHPNAL4rbbN3U88fS6N9OJHegQTfcX0i/1KPk4IN/5Z+/15dHI658BINjRvI/6O1QqaTVZkqM8ORcoGpn6BjAiz5rRhjWpOCwlmT+VzOAp3IqACURS1X+txjWE2mfVjlHLJsvyGRDLv1dUR3IeStDAEfsjR/ruRgn5XTFpYaccB/u//DJonJr5A+KFiLbYl+sbbSVAoQCAiAdxKdUpKPx7C473UJ2nYQGby5H5xwboa0Uj0SnJLYWdQ0jvVvzWpWFVWATc4UqnaxdoUDAmewrM6cSSIAmQBB34orCunFbriK9Z4efZ7gB9erQ1fpi3z/IjQBoTEpOUUIPW/qMAApIDPVM6UV9PumW7RL9zKEP5PuWJoGGnKbWGP/b9G4vMFiWMaSNHBYYMI6OLH4WJ3E+4QBGh2vjjfQ0gobhaLgIerIwCQFYEdl9KddAjaflUEFXal9fIQ8Bz9L3rDhQE5AGBZL6ULZmJe3GnkN6Cc+UWAGyD5zv2rsCG2lvR5ox4UE2mFi6nBJbC5Vj5m9Sz1l0QpRwUkH2kD2QQ5iV6nNmQOcU/mz7ulxluf8+FBJJimYVqK8UkJ6+W6j8Eft9Q8fTpEuEVLxqTWGgOAEUBf87RWDU+iF3A+AxFGsJLc5RC+5BKNTEDlV2qDCjHT7b5wqBKJ3FHulOih9EenlZiI51m6kg5yyxnMdbhasvSh6Az8Mp/4lFo/wSA/mXxNhBrEEmRhFiIE5yYUEYIj5F8fH+93tIuWQqyhXIwCntEOdSSmoei9EYFzj8deXcEzVf8y/N6HQErZcJjyg34caOsfRcJYoxEiCm4icA/btWhdjUNT02B20qnxGFndO4CRUQlyDqTbyVD8LRLK9/95L9+5v9zojLle8xQe30dsxKn7r9TTJH8QQai5iam9lU1ik50lwTKpZb18k4rNdO5cnnYoHzCXeCg38YZxyFt9G7um/MxlID5Qd5Ywq6thDzL7WxvanKeRhCuJ2MTVV0EoJxZKIj9Yv0Ars9mZHkoHoP0ikcW8d5ciDj1Onnbj+XDcYI3FZj0Y2vToZvYi/7eLWi8EnSjaIQrr/AHnrmZK1w3Uicd691U6r3Y0UdnzQEl4Ub/l1uhSaGAg2oEdDxkOdZ3Frvf/C4nTEBmunPlNvnJjVFssdeVVXKLBOZ5eRiJjasHUKnTeJVwolvd/dBI+ypfw1+5ae/0upxd9/gV1lbwX9N2yOwqbxz24cKXZWvOFBAGc3+gQFu8RrF6NAeQ96PlkuRsiNOKPPtJT3JNrLGvVKY8g==
+            </xenc:CipherValue>
+        </xenc:CipherData>
+    </xenc:EncryptedData>
+</saml:EncryptedAssertion>
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-example.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-example.xml
index 591932e..f834c52 100644
--- a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-example.xml
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-assertion-example.xml
@@ -47,7 +47,18 @@
 
         <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
             <saml:SubjectConfirmationData NotOnOrAfter="2009-06-17T18:50:10.738Z"
-                                          Recipient="https://login.salesforce.com"/>
+                                          Recipient="https://login.salesforce.com">
+                <dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
+                    <dsig:KeyValue>
+                        <dsig:RSAKeyValue>
+                            <dsig:Modulus>
+                                2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEik=
+                            </dsig:Modulus>
+                            <dsig:Exponent>AQAB</dsig:Exponent>
+                        </dsig:RSAKeyValue>
+                    </dsig:KeyValue>
+                </dsig:KeyInfo>
+            </saml:SubjectConfirmationData>
         </saml:SubjectConfirmation>
     </saml:Subject>
 
@@ -59,7 +70,7 @@
         </saml:AudienceRestriction>
     </saml:Conditions>
 
-    <saml:AuthnStatement AuthnInstant="2009-06-17T18:45:10.738Z">
+    <saml:AuthnStatement AuthnInstant="2009-06-17T18:45:10.738Z" NotOnOrAfter="2009-06-17T18:55:10.738Z">
         <saml:AuthnContext>
             <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified
             </saml:AuthnContextClassRef>
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-authnrequest.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-authnrequest.xml
index 7e63302..a271d94 100644
--- a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-authnrequest.xml
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-authnrequest.xml
@@ -2,4 +2,8 @@
                     ID="aaf23196-1773-2113-474a-fe114412ab72" Version="2.0" IssueInstant="2004-12-05T09:21:59">
     <saml:Issuer>https://sp/</saml:Issuer>
     <samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
+    <samlp:RequestedAuthnContext Comparison="exact">
+        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
+        <saml:AuthnContextDeclRef>urn:kc:SAML:2.0:ac:ref:demo:decl</saml:AuthnContextDeclRef>
+    </samlp:RequestedAuthnContext>
 </samlp:AuthnRequest>
\ No newline at end of file
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-authnrequest-invalid-namespace.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-authnrequest-invalid-namespace.xml
new file mode 100644
index 0000000..44ac1a1
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-authnrequest-invalid-namespace.xml
@@ -0,0 +1,9 @@
+<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:3.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:3.0:assertion"
+                    ID="aaf23196-1773-2113-474a-fe114412ab72" Version="2.0" IssueInstant="2004-12-05T09:21:59">
+    <saml:Issuer>https://sp/</saml:Issuer>
+    <samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
+    <samlp:RequestedAuthnContext Comparison="exact">
+        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
+        <saml:AuthnContextDeclRef>urn:kc:SAML:2.0:ac:ref:demo:decl</saml:AuthnContextDeclRef>
+    </samlp:RequestedAuthnContext>
+</samlp:AuthnRequest>
\ No newline at end of file
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-authnrequest-invalid-per-xsd.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-authnrequest-invalid-per-xsd.xml
new file mode 100644
index 0000000..d24c6f7
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-authnrequest-invalid-per-xsd.xml
@@ -0,0 +1,10 @@
+<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+                    ID="aaf23196-1773-2113-474a-fe114412ab72" Version="2.0" IssueInstant="2004-12-05T09:21:59">
+    <saml:Issuer>https://sp/</saml:Issuer>
+    <saml:Issuer>https://sp/</saml:Issuer>
+    <samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
+    <samlp:RequestedAuthnContext Comparison="exact">
+        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
+        <saml:AuthnContextDeclRef>urn:kc:SAML:2.0:ac:ref:demo:decl</saml:AuthnContextDeclRef>
+    </samlp:RequestedAuthnContext>
+</samlp:AuthnRequest>
\ No newline at end of file
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-encrypted-signed-redirect-response.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-encrypted-signed-redirect-response.xml
index d8d4c15..3b8c08a 100644
--- a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-encrypted-signed-redirect-response.xml
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-encrypted-signed-redirect-response.xml
@@ -1,5 +1,5 @@
 <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Destination="http://localhost:8080/sales-post-enc/saml" ID="ID_0b43d444-d1a8-44a5-8caf-38e176489e1f" InResponseTo="ID_223d3591-22fb-4b3c-9e38-4719293b2d94" IssueInstant="2016-11-01T13:52:43.054Z" Version="2.0">
-    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://localhost:8081/auth/realms/saml-demo</saml:Issuer>
+    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://localhost:8081/auth/realms/saml-demo</saml:Issuer>
     <samlp:Extensions>
         <kckey:KeyInfo xmlns:kckey="urn:keycloak:ext:key:1.0" MessageSigningKeyId="FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE"/>
     </samlp:Extensions>
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-logout-response-nested-status.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-logout-response-nested-status.xml
new file mode 100644
index 0000000..af6072a
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-logout-response-nested-status.xml
@@ -0,0 +1,8 @@
+<samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="dasda" Version="2.0" IssueInstant="2018-12-18T03:03:54Z" Destination="http://sp/saml" InResponseTo="aa">
+  <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
+  <samlp:Status>
+    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder">
+      <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:AuthnFailed"/>
+    </samlp:StatusCode>
+  </samlp:Status>
+</samlp:LogoutResponse>
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-logout-response-nested-status-deep.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-logout-response-nested-status-deep.xml
new file mode 100644
index 0000000..ff22344
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-logout-response-nested-status-deep.xml
@@ -0,0 +1,16 @@
+<samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="dasda" Version="2.0" IssueInstant="2018-12-18T03:03:54Z" Destination="http://sp/saml" InResponseTo="aa">
+  <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
+  <samlp:Status>
+    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder">
+      <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:AuthnFailed">
+        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:VersionMismatch"/>
+      </samlp:StatusCode>  
+    </samlp:StatusCode>
+    <samlp:StatusDetail>
+        <a>
+            <b>text</b>
+        </a>
+        <Status>text</Status>
+    </samlp:StatusDetail>
+  </samlp:Status>
+</samlp:LogoutResponse>
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-logout-response-status.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-logout-response-status.xml
new file mode 100644
index 0000000..0385cf0
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-logout-response-status.xml
@@ -0,0 +1,7 @@
+<samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="dasda" Version="2.0" IssueInstant="2018-12-18T03:03:54Z" Destination="http://sp/saml" InResponseTo="aa">
+  <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
+  <samlp:Status>
+    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder" />
+    <samlp:StatusMessage>Status Message</samlp:StatusMessage>
+  </samlp:Status>
+</samlp:LogoutResponse>
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-logout-response-status-detail.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-logout-response-status-detail.xml
new file mode 100644
index 0000000..2f36c99
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-logout-response-status-detail.xml
@@ -0,0 +1,13 @@
+<samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="dasda" Version="2.0" IssueInstant="2018-12-18T03:03:54Z" Destination="http://sp/saml" InResponseTo="aa">
+  <saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://idp.example.com/metadata.php</saml:Issuer>
+  <samlp:Status>
+    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder">
+    </samlp:StatusCode>
+    <samlp:StatusDetail>
+        <a>
+            <b>text</b>
+        </a>
+        <Status>text</Status>
+    </samlp:StatusDetail>
+  </samlp:Status>
+</samlp:LogoutResponse>
diff --git a/saml-core-api/src/main/java/org/keycloak/saml/common/constants/JBossSAMLConstants.java b/saml-core-api/src/main/java/org/keycloak/saml/common/constants/JBossSAMLConstants.java
index 13deac5..2615e58 100755
--- a/saml-core-api/src/main/java/org/keycloak/saml/common/constants/JBossSAMLConstants.java
+++ b/saml-core-api/src/main/java/org/keycloak/saml/common/constants/JBossSAMLConstants.java
@@ -16,65 +16,309 @@
  */
 package org.keycloak.saml.common.constants;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.xml.namespace.QName;
+import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.*;
+
 /**
  * SAML Constants
  *
- * @author Anil.Saldhana@redhat.com
  * @since Dec 10, 2008
  */
 public enum JBossSAMLConstants {
-    ADDRESS("Address"), ADVICE("Advice"), ADDITIONAL_METADATA_LOCATION("AdditionalMetadataLocation"), AFFILIATION_DESCRIPTOR(
-            "AffiliationDescriptor"), ALLOW_CREATE("AllowCreate"), ARTIFACT("Artifact"), ARTIFACT_RESOLVE("ArtifactResolve"), ARTIFACT_RESPONSE(
-            "ArtifactResponse"), ARTIFACT_RESOLUTION_SERVICE("ArtifactResolutionService"), ASSERTION("Assertion"), ASSERTION_CONSUMER_SERVICE(
-            "AssertionConsumerService"), ASSERTION_CONSUMER_SERVICE_URL("AssertionConsumerServiceURL"), ASSERTION_CONSUMER_SERVICE_INDEX(
-            "AssertionConsumerServiceIndex"), ASSERTION_ID_REQUEST_SERVICE("AssertionIDRequestService"), ATTRIBUTE("Attribute"), ATTRIBUTE_QUERY(
-            "AttributeQuery"), ATTRIBUTE_AUTHORITY_DESCRIPTOR("AttributeAuthorityDescriptor"), ATTRIBUTE_CONSUMING_SERVICE(
-            "AttributeConsumingService"), ATTRIBUTE_CONSUMING_SERVICE_INDEX("AttributeConsumingServiceIndex"), ATTRIBUTE_PROFILE("AttributeProfile"), ATTRIBUTE_SERVICE(
-            "AttributeService"), ATTRIBUTE_STATEMENT("AttributeStatement"), ATTRIBUTE_VALUE("AttributeValue"), AUDIENCE(
-            "Audience"), AUDIENCE_RESTRICTION("AudienceRestriction"), AUTHN_CONTEXT("AuthnContext"), AUTHENTICATING_AUTHORITY(
-            "AuthenticatingAuthority"), AUTHN_AUTHORITY_DESCRIPTOR("AuthnAuthorityDescriptor"), AUTHN_CONTEXT_CLASS_REF(
-            "AuthnContextClassRef"), AUTHN_CONTEXT_DECLARATION("AuthnContextDecl"), AUTHN_CONTEXT_DECLARATION_REF(
-            "AuthnContextDeclRef"), AUTHN_INSTANT("AuthnInstant"), AUTHN_REQUEST("AuthnRequest"), AUTHN_STATEMENT(
-            "AuthnStatement"), AUTHN_REQUESTS_SIGNED("AuthnRequestsSigned"), BASEID("BaseID"), BINDING("Binding"), CACHE_DURATION(
-            "cacheDuration"), COMPANY("Company"), CONDITIONS("Conditions"), COMPARISON("Comparison"), CONSENT("Consent"), CONTACT_PERSON("ContactPerson"), CONTACT_TYPE(
-            "contactType"), DESTINATION("Destination"), DNS_NAME("DNSName"), EMAIL_ADDRESS("EmailAddress"), ENCODING("Encoding"), ENCRYPTED_ASSERTION(
-            "EncryptedAssertion"), ENCRYPTED_ID("EncryptedID"), ENTITY_ID("entityID"), ENTITY_DESCRIPTOR("EntityDescriptor"), ENTITIES_DESCRIPTOR(
-            "EntitiesDescriptor"), EXTENSIONS("Extensions"), FORMAT("Format"), FRIENDLY_NAME("FriendlyName"), FORCE_AUTHN(
-            "ForceAuthn"), GIVEN_NAME("GivenName"), ID("ID"), IDP_SSO_DESCRIPTOR("IDPSSODescriptor"), INDEX("index"), INPUT_CONTEXT_ONLY(
-            "InputContextOnly"), IN_RESPONSE_TO("InResponseTo"), ISDEFAULT("isDefault"), IS_REQUIRED("isRequired"), IS_PASSIVE(
-            "IsPassive"), ISSUE_INSTANT("IssueInstant"), ISSUER("Issuer"), KEY_DESCRIPTOR("KeyDescriptor"), KEY_INFO("KeyInfo"), ENCRYPTION_METHOD("EncryptionMethod"), LANG(
-            "lang"), LANG_EN("en"), LOCATION("Location"), LOGOUT_REQUEST("LogoutRequest"), LOGOUT_RESPONSE("LogoutResponse"), MANAGE_NAMEID_SERVICE(
-            "ManageNameIDService"), METADATA_MIME("application/samlmetadata+xml"), METHOD("Method"), NAME("Name"), NAME_FORMAT(
-            "NameFormat"), NAMEID("NameID"), NAMEID_FORMAT("NameIDFormat"), NAMEID_MAPPING_SERVICE("NameIDMappingService"), NAMEID_POLICY(
-            "NameIDPolicy"), NAME_QUALIFIER("NameQualifier"), NOT_BEFORE("NotBefore"), NOT_ON_OR_AFTER("NotOnOrAfter"), ORGANIZATION(
-            "Organization"), ORGANIZATION_NAME("OrganizationName"), ORGANIZATION_DISPLAY_NAME("OrganizationDisplayName"), ORGANIZATION_URL(
-            "OrganizationURL"), ORGANIZATION_URL_ALT(
-            "OrganizationUrl"), PDP_DESCRIPTOR("PDPDescriptor"), PROTOCOL_BINDING("ProtocolBinding"), PROTOCOL_SUPPORT_ENUMERATION(
-            "protocolSupportEnumeration"), PROVIDER_NAME("ProviderName"), REQUESTED_AUTHN_CONTEXT("RequestedAuthnContext"), REASON(
-            "Reason"), RECIPIENT("Recipient"), REQUEST("Request"), REQUESTED_ATTRIBUTE("RequestedAttribute"), REQUEST_ABSTRACT(
-            "RequestAbstract"), RESPONSE("Response"), RESPONSE_LOCATION("ResponseLocation"), RETURN_CONTEXT("ReturnContext"), SCOPING("Scoping"), SESSION_INDEX(
-            "SessionIndex"), SERVICE_NAME("ServiceName"), SERVICE_DESCRIPTION("ServiceDescription"), SP_PROVIDED_ID(
-            "SPProvidedID"), SP_NAME_QUALIFIER("SPNameQualifier"), SP_SSO_DESCRIPTOR("SPSSODescriptor"), SIGNATURE("Signature"), SIGNATURE_SHA1_WITH_DSA(
-            "http://www.w3.org/2000/09/xmldsig#dsa-sha1"), SIGNATURE_SHA1_WITH_RSA("http://www.w3.org/2000/09/xmldsig#rsa-sha1"), SINGLE_SIGNON_SERVICE(
-            "SingleSignOnService"), SINGLE_LOGOUT_SERVICE("SingleLogoutService"), STATEMENT("Statement"), STATUS("Status"), STATUS_CODE(
-            "StatusCode"), STATUS_DETAIL("StatusDetail"), STATUS_MESSAGE("StatusMessage"), STATUS_RESPONSE_TYPE(
-            "StatusResponseType"), SUBJECT("Subject"), SUBJECT_CONFIRMATION("SubjectConfirmation"), SUBJECT_CONFIRMATION_DATA(
-            "SubjectConfirmationData"), SUBJECT_LOCALITY("SubjectLocality"), SURNAME("SurName"), TELEPHONE_NUMBER(
-            "TelephoneNumber"), TYPE("type"), USE("use"), VALUE("Value"), VALID_UNTIL("validUntil"), VERSION("Version"), VERSION_2_0(
-            "2.0"), WANT_AUTHN_REQUESTS_SIGNED("WantAuthnRequestsSigned"), WANT_ASSERTIONS_SIGNED("WantAssertionsSigned"), XACML_AUTHZ_DECISION_QUERY(
-            "XACMLAuthzDecisionQuery"), XACML_AUTHZ_DECISION_QUERY_TYPE("XACMLAuthzDecisionQueryType"), XACML_AUTHZ_DECISION_STATEMENT_TYPE(
-            "XACMLAuthzDecisionStatementType"), HTTP_POST_BINDING("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"), ONE_TIME_USE ("OneTimeUse"),
-            UNSOLICITED_RESPONSE_TARGET("TARGET"), UNSOLICITED_RESPONSE_SAML_VERSION("SAML_VERSION"), UNSOLICITED_RESPONSE_SAML_BINDING("SAML_BINDING"),
-            ROLE_DESCRIPTOR("RoleDescriptor"),
-            REQUEST_AUTHENTICATED("RequestAuthenticated");
-
-    private String name;
-
-    private JBossSAMLConstants(String val) {
-        this.name = val;
+    // saml-schema-protocol-2.0.xsd
+    ARTIFACT(PROTOCOL_NSURI, "Artifact"),
+    ARTIFACT_RESOLVE(PROTOCOL_NSURI, "ArtifactResolve"),
+    ARTIFACT_RESPONSE(PROTOCOL_NSURI, "ArtifactResponse"),
+    ASSERTION_ID_REQUEST(PROTOCOL_NSURI, "AssertionIDRequest"),
+    ATTRIBUTE_QUERY(PROTOCOL_NSURI, "AttributeQuery"),
+    AUTHN_QUERY(PROTOCOL_NSURI, "AuthnQuery"),
+    AUTHN_REQUEST(PROTOCOL_NSURI, "AuthnRequest"),
+    AUTHZ_DECISION_QUERY(PROTOCOL_NSURI, "AuthzDecisionQuery"),
+    EXTENSIONS__PROTOCOL(PROTOCOL_NSURI, "Extensions"),
+    GET_COMPLETE(PROTOCOL_NSURI, "GetComplete"),
+    IDP_ENTRY(PROTOCOL_NSURI, "IDPEntry"),
+    IDP_LIST(PROTOCOL_NSURI, "IDPList"),
+    LOGOUT_REQUEST(PROTOCOL_NSURI, "LogoutRequest"),
+    LOGOUT_RESPONSE(PROTOCOL_NSURI, "LogoutResponse"),
+    MANAGE_NAMEID_REQUEST(PROTOCOL_NSURI, "ManageNameIDRequest"),
+    MANAGE_NAMEID_RESPONSE(PROTOCOL_NSURI, "ManageNameIDResponse"),
+    NAMEID_MAPPING_REQUEST(PROTOCOL_NSURI, "NameIDMappingRequest"),
+    NAMEID_MAPPING_RESPONSE(PROTOCOL_NSURI, "NameIDMappingResponse"),
+    NAMEID_POLICY(PROTOCOL_NSURI, "NameIDPolicy"),
+    NEW_ENCRYPTEDID(PROTOCOL_NSURI, "NewEncryptedID"),
+    NEWID(PROTOCOL_NSURI, "NewID"),
+    REQUESTED_AUTHN_CONTEXT(PROTOCOL_NSURI, "RequestedAuthnContext"),
+    REQUESTERID(PROTOCOL_NSURI, "RequesterID"),
+    RESPONSE__PROTOCOL(PROTOCOL_NSURI, "Response"),
+    SCOPING(PROTOCOL_NSURI, "Scoping"),
+    SESSION_INDEX(PROTOCOL_NSURI, "SessionIndex"),
+    STATUS_CODE(PROTOCOL_NSURI, "StatusCode"),
+    STATUS_DETAIL(PROTOCOL_NSURI, "StatusDetail"),
+    STATUS_MESSAGE(PROTOCOL_NSURI, "StatusMessage"),
+    STATUS(PROTOCOL_NSURI, "Status"),
+    SUBJECT_QUERY(PROTOCOL_NSURI, "SubjectQuery"),
+    TERMINATE(PROTOCOL_NSURI, "Terminate"),
+
+    // saml-schema-assertion-2.0.xsd
+    ACTION(ASSERTION_NSURI, "Action"),
+    ADVICE(ASSERTION_NSURI, "Advice"),
+    ASSERTION(ASSERTION_NSURI, "Assertion"),
+    ASSERTION_ID_REF(ASSERTION_NSURI, "AssertionIDRef"),
+    ASSERTION_URI_REF(ASSERTION_NSURI, "AssertionURIRef"),
+    ATTRIBUTE(ASSERTION_NSURI, "Attribute"),
+    ATTRIBUTE_STATEMENT(ASSERTION_NSURI, "AttributeStatement"),
+    ATTRIBUTE_VALUE(ASSERTION_NSURI, "AttributeValue"),
+    AUDIENCE(ASSERTION_NSURI, "Audience"),
+    AUDIENCE_RESTRICTION(ASSERTION_NSURI, "AudienceRestriction"),
+    AUTHENTICATING_AUTHORITY(ASSERTION_NSURI, "AuthenticatingAuthority"),
+    AUTHN_CONTEXT(ASSERTION_NSURI, "AuthnContext"),
+    AUTHN_CONTEXT_CLASS_REF(ASSERTION_NSURI, "AuthnContextClassRef"),
+    AUTHN_CONTEXT_DECL(ASSERTION_NSURI, "AuthnContextDecl"),
+    AUTHN_CONTEXT_DECL_REF(ASSERTION_NSURI, "AuthnContextDeclRef"),
+    AUTHN_STATEMENT(ASSERTION_NSURI, "AuthnStatement"),
+    AUTHZ_DECISION_STATEMENT(ASSERTION_NSURI, "AuthzDecisionStatement"),
+    BASEID(ASSERTION_NSURI, "BaseID"),
+    CONDITION(ASSERTION_NSURI, "Condition"),
+    CONDITIONS(ASSERTION_NSURI, "Conditions"),
+    ENCRYPTED_ASSERTION(ASSERTION_NSURI, "EncryptedAssertion"),
+    ENCRYPTED_ATTRIBUTE(ASSERTION_NSURI, "EncryptedAttribute"),
+    ENCRYPTED_ID(ASSERTION_NSURI, "EncryptedID"),
+    EVIDENCE(ASSERTION_NSURI, "Evidence"),
+    ISSUER(ASSERTION_NSURI, "Issuer"),
+    NAMEID(ASSERTION_NSURI, "NameID"),
+    ONE_TIME_USE(ASSERTION_NSURI, "OneTimeUse"),
+    PROXY_RESTRICTION(ASSERTION_NSURI, "ProxyRestriction"),
+    STATEMENT(ASSERTION_NSURI, "Statement"),
+    SUBJECT_CONFIRMATION_DATA(ASSERTION_NSURI, "SubjectConfirmationData"),
+    SUBJECT_CONFIRMATION(ASSERTION_NSURI, "SubjectConfirmation"),
+    SUBJECT_LOCALITY(ASSERTION_NSURI, "SubjectLocality"),
+    SUBJECT(ASSERTION_NSURI, "Subject"),
+
+    // saml-schema-metadata-2.0.xsd
+    ADDITIONAL_METADATA_LOCATION(METADATA_NSURI, "AdditionalMetadataLocation"),
+    AFFILIATE_MEMBER(METADATA_NSURI, "AffiliateMember"),
+    AFFILIATION_DESCRIPTOR(METADATA_NSURI, "AffiliationDescriptor"),
+    ARTIFACT_RESOLUTION_SERVICE(METADATA_NSURI, "ArtifactResolutionService"),
+    ASSERTION_CONSUMER_SERVICE(METADATA_NSURI, "AssertionConsumerService"),
+    ASSERTION_ID_REQUEST_SERVICE(METADATA_NSURI, "AssertionIDRequestService"),
+    ATTRIBUTE_AUTHORITY_DESCRIPTOR(METADATA_NSURI, "AttributeAuthorityDescriptor"),
+    ATTRIBUTE_CONSUMING_SERVICE(METADATA_NSURI, "AttributeConsumingService"),
+    ATTRIBUTE_PROFILE(METADATA_NSURI, "AttributeProfile"),
+    ATTRIBUTE_SERVICE(METADATA_NSURI, "AttributeService"),
+    AUTHN_AUTHORITY_DESCRIPTOR(METADATA_NSURI, "AuthnAuthorityDescriptor"),
+    AUTHN_QUERY_SERVICE(METADATA_NSURI, "AuthnQueryService"),
+    AUTHZ_SERVICE(METADATA_NSURI, "AuthzService"),
+    COMPANY(METADATA_NSURI, "Company"),
+    CONTACT_PERSON(METADATA_NSURI, "ContactPerson"),
+    EMAIL_ADDRESS(METADATA_NSURI, "EmailAddress"),
+    ENCRYPTION_METHOD(METADATA_NSURI, "EncryptionMethod"),
+    ENTITIES_DESCRIPTOR(METADATA_NSURI, "EntitiesDescriptor"),
+    ENTITY_DESCRIPTOR(METADATA_NSURI, "EntityDescriptor"),
+    EXTENSIONS__METADATA(METADATA_NSURI, "Extensions"),
+    GIVEN_NAME(METADATA_NSURI, "GivenName"),
+    IDP_SSO_DESCRIPTOR(METADATA_NSURI, "IDPSSODescriptor"),
+    KEY_DESCRIPTOR(METADATA_NSURI, "KeyDescriptor"),
+    MANAGE_NAMEID_SERVICE(METADATA_NSURI, "ManageNameIDService"),
+    NAMEID_FORMAT(METADATA_NSURI, "NameIDFormat"),
+    NAMEID_MAPPING_SERVICE(METADATA_NSURI, "NameIDMappingService"),
+    ORGANIZATION_DISPLAY_NAME(METADATA_NSURI, "OrganizationDisplayName"),
+    ORGANIZATION_NAME(METADATA_NSURI, "OrganizationName"),
+    ORGANIZATION(METADATA_NSURI, "Organization"),
+    ORGANIZATION_URL(METADATA_NSURI, "OrganizationURL"),
+    ORGANIZATION_URL_ALT(METADATA_NSURI, "OrganizationUrl"),    // non-standard: KEYCLOAK-4040
+    PDP_DESCRIPTOR(METADATA_NSURI, "PDPDescriptor"),
+    REQUESTED_ATTRIBUTE(METADATA_NSURI, "RequestedAttribute"),
+    ROLE_DESCRIPTOR(METADATA_NSURI, "RoleDescriptor"),
+    SERVICE_DESCRIPTION(METADATA_NSURI, "ServiceDescription"),
+    SERVICE_NAME(METADATA_NSURI, "ServiceName"),
+    SINGLE_LOGOUT_SERVICE(METADATA_NSURI, "SingleLogoutService"),
+    SINGLE_SIGNON_SERVICE(METADATA_NSURI, "SingleSignOnService"),
+    SP_SSO_DESCRIPTOR(METADATA_NSURI, "SPSSODescriptor"),
+    SURNAME(METADATA_NSURI, "SurName"),
+    TELEPHONE_NUMBER(METADATA_NSURI, "TelephoneNumber"),
+
+    // saml-schema-ecp-2.0.xsd
+    RELAY_STATE(ECP_PROFILE, "RelayState"),
+    REQUEST(ECP_PROFILE, "Request"),
+    RESPONSE__ECP(ECP_PROFILE, "Response"),
+
+    SIGNATURE(XMLDSIG_NSURI, "Signature"),
+    DSA_KEY_VALUE(XMLDSIG_NSURI, "DSAKeyValue"),
+    KEY_INFO(XMLDSIG_NSURI, "KeyInfo"),
+    KEY_VALUE(XMLDSIG_NSURI, "KeyValue"),
+    RSA_KEY_VALUE(XMLDSIG_NSURI, "RSAKeyValue"),
+    X509_CERT(XMLDSIG_NSURI, "X509Certificate"),
+    X509_DATA(XMLDSIG_NSURI, "X509Data"),
+
+    // Attribute names and other constants
+    ADDRESS("Address"),
+    ALLOW_CREATE("AllowCreate"),
+    ASSERTION_CONSUMER_SERVICE_URL("AssertionConsumerServiceURL"),
+    ASSERTION_CONSUMER_SERVICE_INDEX("AssertionConsumerServiceIndex"),
+    ATTRIBUTE_CONSUMING_SERVICE_INDEX("AttributeConsumingServiceIndex"),
+    AUTHN_INSTANT("AuthnInstant"),
+    AUTHN_REQUESTS_SIGNED("AuthnRequestsSigned"),
+    BINDING("Binding"),
+    CACHE_DURATION("cacheDuration"),
+    COMPARISON("Comparison"),
+    CONSENT("Consent"),
+    CONTACT_TYPE("contactType"),
+    DESTINATION("Destination"),
+    DNS_NAME("DNSName"),
+    ENCODING("Encoding"),
+    ENCRYPTED_KEY("EncryptedKey"),
+    ENTITY_ID("entityID"),
+    FORMAT("Format"),
+    FRIENDLY_NAME("FriendlyName"),
+    FORCE_AUTHN("ForceAuthn"),
+    ID("ID"),
+    INDEX("index"),
+    INPUT_CONTEXT_ONLY("InputContextOnly"),
+    IN_RESPONSE_TO("InResponseTo"),
+    ISDEFAULT("isDefault"),
+    IS_REQUIRED("isRequired"),
+    IS_PASSIVE("IsPassive"),
+    ISSUE_INSTANT("IssueInstant"),
+    LOCATION("Location"),
+    METHOD("Method"),
+    NAME("Name"),
+    NAME_FORMAT("NameFormat"),
+    NAME_QUALIFIER("NameQualifier"),
+    NOT_BEFORE("NotBefore"),
+    NOT_ON_OR_AFTER("NotOnOrAfter"),
+    PROTOCOL_BINDING("ProtocolBinding"),
+    PROTOCOL_SUPPORT_ENUMERATION("protocolSupportEnumeration"),
+    PROVIDER_NAME("ProviderName"),
+    REASON("Reason"),
+    RECIPIENT("Recipient"),
+    REQUEST_ABSTRACT("RequestAbstract"),
+    RESPONSE_LOCATION("ResponseLocation"),
+    RETURN_CONTEXT("ReturnContext"),
+    SP_PROVIDED_ID("SPProvidedID"),
+    SP_NAME_QUALIFIER("SPNameQualifier"),
+    STATUS_RESPONSE_TYPE("StatusResponseType"),
+    TYPE("type"),
+    USE("use"),
+    VALUE("Value"),
+    VALID_UNTIL("validUntil"),
+    VERSION("Version"),
+    WANT_AUTHN_REQUESTS_SIGNED("WantAuthnRequestsSigned"),
+    WANT_ASSERTIONS_SIGNED("WantAssertionsSigned"),
+    XACML_AUTHZ_DECISION_QUERY("XACMLAuthzDecisionQuery"),
+    XACML_AUTHZ_DECISION_QUERY_TYPE("XACMLAuthzDecisionQueryType"),
+    XACML_AUTHZ_DECISION_STATEMENT_TYPE("XACMLAuthzDecisionStatementType"),
+    REQUEST_AUTHENTICATED("RequestAuthenticated"),
+
+    UNSOLICITED_RESPONSE_TARGET("TARGET"),
+    UNSOLICITED_RESPONSE_SAML_VERSION("SAML_VERSION"),
+    UNSOLICITED_RESPONSE_SAML_BINDING("SAML_BINDING"),
+
+    LANG("lang"),
+    LANG_EN("en"),
+    METADATA_MIME("application/samlmetadata+xml"),
+    SIGNATURE_SHA1_WITH_DSA("http://www.w3.org/2000/09/xmldsig#dsa-sha1"),
+    SIGNATURE_SHA1_WITH_RSA("http://www.w3.org/2000/09/xmldsig#rsa-sha1"),
+    VERSION_2_0("2.0"),
+
+    /** @deprecated Use namespace-aware variant instead */
+    RESPONSE("Response"),
+    /** @deprecated Use namespace-aware variant instead */
+    EXTENSIONS("Extensions"),
+
+    UNKNOWN_VALUE(null)
+    ;
+
+    private final QName asQName;
+    private final JBossSAMLURIConstants nsUri;
+
+    private static class ReverseLookup {
+        // Private class to make sure JBossSAMLURIConstants is fully initialized
+        private static final Map<QName, JBossSAMLConstants> QNAME_CONSTANTS;
+        private static final Map<String, JBossSAMLConstants> CONSTANTS;
+
+        static {
+            HashMap<QName, JBossSAMLConstants> q = new HashMap<>(JBossSAMLConstants.values().length);
+            HashMap<String, JBossSAMLConstants> m = new HashMap<>(JBossSAMLConstants.values().length);
+            JBossSAMLConstants old;
+            for (JBossSAMLConstants c : JBossSAMLConstants.values()) {
+                if ((old = q.put(c.getAsQName(), c)) != null) {
+                    throw new IllegalStateException("Same name " + c.getAsQName() + " used for two distinct constants: " + c + ", " + old);
+                }
+
+                String key = c.get();
+                if ((old = m.put(key, c)) != null) {
+//                    System.out.println("WARNING: " + old);
+                    if (old != null && c.getAsQName().equals(old.getAsQName())) {
+                        throw new IllegalStateException("Same name " + key + " used for two distinct constants: " + c + ", " + old);
+                    }
+                    m.put(key, null);
+                }
+            }
+            QNAME_CONSTANTS = Collections.unmodifiableMap(q);
+            CONSTANTS = Collections.unmodifiableMap(m);
+        }
+
+        public JBossSAMLConstants from(String key) {
+            return CONSTANTS.get(key);
+        }
+
+        public JBossSAMLConstants from(QName key) {
+            return QNAME_CONSTANTS.get(key);
+        }
+    }
+    private static final ReverseLookup REVERSE_LOOKUP = new ReverseLookup();
+
+    private JBossSAMLConstants(String name) {
+        this.asQName = name == null ? null : new QName(name);
+        this.nsUri = null;
+    }
+
+    private JBossSAMLConstants(JBossSAMLURIConstants namespaceUri, String name) {
+        this.nsUri = namespaceUri;
+        this.asQName = name == null ? null : new QName(namespaceUri.get(), name);
     }
 
     public String get() {
-        return this.name;
+        return this.asQName == null ? null : this.asQName.getLocalPart();
+    }
+
+    public QName getAsQName() {
+        return asQName;
+    }
+
+    public JBossSAMLURIConstants getNsUri() {
+        return nsUri;
+    }
+
+    /**
+     * Returns an enum constant based if known for the given {@code key}, or the {@code defaultValue} otherwise.
+     * @param key
+     * @return
+     */
+    public static JBossSAMLConstants from(String key, JBossSAMLConstants defaultValue) {
+        final JBossSAMLConstants res = REVERSE_LOOKUP.from(key);
+        return res == null ? defaultValue : res;
+    }
+
+    /**
+     * Returns an enum constant based if known for the given {@code key}, or the {@code UNKNOWN_VALUE} otherwise.
+     * @param key
+     * @return
+     */
+    public static JBossSAMLConstants from(String key) {
+        return from(key, UNKNOWN_VALUE);
+    }
+
+    /**
+     * Returns an enum constant based if known for the given {@code name} (namespace-aware), or the {@code UNKNOWN_VALUE} otherwise.
+     * @param key
+     * @return
+     */
+    public static JBossSAMLConstants from(QName name) {
+        final JBossSAMLConstants res = REVERSE_LOOKUP.from(name);
+        return res == null ? UNKNOWN_VALUE : res;
     }
 }
\ No newline at end of file
diff --git a/saml-core-api/src/main/java/org/keycloak/saml/common/constants/JBossSAMLURIConstants.java b/saml-core-api/src/main/java/org/keycloak/saml/common/constants/JBossSAMLURIConstants.java
index 1479495..512fecd 100755
--- a/saml-core-api/src/main/java/org/keycloak/saml/common/constants/JBossSAMLURIConstants.java
+++ b/saml-core-api/src/main/java/org/keycloak/saml/common/constants/JBossSAMLURIConstants.java
@@ -16,6 +16,11 @@
  */
 package org.keycloak.saml.common.constants;
 
+import java.net.URI;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Define the constants based on URI
  *
@@ -23,60 +28,58 @@ package org.keycloak.saml.common.constants;
  * @since Dec 10, 2008
  */
 public enum JBossSAMLURIConstants {
-    AC_PASSWORD_PROTECTED_TRANSPORT("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"), AC_PASSWORD(
-            "urn:oasis:names:tc:SAML:2.0:ac:classes:Password"), AC_TLS_CLIENT(
-            "urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient"), AC_PREVIOUS_SESSION(
-            "urn:oasis:names:tc:SAML:2.0:ac:classes:PreviousSession"), AC_UNSPECIFIED(
-            "urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified"), AC_IP(
-            "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol"),
-
-    ASSERTION_NSURI("urn:oasis:names:tc:SAML:2.0:assertion"), ATTRIBUTE_FORMAT_BASIC(
-            "urn:oasis:names:tc:SAML:2.0:attrname-format:basic"), ATTRIBUTE_FORMAT_URI(
-            "urn:oasis:names:tc:SAML:2.0:attrname-format:uri"),
-
-    BEARER("urn:oasis:names:tc:SAML:2.0:cm:bearer"),
-
-    CLAIMS_EMAIL_ADDRESS_2005("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"), CLAIMS_EMAIL_ADDRESS(
-            "http://schemas.xmlsoap.org/claims/EmailAddress"), CLAIMS_GIVEN_NAME(
-            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"), CLAIMS_NAME(
-            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"), CLAIMS_USER_PRINCIPAL_NAME_2005(
-            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"), CLAIMS_USER_PRINCIPAL_NAME(
-            "http://schemas.xmlsoap.org/claims/UPN"), CLAIMS_COMMON_NAME("http://schemas.xmlsoap.org/claims/CommonName"), CLAIMS_GROUP(
-            "http://schemas.xmlsoap.org/claims/Group"), CLAIMS_ROLE(
-            "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"), CLAIMS_SURNAME(
-            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"), CLAIMS_PRIVATE_ID(
-            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier"), CLAIMS_NAME_IDENTIFIER(
-            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"), CLAIMS_AUTHENTICATION_METHOD(
-            "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod"), CLAIMS_DENY_ONLY_GROUP_SID(
-            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/denyonlysid"), CLAIMS_DENY_ONLY_PRIMARY_SID(
-            "http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarysid"), CLAIMS_DENY_ONLY_PRIMARY_GROUP_SID(
-            "http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarygroupsid"), CLAIMS_GROUP_SID(
-            "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid"), CLAIMS_PRIMARY_GROUP_SID(
-            "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid"), CLAIMS_PRIMARY_SID(
-            "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid"), CLAIMS_WINDOWS_ACCOUNT_NAME(
-            "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"), CLAIMS_PUID(
-            "http://schemas.xmlsoap.org/claims/PUID"),
+    AC_PASSWORD_PROTECTED_TRANSPORT("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"),
+    AC_PASSWORD("urn:oasis:names:tc:SAML:2.0:ac:classes:Password"),
+    AC_TLS_CLIENT("urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient"),
+    AC_PREVIOUS_SESSION("urn:oasis:names:tc:SAML:2.0:ac:classes:PreviousSession"),
+    AC_UNSPECIFIED("urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified"),
+    AC_IP("urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol"),
+
+    ASSERTION_NSURI("urn:oasis:names:tc:SAML:2.0:assertion"),
+    ATTRIBUTE_FORMAT_BASIC("urn:oasis:names:tc:SAML:2.0:attrname-format:basic"),
+    ATTRIBUTE_FORMAT_URI("urn:oasis:names:tc:SAML:2.0:attrname-format:uri"),
+
+    CLAIMS_EMAIL_ADDRESS_2005("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"),
+    CLAIMS_EMAIL_ADDRESS("http://schemas.xmlsoap.org/claims/EmailAddress"),
+    CLAIMS_GIVEN_NAME("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"),
+    CLAIMS_NAME("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"),
+    CLAIMS_USER_PRINCIPAL_NAME_2005("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"),
+    CLAIMS_USER_PRINCIPAL_NAME("http://schemas.xmlsoap.org/claims/UPN"),
+    CLAIMS_COMMON_NAME("http://schemas.xmlsoap.org/claims/CommonName"),
+    CLAIMS_GROUP("http://schemas.xmlsoap.org/claims/Group"),
+    CLAIMS_ROLE("http://schemas.microsoft.com/ws/2008/06/identity/claims/role"),
+    CLAIMS_SURNAME("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"),
+    CLAIMS_PRIVATE_ID("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier"),
+    CLAIMS_NAME_IDENTIFIER("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"),
+    CLAIMS_AUTHENTICATION_METHOD("http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod"),
+    CLAIMS_DENY_ONLY_GROUP_SID("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/denyonlysid"),
+    CLAIMS_DENY_ONLY_PRIMARY_SID("http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarysid"),
+    CLAIMS_DENY_ONLY_PRIMARY_GROUP_SID("http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarygroupsid"),
+    CLAIMS_GROUP_SID("http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid"),
+    CLAIMS_PRIMARY_GROUP_SID("http://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid"),
+    CLAIMS_PRIMARY_SID("http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid"),
+    CLAIMS_WINDOWS_ACCOUNT_NAME("http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"),
+    CLAIMS_PUID("http://schemas.xmlsoap.org/claims/PUID"),
 
     HOLDER_OF_KEY("urn:oasis:names:tc:SAML:2.0:cm:holder-of-key"),
 
-    METADATA_NSURI("urn:oasis:names:tc:SAML:2.0:metadata"), METADATA_HTTP_REDIRECT_BINDING(
-            "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"),
+    METADATA_NSURI("urn:oasis:names:tc:SAML:2.0:metadata"),
 
-    NAMEID_FORMAT_TRANSIENT("urn:oasis:names:tc:SAML:2.0:nameid-format:transient"), NAMEID_FORMAT_PERSISTENT(
-            "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"), NAMEID_FORMAT_UNSPECIFIED(
-            "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"), NAMEID_FORMAT_EMAIL(
-            "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"), NAMEID_FORMAT_X509SUBJECTNAME(
-            "urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName"), NAMEID_FORMAT_WINDOWS_DOMAIN_NAME(
-            "urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName"), NAMEID_FORMAT_KERBEROS(
-            "urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos"), NAMEID_FORMAT_ENTITY(
-            "urn:oasis:names:tc:SAML:2.0:nameid-format:entity"),
+    NAMEID_FORMAT_TRANSIENT("urn:oasis:names:tc:SAML:2.0:nameid-format:transient"),
+    NAMEID_FORMAT_PERSISTENT("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"),
+    NAMEID_FORMAT_UNSPECIFIED("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"),
+    NAMEID_FORMAT_EMAIL("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"),
+    NAMEID_FORMAT_X509SUBJECTNAME("urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName"),
+    NAMEID_FORMAT_WINDOWS_DOMAIN_NAME("urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName"),
+    NAMEID_FORMAT_KERBEROS("urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos"),
+    NAMEID_FORMAT_ENTITY("urn:oasis:names:tc:SAML:2.0:nameid-format:entity"),
 
     PROTOCOL_NSURI("urn:oasis:names:tc:SAML:2.0:protocol"),
     ECP_PROFILE("urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp"),
     PAOS_BINDING("urn:liberty:paos:2003-08"),
 
-    SIGNATURE_DSA_SHA1("http://www.w3.org/2000/09/xmldsig#dsa-sha1"), SIGNATURE_RSA_SHA1(
-            "http://www.w3.org/2000/09/xmldsig#rsa-sha1"),
+    SIGNATURE_DSA_SHA1("http://www.w3.org/2000/09/xmldsig#dsa-sha1"),
+    SIGNATURE_RSA_SHA1("http://www.w3.org/2000/09/xmldsig#rsa-sha1"),
 
     SAML_HTTP_POST_BINDING("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"),
     SAML_HTTP_REDIRECT_BINDING("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"),
@@ -87,46 +90,90 @@ public enum JBossSAMLURIConstants {
 
     SUBJECT_CONFIRMATION_BEARER("urn:oasis:names:tc:SAML:2.0:cm:bearer"),
 
-    STATUS_AUTHNFAILED("urn:oasis:names:tc:SAML:2.0:status:AuthnFailed"), STATUS_INVALID_ATTRNAMEVAL(
-            "urn:oasis:names:tc:SAML:2.0:status:InvalidAttrnameOrValue"), STATUS_INVALID_NAMEIDPOLICY(
-            "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy"), STATUS_NOAUTHN_CTX(
-            "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext"), STATUS_NO_AVAILABLE_IDP(
-            "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP"), STATUS_NO_PASSIVE(
-            "urn:oasis:names:tc:SAML:2.0:status:NoPassive"), STATUS_NO_SUPPORTED_IDP(
-            "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP"), STATUS_PARTIAL_LOGOUT(
-            "urn:oasis:names:tc:SAML:2.0:status:PartialLogout"), STATUS_PROXYCOUNT_EXCEEDED(
-            "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded"), STATUS_REQUEST_DENIED(
-            "urn:oasis:names:tc:SAML:2.0:status:RequestDenied"), STATUS_REQUEST_UNSUPPORTED(
-            "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported"), STATUS_REQUEST_VERSION_DEPRECATED(
-            "urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated"), STATUS_REQUEST_VERSION_2HIGH(
-            "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh"), STATUS_REQUEST_VERSION_2LOW(
-            "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow"), STATUS_RESOURCE_NOT_RECOGNIZED(
-            "urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized"), STATUS_2MANY_RESPONSES(
-            "urn:oasis:names:tc:SAML:2.0:status:TooManyResponses"), STATUS_UNKNOWN_ATTR_PROFILE(
-            "urn:oasis:names:tc:SAML:2.0:status:UnknownAttributeProfile"), STATUS_UNKNOWN_PRINCIPAL(
-            "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal"), STATUS_UNSUPPORTED_BINDING(
-            "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding"),
-
-    STATUS_REQUESTOR("urn:oasis:names:tc:SAML:2.0:status:Requestor"), STATUS_RESPONDER(
-            "urn:oasis:names:tc:SAML:2.0:status:Responder"), STATUS_SUCCESS("urn:oasis:names:tc:SAML:2.0:status:Success"), STATUS_VERSION_MISMATCH(
-            "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch"),
-
-    TRANSFORM_ENVELOPED_SIGNATURE("http://www.w3.org/2000/09/xmldsig#enveloped-signature"), TRANSFORM_C14N_EXCL_OMIT_COMMENTS(
-            "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"),
-
-    XSI_PREFIX("xsi"), X500_PREFIX("x500"), X500_NSURI("urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"), XACML_NSURI(
-            "urn:oasis:names:tc:xacml:2.0:context:schema:os"), XACML_SAML_NSURI("urn:oasis:xacml:2.0:saml:assertion:schema:os"), XACML_SAML_PROTO_NSURI(
-            "urn:oasis:xacml:2.0:saml:protocol:schema:os"), XML("http://www.w3.org/XML/1998/namespace"), XMLSCHEMA_NSURI(
-            "http://www.w3.org/2001/XMLSchema"), XMLDSIG_NSURI("http://www.w3.org/2000/09/xmldsig#"), XMLENC_NSURI(
-            "http://www.w3.org/2001/04/xmlenc#"), XSI_NSURI("http://www.w3.org/2001/XMLSchema-instance");
-
-    private String uri = null;
+    STATUS_AUTHNFAILED("urn:oasis:names:tc:SAML:2.0:status:AuthnFailed"),
+    STATUS_INVALID_ATTRNAMEVAL("urn:oasis:names:tc:SAML:2.0:status:InvalidAttrnameOrValue"),
+    STATUS_INVALID_NAMEIDPOLICY("urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy"),
+    STATUS_NOAUTHN_CTX("urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext"),
+    STATUS_NO_AVAILABLE_IDP("urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP"),
+    STATUS_NO_PASSIVE("urn:oasis:names:tc:SAML:2.0:status:NoPassive"),
+    STATUS_NO_SUPPORTED_IDP("urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP"),
+    STATUS_PARTIAL_LOGOUT("urn:oasis:names:tc:SAML:2.0:status:PartialLogout"),
+    STATUS_PROXYCOUNT_EXCEEDED("urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded"),
+    STATUS_REQUEST_DENIED("urn:oasis:names:tc:SAML:2.0:status:RequestDenied"),
+    STATUS_REQUEST_UNSUPPORTED("urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported"),
+    STATUS_REQUEST_VERSION_DEPRECATED("urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated"),
+    STATUS_REQUEST_VERSION_2HIGH("urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh"),
+    STATUS_REQUEST_VERSION_2LOW("urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow"),
+    STATUS_RESOURCE_NOT_RECOGNIZED("urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized"),
+    STATUS_2MANY_RESPONSES("urn:oasis:names:tc:SAML:2.0:status:TooManyResponses"),
+    STATUS_UNKNOWN_ATTR_PROFILE("urn:oasis:names:tc:SAML:2.0:status:UnknownAttributeProfile"),
+    STATUS_UNKNOWN_PRINCIPAL("urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal"),
+    STATUS_UNSUPPORTED_BINDING("urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding"),
+
+    STATUS_REQUESTOR("urn:oasis:names:tc:SAML:2.0:status:Requestor"),
+    STATUS_RESPONDER("urn:oasis:names:tc:SAML:2.0:status:Responder"),
+    STATUS_SUCCESS("urn:oasis:names:tc:SAML:2.0:status:Success"),
+    STATUS_VERSION_MISMATCH("urn:oasis:names:tc:SAML:2.0:status:VersionMismatch"),
+
+    TRANSFORM_ENVELOPED_SIGNATURE("http://www.w3.org/2000/09/xmldsig#enveloped-signature"),
+    TRANSFORM_C14N_EXCL_OMIT_COMMENTS("http://www.w3.org/2001/10/xml-exc-c14n#WithComments"),
+
+    XSI_PREFIX("xsi"),
+    X500_PREFIX("x500"),
+    X500_NSURI("urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"),
+    XACML_NSURI("urn:oasis:names:tc:xacml:2.0:context:schema:os"),
+    XACML_SAML_NSURI("urn:oasis:xacml:2.0:saml:assertion:schema:os"),
+    XACML_SAML_PROTO_NSURI("urn:oasis:xacml:2.0:saml:protocol:schema:os"),
+    XML("http://www.w3.org/XML/1998/namespace"),
+    XMLSCHEMA_NSURI("http://www.w3.org/2001/XMLSchema"),
+    XMLDSIG_NSURI("http://www.w3.org/2000/09/xmldsig#"),
+    XMLENC_NSURI("http://www.w3.org/2001/04/xmlenc#"),
+    XSI_NSURI("http://www.w3.org/2001/XMLSchema-instance"),
+    ;
+
+    private final String uriStr;
+    private final URI uri;
+
+    private static class ReverseLookup {
+        // Private class to make sure JBossSAMLURIConstants is fully initialized
+        private static final Map<String, JBossSAMLURIConstants> CONSTANTS;
+
+        static {
+            HashMap<String, JBossSAMLURIConstants> m = new HashMap<>(JBossSAMLURIConstants.values().length);
+            JBossSAMLURIConstants old;
+            for (JBossSAMLURIConstants c : JBossSAMLURIConstants.values()) {
+                if ((old = m.put(c.get(), c)) != null) {
+                    throw new IllegalStateException("Same name " + c.get() + " used for two constants: " + c + ", " + old);
+                }
+            }
+            CONSTANTS = Collections.unmodifiableMap(m);
+        }
+
+        public JBossSAMLURIConstants from(String key) {
+            return CONSTANTS.get(key);
+        }
+    }
+    private static final ReverseLookup REVERSE_LOOKUP = new ReverseLookup();
 
     private JBossSAMLURIConstants(String uristr) {
-        this.uri = uristr;
+        this.uriStr = uristr;
+        this.uri = URI.create(uristr);
     }
 
     public String get() {
+        return this.uriStr;
+    }
+
+    public URI getUri() {
         return this.uri;
     }
+
+    /**
+     * Returns an enum constant based if known for the given {@code key}, or {@code null} otherwise.
+     * @param key
+     * @return
+     */
+    public static JBossSAMLURIConstants from(String key) {
+        return REVERSE_LOOKUP.from(key);
+    }
 }
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLDataMarshaller.java b/services/src/main/java/org/keycloak/broker/saml/SAMLDataMarshaller.java
index dc32463..532c284 100644
--- a/services/src/main/java/org/keycloak/broker/saml/SAMLDataMarshaller.java
+++ b/services/src/main/java/org/keycloak/broker/saml/SAMLDataMarshaller.java
@@ -26,11 +26,9 @@ import org.keycloak.saml.common.exceptions.ParsingException;
 import org.keycloak.saml.common.exceptions.ProcessingException;
 import org.keycloak.saml.common.util.StaxUtil;
 import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
-import org.keycloak.saml.processing.core.parsers.util.SAMLParserUtil;
 import org.keycloak.saml.processing.core.saml.v2.writers.SAMLAssertionWriter;
 import org.keycloak.saml.processing.core.saml.v2.writers.SAMLResponseWriter;
 
-import javax.xml.stream.XMLEventReader;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
@@ -79,17 +77,11 @@ public class SAMLDataMarshaller extends DefaultDataMarshaller {
             String xmlString = serialized;
 
             try {
-                if (clazz.equals(ResponseType.class) || clazz.equals(AssertionType.class)) {
+                if (clazz.equals(ResponseType.class) || clazz.equals(AssertionType.class) || clazz.equals(AuthnStatementType.class)) {
                     byte[] bytes = xmlString.getBytes(GeneralConstants.SAML_CHARSET);
                     InputStream is = new ByteArrayInputStream(bytes);
-                    Object respType = new SAMLParser().parse(is);
+                    Object respType = SAMLParser.getInstance().parse(is);
                     return clazz.cast(respType);
-                } else if (clazz.equals(AuthnStatementType.class)) {
-                    byte[] bytes = xmlString.getBytes(GeneralConstants.SAML_CHARSET);
-                    InputStream is = new ByteArrayInputStream(bytes);
-                    XMLEventReader xmlEventReader = new SAMLParser().createEventReader(is);
-                    AuthnStatementType authnStatement = SAMLParserUtil.parseAuthnStatement(xmlEventReader);
-                    return clazz.cast(authnStatement);
                 } else {
                     throw new IllegalArgumentException("Don't know how to deserialize object of type " + clazz.getName());
                 }
diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderFactory.java b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderFactory.java
index 75fbfdb..0170424 100755
--- a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderFactory.java
+++ b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderFactory.java
@@ -57,7 +57,7 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
     @Override
     public Map<String, String> parseConfig(KeycloakSession session, InputStream inputStream) {
         try {
-            Object parsedObject = new SAMLParser().parse(inputStream);
+            Object parsedObject = SAMLParser.getInstance().parse(inputStream);
             EntityDescriptorType entityType;
 
             if (EntitiesDescriptorType.class.isInstance(parsedObject)) {
diff --git a/services/src/main/java/org/keycloak/protocol/saml/EntityDescriptorDescriptionConverter.java b/services/src/main/java/org/keycloak/protocol/saml/EntityDescriptorDescriptionConverter.java
index 59e32ef..7db9f2e 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/EntityDescriptorDescriptionConverter.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/EntityDescriptorDescriptionConverter.java
@@ -106,7 +106,7 @@ public class EntityDescriptorDescriptionConverter implements ClientDescriptionCo
     private static ClientRepresentation loadEntityDescriptors(InputStream is) {
         Object metadata;
         try {
-            metadata = new SAMLParser().parse(is);
+            metadata = SAMLParser.getInstance().parse(is);
         } catch (ParsingException e) {
             throw new RuntimeException(e);
         }
diff --git a/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java b/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java
index cb0c367..c15444b 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java
@@ -127,7 +127,7 @@ public class SamlEcpProfileService extends SamlService {
             }
 
             private void createEcpResponseHeader(String redirectUri, Soap.SoapMessageBuilder messageBuilder) throws SOAPException {
-                SOAPHeaderElement ecpResponseHeader = messageBuilder.addHeader(JBossSAMLConstants.RESPONSE.get(), NS_PREFIX_PROFILE_ECP);
+                SOAPHeaderElement ecpResponseHeader = messageBuilder.addHeader(JBossSAMLConstants.RESPONSE__ECP.get(), NS_PREFIX_PROFILE_ECP);
 
                 ecpResponseHeader.setMustUnderstand(true);
                 ecpResponseHeader.setActor("http://schemas.xmlsoap.org/soap/actor/next");
diff --git a/services/src/test/java/org/keycloak/test/broker/saml/SAMLDataMarshallerTest.java b/services/src/test/java/org/keycloak/test/broker/saml/SAMLDataMarshallerTest.java
index 5f7e0e4..4fcd3ac 100755
--- a/services/src/test/java/org/keycloak/test/broker/saml/SAMLDataMarshallerTest.java
+++ b/services/src/test/java/org/keycloak/test/broker/saml/SAMLDataMarshallerTest.java
@@ -103,7 +103,7 @@ public class SAMLDataMarshallerTest {
 
     @Test
     public void testSerializeWithNamespaceInSignatureElement() throws Exception {
-        SAMLParser parser = new SAMLParser();
+        SAMLParser parser = SAMLParser.getInstance();
         try (InputStream st = SAMLDataMarshallerTest.class.getResourceAsStream("saml-response-ds-ns-in-signature.xml")) {
             Object parsedObject = parser.parse(st);
             assertThat(parsedObject, instanceOf(ResponseType.class));
@@ -121,7 +121,7 @@ public class SAMLDataMarshallerTest {
 
     @Test
     public void testSerializeWithNamespaceNotInSignatureElement() throws Exception {
-        SAMLParser parser = new SAMLParser();
+        SAMLParser parser = SAMLParser.getInstance();
         try (InputStream st = SAMLDataMarshallerTest.class.getResourceAsStream("saml-response-ds-ns-above-signature.xml")) {
             Object parsedObject = parser.parse(st);
             assertThat(parsedObject, instanceOf(ResponseType.class));
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/Matchers.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/Matchers.java
index 0ab3a7b..40ac6d1 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/Matchers.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/Matchers.java
@@ -126,7 +126,7 @@ public class Matchers {
     public static <T> Matcher<SAML2Object> isSamlResponse(JBossSAMLURIConstants expectedStatus) {
         return allOf(
           instanceOf(ResponseType.class),
-          new SamlResponseTypeMatcher(is(URI.create(expectedStatus.get())))
+          new SamlResponseTypeMatcher(is(expectedStatus.getUri()))
         );
     }
 
@@ -150,7 +150,7 @@ public class Matchers {
     public static <T> Matcher<SAML2Object> isSamlStatusResponse(JBossSAMLURIConstants expectedStatus) {
         return allOf(
           instanceOf(StatusResponseType.class),
-          new SamlStatusResponseTypeMatcher(is(URI.create(expectedStatus.get())))
+          new SamlStatusResponseTypeMatcher(is(expectedStatus.getUri()))
         );
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/matchers/SamlResponseTypeMatcher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/matchers/SamlResponseTypeMatcher.java
index 46eedde..05dd9b1 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/matchers/SamlResponseTypeMatcher.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/matchers/SamlResponseTypeMatcher.java
@@ -21,7 +21,7 @@ public class SamlResponseTypeMatcher extends BaseMatcher<SAML2Object> {
     private final Matcher<URI> statusMatcher;
 
     public SamlResponseTypeMatcher(JBossSAMLURIConstants expectedStatus) {
-        this.statusMatcher = is(URI.create(expectedStatus.get()));
+        this.statusMatcher = is(expectedStatus.getUri());
     }
 
     public SamlResponseTypeMatcher(Matcher<URI> statusMatcher) {
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/saml/SamlDocumentStepBuilder.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/saml/SamlDocumentStepBuilder.java
index 5fb2284..e905532 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/saml/SamlDocumentStepBuilder.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/saml/SamlDocumentStepBuilder.java
@@ -26,20 +26,18 @@ import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
 import org.keycloak.dom.saml.v2.protocol.ResponseType;
 import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
 import org.keycloak.saml.common.constants.GeneralConstants;
-import org.keycloak.saml.common.constants.JBossSAMLConstants;
 import org.keycloak.saml.common.util.DocumentUtil;
 import org.keycloak.saml.common.util.StaxUtil;
-import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
+import org.keycloak.saml.processing.api.saml.v2.response.SAML2Response;
+import org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLProtocolQNames;
 import org.keycloak.saml.processing.core.saml.v2.writers.SAMLRequestWriter;
 import org.keycloak.saml.processing.core.saml.v2.writers.SAMLResponseWriter;
 import org.keycloak.testsuite.util.SamlClient.Step;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import javax.xml.namespace.QName;
 import javax.xml.stream.XMLStreamWriter;
 import org.junit.Assert;
 import org.w3c.dom.Document;
-import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.PROTOCOL_NSURI;
 
 /**
  *
@@ -81,7 +79,7 @@ public abstract class SamlDocumentStepBuilder<T extends SAML2Object, This extend
             }
 
             final ByteArrayInputStream baos = new ByteArrayInputStream(originalTransformed.getBytes());
-            final T saml2Object = (T) new SAMLParser().parse(baos);
+            final T saml2Object = (T) new SAML2Response().getSAML2ObjectFromStream(baos);
             final T transformed = tr.transform(saml2Object);
 
             if (transformed == null) {
@@ -104,7 +102,7 @@ public abstract class SamlDocumentStepBuilder<T extends SAML2Object, This extend
             } else if (transformed instanceof ArtifactResponseType) {
                 new SAMLResponseWriter(xmlStreamWriter).write((ArtifactResponseType) transformed);
             } else if (transformed instanceof StatusResponseType) {
-                new SAMLResponseWriter(xmlStreamWriter).write((StatusResponseType) transformed, new QName(PROTOCOL_NSURI.get(), JBossSAMLConstants.LOGOUT_RESPONSE.get(), "samlp"));
+                new SAMLResponseWriter(xmlStreamWriter).write((StatusResponseType) transformed, SAMLProtocolQNames.LOGOUT_RESPONSE.getQName("samlp"));
             } else {
                 Assert.assertNotNull("Unknown type: <null>", transformed);
                 Assert.fail("Unknown type: " + transformed.getClass().getName());
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java
index 257afc0..84691be 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SamlClient.java
@@ -173,7 +173,7 @@ public class SamlClient {
 
             @Override
             public URI getBindingUri() {
-                return URI.create(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
+                return JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.getUri();
             }
         },
 
@@ -201,7 +201,7 @@ public class SamlClient {
 
             @Override
             public URI getBindingUri() {
-                return URI.create(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
+                return JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.getUri();
             }
 
             @Override
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
index 2ec225c..ae958b7 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
@@ -35,8 +35,7 @@ import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
 import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.saml.common.exceptions.ParsingException;
-import org.keycloak.saml.common.util.StaxParserUtil;
-import org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLEntityDescriptorParser;
+import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
 import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.util.AdminEventPaths;
 import org.w3c.dom.NodeList;
@@ -599,8 +598,8 @@ public class IdentityProviderTest extends AbstractAdminTest {
     private void assertSamlExport(String body) throws ParsingException, URISyntaxException {
         //System.out.println(body);
 
-        Object entBody = new SAMLEntityDescriptorParser().parse(StaxParserUtil.getXMLEventReader(
-                new ByteArrayInputStream(body.getBytes(Charset.forName("utf-8")))));
+        Object entBody = SAMLParser.getInstance().parse(
+                new ByteArrayInputStream(body.getBytes(Charset.forName("utf-8"))));
 
         Assert.assertEquals("Parsed export type", EntityDescriptorType.class, entBody.getClass());
         EntityDescriptorType entity = (EntityDescriptorType) entBody;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/AuthnRequestNameIdFormatTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/AuthnRequestNameIdFormatTest.java
index 484b9cc..e84daa1 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/AuthnRequestNameIdFormatTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/AuthnRequestNameIdFormatTest.java
@@ -26,7 +26,6 @@ import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
 import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
 import org.keycloak.testsuite.util.SamlClientBuilder;
-import java.net.URI;
 import java.util.List;
 import org.hamcrest.Matcher;
 import org.junit.Test;
@@ -68,21 +67,21 @@ public class AuthnRequestNameIdFormatTest extends AbstractSamlTest {
     @Test
     public void testPostLoginNameIdPolicyUnspecified() throws Exception {
         NameIDPolicyType nameIdPolicy = new NameIDPolicyType();
-        nameIdPolicy.setFormat(URI.create(JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get()));
+        nameIdPolicy.setFormat(JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.getUri());
         testLoginWithNameIdPolicy(Binding.POST, Binding.POST, nameIdPolicy, is("bburke"));
     }
 
     @Test
     public void testPostLoginNameIdPolicyEmail() throws Exception {
         NameIDPolicyType nameIdPolicy = new NameIDPolicyType();
-        nameIdPolicy.setFormat(URI.create(JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get()));
+        nameIdPolicy.setFormat(JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.getUri());
         testLoginWithNameIdPolicy(Binding.POST, Binding.POST, nameIdPolicy, is("bburke@redhat.com"));
     }
 
     @Test
     public void testPostLoginNameIdPolicyPersistent() throws Exception {
         NameIDPolicyType nameIdPolicy = new NameIDPolicyType();
-        nameIdPolicy.setFormat(URI.create(JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get()));
+        nameIdPolicy.setFormat(JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.getUri());
         testLoginWithNameIdPolicy(Binding.POST, Binding.POST, nameIdPolicy, startsWith("G-"));
     }
 
@@ -94,21 +93,21 @@ public class AuthnRequestNameIdFormatTest extends AbstractSamlTest {
     @Test
     public void testRedirectLoginNameIdPolicyUnspecified() throws Exception {
         NameIDPolicyType nameIdPolicy = new NameIDPolicyType();
-        nameIdPolicy.setFormat(URI.create(JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get()));
+        nameIdPolicy.setFormat(JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.getUri());
         testLoginWithNameIdPolicy(Binding.REDIRECT, Binding.REDIRECT, nameIdPolicy, is("bburke"));
     }
 
     @Test
     public void testRedirectLoginNameIdPolicyEmail() throws Exception {
         NameIDPolicyType nameIdPolicy = new NameIDPolicyType();
-        nameIdPolicy.setFormat(URI.create(JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get()));
+        nameIdPolicy.setFormat(JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.getUri());
         testLoginWithNameIdPolicy(Binding.REDIRECT, Binding.REDIRECT, nameIdPolicy, is("bburke@redhat.com"));
     }
 
     @Test
     public void testRedirectLoginNameIdPolicyPersistent() throws Exception {
         NameIDPolicyType nameIdPolicy = new NameIDPolicyType();
-        nameIdPolicy.setFormat(URI.create(JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get()));
+        nameIdPolicy.setFormat(JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.getUri());
         testLoginWithNameIdPolicy(Binding.REDIRECT, Binding.REDIRECT, nameIdPolicy, startsWith("G-"));
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/LogoutTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/LogoutTest.java
index fb64e9a..24967ae 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/LogoutTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/LogoutTest.java
@@ -276,7 +276,7 @@ public class LogoutTest extends AbstractSamlTest {
           .processSamlResponse(REDIRECT)
             .transformDocument(doc -> {
               // Expect logout request for sales-post2
-              SAML2Object so = (SAML2Object) new SAMLParser().parse(new DOMSource(doc));
+              SAML2Object so = (SAML2Object) SAMLParser.getInstance().parse(new DOMSource(doc));
               assertThat(so, isSamlLogoutRequest("http://url-to-sales-2"));
 
               // Emulate successful logout response from sales-post2 logout
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java
index bc6d316..5ac5722 100755
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java
@@ -138,7 +138,7 @@ public class SamlEcpProfileTest {
 
         SOAPHeader responseMessageHeaders = responseMessage.getSOAPHeader();
 
-        NodeList ecpResponse = responseMessageHeaders.getElementsByTagNameNS(JBossSAMLURIConstants.ECP_PROFILE.get(), JBossSAMLConstants.RESPONSE.get());
+        NodeList ecpResponse = responseMessageHeaders.getElementsByTagNameNS(JBossSAMLURIConstants.ECP_PROFILE.get(), JBossSAMLConstants.RESPONSE__ECP.get());
 
         assertEquals("No ECP Response", 1, ecpResponse.getLength());
 
@@ -146,7 +146,7 @@ public class SamlEcpProfileTest {
 
         assertNotNull(samlResponse);
 
-        ResponseType responseType = (ResponseType) new SAMLParser().parse(samlResponse);
+        ResponseType responseType = (ResponseType) SAMLParser.getInstance().parse(samlResponse);
         StatusCodeType statusCode = responseType.getStatus().getStatusCode();
 
         assertEquals(statusCode.getValue().toString(), JBossSAMLURIConstants.STATUS_SUCCESS.get());
@@ -229,7 +229,7 @@ public class SamlEcpProfileTest {
 
         assertNotNull(samlResponse);
 
-        StatusResponseType responseType = (StatusResponseType) new SAMLParser().parse(samlResponse);
+        StatusResponseType responseType = (StatusResponseType) SAMLParser.getInstance().parse(samlResponse);
         StatusCodeType statusCode = responseType.getStatus().getStatusCode();
 
         assertNotEquals(statusCode.getStatusCode().getValue().toString(), JBossSAMLURIConstants.STATUS_SUCCESS.get());