diff --git a/saml-core-api/src/main/java/org/keycloak/dom/saml/v2/metadata/ExtensionsType.java b/saml-core-api/src/main/java/org/keycloak/dom/saml/v2/metadata/ExtensionsType.java
index 364c90ec01..3420167779 100755
--- a/saml-core-api/src/main/java/org/keycloak/dom/saml/v2/metadata/ExtensionsType.java
+++ b/saml-core-api/src/main/java/org/keycloak/dom/saml/v2/metadata/ExtensionsType.java
@@ -18,6 +18,10 @@ package org.keycloak.dom.saml.v2.metadata;
import org.w3c.dom.Element;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
/**
*
* Java class for ExtensionsType complex type.
@@ -39,13 +43,49 @@ import org.w3c.dom.Element;
*/
public class ExtensionsType {
- protected Element element = null;
+ protected List any = new ArrayList();
+ /**
+ * Function is obsoleted with getAny
+ * @return
+ */
+ @Deprecated
public Element getElement() {
- return element;
+ return (any.isEmpty()) ? null : (Element) any.get(0);
}
+ /**
+ * Function is obsoleted with addExtension
+ * @return
+ */
+ @Deprecated
public void setElement(Element element) {
- this.element = element;
+ any.clear();
+ any.add(element);
+ }
+
+ /**
+ * Add an extension
+ *
+ * @param extension
+ */
+ public void addExtension(Object extension) {
+ any.add(extension);
+ }
+
+ /**
+ * Remove an extension
+ *
+ * @param extension
+ */
+ public void removeExtension(Object extension) {
+ any.remove(extension);
+ }
+
+ /**
+ * Gets the value of the any property.
+ */
+ public List getAny() {
+ return Collections.unmodifiableList(this.any);
}
}
\ No newline at end of file
diff --git a/saml-core-api/src/main/java/org/keycloak/dom/xmlsec/w3/xmlenc/EncryptionMethodType.java b/saml-core-api/src/main/java/org/keycloak/dom/xmlsec/w3/xmlenc/EncryptionMethodType.java
index a88273de06..2d3e82b8aa 100755
--- a/saml-core-api/src/main/java/org/keycloak/dom/xmlsec/w3/xmlenc/EncryptionMethodType.java
+++ b/saml-core-api/src/main/java/org/keycloak/dom/xmlsec/w3/xmlenc/EncryptionMethodType.java
@@ -56,6 +56,11 @@ public class EncryptionMethodType {
OAEPparams = oAEPparams;
}
+ public EncryptionMethod() {
+ this.keySize = null;
+ this.OAEPparams = null;
+ }
+
public BigInteger getKeySize() {
return keySize;
}
@@ -63,6 +68,14 @@ public class EncryptionMethodType {
public byte[] getOAEPparams() {
return OAEPparams;
}
+
+ public void setKeySize(BigInteger keySize) {
+ this.keySize = keySize;
+ }
+
+ public void setOAEPparams(byte[] OAEPparams) {
+ this.OAEPparams = OAEPparams;
+ }
}
public EncryptionMethodType(String algo) {
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 4f8a9a8614..aee809104a 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
@@ -32,6 +32,7 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.XMLConstants;
+import javax.xml.datatype.Duration;
import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLEventReader;
@@ -52,7 +53,10 @@ import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.InputStream;
import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
+import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.xml.datatype.XMLGregorianCalendar;
@@ -288,6 +292,20 @@ public class StaxParserUtil {
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 Duration getXmlDurationAttributeValue(StartElement startElement, HasQName attrName) throws ParsingException {
+ Attribute attr = startElement.getAttributeByName(attrName.getQName());
+ String value = getAttributeValue(attr);
+ return value == null ? null : XMLTimeUtil.parseAsDuration(value);
+ }
+
/**
* Get the Attribute value
*
@@ -391,6 +409,29 @@ public class StaxParserUtil {
return StaxParserUtil.getAttributeValueRP(attr);
}
+ /**
+ * Parse a space delimited list of strings
+ *
+ * @param startElement
+ * @param attrName
+ *
+ * @return
+ */
+ public static List getRequiredStringListAttributeValue(StartElement startElement, HasQName attrName) throws ParsingException{
+ List protocolEnum = new ArrayList<>();
+
+ String val = StaxParserUtil.getRequiredAttributeValue(startElement, attrName);
+ if (StringUtil.isNotNull(val)) {
+ StringTokenizer st = new StringTokenizer(val);
+ while (st.hasMoreTokens()) {
+ protocolEnum.add(st.nextToken());
+ }
+
+ }
+
+ return protocolEnum;
+ }
+
private static final String JDK_TRANSFORMER_PROPERTY = "picketlink.jdk.transformer";
/**
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 b4695473f1..52599a1e67 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,6 +16,7 @@
*/
package org.keycloak.saml.processing.core.parsers.saml;
+import org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLMetadataQNames;
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;
@@ -53,8 +54,6 @@ import java.io.InputStream;
*/
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();
@@ -88,9 +87,8 @@ public class SAMLParser extends AbstractParser {
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(SAMLMetadataQNames.ENTITY_DESCRIPTOR.getQName(), new ParserFactory() { @Override public StaxParser create() { return SAMLEntityDescriptorParser.getInstance(); }});
+ PARSERS.put(SAMLMetadataQNames.ENTITIES_DESCRIPTOR.getQName(),new ParserFactory() { @Override public StaxParser create() { return SAMLEntitiesDescriptorParser.getInstance(); }});
PARSERS.put(SAMLProtocolQNames.ATTRIBUTE_QUERY.getQName(), new ParserFactory() { @Override public StaxParser create() { return SAMLAttributeQueryParser.getInstance(); }});
}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/AbstractStaxSamlMetadataParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/AbstractStaxSamlMetadataParser.java
new file mode 100644
index 0000000000..9d9122a8f3
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/AbstractStaxSamlMetadataParser.java
@@ -0,0 +1,24 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.saml.common.parsers.AbstractStaxParser;
+import org.keycloak.saml.processing.core.parsers.util.QNameEnumLookup;
+
+import javax.xml.namespace.QName;
+
+/**
+ * @author mhajas
+ */
+abstract public class AbstractStaxSamlMetadataParser extends AbstractStaxParser {
+
+ protected static final QNameEnumLookup LOOKUP = new QNameEnumLookup(SAMLMetadataQNames.values());
+
+
+ public AbstractStaxSamlMetadataParser(SAMLMetadataQNames expectedStartElement) {
+ super(expectedStartElement.getQName(), SAMLMetadataQNames.UNKNOWN_ELEMENT);
+ }
+
+ @Override
+ protected SAMLMetadataQNames getElementFromName(QName name) {
+ return LOOKUP.from(name);
+ }
+}
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
deleted file mode 100644
index c43754c445..0000000000
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/AbstractStaxSamlParser.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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 extends AbstractStaxParser {
-
- 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/SAMLArtifactResolutionServiceParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLArtifactResolutionServiceParser.java
new file mode 100644
index 0000000000..45ba48806d
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLArtifactResolutionServiceParser.java
@@ -0,0 +1,17 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+/**
+ * @author mhajas
+ */
+public class SAMLArtifactResolutionServiceParser extends SAMLIndexedEndpointTypeParser {
+
+ private static final SAMLArtifactResolutionServiceParser INSTANCE = new SAMLArtifactResolutionServiceParser();
+
+ public SAMLArtifactResolutionServiceParser() {
+ super(SAMLMetadataQNames.ARTIFACT_RESOLUTION_SERVICE);
+ }
+
+ public static SAMLArtifactResolutionServiceParser getInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAssertinIDRequestServiceParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAssertinIDRequestServiceParser.java
new file mode 100644
index 0000000000..a7d7beefb8
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAssertinIDRequestServiceParser.java
@@ -0,0 +1,17 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+/**
+ * @author mhajas
+ */
+public class SAMLAssertinIDRequestServiceParser extends SAMLEndpointTypeParser {
+
+ private static final SAMLAssertinIDRequestServiceParser INSTANCE = new SAMLAssertinIDRequestServiceParser();
+
+ public SAMLAssertinIDRequestServiceParser() {
+ super(SAMLMetadataQNames.ASSERTION_ID_REQUEST_SERVICE);
+ }
+
+ public static SAMLAssertinIDRequestServiceParser getInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAssertionConsumerServiceParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAssertionConsumerServiceParser.java
new file mode 100644
index 0000000000..28b54e4b8c
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAssertionConsumerServiceParser.java
@@ -0,0 +1,17 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+/**
+ * @author mhajas
+ */
+public class SAMLAssertionConsumerServiceParser extends SAMLIndexedEndpointTypeParser {
+
+ private static final SAMLAssertionConsumerServiceParser INSTANCE = new SAMLAssertionConsumerServiceParser();
+
+ public SAMLAssertionConsumerServiceParser() {
+ super(SAMLMetadataQNames.ASSERTION_CONSUMER_SERVICE);
+ }
+
+ public static SAMLAssertionConsumerServiceParser getInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAttributeAuthorityDescriptorParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAttributeAuthorityDescriptorParser.java
new file mode 100644
index 0000000000..0a1a83ea32
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAttributeAuthorityDescriptorParser.java
@@ -0,0 +1,65 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.saml.v2.metadata.AttributeAuthorityDescriptorType;
+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 java.util.List;
+
+/**
+ * @author mhajas
+ */
+public class SAMLAttributeAuthorityDescriptorParser extends SAMLRoleDecriptorTypeParser {
+
+ private static final SAMLAttributeAuthorityDescriptorParser INSTANCE = new SAMLAttributeAuthorityDescriptorParser();
+
+ public SAMLAttributeAuthorityDescriptorParser() {
+ super(SAMLMetadataQNames.ATTRIBUTE_AUTHORITY_DESCRIPTOR);
+ }
+
+ public static SAMLAttributeAuthorityDescriptorParser getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ protected AttributeAuthorityDescriptorType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ List protocolEnum = StaxParserUtil.getRequiredStringListAttributeValue(element, SAMLMetadataQNames.ATTR_PROTOCOL_SUPPORT_ENUMERATION);
+ AttributeAuthorityDescriptorType descriptor = new AttributeAuthorityDescriptorType(protocolEnum);
+
+ parseOptionalArguments(element, descriptor);
+
+ return descriptor;
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, AttributeAuthorityDescriptorType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch (element) {
+ case ATTRIBUTE_SERVICE:
+ target.addAttributeService(SAMLAttributeServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case ASSERTION_ID_REQUEST_SERVICE:
+ target.addAssertionIDRequestService(SAMLAssertinIDRequestServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case NAMEID_FORMAT:
+ StaxParserUtil.advance(xmlEventReader);
+ target.addNameIDFormat(StaxParserUtil.getElementText(xmlEventReader));
+ break;
+
+ case ATTRIBUTE_PROFILE:
+ StaxParserUtil.advance(xmlEventReader);
+ target.addAttributeProfile(StaxParserUtil.getElementText(xmlEventReader));
+ break;
+
+ case ATTRIBUTE:
+ target.addAttribute(SAMLAttributeParser.getInstance().parse(xmlEventReader));
+ break;
+
+ default:
+ super.processSubElement(xmlEventReader, target, element, elementDetail);
+ }
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAttributeConsumingServiceParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAttributeConsumingServiceParser.java
new file mode 100644
index 0000000000..6bdded981b
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAttributeConsumingServiceParser.java
@@ -0,0 +1,61 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.saml.v2.metadata.AttributeConsumingServiceType;
+import org.keycloak.dom.saml.v2.metadata.LocalizedNameType;
+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 static org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLMetadataQNames.ATTR_LANG;
+
+
+/**
+ * @author mhajas
+ */
+public class SAMLAttributeConsumingServiceParser extends AbstractStaxSamlMetadataParser {
+
+ private static final SAMLAttributeConsumingServiceParser INSTANCE = new SAMLAttributeConsumingServiceParser();
+
+ public SAMLAttributeConsumingServiceParser() {
+ super(SAMLMetadataQNames.ATTRIBUTE_CONSUMING_SERVICE);
+ }
+
+ public static SAMLAttributeConsumingServiceParser getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ protected AttributeConsumingServiceType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ int index = Integer.parseInt(StaxParserUtil.getRequiredAttributeValue(element, SAMLMetadataQNames.ATTR_INDEX));
+
+ AttributeConsumingServiceType service = new AttributeConsumingServiceType(index);
+ service.setIsDefault(StaxParserUtil.getBooleanAttributeValue(element, SAMLMetadataQNames.ATTR_IS_DEFAULT));
+
+ return service;
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, AttributeConsumingServiceType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch (element) {
+ case SERVICE_NAME:
+ LocalizedNameType serviceName = new LocalizedNameType(StaxParserUtil.getAttributeValue(elementDetail, ATTR_LANG));
+ StaxParserUtil.advance(xmlEventReader);
+ serviceName.setValue(StaxParserUtil.getElementText(xmlEventReader));
+ target.addServiceName(serviceName);
+ break;
+
+ case SERVICE_DESCRIPTION:
+ target.addServiceDescription(new LocalizedNameType(StaxParserUtil.getAttributeValue(elementDetail, ATTR_LANG)));
+ break;
+
+ case REQUESTED_ATTRIBUTE:
+ target.addRequestedAttribute(SAMLRequestedAttributeParser.getInstance().parse(xmlEventReader));
+ break;
+
+ default:
+ throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+ }
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAttributeParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAttributeParser.java
new file mode 100644
index 0000000000..0b719a292d
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAttributeParser.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.metadata;
+
+import org.keycloak.dom.saml.v2.assertion.AttributeType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAttributeValueParser;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * Parse the in the saml assertion
+ *
+ * @since Oct 14, 2010
+ */
+public class SAMLAttributeParser extends AbstractStaxSamlMetadataParser {
+
+ private static final SAMLAttributeParser INSTANCE = new SAMLAttributeParser();
+
+ private SAMLAttributeParser() {
+ super(SAMLMetadataQNames.ATTRIBUTE);
+ }
+
+ public static SAMLAttributeParser getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ protected AttributeType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ String name = StaxParserUtil.getRequiredAttributeValue(element, SAMLMetadataQNames.ATTR_NAME);
+ final AttributeType attribute = new AttributeType(name);
+
+ attribute.setFriendlyName(StaxParserUtil.getAttributeValue(element, SAMLMetadataQNames.ATTR_FRIENDLY_NAME));
+ attribute.setNameFormat(StaxParserUtil.getAttributeValue(element, SAMLMetadataQNames.ATTR_NAME_FORMAT));
+
+ final String x500Encoding = StaxParserUtil.getAttributeValue(element, SAMLMetadataQNames.ATTR_X500_ENCODING);
+ if (x500Encoding != null) {
+ attribute.getOtherAttributes().put(SAMLMetadataQNames.ATTR_X500_ENCODING.getQName(), x500Encoding);
+ }
+
+ return attribute;
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, AttributeType target, SAMLMetadataQNames 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/metadata/SAMLAttributeServiceParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAttributeServiceParser.java
new file mode 100644
index 0000000000..a8d15cd4a2
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAttributeServiceParser.java
@@ -0,0 +1,17 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+/**
+ * @author mhajas
+ */
+public class SAMLAttributeServiceParser extends SAMLEndpointTypeParser {
+
+ private static final SAMLAttributeServiceParser INSTANCE = new SAMLAttributeServiceParser();
+
+ public SAMLAttributeServiceParser() {
+ super(SAMLMetadataQNames.ATTRIBUTE_SERVICE);
+ }
+
+ public static SAMLAttributeServiceParser getInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAuthnAuthorityDescriptorParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAuthnAuthorityDescriptorParser.java
new file mode 100644
index 0000000000..f67620687e
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAuthnAuthorityDescriptorParser.java
@@ -0,0 +1,56 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.saml.v2.metadata.AuthnAuthorityDescriptorType;
+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 java.util.List;
+
+/**
+ * @author mhajas
+ */
+public class SAMLAuthnAuthorityDescriptorParser extends SAMLRoleDecriptorTypeParser {
+
+ private static final SAMLAuthnAuthorityDescriptorParser INSTANCE = new SAMLAuthnAuthorityDescriptorParser();
+
+ public SAMLAuthnAuthorityDescriptorParser() {
+ super(SAMLMetadataQNames.AUTHN_AUTHORITY_DESCRIPTOR);
+ }
+
+ public static SAMLAuthnAuthorityDescriptorParser getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ protected AuthnAuthorityDescriptorType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ List protocolEnum = StaxParserUtil.getRequiredStringListAttributeValue(element, SAMLMetadataQNames.ATTR_PROTOCOL_SUPPORT_ENUMERATION);
+ AuthnAuthorityDescriptorType descriptor = new AuthnAuthorityDescriptorType(protocolEnum);
+
+ parseOptionalArguments(element, descriptor);
+
+ return descriptor;
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, AuthnAuthorityDescriptorType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch (element) {
+ case AUTHN_QUERY_SERVICE:
+ target.addAuthnQueryService(SAMLAuthnQueryServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case ASSERTION_ID_REQUEST_SERVICE:
+ target.addAssertionIDRequestService(SAMLAssertinIDRequestServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case NAMEID_FORMAT:
+ StaxParserUtil.advance(xmlEventReader);
+ target.addNameIDFormat(StaxParserUtil.getElementText(xmlEventReader));
+ break;
+
+ default:
+ super.processSubElement(xmlEventReader, target, element, elementDetail);
+ }
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAuthnQueryServiceParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAuthnQueryServiceParser.java
new file mode 100644
index 0000000000..9f10ce45d2
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAuthnQueryServiceParser.java
@@ -0,0 +1,17 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+/**
+ * @author mhajas
+ */
+public class SAMLAuthnQueryServiceParser extends SAMLEndpointTypeParser {
+
+ private static final SAMLAuthnQueryServiceParser INSTANCE = new SAMLAuthnQueryServiceParser();
+
+ public SAMLAuthnQueryServiceParser() {
+ super(SAMLMetadataQNames.AUTHN_QUERY_SERVICE);
+ }
+
+ public static SAMLAuthnQueryServiceParser getInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAuthzServiceParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAuthzServiceParser.java
new file mode 100644
index 0000000000..1c489a3a50
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLAuthzServiceParser.java
@@ -0,0 +1,17 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+/**
+ * @author mhajas
+ */
+public class SAMLAuthzServiceParser extends SAMLEndpointTypeParser {
+
+ private static final SAMLAuthzServiceParser INSTANCE = new SAMLAuthzServiceParser();
+
+ public SAMLAuthzServiceParser() {
+ super(SAMLMetadataQNames.AUTHZ_SERVICE);
+ }
+
+ public static SAMLAuthzServiceParser getInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLContactPersonParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLContactPersonParser.java
new file mode 100644
index 0000000000..aa16eb336b
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLContactPersonParser.java
@@ -0,0 +1,70 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.saml.v2.metadata.ContactType;
+import org.keycloak.dom.saml.v2.metadata.ContactTypeType;
+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 static org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLMetadataQNames.ATTR_CONTACT_TYPE;
+import static org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLMetadataQNames.CONTACT_PERSON;
+
+/**
+ * @author mhajas
+ */
+public class SAMLContactPersonParser extends AbstractStaxSamlMetadataParser {
+
+ private static final SAMLContactPersonParser INSTANCE = new SAMLContactPersonParser();
+
+ public SAMLContactPersonParser() {
+ super(CONTACT_PERSON);
+ }
+
+ public static SAMLContactPersonParser getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ protected ContactType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ return new ContactType(ContactTypeType.fromValue(StaxParserUtil.getRequiredAttributeValue(element, ATTR_CONTACT_TYPE)));
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, ContactType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch (element) {
+ case COMPANY:
+ StaxParserUtil.advance(xmlEventReader);
+ target.setCompany(StaxParserUtil.getElementText(xmlEventReader));
+ break;
+
+ case GIVEN_NAME:
+ StaxParserUtil.advance(xmlEventReader);
+ target.setGivenName(StaxParserUtil.getElementText(xmlEventReader));
+ break;
+
+ case SURNAME:
+ StaxParserUtil.advance(xmlEventReader);
+ target.setSurName(StaxParserUtil.getElementText(xmlEventReader));
+ break;
+
+ case EMAIL_ADDRESS:
+ StaxParserUtil.advance(xmlEventReader);
+ target.addEmailAddress(StaxParserUtil.getElementText(xmlEventReader));
+ break;
+
+ case TELEPHONE_NUMBER:
+ StaxParserUtil.advance(xmlEventReader);
+ target.addTelephone(StaxParserUtil.getElementText(xmlEventReader));
+ break;
+
+ case EXTENSIONS:
+ target.setExtensions(SAMLExtensionsParser.getInstance().parse(xmlEventReader));
+ break;
+
+ default:
+ throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+ }
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEncryptionMethodParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEncryptionMethodParser.java
new file mode 100644
index 0000000000..70dec2a836
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEncryptionMethodParser.java
@@ -0,0 +1,70 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.xmlsec.w3.xmlenc.EncryptionMethodType;
+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;
+import java.math.BigInteger;
+
+import static org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLMetadataQNames.ENCRYPTION_METHOD;
+
+/**
+ * @author mhajas
+ */
+public class SAMLEncryptionMethodParser extends AbstractStaxSamlMetadataParser {
+
+ private static final SAMLEncryptionMethodParser INSTANCE = new SAMLEncryptionMethodParser();
+
+ public SAMLEncryptionMethodParser() {
+ super(ENCRYPTION_METHOD);
+ }
+
+ public static SAMLEncryptionMethodParser getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ protected EncryptionMethodType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ return new EncryptionMethodType(StaxParserUtil.getRequiredAttributeValue(element, SAMLMetadataQNames.ATTR_ALGORITHM));
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, EncryptionMethodType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch(element) {
+ case KEY_SIZE:
+ {
+ StaxParserUtil.advance(xmlEventReader);
+ BigInteger keySize = BigInteger.valueOf(Long.valueOf(StaxParserUtil.getElementText(xmlEventReader)));
+
+ EncryptionMethodType.EncryptionMethod encMethod = target.getEncryptionMethod();
+ if (encMethod == null) {
+ encMethod = new EncryptionMethodType.EncryptionMethod();
+ target.setEncryptionMethod(encMethod);
+ }
+
+ encMethod.setKeySize(keySize);
+ }
+ break;
+
+ case OAEP_PARAMS:
+ {
+ StaxParserUtil.advance(xmlEventReader);
+ byte[] OAEPparams = StaxParserUtil.getElementText(xmlEventReader).getBytes(GeneralConstants.SAML_CHARSET);
+ EncryptionMethodType.EncryptionMethod encMethod = target.getEncryptionMethod();
+ if (encMethod == null){
+ encMethod = new EncryptionMethodType.EncryptionMethod();
+ target.setEncryptionMethod(encMethod);
+ }
+
+ encMethod.setOAEPparams(OAEPparams);
+ }
+ break;
+
+ default:
+ throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+ }
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEndpointTypeParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEndpointTypeParser.java
new file mode 100644
index 0000000000..d0b276ec89
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEndpointTypeParser.java
@@ -0,0 +1,40 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.saml.v2.metadata.EndpointType;
+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 java.net.URI;
+
+/**
+ * @author mhajas
+ */
+public abstract class SAMLEndpointTypeParser extends AbstractStaxSamlMetadataParser {
+
+ public SAMLEndpointTypeParser(SAMLMetadataQNames expectedStartElement) {
+ super(expectedStartElement);
+ }
+
+ @Override
+ protected EndpointType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ String binding = StaxParserUtil.getRequiredAttributeValue(element, SAMLMetadataQNames.ATTR_BINDING);
+ String location = StaxParserUtil.getRequiredAttributeValue(element, SAMLMetadataQNames.ATTR_LOCATION);
+
+ EndpointType endpoint = new EndpointType(URI.create(binding), URI.create(location));
+
+ String responseLocation = StaxParserUtil.getAttributeValue(element, SAMLMetadataQNames.ATTR_RESPONSE_LOCATION);
+
+ if (responseLocation != null) {
+ endpoint.setResponseLocation(URI.create(responseLocation));
+ }
+
+ return endpoint;
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, EndpointType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+ }
+}
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 83e9179986..56a1c34c00 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
@@ -17,24 +17,12 @@
package org.keycloak.saml.processing.core.parsers.saml.metadata;
import org.keycloak.dom.saml.v2.metadata.EntitiesDescriptorType;
-import org.keycloak.dom.saml.v2.metadata.ExtensionsType;
-import org.keycloak.saml.common.PicketLinkLogger;
-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.AbstractParser;
import org.keycloak.saml.common.util.StaxParserUtil;
-import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
import org.w3c.dom.Element;
-import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
-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
@@ -42,74 +30,53 @@ import org.keycloak.saml.common.parsers.StaxParser;
* @author Anil.Saldhana@redhat.com
* @since Jan 31, 2011
*/
-public class SAMLEntitiesDescriptorParser extends AbstractParser {
+public class SAMLEntitiesDescriptorParser extends AbstractStaxSamlMetadataParser {
- private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
+ private static final SAMLEntitiesDescriptorParser INSTANCE = new SAMLEntitiesDescriptorParser();
- private static final String EDT = JBossSAMLConstants.ENTITIES_DESCRIPTOR.get();
+ public SAMLEntitiesDescriptorParser() {
+ super(SAMLMetadataQNames.ENTITIES_DESCRIPTOR);
+ }
- public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
+ public static SAMLEntitiesDescriptorParser getInstance() {
+ return INSTANCE;
+ }
- StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- StaxParserUtil.validate(startElement, EDT);
-
- EntitiesDescriptorType entitiesDescriptorType = new EntitiesDescriptorType();
+ @Override
+ protected EntitiesDescriptorType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ EntitiesDescriptorType descriptor = new EntitiesDescriptorType();
// Parse the attributes
- Attribute validUntil = startElement.getAttributeByName(new QName(JBossSAMLConstants.VALID_UNTIL.get()));
- if (validUntil != null) {
- String validUntilValue = StaxParserUtil.getAttributeValue(validUntil);
- entitiesDescriptorType.setValidUntil(XMLTimeUtil.parse(validUntilValue));
- }
+ descriptor.setID(StaxParserUtil.getAttributeValue(element, SAMLMetadataQNames.ATTR_ID));
+ descriptor.setValidUntil(StaxParserUtil.getXmlTimeAttributeValue(element, SAMLMetadataQNames.ATTR_VALID_UNTIL));
+ descriptor.setCacheDuration(StaxParserUtil.getXmlDurationAttributeValue(element, SAMLMetadataQNames.ATTR_CACHE_DURATION));
+ descriptor.setName(StaxParserUtil.getAttributeValue(element, SAMLMetadataQNames.ATTR_NAME));
- Attribute id = startElement.getAttributeByName(new QName(JBossSAMLConstants.ID.get()));
- if (id != null) {
- entitiesDescriptorType.setID(StaxParserUtil.getAttributeValue(id));
- }
-
- Attribute name = startElement.getAttributeByName(new QName(JBossSAMLConstants.NAME.get()));
- if (name != null) {
- entitiesDescriptorType.setName(StaxParserUtil.getAttributeValue(name));
- }
-
- Attribute cacheDuration = startElement.getAttributeByName(new QName(JBossSAMLConstants.CACHE_DURATION.get()));
- if (cacheDuration != null) {
- entitiesDescriptorType
- .setCacheDuration(XMLTimeUtil.parseAsDuration(StaxParserUtil.getAttributeValue(cacheDuration)));
- }
-
- // Get the Child Elements
- while (xmlEventReader.hasNext()) {
- XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
- if (xmlEvent instanceof EndElement) {
- StaxParserUtil.validate((EndElement) xmlEvent, EDT);
- StaxParserUtil.getNextEndElement(xmlEventReader);
- break;
- }
- startElement = (StartElement) xmlEvent;
- String localPart = startElement.getName().getLocalPart();
-
- if (JBossSAMLConstants.ENTITY_DESCRIPTOR.get().equals(localPart)) {
- SAMLEntityDescriptorParser entityParser = new SAMLEntityDescriptorParser();
- entitiesDescriptorType.addEntityDescriptor(entityParser.parse(xmlEventReader));
- } else if (JBossSAMLConstants.EXTENSIONS__METADATA.get().equalsIgnoreCase(localPart)) {
- entitiesDescriptorType.setExtensions(parseExtensions(xmlEventReader));
- } else if (JBossSAMLConstants.ENTITIES_DESCRIPTOR.get().equalsIgnoreCase(localPart)) {
- SAMLEntitiesDescriptorParser parser = new SAMLEntitiesDescriptorParser();
- entitiesDescriptorType.addEntityDescriptor(parser.parse(xmlEventReader));
- } else if (localPart.equals(JBossSAMLConstants.SIGNATURE.get())) {
- entitiesDescriptorType.setSignature(StaxParserUtil.getDOMElement(xmlEventReader));
- } else
- throw logger.parserUnknownTag(localPart, startElement.getLocation());
- }
- return entitiesDescriptorType;
+ return descriptor;
}
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, EntitiesDescriptorType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch (element) {
+ case SIGNATURE:
+ Element sig = StaxParserUtil.getDOMElement(xmlEventReader);
+ target.setSignature(sig);
+ break;
- private ExtensionsType parseExtensions(XMLEventReader xmlEventReader) throws ParsingException {
- ExtensionsType extensions = new ExtensionsType();
- Element extElement = StaxParserUtil.getDOMElement(xmlEventReader);
- extensions.setElement(extElement);
- return extensions;
+ case EXTENSIONS:
+ target.setExtensions(SAMLExtensionsParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case ENTITY_DESCRIPTOR:
+ target.addEntityDescriptor(SAMLEntityDescriptorParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case ENTITIES_DESCRIPTOR:
+ target.addEntityDescriptor(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/SAMLEntityDescriptorParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLEntityDescriptorParser.java
index f94027db61..9c4eb187d3 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
@@ -16,50 +16,20 @@
*/
package org.keycloak.saml.processing.core.parsers.saml.metadata;
-import org.keycloak.dom.saml.v2.assertion.AttributeType;
import org.keycloak.dom.saml.v2.metadata.AttributeAuthorityDescriptorType;
-import org.keycloak.dom.saml.v2.metadata.AttributeConsumingServiceType;
-import org.keycloak.dom.saml.v2.metadata.ContactType;
-import org.keycloak.dom.saml.v2.metadata.ContactTypeType;
-import org.keycloak.dom.saml.v2.metadata.EndpointType;
+import org.keycloak.dom.saml.v2.metadata.AuthnAuthorityDescriptorType;
import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType;
-import org.keycloak.dom.saml.v2.metadata.ExtensionsType;
import org.keycloak.dom.saml.v2.metadata.IDPSSODescriptorType;
-import org.keycloak.dom.saml.v2.metadata.IndexedEndpointType;
-import org.keycloak.dom.saml.v2.metadata.KeyDescriptorType;
-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.PDPDescriptorType;
import org.keycloak.dom.saml.v2.metadata.RoleDescriptorType;
import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
-import org.keycloak.dom.xmlsec.w3.xmlenc.EncryptionMethodType;
-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.ParsingException;
-import org.keycloak.saml.common.parsers.AbstractParser;
import org.keycloak.saml.common.util.StaxParserUtil;
-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;
-
-import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
-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.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;
+
+import static org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLMetadataQNames.ENTITY_DESCRIPTOR;
/**
* Parse the SAML Metadata element "EntityDescriptor"
@@ -67,621 +37,107 @@ import org.keycloak.saml.common.parsers.StaxParser;
* @author Anil.Saldhana@redhat.com
* @since Dec 14, 2010
*/
-public class SAMLEntityDescriptorParser extends AbstractParser {
+public class SAMLEntityDescriptorParser extends AbstractStaxSamlMetadataParser {
- private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
+ private static final SAMLEntityDescriptorParser INSTANCE = new SAMLEntityDescriptorParser();
- private static final String EDT = JBossSAMLConstants.ENTITY_DESCRIPTOR.get();
+ private SAMLEntityDescriptorParser() {
+ super(ENTITY_DESCRIPTOR);
+ }
- public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
+ public static SAMLEntityDescriptorParser getInstance() {
+ return INSTANCE;
+ }
- StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- StaxParserUtil.validate(startElement, EDT);
+ @Override
+ protected EntityDescriptorType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ String entityID = StaxParserUtil.getRequiredAttributeValue(element, SAMLMetadataQNames.ATTR_ENTITY_ID);
+ EntityDescriptorType descriptor = new EntityDescriptorType(entityID);
- Attribute entityID = startElement.getAttributeByName(new QName(JBossSAMLConstants.ENTITY_ID.get()));
- String entityIDValue = StaxParserUtil.getAttributeValue(entityID);
- EntityDescriptorType entityDescriptorType = new EntityDescriptorType(entityIDValue);
+ descriptor.setValidUntil(StaxParserUtil.getXmlTimeAttributeValue(element, SAMLMetadataQNames.ATTR_VALID_UNTIL));
+ descriptor.setCacheDuration(StaxParserUtil.getXmlDurationAttributeValue(element, SAMLMetadataQNames.ATTR_CACHE_DURATION));
+ descriptor.setID(StaxParserUtil.getAttributeValue(element, SAMLMetadataQNames.ATTR_ID));
- Attribute validUntil = startElement.getAttributeByName(new QName(JBossSAMLConstants.VALID_UNTIL.get()));
- if (validUntil != null) {
- String validUntilValue = StaxParserUtil.getAttributeValue(validUntil);
- entityDescriptorType.setValidUntil(XMLTimeUtil.parse(validUntilValue));
- }
+ return descriptor;
+ }
- Attribute id = startElement.getAttributeByName(new QName(JBossSAMLConstants.ID.get()));
- if (id != null) {
- entityDescriptorType.setID(StaxParserUtil.getAttributeValue(id));
- }
-
- Attribute cacheDuration = startElement.getAttributeByName(new QName(JBossSAMLConstants.CACHE_DURATION.get()));
- if (cacheDuration != null) {
- entityDescriptorType.setCacheDuration(XMLTimeUtil.parseAsDuration(StaxParserUtil.getAttributeValue(cacheDuration)));
- }
-
- // Get the Child Elements
- while (xmlEventReader.hasNext()) {
- XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
- if (xmlEvent instanceof EndElement) {
- StaxParserUtil.validate((EndElement) xmlEvent, EDT);
- StaxParserUtil.getNextEndElement(xmlEventReader);
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, EntityDescriptorType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch (element) {
+ case SIGNATURE:
+ target.setSignature(StaxParserUtil.getDOMElement(xmlEventReader));
break;
- }
- startElement = (StartElement) xmlEvent;
- String localPart = startElement.getName().getLocalPart();
- if (JBossSAMLConstants.IDP_SSO_DESCRIPTOR.get().equals(localPart)) {
- IDPSSODescriptorType idpSSO = parseIDPSSODescriptor(xmlEventReader);
-
- EntityDescriptorType.EDTDescriptorChoiceType edtDescChoice = new EntityDescriptorType.EDTDescriptorChoiceType(idpSSO);
- EntityDescriptorType.EDTChoiceType edtChoice = EntityDescriptorType.EDTChoiceType.oneValue(edtDescChoice);
- entityDescriptorType.addChoiceType(edtChoice);
- } else if (JBossSAMLConstants.SP_SSO_DESCRIPTOR.get().equals(localPart)) {
- SPSSODescriptorType spSSO = parseSPSSODescriptor(xmlEventReader);
-
- EntityDescriptorType.EDTDescriptorChoiceType edtDescChoice = new EntityDescriptorType.EDTDescriptorChoiceType(spSSO);
- EntityDescriptorType.EDTChoiceType edtChoice = EntityDescriptorType.EDTChoiceType.oneValue(edtDescChoice);
- entityDescriptorType.addChoiceType(edtChoice);
- } else if (JBossSAMLConstants.ATTRIBUTE_AUTHORITY_DESCRIPTOR.get().equals(localPart)) {
- AttributeAuthorityDescriptorType attrAuthority = parseAttributeAuthorityDescriptor(xmlEventReader);
-
- EntityDescriptorType.EDTDescriptorChoiceType edtDescChoice = new EntityDescriptorType.EDTDescriptorChoiceType(attrAuthority);
- EntityDescriptorType.EDTChoiceType edtChoice = EntityDescriptorType.EDTChoiceType.oneValue(edtDescChoice);
- entityDescriptorType.addChoiceType(edtChoice);
- } else if (JBossSAMLConstants.AUTHN_AUTHORITY_DESCRIPTOR.get().equals(localPart)) {
- throw logger.unsupportedType("AuthnAuthorityDescriptor");
- } else if (JBossSAMLConstants.AFFILIATION_DESCRIPTOR.get().equals(localPart)) {
- throw logger.unsupportedType(" AffiliationDescriptor");
- } else if (JBossSAMLConstants.PDP_DESCRIPTOR.get().equals(localPart)) {
- throw logger.unsupportedType(" PDPDescriptor");
- } else if (localPart.equals(JBossSAMLConstants.SIGNATURE.get())) {
- entityDescriptorType.setSignature(StaxParserUtil.getDOMElement(xmlEventReader));
- } else if (JBossSAMLConstants.ORGANIZATION.get().equals(localPart)) {
- OrganizationType organization = parseOrganization(xmlEventReader);
-
- entityDescriptorType.setOrganization(organization);
- } else if (JBossSAMLConstants.CONTACT_PERSON.get().equals(localPart)) {
- entityDescriptorType.addContactPerson(parseContactPerson(xmlEventReader));
- } else if (JBossSAMLConstants.ADDITIONAL_METADATA_LOCATION.get().equals(localPart)) {
- throw logger.unsupportedType("AdditionalMetadataLocation");
- } 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);
-
- EntityDescriptorType.EDTDescriptorChoiceType edtDescChoice = new EntityDescriptorType.EDTDescriptorChoiceType(roleDescriptor);
- EntityDescriptorType.EDTChoiceType edtChoice = EntityDescriptorType.EDTChoiceType.oneValue(edtDescChoice);
-
- entityDescriptorType.addChoiceType(edtChoice);
- } else
- throw logger.parserUnknownStartElement(localPart, startElement.getLocation());
- }
- return entityDescriptorType;
- }
-
-
- private SPSSODescriptorType parseSPSSODescriptor(XMLEventReader xmlEventReader) throws ParsingException {
- StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- StaxParserUtil.validate(startElement, JBossSAMLConstants.SP_SSO_DESCRIPTOR.get());
-
- List protocolEnum = parseProtocolEnumeration(startElement);
- SPSSODescriptorType spSSODescriptor = new SPSSODescriptorType(protocolEnum);
-
- Attribute wantAssertionsSigned = startElement.getAttributeByName(new QName(JBossSAMLConstants.WANT_ASSERTIONS_SIGNED
- .get()));
- if (wantAssertionsSigned != null) {
- spSSODescriptor
- .setWantAssertionsSigned(Boolean.parseBoolean(StaxParserUtil.getAttributeValue(wantAssertionsSigned)));
- }
- Attribute wantAuthnSigned = startElement.getAttributeByName(new QName(JBossSAMLConstants.AUTHN_REQUESTS_SIGNED.get()));
- if (wantAuthnSigned != null) {
- spSSODescriptor.setAuthnRequestsSigned(Boolean.parseBoolean(StaxParserUtil.getAttributeValue(wantAuthnSigned)));
- }
-
- while (xmlEventReader.hasNext()) {
- XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
- if (xmlEvent instanceof EndElement) {
- EndElement end = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(end, JBossSAMLConstants.SP_SSO_DESCRIPTOR.get());
+ case EXTENSIONS:
+ target.setExtensions(SAMLExtensionsParser.getInstance().parse(xmlEventReader));
break;
- }
- startElement = (StartElement) xmlEvent;
- String localPart = startElement.getName().getLocalPart();
+ case IDP_SSO_DESCRIPTOR:
+ {
+ IDPSSODescriptorType idpSSO = SAMLIDPSSODescriptorParser.getInstance().parse(xmlEventReader);
- if (JBossSAMLConstants.ARTIFACT_RESOLUTION_SERVICE.get().equals(localPart)) {
- IndexedEndpointType endpoint = parseArtifactResolutionService(xmlEventReader, startElement);
- spSSODescriptor.addArtifactResolutionService(endpoint);
- } else if (JBossSAMLConstants.ASSERTION_CONSUMER_SERVICE.get().equals(localPart)) {
- IndexedEndpointType endpoint = parseAssertionConsumerService(xmlEventReader, startElement);
- spSSODescriptor.addAssertionConsumerService(endpoint);
- } else if (JBossSAMLConstants.ATTRIBUTE_CONSUMING_SERVICE.get().equals(localPart)) {
- AttributeConsumingServiceType attributeConsumer = parseAttributeConsumingService(xmlEventReader, startElement);
- spSSODescriptor.addAttributeConsumerService(attributeConsumer);
- } else if (JBossSAMLConstants.SINGLE_LOGOUT_SERVICE.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- EndpointType endpoint = getEndpointType(startElement);
-
- EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(endElement, JBossSAMLConstants.SINGLE_LOGOUT_SERVICE.get());
-
- spSSODescriptor.addSingleLogoutService(endpoint);
- } else if (JBossSAMLConstants.MANAGE_NAMEID_SERVICE.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- EndpointType endpoint = getEndpointType(startElement);
-
- EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(endElement, JBossSAMLConstants.MANAGE_NAMEID_SERVICE.get());
-
- spSSODescriptor.addManageNameIDService(endpoint);
- } else if (JBossSAMLConstants.NAMEID_FORMAT.get().equalsIgnoreCase(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- spSSODescriptor.addNameIDFormat(StaxParserUtil.getElementText(xmlEventReader));
- } else if (JBossSAMLConstants.KEY_DESCRIPTOR.get().equalsIgnoreCase(localPart)) {
- spSSODescriptor.addKeyDescriptor(parseKeyDescriptor(xmlEventReader));
- } else if (JBossSAMLConstants.EXTENSIONS__PROTOCOL.get().equalsIgnoreCase(localPart)) {
- spSSODescriptor.setExtensions(parseExtensions(xmlEventReader));
- } else
- throw logger.parserUnknownTag(localPart, startElement.getLocation());
- }
- return spSSODescriptor;
- }
-
- private IDPSSODescriptorType parseIDPSSODescriptor(XMLEventReader xmlEventReader) throws ParsingException {
- StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- StaxParserUtil.validate(startElement, JBossSAMLConstants.IDP_SSO_DESCRIPTOR.get());
-
- List protocolEnum = parseProtocolEnumeration(startElement);
- IDPSSODescriptorType idpSSODescriptor = new IDPSSODescriptorType(protocolEnum);
-
- Attribute wantAuthnSigned = startElement.getAttributeByName(new QName(JBossSAMLConstants.WANT_AUTHN_REQUESTS_SIGNED
- .get()));
- if (wantAuthnSigned != null) {
- idpSSODescriptor
- .setWantAuthnRequestsSigned(Boolean.parseBoolean(StaxParserUtil.getAttributeValue(wantAuthnSigned)));
- }
-
- while (xmlEventReader.hasNext()) {
- XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
- if (xmlEvent instanceof EndElement) {
- EndElement end = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(end, JBossSAMLConstants.IDP_SSO_DESCRIPTOR.get());
+ EntityDescriptorType.EDTDescriptorChoiceType edtDescChoice = new EntityDescriptorType.EDTDescriptorChoiceType(idpSSO);
+ EntityDescriptorType.EDTChoiceType edtChoice = EntityDescriptorType.EDTChoiceType.oneValue(edtDescChoice);
+ target.addChoiceType(edtChoice);
+ }
break;
- }
- startElement = (StartElement) xmlEvent;
- String localPart = startElement.getName().getLocalPart();
+ case SP_SSO_DESCRIPTOR:
+ {
+ SPSSODescriptorType spSSO = SAMLSPSSODescriptorParser.getInstance().parse(xmlEventReader);
- if (JBossSAMLConstants.ARTIFACT_RESOLUTION_SERVICE.get().equals(localPart)) {
- IndexedEndpointType endpoint = parseArtifactResolutionService(xmlEventReader, startElement);
- idpSSODescriptor.addArtifactResolutionService(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());
-
- idpSSODescriptor.addAssertionIDRequestService(endpoint);
- } else if (JBossSAMLConstants.SINGLE_LOGOUT_SERVICE.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- EndpointType endpoint = getEndpointType(startElement);
-
- EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(endElement, JBossSAMLConstants.SINGLE_LOGOUT_SERVICE.get());
-
- idpSSODescriptor.addSingleLogoutService(endpoint);
- } else if (JBossSAMLConstants.SINGLE_SIGNON_SERVICE.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- EndpointType endpoint = getEndpointType(startElement);
-
- EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(endElement, JBossSAMLConstants.SINGLE_SIGNON_SERVICE.get());
-
- idpSSODescriptor.addSingleSignOnService(endpoint);
- } else if (JBossSAMLConstants.MANAGE_NAMEID_SERVICE.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- EndpointType endpoint = getEndpointType(startElement);
-
- EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(endElement, JBossSAMLConstants.MANAGE_NAMEID_SERVICE.get());
-
- idpSSODescriptor.addManageNameIDService(endpoint);
- } else if (JBossSAMLConstants.NAMEID_MAPPING_SERVICE.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- EndpointType endpoint = getEndpointType(startElement);
-
- EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(endElement, JBossSAMLConstants.NAMEID_MAPPING_SERVICE.get());
-
- idpSSODescriptor.addNameIDMappingService(endpoint);
- } else if (JBossSAMLConstants.NAMEID_FORMAT.get().equalsIgnoreCase(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- idpSSODescriptor.addNameIDFormat(StaxParserUtil.getElementText(xmlEventReader));
- } else if (JBossSAMLConstants.ATTRIBUTE.get().equalsIgnoreCase(localPart)) {
- 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__PROTOCOL.get().equalsIgnoreCase(localPart)) {
- idpSSODescriptor.setExtensions(parseExtensions(xmlEventReader));
- } else
- throw logger.parserUnknownTag(localPart, startElement.getLocation());
- }
- return idpSSODescriptor;
- }
-
- private EndpointType getEndpointType(StartElement startElement) {
- Attribute bindingAttr = startElement.getAttributeByName(new QName(JBossSAMLConstants.BINDING.get()));
- String binding = StaxParserUtil.getAttributeValue(bindingAttr);
-
- Attribute locationAttr = startElement.getAttributeByName(new QName(JBossSAMLConstants.LOCATION.get()));
- String location = StaxParserUtil.getAttributeValue(locationAttr);
-
- EndpointType endpoint = new IndexedEndpointType(URI.create(binding), URI.create(location));
- Attribute responseLocation = startElement.getAttributeByName(new QName(JBossSAMLConstants.RESPONSE_LOCATION.get()));
- if (responseLocation != null) {
- endpoint.setResponseLocation(URI.create(StaxParserUtil.getAttributeValue(responseLocation)));
- }
- return endpoint;
- }
-
- private AttributeAuthorityDescriptorType parseAttributeAuthorityDescriptor(XMLEventReader xmlEventReader)
- throws ParsingException {
- StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- StaxParserUtil.validate(startElement, JBossSAMLConstants.ATTRIBUTE_AUTHORITY_DESCRIPTOR.get());
- List protocolEnum = parseProtocolEnumeration(startElement);
- AttributeAuthorityDescriptorType attributeAuthority = new AttributeAuthorityDescriptorType(protocolEnum);
-
- while (xmlEventReader.hasNext()) {
- XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
- if (xmlEvent instanceof EndElement) {
- EndElement end = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(end, JBossSAMLConstants.ATTRIBUTE_AUTHORITY_DESCRIPTOR.get());
+ EntityDescriptorType.EDTDescriptorChoiceType edtDescChoice = new EntityDescriptorType.EDTDescriptorChoiceType(spSSO);
+ EntityDescriptorType.EDTChoiceType edtChoice = EntityDescriptorType.EDTChoiceType.oneValue(edtDescChoice);
+ target.addChoiceType(edtChoice);
+ }
break;
- }
- startElement = (StartElement) xmlEvent;
- String localPart = startElement.getName().getLocalPart();
+ case ATTRIBUTE_AUTHORITY_DESCRIPTOR:
+ {
+ AttributeAuthorityDescriptorType attrAuthority = SAMLAttributeAuthorityDescriptorParser.getInstance().parse(xmlEventReader);
- if (JBossSAMLConstants.ATTRIBUTE_SERVICE.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- Attribute bindingAttr = startElement.getAttributeByName(new QName(JBossSAMLConstants.BINDING.get()));
- String binding = StaxParserUtil.getAttributeValue(bindingAttr);
-
- Attribute locationAttr = startElement.getAttributeByName(new QName(JBossSAMLConstants.LOCATION.get()));
- String location = StaxParserUtil.getAttributeValue(locationAttr);
-
- IndexedEndpointType endpoint = new IndexedEndpointType(URI.create(binding), URI.create(location));
-
- EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
- 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(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__PROTOCOL.get().equalsIgnoreCase(localPart)) {
- attributeAuthority.setExtensions(parseExtensions(xmlEventReader));
- } else
- throw logger.parserUnknownTag(localPart, startElement.getLocation());
-
- }
- return attributeAuthority;
- }
-
- private OrganizationType parseOrganization(XMLEventReader xmlEventReader) throws ParsingException {
- StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- StaxParserUtil.validate(startElement, JBossSAMLConstants.ORGANIZATION.get());
-
- OrganizationType org = new OrganizationType();
-
- while (xmlEventReader.hasNext()) {
- XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
- if (xmlEvent instanceof EndElement) {
- EndElement end = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(end, JBossSAMLConstants.ORGANIZATION.get());
+ EntityDescriptorType.EDTDescriptorChoiceType edtDescChoice = new EntityDescriptorType.EDTDescriptorChoiceType(attrAuthority);
+ EntityDescriptorType.EDTChoiceType edtChoice = EntityDescriptorType.EDTChoiceType.oneValue(edtDescChoice);
+ target.addChoiceType(edtChoice);
+ }
break;
- }
- startElement = (StartElement) xmlEvent;
- String localPart = startElement.getName().getLocalPart();
+ case AUTHN_AUTHORITY_DESCRIPTOR:
+ {
+ AuthnAuthorityDescriptorType authAuthority = SAMLAuthnAuthorityDescriptorParser.getInstance().parse(xmlEventReader);
- if (JBossSAMLConstants.ORGANIZATION_NAME.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- LocalizedNameType localName = getLocalizedName(xmlEventReader, startElement);
- org.addOrganizationName(localName);
- } else if (JBossSAMLConstants.ORGANIZATION_DISPLAY_NAME.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- LocalizedNameType localName = getLocalizedName(xmlEventReader, startElement);
- org.addOrganizationDisplayName(localName);
- } else if (JBossSAMLConstants.ORGANIZATION_URL.get().equals(localPart) ||
- (JBossSAMLConstants.ORGANIZATION_URL_ALT.get().equals(localPart))) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- Attribute lang = startElement.getAttributeByName(new QName(JBossSAMLURIConstants.XML.get(), "lang"));
- String langVal = StaxParserUtil.getAttributeValue(lang);
- LocalizedURIType localName = new LocalizedURIType(langVal);
- localName.setValue(URI.create(StaxParserUtil.getElementText(xmlEventReader)));
- org.addOrganizationURL(localName);
- } else if (JBossSAMLConstants.EXTENSIONS__PROTOCOL.get().equalsIgnoreCase(localPart)) {
- org.setExtensions(parseExtensions(xmlEventReader));
- } else
- throw logger.parserUnknownTag(localPart, startElement.getLocation());
- }
- return org;
- }
-
- private KeyDescriptorType parseKeyDescriptor(XMLEventReader xmlEventReader) throws ParsingException {
- StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- StaxParserUtil.validate(startElement, JBossSAMLConstants.KEY_DESCRIPTOR.get());
-
- KeyDescriptorType keyDescriptor = new KeyDescriptorType();
-
- String use = StaxParserUtil.getAttributeValue(startElement, "use");
-
- if (use != null && !use.isEmpty()) {
- keyDescriptor.setUse(KeyTypes.fromValue(use));
- }
-
- while (xmlEventReader.hasNext()) {
- XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
- if (xmlEvent instanceof EndElement) {
- EndElement end = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(end, JBossSAMLConstants.KEY_DESCRIPTOR.get());
+ EntityDescriptorType.EDTDescriptorChoiceType edtDescChoice = new EntityDescriptorType.EDTDescriptorChoiceType(authAuthority);
+ EntityDescriptorType.EDTChoiceType edtChoice = EntityDescriptorType.EDTChoiceType.oneValue(edtDescChoice);
+ target.addChoiceType(edtChoice);
+ }
break;
- }
- startElement = (StartElement) xmlEvent;
- String localPart = startElement.getName().getLocalPart();
+ case PDP_DESCRIPTOR:
+ {
+ PDPDescriptorType pdpDescriptor = SAMLPDPDescriptorParser.getInstance().parse(xmlEventReader);
- if (JBossSAMLConstants.KEY_INFO.get().equals(localPart)) {
- Element key = StaxParserUtil.getDOMElement(xmlEventReader);
- keyDescriptor.setKeyInfo(key);
- } else if (JBossSAMLConstants.ENCRYPTION_METHOD.get().equals(localPart)) {
- keyDescriptor.addEncryptionMethod(parseEncryptionMethod(xmlEventReader));
- } else
- throw logger.parserUnknownTag(localPart, startElement.getLocation());
- }
-
- return keyDescriptor;
- }
-
- private EncryptionMethodType parseEncryptionMethod(XMLEventReader xmlEventReader) throws ParsingException {
- StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- StaxParserUtil.validate(startElement, JBossSAMLConstants.ENCRYPTION_METHOD.get());
- Attribute algorithm = startElement.getAttributeByName(new QName("Algorithm"));
- EncryptionMethodType encryptionMethodType = new EncryptionMethodType(algorithm.getValue());
-
- BigInteger keySize = null;
- byte[] OAEPparams = null;
-
- while (xmlEventReader.hasNext()) {
- XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
- if (xmlEvent instanceof EndElement) {
- EndElement end = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(end, JBossSAMLConstants.ENCRYPTION_METHOD.get());
+ EntityDescriptorType.EDTDescriptorChoiceType edtDescChoice = new EntityDescriptorType.EDTDescriptorChoiceType(pdpDescriptor);
+ EntityDescriptorType.EDTChoiceType edtChoice = EntityDescriptorType.EDTChoiceType.oneValue(edtDescChoice);
+ target.addChoiceType(edtChoice);
+ }
break;
- }
-
- startElement = (StartElement) xmlEvent;
- String localPart = startElement.getName().getLocalPart();
-
- if ("KeySize".equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- keySize = BigInteger.valueOf(Long.valueOf(StaxParserUtil.getElementText(xmlEventReader)));
- } else if ("OAEPparams".equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- OAEPparams = StaxParserUtil.getElementText(xmlEventReader).getBytes(GeneralConstants.SAML_CHARSET);
- } else {
- throw logger.parserUnknownTag(localPart, startElement.getLocation());
- }
- }
-
- EncryptionMethodType.EncryptionMethod encryptionMethod = new EncryptionMethodType.EncryptionMethod(keySize, OAEPparams);
-
- encryptionMethodType.setEncryptionMethod(encryptionMethod);
-
- return encryptionMethodType;
- }
-
- private ContactType parseContactPerson(XMLEventReader xmlEventReader) throws ParsingException {
- StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- StaxParserUtil.validate(startElement, JBossSAMLConstants.CONTACT_PERSON.get());
-
- Attribute attr = startElement.getAttributeByName(new QName(JBossSAMLConstants.CONTACT_TYPE.get()));
- if (attr == null)
- throw logger.parserRequiredAttribute("contactType");
- ContactType contactType = new ContactType(ContactTypeType.fromValue(StaxParserUtil.getAttributeValue(attr)));
-
- while (xmlEventReader.hasNext()) {
- XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
- if (xmlEvent instanceof EndElement) {
- EndElement end = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(end, JBossSAMLConstants.CONTACT_PERSON.get());
+ case ROLE_DESCRIPTOR:
+ case AFFILIATION_DESCRIPTOR:
+ case ADDITIONAL_METADATA_LOCATION:
+ StaxParserUtil.bypassElementBlock(xmlEventReader);
break;
- }
- startElement = (StartElement) xmlEvent;
- String localPart = startElement.getName().getLocalPart();
-
- if (JBossSAMLConstants.COMPANY.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- contactType.setCompany(StaxParserUtil.getElementText(xmlEventReader));
- } else if (JBossSAMLConstants.GIVEN_NAME.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- contactType.setGivenName(StaxParserUtil.getElementText(xmlEventReader));
- } else if (JBossSAMLConstants.SURNAME.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- contactType.setSurName(StaxParserUtil.getElementText(xmlEventReader));
- } else if (JBossSAMLConstants.EMAIL_ADDRESS.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- contactType.addEmailAddress(StaxParserUtil.getElementText(xmlEventReader));
- } else if (JBossSAMLConstants.TELEPHONE_NUMBER.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- contactType.addTelephone(StaxParserUtil.getElementText(xmlEventReader));
- } else if (JBossSAMLConstants.EXTENSIONS__PROTOCOL.get().equalsIgnoreCase(localPart)) {
- contactType.setExtensions(parseExtensions(xmlEventReader));
- } else
- throw logger.parserUnknownTag(localPart, startElement.getLocation());
- }
- return contactType;
- }
-
- private LocalizedNameType getLocalizedName(XMLEventReader xmlEventReader, StartElement startElement)
- throws ParsingException {
- Attribute lang = startElement.getAttributeByName(new QName(JBossSAMLURIConstants.XML.get(), "lang"));
- String langVal = StaxParserUtil.getAttributeValue(lang);
- LocalizedNameType localName = new LocalizedNameType(langVal);
- localName.setValue(StaxParserUtil.getElementText(xmlEventReader));
- return localName;
- }
-
- private IndexedEndpointType parseAssertionConsumerService(XMLEventReader xmlEventReader, StartElement startElement)
- throws ParsingException {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- IndexedEndpointType endpoint = parseIndexedEndpoint(xmlEventReader, startElement);
-
- EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(endElement, JBossSAMLConstants.ASSERTION_CONSUMER_SERVICE.get());
-
- return endpoint;
- }
-
- private IndexedEndpointType parseArtifactResolutionService(XMLEventReader xmlEventReader, StartElement startElement)
- throws ParsingException {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- IndexedEndpointType endpoint = parseIndexedEndpoint(xmlEventReader, startElement);
-
- EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(endElement, JBossSAMLConstants.ARTIFACT_RESOLUTION_SERVICE.get());
-
- return endpoint;
- }
-
- private IndexedEndpointType parseIndexedEndpoint(XMLEventReader xmlEventReader, StartElement startElement) {
- Attribute bindingAttr = startElement.getAttributeByName(new QName(JBossSAMLConstants.BINDING.get()));
- String binding = StaxParserUtil.getAttributeValue(bindingAttr);
-
- Attribute locationAttr = startElement.getAttributeByName(new QName(JBossSAMLConstants.LOCATION.get()));
- String location = StaxParserUtil.getAttributeValue(locationAttr);
-
- IndexedEndpointType endpoint = new IndexedEndpointType(URI.create(binding), URI.create(location));
- Attribute isDefault = startElement.getAttributeByName(new QName(JBossSAMLConstants.ISDEFAULT.get()));
- if (isDefault != null) {
- endpoint.setIsDefault(Boolean.parseBoolean(StaxParserUtil.getAttributeValue(isDefault)));
- }
- Attribute index = startElement.getAttributeByName(new QName(JBossSAMLConstants.INDEX.get()));
- if (index != null) {
- endpoint.setIndex(Integer.parseInt(StaxParserUtil.getAttributeValue(index)));
- }
- return endpoint;
- }
-
- private AttributeConsumingServiceType parseAttributeConsumingService(XMLEventReader xmlEventReader,
- StartElement startElement) throws ParsingException {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
-
- Attribute indexAttr = startElement.getAttributeByName(new QName(JBossSAMLConstants.INDEX.get()));
- if (indexAttr == null)
- throw logger.parserRequiredAttribute("index");
-
- AttributeConsumingServiceType attributeConsumer = new AttributeConsumingServiceType(Integer.parseInt(StaxParserUtil
- .getAttributeValue(indexAttr)));
- while (xmlEventReader.hasNext()) {
- XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
- if (xmlEvent instanceof EndElement) {
- EndElement end = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(end, JBossSAMLConstants.ATTRIBUTE_CONSUMING_SERVICE.get());
+ case ORGANIZATION:
+ target.setOrganization(SAMLOrganizationParser.getInstance().parse(xmlEventReader));
break;
- }
- startElement = (StartElement) xmlEvent;
- String localPart = startElement.getName().getLocalPart();
-
- if (JBossSAMLConstants.SERVICE_NAME.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- LocalizedNameType localName = getLocalizedName(xmlEventReader, startElement);
- attributeConsumer.addServiceName(localName);
- } else if (JBossSAMLConstants.SERVICE_DESCRIPTION.get().equals(localPart)) {
- startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- LocalizedNameType localName = getLocalizedName(xmlEventReader, startElement);
- attributeConsumer.addServiceDescription(localName);
- } else if (JBossSAMLConstants.REQUESTED_ATTRIBUTE.get().equals(localPart)) {
- attributeConsumer.addRequestedAttribute(SAMLRequestedAttributeParser.getInstance().parse(xmlEventReader));
- } else
- throw logger.parserUnknownTag(localPart, startElement.getLocation());
- }
-
- return attributeConsumer;
- }
-
- private ExtensionsType parseExtensions(XMLEventReader xmlEventReader) throws ParsingException {
- ExtensionsType extensions = new ExtensionsType();
- Element extElement = StaxParserUtil.getDOMElement(xmlEventReader);
- extensions.setElement(extElement);
- return extensions;
- }
-
- private RoleDescriptorType parseRoleDescriptor(XMLEventReader xmlEventReader) throws ParsingException {
- StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
- StaxParserUtil.validate(startElement, JBossSAMLConstants.ROLE_DESCRIPTOR.get());
- List protocolEnum = parseProtocolEnumeration(startElement);
- RoleDescriptorType roleDescriptorType = new RoleDescriptorType(protocolEnum) {};
-
- while (xmlEventReader.hasNext()) {
- XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
- if (xmlEvent instanceof EndElement) {
- EndElement end = StaxParserUtil.getNextEndElement(xmlEventReader);
- StaxParserUtil.validate(end, JBossSAMLConstants.ROLE_DESCRIPTOR.get());
+ case CONTACT_PERSON:
+ target.addContactPerson(SAMLContactPersonParser.getInstance().parse(xmlEventReader));
break;
- }
- startElement = (StartElement) xmlEvent;
- String localPart = startElement.getName().getLocalPart();
-
- if (JBossSAMLConstants.KEY_DESCRIPTOR.get().equalsIgnoreCase(localPart)) {
- KeyDescriptorType keyDescriptor = parseKeyDescriptor(xmlEventReader);
- roleDescriptorType.addKeyDescriptor(keyDescriptor);
- } else {
- StaxParserUtil.bypassElementBlock(xmlEventReader, localPart);
- }
- }
-
- return roleDescriptorType;
- }
-
- /**
- * Parse a space delimited list of strings
- *
- * @param startElement
- *
- * @return
- */
- public static List parseProtocolEnumeration(StartElement startElement) {
- List 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());
- }
+ default:
+ throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
}
- return protocolEnum;
}
}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLExtensionsParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLExtensionsParser.java
index 585c88f1f2..4dc8ab53fd 100644
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLExtensionsParser.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLExtensionsParser.java
@@ -16,24 +16,24 @@
*/
package org.keycloak.saml.processing.core.parsers.saml.metadata;
-import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.events.StartElement;
import org.keycloak.dom.saml.v2.metadata.ExtensionsType;
-import org.keycloak.saml.common.constants.JBossSAMLConstants;
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;
+
/**
* Parses <samlp:Extensions> SAML2 element into series of DOM nodes.
*
* @author hmlnarik
*/
-public class SAMLExtensionsParser extends AbstractStaxSamlParser {
+public class SAMLExtensionsParser extends AbstractStaxSamlMetadataParser {
private static final SAMLExtensionsParser INSTANCE = new SAMLExtensionsParser();
private SAMLExtensionsParser() {
- super(JBossSAMLConstants.EXTENSIONS__METADATA);
+ super(SAMLMetadataQNames.EXTENSIONS);
}
public static SAMLExtensionsParser getInstance() {
@@ -46,7 +46,7 @@ public class SAMLExtensionsParser extends AbstractStaxSamlParser
}
@Override
- protected void processSubElement(XMLEventReader xmlEventReader, ExtensionsType target, JBossSAMLConstants element, StartElement elementDetail) throws ParsingException {
- target.setElement(StaxParserUtil.getDOMElement(xmlEventReader));
+ protected void processSubElement(XMLEventReader xmlEventReader, ExtensionsType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ target.addExtension(StaxParserUtil.getDOMElement(xmlEventReader));
}
}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLIDPSSODescriptorParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLIDPSSODescriptorParser.java
new file mode 100644
index 0000000000..f90b7b6129
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLIDPSSODescriptorParser.java
@@ -0,0 +1,73 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.saml.v2.metadata.IDPSSODescriptorType;
+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 java.util.List;
+
+import static org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLMetadataQNames.IDP_SSO_DESCRIPTOR;
+
+/**
+ * @author mhajas
+ */
+public class SAMLIDPSSODescriptorParser extends SAMLSSODescriptorTypeParser {
+
+ private static final SAMLIDPSSODescriptorParser INSTANCE = new SAMLIDPSSODescriptorParser();
+
+ private SAMLIDPSSODescriptorParser() {
+ super(IDP_SSO_DESCRIPTOR);
+ }
+
+ public static SAMLIDPSSODescriptorParser getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ protected IDPSSODescriptorType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ List protocolEnum = StaxParserUtil.getRequiredStringListAttributeValue(element, SAMLMetadataQNames.ATTR_PROTOCOL_SUPPORT_ENUMERATION);
+ IDPSSODescriptorType descriptor = new IDPSSODescriptorType(protocolEnum);
+
+ // Role descriptor optional arguments
+ parseOptionalArguments(element, descriptor);
+
+ // IDPSSODecsriptor optional attributes
+ Boolean wantAuthnRequestsSigned = StaxParserUtil.getBooleanAttributeValue(element, SAMLMetadataQNames.ATTR_WANT_AUTHN_REQUESTS_SIGNED);
+ if (wantAuthnRequestsSigned != null) {
+ descriptor.setWantAuthnRequestsSigned(wantAuthnRequestsSigned);
+ }
+
+ return descriptor;
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, IDPSSODescriptorType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch (element) {
+ case SINGLE_SIGNON_SERVICE:
+ target.addSingleSignOnService(SAMLSingleSignOnServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case NAMEID_MAPPING_SERVICE:
+ target.addNameIDMappingService(SAMLNameIDMappingServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case ASSERTION_ID_REQUEST_SERVICE:
+ target.addAssertionIDRequestService(SAMLAssertinIDRequestServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case ATTRIBUTE_PROFILE:
+ StaxParserUtil.advance(xmlEventReader);
+ target.addAttributeProfile(StaxParserUtil.getElementText(xmlEventReader));
+ break;
+
+ case ATTRIBUTE:
+ target.addAttribute(SAMLAttributeParser.getInstance().parse(xmlEventReader));
+ break;
+
+ default:
+ super.processSubElement(xmlEventReader, target, element, elementDetail);
+ }
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLIndexedEndpointTypeParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLIndexedEndpointTypeParser.java
new file mode 100644
index 0000000000..68b5e170fe
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLIndexedEndpointTypeParser.java
@@ -0,0 +1,50 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.saml.v2.metadata.IndexedEndpointType;
+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 java.net.URI;
+
+/**
+ * @author mhajas
+ */
+public abstract class SAMLIndexedEndpointTypeParser extends AbstractStaxSamlMetadataParser {
+
+ public SAMLIndexedEndpointTypeParser(SAMLMetadataQNames expectedStartElement) {
+ super(expectedStartElement);
+ }
+
+ @Override
+ protected IndexedEndpointType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ String binding = StaxParserUtil.getRequiredAttributeValue(element, SAMLMetadataQNames.ATTR_BINDING);
+ String location = StaxParserUtil.getRequiredAttributeValue(element, SAMLMetadataQNames.ATTR_LOCATION);
+
+ IndexedEndpointType endpoint = new IndexedEndpointType(URI.create(binding), URI.create(location));
+
+ Boolean isDefault = StaxParserUtil.getBooleanAttributeValue(element, SAMLMetadataQNames.ATTR_IS_DEFAULT);
+ if (isDefault != null) {
+ endpoint.setIsDefault(isDefault);
+ }
+
+ Integer index = StaxParserUtil.getIntegerAttributeValue(element, SAMLMetadataQNames.ATTR_INDEX);
+ if (index != null)
+ endpoint.setIndex(index);
+
+ // EndpointType attributes
+ String responseLocation = StaxParserUtil.getAttributeValue(element, SAMLMetadataQNames.ATTR_RESPONSE_LOCATION);
+
+ if (responseLocation != null) {
+ endpoint.setResponseLocation(URI.create(responseLocation));
+ }
+
+ return endpoint;
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, IndexedEndpointType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLKeyDescriptorParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLKeyDescriptorParser.java
new file mode 100644
index 0000000000..3e435ff525
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLKeyDescriptorParser.java
@@ -0,0 +1,56 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.saml.v2.metadata.KeyDescriptorType;
+import org.keycloak.dom.saml.v2.metadata.KeyTypes;
+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 static org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLMetadataQNames.KEY_DESCRIPTOR;
+
+/**
+ * @author mhajas
+ */
+public class SAMLKeyDescriptorParser extends AbstractStaxSamlMetadataParser {
+
+ private static final SAMLKeyDescriptorParser INSTANCE = new SAMLKeyDescriptorParser();
+
+ public SAMLKeyDescriptorParser() {
+ super(KEY_DESCRIPTOR);
+ }
+
+ public static SAMLKeyDescriptorParser getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ protected KeyDescriptorType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ KeyDescriptorType keyDescriptor = new KeyDescriptorType();
+
+ String use = StaxParserUtil.getAttributeValue(element, SAMLMetadataQNames.ATTR_USE);
+
+ if (use != null && !use.isEmpty()) {
+ keyDescriptor.setUse(KeyTypes.fromValue(use));
+ }
+
+ return keyDescriptor;
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, KeyDescriptorType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch(element) {
+ case KEY_INFO:
+ target.setKeyInfo(StaxParserUtil.getDOMElement(xmlEventReader));
+ break;
+
+ case ENCRYPTION_METHOD:
+ target.addEncryptionMethod(SAMLEncryptionMethodParser.getInstance().parse(xmlEventReader));
+ break;
+
+ default:
+ throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+ }
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLManageNameIDServiceParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLManageNameIDServiceParser.java
new file mode 100644
index 0000000000..715f28c752
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLManageNameIDServiceParser.java
@@ -0,0 +1,17 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+/**
+ * @author mhajas
+ */
+public class SAMLManageNameIDServiceParser extends SAMLEndpointTypeParser {
+
+ private static final SAMLManageNameIDServiceParser INSTANCE = new SAMLManageNameIDServiceParser();
+
+ public SAMLManageNameIDServiceParser() {
+ super(SAMLMetadataQNames.MANAGE_NAMEID_SERVICE);
+ }
+
+ public static SAMLManageNameIDServiceParser getInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLMetadataQNames.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLMetadataQNames.java
new file mode 100644
index 0000000000..250748a5df
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLMetadataQNames.java
@@ -0,0 +1,113 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+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 org.keycloak.saml.processing.core.parsers.util.HasQName;
+
+import javax.xml.namespace.QName;
+
+
+/**
+ * @author mhajas
+ */
+public enum SAMLMetadataQNames implements HasQName {
+ ADDITIONAL_METADATA_LOCATION("AdditionalMetadataLocation"),
+ AFFILIATE_MEMBER("AffiliateMember"),
+ AFFILIATION_DESCRIPTOR("AffiliationDescriptor"),
+ ARTIFACT_RESOLUTION_SERVICE("ArtifactResolutionService"),
+ ASSERTION_CONSUMER_SERVICE("AssertionConsumerService"),
+ ASSERTION_ID_REQUEST_SERVICE("AssertionIDRequestService"),
+ ATTRIBUTE_AUTHORITY_DESCRIPTOR("AttributeAuthorityDescriptor"),
+ ATTRIBUTE_CONSUMING_SERVICE("AttributeConsumingService"),
+ ATTRIBUTE_PROFILE("AttributeProfile"),
+ ATTRIBUTE_SERVICE("AttributeService"),
+ ATTRIBUTE_VALUE("AttributeValue"),
+ AUTHN_AUTHORITY_DESCRIPTOR("AuthnAuthorityDescriptor"),
+ AUTHN_QUERY_SERVICE("AuthnQueryService"),
+ AUTHZ_SERVICE("AuthzService"),
+ COMPANY("Company"),
+ CONTACT_PERSON("ContactPerson"),
+ EMAIL_ADDRESS("EmailAddress"),
+ ENCRYPTION_METHOD("EncryptionMethod"),
+ ENTITIES_DESCRIPTOR("EntitiesDescriptor"),
+ ENTITY_DESCRIPTOR("EntityDescriptor"),
+ EXTENSIONS("Extensions"),
+ GIVEN_NAME("GivenName"),
+ IDP_SSO_DESCRIPTOR("IDPSSODescriptor"),
+ KEY_DESCRIPTOR("KeyDescriptor"),
+ MANAGE_NAMEID_SERVICE("ManageNameIDService"),
+ NAMEID_FORMAT("NameIDFormat"),
+ NAMEID_MAPPING_SERVICE("NameIDMappingService"),
+ ORGANIZATION_DISPLAY_NAME("OrganizationDisplayName"),
+ ORGANIZATION_NAME("OrganizationName"),
+ ORGANIZATION("Organization"),
+ ORGANIZATION_URL("OrganizationURL"),
+ ORGANIZATION_URL_ALT("OrganizationUrl"), // non-standard: KEYCLOAK-4040,
+ PDP_DESCRIPTOR("PDPDescriptor"),
+ REQUESTED_ATTRIBUTE("RequestedAttribute"),
+ ROLE_DESCRIPTOR("RoleDescriptor"),
+ SERVICE_DESCRIPTION("ServiceDescription"),
+ SERVICE_NAME("ServiceName"),
+ SINGLE_LOGOUT_SERVICE("SingleLogoutService"),
+ SINGLE_SIGNON_SERVICE("SingleSignOnService"),
+ SP_SSO_DESCRIPTOR("SPSSODescriptor"),
+ SURNAME("SurName"),
+ TELEPHONE_NUMBER("TelephoneNumber"),
+
+ // Attribute names
+ ATTR_ENTITY_ID(null, "entityID"),
+ ATTR_ID(null, "ID"),
+ ATTR_VALID_UNTIL(null, "validUntil"),
+ ATTR_CACHE_DURATION(null, "cacheDuration"),
+ ATTR_PROTOCOL_SUPPORT_ENUMERATION(null, "protocolSupportEnumeration"),
+ ATTR_USE(null, "use"),
+ ATTR_ALGORITHM(null, "Algorithm"),
+ ATTR_LANG(JBossSAMLURIConstants.XML, "lang"),
+ ATTR_CONTACT_TYPE(null, "contactType"),
+ ATTR_AUTHN_REQUESTS_SIGNED(null, "AuthnRequestsSigned"),
+ ATTR_WANT_ASSERTIONS_SIGNED(null, "WantAssertionsSigned"),
+ ATTR_WANT_AUTHN_REQUESTS_SIGNED(null, "WantAuthnRequestsSigned"),
+ ATTR_BINDING(null, "Binding"),
+ ATTR_LOCATION(null, "Location"),
+ ATTR_IS_DEFAULT(null, "isDefault"),
+ ATTR_INDEX(null, "index"),
+ ATTR_RESPONSE_LOCATION(null, "ResponseLocation"),
+ ATTR_FRIENDLY_NAME(null, "FriendlyName"),
+ ATTR_IS_REQUIRED(null, "isRequired"),
+ ATTR_NAME(null, "Name"),
+ ATTR_NAME_FORMAT(null, "NameFormat"),
+
+ // Elements from other namespaces that can be direct subelements of this namespace's elements
+ SIGNATURE(XmlDSigQNames.SIGNATURE),
+ KEY_INFO(XmlDSigQNames.KEY_INFO),
+ KEY_SIZE(JBossSAMLURIConstants.XMLENC_NSURI, "KeySize"),
+ OAEP_PARAMS(JBossSAMLURIConstants.XMLENC_NSURI, "OAEPparams"),
+ ATTR_X500_ENCODING(JBossSAMLURIConstants.X500_NSURI, "Encoding"),
+ ATTRIBUTE(SAMLAssertionQNames.ATTRIBUTE),
+
+ UNKNOWN_ELEMENT("");
+
+ private final QName qName;
+
+ private SAMLMetadataQNames(String localName) {
+ this.qName = new QName(JBossSAMLURIConstants.METADATA_NSURI.get(), localName);
+ }
+
+ private SAMLMetadataQNames(HasQName source) {
+ this.qName = source.getQName();
+ }
+
+ private SAMLMetadataQNames(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/metadata/SAMLNameIDMappingServiceParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLNameIDMappingServiceParser.java
new file mode 100644
index 0000000000..c978fbef60
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLNameIDMappingServiceParser.java
@@ -0,0 +1,17 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+/**
+ * @author mhajas
+ */
+public class SAMLNameIDMappingServiceParser extends SAMLEndpointTypeParser {
+
+ private static final SAMLNameIDMappingServiceParser INSTANCE = new SAMLNameIDMappingServiceParser();
+
+ public SAMLNameIDMappingServiceParser() {
+ super(SAMLMetadataQNames.NAMEID_MAPPING_SERVICE);
+ }
+
+ public static SAMLNameIDMappingServiceParser getInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLOrganizationParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLOrganizationParser.java
new file mode 100644
index 0000000000..da3e2277bb
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLOrganizationParser.java
@@ -0,0 +1,68 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+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.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+import java.net.URI;
+
+import static org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLMetadataQNames.ATTR_LANG;
+import static org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLMetadataQNames.ORGANIZATION;
+
+/**
+ * @author mhajas
+ */
+public class SAMLOrganizationParser extends AbstractStaxSamlMetadataParser {
+
+ private static final SAMLOrganizationParser INSTANCE = new SAMLOrganizationParser();
+
+ public SAMLOrganizationParser() {
+ super(ORGANIZATION);
+ }
+
+ public static SAMLOrganizationParser getInstance() {
+ return INSTANCE;
+ }
+ @Override
+ protected OrganizationType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ return new OrganizationType();
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, OrganizationType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch (element) {
+ case ORGANIZATION_NAME:
+ LocalizedNameType orgName = new LocalizedNameType(StaxParserUtil.getAttributeValue(elementDetail, ATTR_LANG));
+ StaxParserUtil.advance(xmlEventReader);
+ orgName.setValue(StaxParserUtil.getElementText(xmlEventReader));
+ target.addOrganizationName(orgName);
+ break;
+
+ case ORGANIZATION_DISPLAY_NAME:
+ LocalizedNameType orgDispName = new LocalizedNameType(StaxParserUtil.getAttributeValue(elementDetail, ATTR_LANG));
+ StaxParserUtil.advance(xmlEventReader);
+ orgDispName.setValue(StaxParserUtil.getElementText(xmlEventReader));
+ target.addOrganizationDisplayName(orgDispName);
+ break;
+
+ case ORGANIZATION_URL:
+ case ORGANIZATION_URL_ALT:
+ LocalizedURIType orgURL = new LocalizedURIType(StaxParserUtil.getAttributeValue(elementDetail, ATTR_LANG));
+ StaxParserUtil.advance(xmlEventReader);
+ orgURL.setValue(URI.create(StaxParserUtil.getElementText(xmlEventReader)));
+ target.addOrganizationURL(orgURL);
+ break;
+
+ case EXTENSIONS:
+ target.setExtensions(SAMLExtensionsParser.getInstance().parse(xmlEventReader));
+ break;
+
+ default:
+ throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+ }
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLPDPDescriptorParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLPDPDescriptorParser.java
new file mode 100644
index 0000000000..07239e6bb8
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLPDPDescriptorParser.java
@@ -0,0 +1,56 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.saml.v2.metadata.PDPDescriptorType;
+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 java.util.List;
+
+/**
+ * @author mhajas
+ */
+public class SAMLPDPDescriptorParser extends SAMLRoleDecriptorTypeParser {
+
+ private static final SAMLPDPDescriptorParser INSTANCE = new SAMLPDPDescriptorParser();
+
+ public SAMLPDPDescriptorParser() {
+ super(SAMLMetadataQNames.PDP_DESCRIPTOR);
+ }
+
+ public static SAMLPDPDescriptorParser getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ protected PDPDescriptorType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ List protocolEnum = StaxParserUtil.getRequiredStringListAttributeValue(element, SAMLMetadataQNames.ATTR_PROTOCOL_SUPPORT_ENUMERATION);
+ PDPDescriptorType descriptor = new PDPDescriptorType(protocolEnum);
+
+ parseOptionalArguments(element, descriptor);
+
+ return descriptor;
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, PDPDescriptorType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch (element) {
+ case AUTHZ_SERVICE:
+ target.addAuthZService(SAMLAuthzServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case ASSERTION_ID_REQUEST_SERVICE:
+ target.addAssertionIDRequestService(SAMLAssertinIDRequestServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case NAMEID_FORMAT:
+ StaxParserUtil.advance(xmlEventReader);
+ target.addNameIDFormat(StaxParserUtil.getElementText(xmlEventReader));
+ break;
+
+ default:
+ super.processSubElement(xmlEventReader, target, element, elementDetail);
+ }
+ }
+}
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
index b1dbb7d454..77543ebbd5 100644
--- 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
@@ -17,31 +17,25 @@
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;
+import org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAttributeValueParser;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
/**
* Parse the in the saml assertion
*
* @since Oct 14, 2010
*/
-public class SAMLRequestedAttributeParser extends AbstractStaxSamlParser {
+public class SAMLRequestedAttributeParser extends AbstractStaxSamlMetadataParser {
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);
+ super(SAMLMetadataQNames.REQUESTED_ATTRIBUTE);
}
public static SAMLRequestedAttributeParser getInstance() {
@@ -50,24 +44,22 @@ public class SAMLRequestedAttributeParser extends AbstractStaxSamlParser extends AbstractStaxSamlMetadataParser {
+
+ public SAMLRoleDecriptorTypeParser(SAMLMetadataQNames expectedStartElement) {
+ super(expectedStartElement);
+ }
+
+ protected void parseOptionalArguments(StartElement element, RoleDescriptorType descriptor) throws ParsingException {
+ descriptor.setID(StaxParserUtil.getAttributeValue(element, SAMLMetadataQNames.ATTR_ID));
+ descriptor.setValidUntil(StaxParserUtil.getXmlTimeAttributeValue(element, SAMLMetadataQNames.ATTR_VALID_UNTIL));
+ descriptor.setCacheDuration(StaxParserUtil.getXmlDurationAttributeValue(element, SAMLMetadataQNames.ATTR_CACHE_DURATION));
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, T target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch (element) {
+ case KEY_DESCRIPTOR:
+ target.addKeyDescriptor(SAMLKeyDescriptorParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case SIGNATURE:
+ Element sig = StaxParserUtil.getDOMElement(xmlEventReader);
+ target.setSignature(sig);
+ break;
+
+ case EXTENSIONS:
+ target.setExtensions(SAMLExtensionsParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case ORGANIZATION:
+ target.setOrganization(SAMLOrganizationParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case CONTACT_PERSON:
+ target.addContactPerson(SAMLContactPersonParser.getInstance().parse(xmlEventReader));
+ break;
+
+ default:
+ throw LOGGER.parserUnknownTag(StaxParserUtil.getElementName(elementDetail), elementDetail.getLocation());
+ }
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLSPSSODescriptorParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLSPSSODescriptorParser.java
new file mode 100644
index 0000000000..84eeb1a99c
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLSPSSODescriptorParser.java
@@ -0,0 +1,65 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
+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 java.util.List;
+
+import static org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLMetadataQNames.SP_SSO_DESCRIPTOR;
+
+/**
+ * @author mhajas
+ */
+public class SAMLSPSSODescriptorParser extends SAMLSSODescriptorTypeParser {
+
+ private static final SAMLSPSSODescriptorParser INSTANCE = new SAMLSPSSODescriptorParser();
+
+ private SAMLSPSSODescriptorParser() {
+ super(SP_SSO_DESCRIPTOR);
+ }
+
+ public static SAMLSPSSODescriptorParser getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ protected SPSSODescriptorType instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
+ List protocolEnum = StaxParserUtil.getRequiredStringListAttributeValue(element, SAMLMetadataQNames.ATTR_PROTOCOL_SUPPORT_ENUMERATION);
+ SPSSODescriptorType descriptor = new SPSSODescriptorType(protocolEnum);
+
+ // Role descriptor optional arguments
+ parseOptionalArguments(element, descriptor);
+
+ // SPSSODecsriptor optional attributes
+ Boolean authnRequestsSigned = StaxParserUtil.getBooleanAttributeValue(element, SAMLMetadataQNames.ATTR_AUTHN_REQUESTS_SIGNED);
+ if (authnRequestsSigned != null) {
+ descriptor.setAuthnRequestsSigned(authnRequestsSigned);
+ }
+
+ Boolean wantAssertionSigned = StaxParserUtil.getBooleanAttributeValue(element, SAMLMetadataQNames.ATTR_WANT_ASSERTIONS_SIGNED);
+ if (wantAssertionSigned != null) {
+ descriptor.setWantAssertionsSigned(wantAssertionSigned);
+ }
+
+ return descriptor;
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, SPSSODescriptorType target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch (element) {
+ case ASSERTION_CONSUMER_SERVICE:
+ target.addAssertionConsumerService(SAMLAssertionConsumerServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case ATTRIBUTE_CONSUMING_SERVICE:
+ target.addAttributeConsumerService(SAMLAttributeConsumingServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ default:
+ super.processSubElement(xmlEventReader, target, element, elementDetail);
+ }
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLSSODescriptorTypeParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLSSODescriptorTypeParser.java
new file mode 100644
index 0000000000..65ca09736a
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLSSODescriptorTypeParser.java
@@ -0,0 +1,43 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+import org.keycloak.dom.saml.v2.metadata.SSODescriptorType;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.util.StaxParserUtil;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+
+/**
+ * @author mhajas
+ */
+public abstract class SAMLSSODescriptorTypeParser extends SAMLRoleDecriptorTypeParser {
+
+ public SAMLSSODescriptorTypeParser(SAMLMetadataQNames expectedStartElement) {
+ super(expectedStartElement);
+ }
+
+ @Override
+ protected void processSubElement(XMLEventReader xmlEventReader, T target, SAMLMetadataQNames element, StartElement elementDetail) throws ParsingException {
+ switch (element) {
+ case ARTIFACT_RESOLUTION_SERVICE:
+ target.addArtifactResolutionService(SAMLArtifactResolutionServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case SINGLE_LOGOUT_SERVICE:
+ target.addSingleLogoutService(SAMLSingleLogoutServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case MANAGE_NAMEID_SERVICE:
+ target.addSingleLogoutService(SAMLManageNameIDServiceParser.getInstance().parse(xmlEventReader));
+ break;
+
+ case NAMEID_FORMAT:
+ StaxParserUtil.advance(xmlEventReader);
+ target.addNameIDFormat(StaxParserUtil.getElementText(xmlEventReader));
+ break;
+
+ default:
+ super.processSubElement(xmlEventReader, target, element, elementDetail);
+ }
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLSingleLogoutServiceParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLSingleLogoutServiceParser.java
new file mode 100644
index 0000000000..7d7abd6ee1
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLSingleLogoutServiceParser.java
@@ -0,0 +1,17 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+/**
+ * @author mhajas
+ */
+public class SAMLSingleLogoutServiceParser extends SAMLEndpointTypeParser {
+
+ private static final SAMLSingleLogoutServiceParser INSTANCE = new SAMLSingleLogoutServiceParser();
+
+ public SAMLSingleLogoutServiceParser() {
+ super(SAMLMetadataQNames.SINGLE_LOGOUT_SERVICE);
+ }
+
+ public static SAMLSingleLogoutServiceParser getInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLSingleSignOnServiceParser.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLSingleSignOnServiceParser.java
new file mode 100644
index 0000000000..b713ae3b16
--- /dev/null
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/parsers/saml/metadata/SAMLSingleSignOnServiceParser.java
@@ -0,0 +1,17 @@
+package org.keycloak.saml.processing.core.parsers.saml.metadata;
+
+/**
+ * @author mhajas
+ */
+public class SAMLSingleSignOnServiceParser extends SAMLEndpointTypeParser {
+
+ private static final SAMLSingleSignOnServiceParser INSTANCE = new SAMLSingleSignOnServiceParser();
+
+ public SAMLSingleSignOnServiceParser() {
+ super(SAMLMetadataQNames.SINGLE_SIGNON_SERVICE);
+ }
+
+ public static SAMLSingleSignOnServiceParser getInstance() {
+ return INSTANCE;
+ }
+}
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 9ab24be51b..c395f86850 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,24 +16,12 @@
*/
package org.keycloak.saml.processing.core.parsers.saml;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.security.PrivateKey;
-
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-
import org.keycloak.common.util.Base64;
import org.keycloak.common.util.DerUtils;
import org.keycloak.common.util.StreamUtil;
@@ -50,7 +38,21 @@ 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.AttributeAuthorityDescriptorType;
+import org.keycloak.dom.saml.v2.metadata.AttributeConsumingServiceType;
+import org.keycloak.dom.saml.v2.metadata.AuthnAuthorityDescriptorType;
+import org.keycloak.dom.saml.v2.metadata.EndpointType;
+import org.keycloak.dom.saml.v2.metadata.EntitiesDescriptorType;
import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType;
+import org.keycloak.dom.saml.v2.metadata.IDPSSODescriptorType;
+import org.keycloak.dom.saml.v2.metadata.IndexedEndpointType;
+import org.keycloak.dom.saml.v2.metadata.KeyDescriptorType;
+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.PDPDescriptorType;
+import org.keycloak.dom.saml.v2.metadata.RequestedAttributeType;
+import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
import org.keycloak.dom.saml.v2.protocol.ResponseType;
@@ -60,6 +62,7 @@ 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.dom.xmlsec.w3.xmlenc.EncryptionMethodType;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ConfigurationException;
import org.keycloak.saml.common.exceptions.ParsingException;
@@ -67,11 +70,38 @@ 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;
+import javax.xml.namespace.QName;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.security.PrivateKey;
+import java.util.Collections;
+import java.util.List;
+
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.emptyCollectionOf;
+import static org.hamcrest.Matchers.endsWith;
+import static org.hamcrest.Matchers.everyItem;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
/**
* Test class for SAML parser.
*
@@ -251,12 +281,341 @@ public class SAMLParserTest {
@Test
public void testSaml20MetadataEntityDescriptorIdP() throws Exception {
- assertParsed("saml20-entity-descriptor-idp.xml", EntityDescriptorType.class);
+ EntityDescriptorType entityDescriptor = assertParsed("saml20-entity-descriptor-idp.xml", EntityDescriptorType.class);
+
+ List descriptors = entityDescriptor.getChoiceType();
+ assertThat(descriptors, hasSize(2));
+
+ // IDPSSO descriptor
+ IDPSSODescriptorType idpDescriptor = descriptors.get(0).getDescriptors().get(0).getIdpDescriptor();
+ assertThat(idpDescriptor, is(notNullValue()));
+ assertThat(idpDescriptor.isWantAuthnRequestsSigned(), is(true));
+ assertThat(idpDescriptor.getProtocolSupportEnumeration(), contains("urn:oasis:names:tc:SAML:2.0:protocol"));
+
+ // Key descriptor
+ List keyDescriptors = idpDescriptor.getKeyDescriptor();
+ assertThat(keyDescriptors, hasSize(1));
+
+ KeyDescriptorType signingKey = keyDescriptors.get(0);
+ assertThat(signingKey.getUse(), is(KeyTypes.SIGNING));
+ assertThat(signingKey.getEncryptionMethod(), is(emptyCollectionOf(EncryptionMethodType.class)));
+ assertThat(signingKey.getKeyInfo().getElementsByTagName("ds:KeyName").item(0).getTextContent(), is("IdentityProvider.com SSO Key"));
+
+ // Single logout services
+ assertThat(idpDescriptor.getSingleLogoutService(), hasSize(2));
+ EndpointType singleLS1 = idpDescriptor.getSingleLogoutService().get(0);
+ assertThat(singleLS1.getBinding(), is(URI.create("urn:oasis:names:tc:SAML:2.0:bindings:SOAP")));
+ assertThat(singleLS1.getLocation(), is(URI.create("https://IdentityProvider.com/SAML/SLO/SOAP")));
+ assertThat(singleLS1.getResponseLocation(), is(nullValue()));
+ assertThat(singleLS1.getAny(), is(emptyCollectionOf(Object.class)));
+ assertThat(singleLS1.getOtherAttributes(), is(Collections.emptyMap()));
+
+ EndpointType singleLS2 = idpDescriptor.getSingleLogoutService().get(1);
+ assertThat(singleLS2.getBinding(), is(URI.create("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect")));
+ assertThat(singleLS2.getLocation(), is(URI.create("https://IdentityProvider.com/SAML/SLO/Browser")));
+ assertThat(singleLS2.getResponseLocation(), is(URI.create("https://IdentityProvider.com/SAML/SLO/Response")));
+ assertThat(singleLS2.getAny(), is(emptyCollectionOf(Object.class)));
+ assertThat(singleLS2.getOtherAttributes(), is(Collections.emptyMap()));
+
+ // NameID
+ assertThat(idpDescriptor.getNameIDFormat(),
+ containsInAnyOrder("urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName",
+ "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
+ "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+ ));
+
+ // Single sign on services
+ assertThat(idpDescriptor.getSingleSignOnService(), hasSize(2));
+
+ EndpointType singleSO1 = idpDescriptor.getSingleSignOnService().get(0);
+ assertThat(singleSO1.getBinding(), is(URI.create("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect")));
+ assertThat(singleSO1.getLocation(), is(URI.create("https://IdentityProvider.com/SAML/SSO/Browser")));
+ assertThat(singleSO1.getResponseLocation(), is(nullValue()));
+ assertThat(singleSO1.getAny(), is(emptyCollectionOf(Object.class)));
+ assertThat(singleSO1.getOtherAttributes(), is(Collections.emptyMap()));
+
+ EndpointType singleSO2 = idpDescriptor.getSingleSignOnService().get(1);
+ assertThat(singleSO2.getBinding(), is(URI.create("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST")));
+ assertThat(singleSO2.getLocation(), is(URI.create("https://IdentityProvider.com/SAML/SSO/Browser")));
+ assertThat(singleSO2.getResponseLocation(), is(nullValue()));
+ assertThat(singleSO2.getAny(), is(emptyCollectionOf(Object.class)));
+ assertThat(singleSO2.getOtherAttributes(), is(Collections.emptyMap()));
+
+ // Attributes
+ assertThat(idpDescriptor.getAttribute(), hasSize(2));
+
+ AttributeType attr1 = idpDescriptor.getAttribute().get(0);
+ assertThat(attr1.getNameFormat(), is("urn:oasis:names:tc:SAML:2.0:attrname-format:uri"));
+ assertThat(attr1.getName(), is("urn:oid:1.3.6.1.4.1.5923.1.1.1.6"));
+ assertThat(attr1.getFriendlyName(), is("eduPersonPrincipalName"));
+ assertThat(attr1.getOtherAttributes(), is(Collections.emptyMap()));
+ assertThat(attr1.getAttributeValue(), is(emptyCollectionOf(Object.class)));
+
+ AttributeType attr2 = idpDescriptor.getAttribute().get(1);
+ assertThat(attr2.getNameFormat(), is("urn:oasis:names:tc:SAML:2.0:attrname-format:uri"));
+ assertThat(attr2.getName(), is("urn:oid:1.3.6.1.4.1.5923.1.1.1.1"));
+ assertThat(attr2.getFriendlyName(), is("eduPersonAffiliation"));
+ assertThat(attr2.getOtherAttributes(), is(Collections.emptyMap()));
+ assertThat(attr2.getAttributeValue(), containsInAnyOrder((Object) "member", "student", "faculty", "employee", "staff"));
+
+ // Organization
+ assertThat(entityDescriptor.getOrganization().getOrganizationName(), hasSize(1));
+ LocalizedNameType orgName = entityDescriptor.getOrganization().getOrganizationName().get(0);
+ assertThat(orgName.getLang(), is("en"));
+ assertThat(orgName.getValue(), is("Identity Providers R\n US"));
+
+ assertThat(entityDescriptor.getOrganization().getOrganizationDisplayName(), hasSize(1));
+ LocalizedNameType orgDispName = entityDescriptor.getOrganization().getOrganizationDisplayName().get(0);
+ assertThat(orgDispName.getLang(), is("en"));
+ assertThat(orgDispName.getValue(), is("Identity Providers R US, a Division of Lerxst Corp."));
+
+ assertThat(entityDescriptor.getOrganization().getOrganizationURL(), hasSize(1));
+ LocalizedURIType orgURL = entityDescriptor.getOrganization().getOrganizationURL().get(0);
+ assertThat(orgURL.getLang(), is("en"));
+ assertThat(orgURL.getValue(), is(URI.create("https://IdentityProvider.com")));
+ }
+
+ @Test
+ public void testSAML20MetadataEntityDescriptorAttrA() throws Exception{
+ EntityDescriptorType entityDescriptor = assertParsed("saml20-entity-descriptor-idp.xml", EntityDescriptorType.class);
+
+ List descriptors = entityDescriptor.getChoiceType();
+ assertThat(descriptors, hasSize(2));
+
+ AttributeAuthorityDescriptorType aaDescriptor = descriptors.get(1).getDescriptors().get(0).getAttribDescriptor();
+ assertThat(aaDescriptor, is(notNullValue()));
+ assertThat(aaDescriptor.getProtocolSupportEnumeration(), contains("urn:oasis:names:tc:SAML:2.0:protocol"));
+
+ // Key descriptor
+ List keyDescriptors = aaDescriptor.getKeyDescriptor();
+ assertThat(keyDescriptors, hasSize(1));
+
+ KeyDescriptorType signingKey = keyDescriptors.get(0);
+ assertThat(signingKey.getUse(), is(KeyTypes.SIGNING));
+ assertThat(signingKey.getEncryptionMethod(), is(emptyCollectionOf(EncryptionMethodType.class)));
+ assertThat(signingKey.getKeyInfo().getElementsByTagName("ds:KeyName").item(0).getTextContent(), is("IdentityProvider.com AA Key"));
+
+ // Attribute service
+ assertThat(aaDescriptor.getAttributeService(), hasSize(1));
+ EndpointType attrServ = aaDescriptor.getAttributeService().get(0);
+ assertThat(attrServ.getBinding(), is(URI.create("urn:oasis:names:tc:SAML:2.0:bindings:SOAP")));
+ assertThat(attrServ.getLocation(), is(URI.create("https://IdentityProvider.com/SAML/AA/SOAP")));
+ assertThat(attrServ.getResponseLocation(), is(nullValue()));
+ assertThat(attrServ.getAny(), is(emptyCollectionOf(Object.class)));
+ assertThat(attrServ.getOtherAttributes(), is(Collections.emptyMap()));
+
+ // AssertionIDRequestService
+ assertThat(aaDescriptor.getAssertionIDRequestService(), hasSize(1));
+ EndpointType assertIDRServ = aaDescriptor.getAssertionIDRequestService().get(0);
+ assertThat(assertIDRServ.getBinding(), is(URI.create("urn:oasis:names:tc:SAML:2.0:bindings:URI")));
+ assertThat(assertIDRServ.getLocation(), is(URI.create("https://IdentityProvider.com/SAML/AA/URI")));
+ assertThat(assertIDRServ.getResponseLocation(), is(nullValue()));
+ assertThat(assertIDRServ.getAny(), is(emptyCollectionOf(Object.class)));
+ assertThat(assertIDRServ.getOtherAttributes(), is(Collections.emptyMap()));
+
+ // NameID
+ assertThat(aaDescriptor.getNameIDFormat(),
+ containsInAnyOrder("urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName",
+ "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
+ "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+ ));
+
+ assertThat(aaDescriptor.getAttribute(), hasSize(2));
+
+ AttributeType attr1 = aaDescriptor.getAttribute().get(0);
+ assertThat(attr1.getNameFormat(), is("urn:oasis:names:tc:SAML:2.0:attrname-format:uri"));
+ assertThat(attr1.getName(), is("urn:oid:1.3.6.1.4.1.5923.1.1.1.6"));
+ assertThat(attr1.getFriendlyName(), is("eduPersonPrincipalName"));
+ assertThat(attr1.getOtherAttributes(), is(Collections.emptyMap()));
+ assertThat(attr1.getAttributeValue(), is(emptyCollectionOf(Object.class)));
+
+ AttributeType attr2 = aaDescriptor.getAttribute().get(1);
+ assertThat(attr2.getNameFormat(), is("urn:oasis:names:tc:SAML:2.0:attrname-format:uri"));
+ assertThat(attr2.getName(), is("urn:oid:1.3.6.1.4.1.5923.1.1.1.1"));
+ assertThat(attr2.getFriendlyName(), is("eduPersonAffiliation"));
+ assertThat(attr2.getOtherAttributes(), is(Collections.emptyMap()));
+ assertThat(attr2.getAttributeValue(), containsInAnyOrder((Object) "member", "student", "faculty", "employee", "staff"));
}
@Test
public void testSaml20MetadataEntityDescriptorSP() throws Exception {
- assertParsed("saml20-entity-descriptor-sp.xml", EntityDescriptorType.class);
+ EntityDescriptorType entityDescriptor = assertParsed("saml20-entity-descriptor-sp.xml", EntityDescriptorType.class);
+
+ assertThat(entityDescriptor.getEntityID(), is("https://ServiceProvider.com/SAML"));
+ assertThat(entityDescriptor.getValidUntil(), is(nullValue()));
+ assertThat(entityDescriptor.getCacheDuration(), is(nullValue()));
+ assertThat(entityDescriptor.getID(), is(nullValue()));
+
+ assertThat(entityDescriptor.getExtensions(), is(nullValue()));
+
+ List descriptors = entityDescriptor.getChoiceType();
+ assertThat(descriptors, hasSize(1));
+
+ // SP Descriptor
+ SPSSODescriptorType spDescriptor = descriptors.get(0).getDescriptors().get(0).getSpDescriptor();
+ assertThat(spDescriptor, is(notNullValue()));
+
+ assertThat(spDescriptor.isAuthnRequestsSigned(), is(true));
+ assertThat(spDescriptor.isWantAssertionsSigned(), is(false));
+ assertThat(spDescriptor.getProtocolSupportEnumeration(), contains("urn:oasis:names:tc:SAML:2.0:protocol"));
+
+ // Key descriptor
+ List keyDescriptors = spDescriptor.getKeyDescriptor();
+ assertThat(keyDescriptors, hasSize(2));
+
+ KeyDescriptorType signingKey = keyDescriptors.get(0);
+ assertThat(signingKey.getUse(), is(KeyTypes.SIGNING));
+ assertThat(signingKey.getEncryptionMethod(), is(emptyCollectionOf(EncryptionMethodType.class)));
+ assertThat(signingKey.getKeyInfo().getElementsByTagName("ds:KeyName").item(0).getTextContent(), is("ServiceProvider.com SSO Key"));
+
+ KeyDescriptorType encryptionKey = keyDescriptors.get(1);
+ assertThat(encryptionKey.getUse(), is(KeyTypes.ENCRYPTION));
+ assertThat(encryptionKey.getKeyInfo().getElementsByTagName("ds:KeyName").item(0).getTextContent(), is("ServiceProvider.com Encrypt Key"));
+
+ List encryptionMethods = encryptionKey.getEncryptionMethod();
+ assertThat(encryptionMethods, Matchers.hasSize(1));
+ assertThat(encryptionMethods.get(0).getAlgorithm(), is("http://www.w3.org/2001/04/xmlenc#rsa-1_5"));
+ assertThat(encryptionMethods.get(0).getEncryptionMethod(), is(nullValue()));
+
+ // Single logout services
+ assertThat(spDescriptor.getSingleLogoutService(), hasSize(2));
+ EndpointType singleLS1 = spDescriptor.getSingleLogoutService().get(0);
+ assertThat(singleLS1.getBinding(), is(URI.create("urn:oasis:names:tc:SAML:2.0:bindings:SOAP")));
+ assertThat(singleLS1.getLocation(), is(URI.create("https://ServiceProvider.com/SAML/SLO/SOAP")));
+ assertThat(singleLS1.getResponseLocation(), is(nullValue()));
+ assertThat(singleLS1.getAny(), is(emptyCollectionOf(Object.class)));
+ assertThat(singleLS1.getOtherAttributes(), is(Collections.emptyMap()));
+
+ EndpointType singleLS2 = spDescriptor.getSingleLogoutService().get(1);
+ assertThat(singleLS2.getBinding(), is(URI.create("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect")));
+ assertThat(singleLS2.getLocation(), is(URI.create("https://ServiceProvider.com/SAML/SLO/Browser")));
+ assertThat(singleLS2.getResponseLocation(), is(URI.create("https://ServiceProvider.com/SAML/SLO/Response")));
+ assertThat(singleLS2.getAny(), is(emptyCollectionOf(Object.class)));
+ assertThat(singleLS2.getOtherAttributes(), is(Collections.emptyMap()));
+
+ // NameID
+ assertThat(spDescriptor.getNameIDFormat(), contains("urn:oasis:names:tc:SAML:2.0:nameid-format:transient"));
+
+ // Assertion consumer services
+ List assertionConsumerServices = spDescriptor.getAssertionConsumerService();
+ assertThat(assertionConsumerServices, hasSize(2));
+
+ IndexedEndpointType assertionCS1 = assertionConsumerServices.get(0);
+ assertThat(assertionCS1.getIndex(), is(0));
+ assertThat(assertionCS1.isIsDefault(), is(true));
+ assertThat(assertionCS1.getBinding(), is(URI.create("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact")));
+ assertThat(assertionCS1.getLocation(), is(URI.create("https://ServiceProvider.com/SAML/SSO/Artifact")));
+ assertThat(assertionCS1.getResponseLocation(), is(nullValue()));
+ assertThat(assertionCS1.getOtherAttributes(), is(Collections.emptyMap()));
+
+ IndexedEndpointType assertionCS2 = assertionConsumerServices.get(1);
+ assertThat(assertionCS2.getIndex(), is(1));
+ assertThat(assertionCS2.isIsDefault(), is(nullValue()));
+ assertThat(assertionCS2.getBinding(), is(URI.create("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST")));
+ assertThat(assertionCS2.getLocation(), is(URI.create("https://ServiceProvider.com/SAML/SSO/POST")));
+ assertThat(assertionCS2.getResponseLocation(), is(nullValue()));
+ assertThat(assertionCS2.getOtherAttributes(), is(Collections.emptyMap()));
+
+ // Attribute consuming services
+ List attributeConsumingServices = spDescriptor.getAttributeConsumingService();
+ assertThat(attributeConsumingServices, hasSize(1));
+
+ AttributeConsumingServiceType attributeConsumingService = attributeConsumingServices.get(0);
+ assertThat(attributeConsumingService.getIndex(), is(0));
+ assertThat(attributeConsumingService.getServiceName(), hasSize(1));
+ LocalizedNameType servName = attributeConsumingService.getServiceName().get(0);
+ assertThat(servName.getLang(), is("en"));
+ assertThat(servName.getValue(), is("Academic Journals R US"));
+ assertThat(attributeConsumingService.getServiceDescription(), is(emptyCollectionOf(LocalizedNameType.class)));
+
+ List requestedAttributes = attributeConsumingService.getRequestedAttribute();
+ assertThat(requestedAttributes, hasSize(1));
+
+ // Requested attribute
+ RequestedAttributeType requestedAttribute = requestedAttributes.get(0);
+ assertThat(requestedAttribute.getNameFormat(), is("urn:oasis:names:tc:SAML:2.0:attrname-format:uri"));
+ assertThat(requestedAttribute.getName(), is("urn:oid:1.3.6.1.4.1.5923.1.1.1.7"));
+ assertThat(requestedAttribute.getFriendlyName(), is("eduPersonEntitlement"));
+
+ assertThat(requestedAttribute.getAttributeValue(), hasSize(1));
+ assertThat((String) requestedAttribute.getAttributeValue().get(0), is("https://ServiceProvider.com/entitlements/123456789"));
+
+ assertThat(requestedAttribute.getOtherAttributes(), is(Collections.emptyMap()));
+
+ // Organization
+ assertThat(entityDescriptor.getOrganization().getOrganizationName(), hasSize(1));
+ LocalizedNameType orgName = entityDescriptor.getOrganization().getOrganizationName().get(0);
+ assertThat(orgName.getLang(), is("en"));
+ assertThat(orgName.getValue(), is("Academic Journals R\n US"));
+
+ assertThat(entityDescriptor.getOrganization().getOrganizationDisplayName(), hasSize(1));
+ LocalizedNameType orgDispName = entityDescriptor.getOrganization().getOrganizationDisplayName().get(0);
+ assertThat(orgDispName.getLang(), is("en"));
+ assertThat(orgDispName.getValue(), is("Academic Journals R US, a Division of Dirk Corp."));
+
+ assertThat(entityDescriptor.getOrganization().getOrganizationURL(), hasSize(1));
+ LocalizedURIType orgURL = entityDescriptor.getOrganization().getOrganizationURL().get(0);
+ assertThat(orgURL.getLang(), is("en"));
+ assertThat(orgURL.getValue(), is(URI.create("https://ServiceProvider.com")));
+ }
+
+ @Test
+ public void testSaml20MetadataEntityDescriptorPDP() throws Exception {
+ EntityDescriptorType descriptor = assertParsed("saml20-entity-descriptor-pdp.xml", EntityDescriptorType.class);
+
+ assertThat(descriptor.getChoiceType(), Matchers.hasSize(1));
+ assertThat(descriptor.getChoiceType().get(0).getDescriptors().get(0).getPdpDescriptor(), is(notNullValue()));
+
+ PDPDescriptorType pdpDescriptor = descriptor.getChoiceType().get(0).getDescriptors().get(0).getPdpDescriptor();
+
+ assertThat(pdpDescriptor.getKeyDescriptor(), Matchers.hasSize(1));
+
+ KeyDescriptorType keyDescriptorType = pdpDescriptor.getKeyDescriptor().get(0);
+ assertThat(keyDescriptorType.getEncryptionMethod(), Matchers.hasSize(1));
+
+ EncryptionMethodType encryptionMethodType = keyDescriptorType.getEncryptionMethod().get(0);
+ assertThat(encryptionMethodType.getAlgorithm(), is("http://www.example.com/"));
+
+ EncryptionMethodType.EncryptionMethod encryptionMethod = encryptionMethodType.getEncryptionMethod();
+ assertThat(encryptionMethod.getKeySize(), is(BigInteger.ONE));
+ assertThat(encryptionMethod.getOAEPparams(), is("GpM7".getBytes()));
+
+ // EndpointType parser already tested so we are not checking further
+ assertThat(pdpDescriptor.getAuthzService(), Matchers.hasSize(1));
+ assertThat(pdpDescriptor.getAssertionIDRequestService(), Matchers.hasSize(1));
+ }
+
+ @Test
+ public void testSaml20MetadataEntityDescriptorAuthnAuthority() throws Exception {
+ EntityDescriptorType descriptor = assertParsed("saml20-entity-descriptor-authn-authority.xml", EntityDescriptorType.class);
+
+ assertThat(descriptor.getChoiceType(), Matchers.hasSize(1));
+ assertThat(descriptor.getChoiceType().get(0).getDescriptors().get(0).getAuthnDescriptor(), is(notNullValue()));
+
+ AuthnAuthorityDescriptorType authnDescriptor = descriptor.getChoiceType().get(0).getDescriptors().get(0).getAuthnDescriptor();
+
+ assertThat(authnDescriptor.getAssertionIDRequestService(), hasSize(1));
+ assertThat(authnDescriptor.getAuthnQueryService(), hasSize(1));
+ assertThat(authnDescriptor.getProtocolSupportEnumeration(), containsInAnyOrder("http://www.example.com/", "http://www.example2.com/"));
+ }
+
+ @Test
+ public void testSaml20MetadataEntitiesDescriptor() throws Exception {
+ EntitiesDescriptorType entities = assertParsed("saml20-entities-descriptor.xml", EntitiesDescriptorType.class);
+
+ assertThat(entities.getName(), is("https://your-federation.org/metadata/federation-name.xml"));
+ assertThat(entities.getID(), is(nullValue()));
+ assertThat(entities.getCacheDuration(), is(nullValue()));
+ assertThat(entities.getExtensions(), is(nullValue()));
+ assertThat(entities.getSignature(), is(nullValue()));
+ assertThat(entities.getValidUntil(), is(nullValue()));
+ assertThat(entities.getEntityDescriptor(), hasSize(3));
+ assertThat(entities.getEntityDescriptor().get(0), instanceOf(EntityDescriptorType.class));
+ assertThat(entities.getEntityDescriptor().get(1), instanceOf(EntityDescriptorType.class));
+ assertThat(entities.getEntityDescriptor().get(2), instanceOf(EntitiesDescriptorType.class));
+
+ EntitiesDescriptorType nestedEntities = (EntitiesDescriptorType) entities.getEntityDescriptor().get(2);
+ assertThat(nestedEntities.getEntityDescriptor(), hasSize(2));
}
@Test
@@ -341,6 +700,86 @@ public class SAMLParserTest {
assertParsed("saml20-authnrequest-invalid-namespace.xml", AuthnRequestType.class);
}
+ @Test
+ public void testInvalidEndElement() throws Exception {
+ thrown.expect(ParsingException.class);
+ thrown.expectMessage(containsString("The element type \"NameIDFormat\" must be terminated by the matching end-tag \"\"."));
+
+ assertParsed("saml20-entity-descriptor-idp-invalid-end-element.xml", EntityDescriptorType.class);
+ }
+
+ @Test
+ public void testMissingRequiredAttributeIDPSSODescriptorType() throws Exception {
+ testMissingAttribute("IDPSSODescriptorType", "protocolSupportEnumeration");
+ }
+
+ @Test
+ public void testMissingRequiredAttributeSPSSODescriptorType() throws Exception {
+ testMissingAttribute("SPSSODescriptorType", "protocolSupportEnumeration");
+ }
+
+ @Test
+ public void testMissingRequiredAttributeAttributeAuthorityDescriptorType() throws Exception {
+ testMissingAttribute("AttributeAuthorityDescriptorType", "protocolSupportEnumeration");
+ }
+
+ @Test
+ public void testMissingRequiredAttributeAuthnAuthorityDescriptorType() throws Exception {
+ testMissingAttribute("AuthnAuthorityDescriptorType", "protocolSupportEnumeration");
+ }
+
+ @Test
+ public void testMissingRequiredAttributePDPDescriptorType() throws Exception {
+ testMissingAttribute("PDPDescriptorType", "protocolSupportEnumeration");
+ }
+
+ @Test
+ public void testMissingRequiredAttributeAttributeConsumingServiceType() throws Exception {
+ testMissingAttribute("AttributeConsumingServiceType", "index");
+ }
+
+ @Test
+ public void testMissingRequiredAttributeAttributeType() throws Exception {
+ testMissingAttribute("AttributeType", "Name");
+ }
+
+ @Test
+ public void testMissingRequiredAttributeContactType() throws Exception {
+ testMissingAttribute("ContactType", "contactType");
+ }
+
+ @Test
+ public void testMissingRequiredAttributeEncryptionMethodType() throws Exception {
+ testMissingAttribute("EncryptionMethodType", "Algorithm");
+ }
+
+ @Test
+ public void testMissingRequiredAttributeEndpointTypeBinding() throws Exception {
+ testMissingAttribute("EndpointType", "Binding");
+ }
+
+ @Test
+ public void testMissingRequiredAttributeEndpointTypeLocation() throws Exception {
+ testMissingAttribute("EndpointType", "Location");
+ }
+
+ @Test
+ public void testMissingRequiredAttributeEntityDescriptorType() throws Exception {
+ testMissingAttribute("EntityDescriptorType", "entityID");
+ }
+
+ @Test
+ public void testMissingRequiredAttributeRequestedAttributeType() throws Exception {
+ testMissingAttribute("RequestedAttributeType", "Name");
+ }
+
+ private void testMissingAttribute(String type, String attributeName) throws Exception {
+ thrown.expect(ParsingException.class);
+ thrown.expectMessage(containsString("Parser: Required attribute missing: " + attributeName));
+
+ assertParsed("missing-attribute/saml20-" + type + "-" + attributeName + ".xml", EntityDescriptorType.class);
+ }
+
@Test
public void testAuthnRequestScoping() throws Exception {
assertParsed("KEYCLOAK-6109-authnrequest-scoping.xml", AuthnRequestType.class);
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-AttributeAuthorityDescriptorType-protocolSupportEnumeration.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-AttributeAuthorityDescriptorType-protocolSupportEnumeration.xml
new file mode 100644
index 0000000000..069decdfb9
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-AttributeAuthorityDescriptorType-protocolSupportEnumeration.xml
@@ -0,0 +1,19 @@
+
+ ...
+
+
+
+
+
+ Identity Providers R
+ US
+
+ Identity Providers R US, a Division of Lerxst Corp.
+
+ https://IdentityProvider.com
+
+
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-AttributeConsumingServiceType-index.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-AttributeConsumingServiceType-index.xml
new file mode 100644
index 0000000000..af8afb3c06
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-AttributeConsumingServiceType-index.xml
@@ -0,0 +1,20 @@
+
+ ...
+
+
+ Academic Journals R US
+
+
+ https://ServiceProvider.com/entitlements/123456789
+
+
+
+
+
\ No newline at end of file
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-AttributeType-Name.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-AttributeType-Name.xml
new file mode 100644
index 0000000000..efbe38517a
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-AttributeType-Name.xml
@@ -0,0 +1,13 @@
+
+ ...
+
+
+
+
+
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-AuthnAuthorityDescriptorType-protocolSupportEnumeration.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-AuthnAuthorityDescriptorType-protocolSupportEnumeration.xml
new file mode 100644
index 0000000000..301bc1eba6
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-AuthnAuthorityDescriptorType-protocolSupportEnumeration.xml
@@ -0,0 +1,10 @@
+
+ ...
+
+
+
+
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-ContactType-contactType.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-ContactType-contactType.xml
new file mode 100644
index 0000000000..b4e12c1c33
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-ContactType-contactType.xml
@@ -0,0 +1,18 @@
+
+ ...
+
+
+
+ string
+ string
+ string
+ http://www.example.com/
+ string
+
+
+
+
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-EncryptionMethodType-Algorithm.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-EncryptionMethodType-Algorithm.xml
new file mode 100644
index 0000000000..8ce23321d9
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-EncryptionMethodType-Algorithm.xml
@@ -0,0 +1,19 @@
+
+ ...
+
+
+
+
+ string
+
+
+ 1
+ GpM7
+
+
+
+
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-EndpointType-Binding.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-EndpointType-Binding.xml
new file mode 100644
index 0000000000..fe1d1862be
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-EndpointType-Binding.xml
@@ -0,0 +1,12 @@
+
+ ...
+
+
+
+
+
\ No newline at end of file
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-EndpointType-Location.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-EndpointType-Location.xml
new file mode 100644
index 0000000000..8eb5a5b2f7
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-EndpointType-Location.xml
@@ -0,0 +1,11 @@
+
+ ...
+
+
+
+
\ No newline at end of file
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-EntityDescriptorType-entityID.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-EntityDescriptorType-entityID.xml
new file mode 100644
index 0000000000..071803da6b
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-EntityDescriptorType-entityID.xml
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-IDPSSODescriptorType-protocolSupportEnumeration.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-IDPSSODescriptorType-protocolSupportEnumeration.xml
new file mode 100644
index 0000000000..5a971c959b
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-IDPSSODescriptorType-protocolSupportEnumeration.xml
@@ -0,0 +1,9 @@
+
+ ...
+
+
+
+
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-PDPDescriptorType-protocolSupportEnumeration.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-PDPDescriptorType-protocolSupportEnumeration.xml
new file mode 100644
index 0000000000..c6b2a633fc
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-PDPDescriptorType-protocolSupportEnumeration.xml
@@ -0,0 +1,10 @@
+
+ ...
+
+
+
+
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-RequestedAttributeType-Name.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-RequestedAttributeType-Name.xml
new file mode 100644
index 0000000000..7695618564
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-RequestedAttributeType-Name.xml
@@ -0,0 +1,19 @@
+
+ ...
+
+
+ Academic Journals R US
+
+
+ https://ServiceProvider.com/entitlements/123456789
+
+
+
+
+
\ No newline at end of file
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-SPSSODescriptorType-protocolSupportEnumeration.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-SPSSODescriptorType-protocolSupportEnumeration.xml
new file mode 100644
index 0000000000..492cca823a
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/missing-attribute/saml20-SPSSODescriptorType-protocolSupportEnumeration.xml
@@ -0,0 +1,9 @@
+
+ ...
+
+
+
+
\ No newline at end of file
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-entities-descriptor.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-entities-descriptor.xml
new file mode 100644
index 0000000000..c3b7062887
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-entities-descriptor.xml
@@ -0,0 +1,240 @@
+
+
+
+
+
+ example.org
+
+
+
+
+ ...
+
+
+
+
+ urn:mace:shibboleth:1.0:nameIdentifier
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...
+
+
+
+
+
+
+
+
+ urn:mace:shibboleth:1.0:nameIdentifier
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+ Your Identities
+ Your Identities
+ http://www.example.org/
+
+
+ Your
+ Contact
+ admin@example.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...
+
+
+
+
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ urn:mace:shibboleth:1.0:nameIdentifier
+
+
+
+
+
+
+
+
+
+
+ Your Service
+ Your Service
+ http://sp.example.org/
+
+
+ Your
+ Admin
+ admin@example.org
+
+
+
+
+
+
+
+
+
+ example.org
+
+
+
+
+ ...
+
+
+
+
+ urn:mace:shibboleth:1.0:nameIdentifier
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...
+
+
+
+
+
+
+
+
+ urn:mace:shibboleth:1.0:nameIdentifier
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+ Your Identities
+ Your Identities
+ http://www.example.org/
+
+
+ Your
+ Contact
+ admin@example.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...
+
+
+
+
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ urn:mace:shibboleth:1.0:nameIdentifier
+
+
+
+
+
+
+
+
+
+
+ Your Service
+ Your Service
+ http://sp.example.org/
+
+
+ Your
+ Admin
+ admin@example.org
+
+
+
+
+
+
\ No newline at end of file
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-entity-descriptor-authn-authority.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-entity-descriptor-authn-authority.xml
new file mode 100644
index 0000000000..47cd9e6147
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-entity-descriptor-authn-authority.xml
@@ -0,0 +1,58 @@
+
+ ...
+
+
+
+ ...
+ ...
+ ...
+
+ GpM7
+
+ string
+
+ ...
+
+ ...
+
+
+ string
+
+
+ 1
+ GpM7
+
+
+
+
+
+ string
+ string
+ http://www.example.com/
+
+
+ ...
+ string
+ string
+ string
+ http://www.example.com/
+ string
+
+ ...
+ ...
+ http://www.example.com/
+
+
+ Identity Providers R
+ US
+
+ Identity Providers R US, a Division of Lerxst Corp.
+
+ https://IdentityProvider.com
+
+
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-entity-descriptor-idp-invalid-end-element.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-entity-descriptor-idp-invalid-end-element.xml
new file mode 100644
index 0000000000..6d92f62154
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-entity-descriptor-idp-invalid-end-element.xml
@@ -0,0 +1,101 @@
+
+ ...
+
+
+
+ IdentityProvider.com SSO Key
+
+
+
+
+
+
+ urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
+
+
+ urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
+
+
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+
+
+ member
+ student
+ faculty
+ employee
+ staff
+
+
+
+
+
+ IdentityProvider.com AA Key
+
+
+
+
+
+ urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
+
+
+ urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
+
+
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+ member
+ student
+ faculty
+ employee
+ staff
+
+
+
+ Identity Providers R
+ US
+
+ Identity Providers R US, a Division of Lerxst Corp.
+
+ https://IdentityProvider.com
+
+
diff --git a/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-entity-descriptor-pdp.xml b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-entity-descriptor-pdp.xml
new file mode 100644
index 0000000000..a0518c398d
--- /dev/null
+++ b/saml-core/src/test/resources/org/keycloak/saml/processing/core/parsers/saml/saml20-entity-descriptor-pdp.xml
@@ -0,0 +1,58 @@
+
+ ...
+
+
+
+ ...
+ ...
+ ...
+
+ GpM7
+
+ string
+
+ Any text, intermingled with:
+
+
+
+
+
+ string
+
+
+ 1
+ GpM7
+
+
+
+ string
+ string
+ http://www.example.com/
+
+
+ string
+ string
+ string
+ http://www.example.com/
+ string
+
+
+
+
+
+ http://www.example.com/
+
+
+ Identity Providers R
+ US
+
+ Identity Providers R US, a Division of Lerxst Corp.
+
+ https://IdentityProvider.com
+
+