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