From d06237a3fd94e02b984e67eb163b225cc50a05f5 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 2 Oct 2015 18:39:50 -0400 Subject: [PATCH] saml adapter schema and simplifications --- .../adapters/saml/DefaultSamlDeployment.java | 12 +- .../adapters/saml/SamlAuthenticator.java | 2 +- .../adapters/saml/SamlDeployment.java | 1 - .../keycloak/adapters/saml/config/IDP.java | 19 +++ .../org/keycloak/adapters/saml/config/SP.java | 26 ---- .../config/parsers/ConfigXmlConstants.java | 2 +- .../config/parsers/DeploymentBuilder.java | 7 +- .../saml/config/parsers/IDPXmlParser.java | 24 ++-- .../saml/config/parsers/KeyXmlParser.java | 2 + .../saml/config/parsers/SPXmlParser.java | 12 -- .../schema/keycloak_saml_adapter_1_6.xsd | 115 ++++++++++++++++++ .../test/adapters/saml/XmlParserTest.java | 43 ++++++- .../core/src/test/resources/keycloak-saml.xml | 11 +- .../src/test/resources/keycloak-saml2.xml | 46 +++++++ .../subsystem-templates/keycloak-adapter.xml | 7 ++ .../saml/common/util/StaxParserUtil.java | 57 ++++++++- .../WEB-INF/keycloak-saml.xml | 11 +- .../signed-post/WEB-INF/keycloak-saml.xml | 13 +- 18 files changed, 318 insertions(+), 92 deletions(-) create mode 100755 saml/client-adapter/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd create mode 100755 saml/client-adapter/core/src/test/resources/keycloak-saml2.xml create mode 100755 saml/client-adapter/wildfly/wildfly9-subsystem/src/main/resources/subsystem-templates/keycloak-adapter.xml diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java index 28a4eadc92..4aa54d6422 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java @@ -210,7 +210,6 @@ public class DefaultSamlDeployment implements SamlDeployment { private KeyPair signingKeyPair; private String assertionConsumerServiceUrl; private Set roleAttributeNames; - private Set roleFriendlyAttributeNames; private PrincipalNamePolicy principalNamePolicy = PrincipalNamePolicy.FROM_NAME_ID; private String principalAttributeName; private String logoutPage; @@ -268,12 +267,7 @@ public class DefaultSamlDeployment implements SamlDeployment { return roleAttributeNames; } - @Override - public Set getRoleAttributeFriendlyNames() { - return roleFriendlyAttributeNames; - } - - @Override + @Override public PrincipalNamePolicy getPrincipalNamePolicy() { return principalNamePolicy; } @@ -323,10 +317,6 @@ public class DefaultSamlDeployment implements SamlDeployment { this.roleAttributeNames = roleAttributeNames; } - public void setRoleFriendlyAttributeNames(Set roleFriendlyAttributeNames) { - this.roleFriendlyAttributeNames = roleFriendlyAttributeNames; - } - public void setPrincipalNamePolicy(PrincipalNamePolicy principalNamePolicy) { this.principalNamePolicy = principalNamePolicy; } diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java index ae7eb4baf6..bebb506903 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java @@ -354,7 +354,7 @@ public abstract class SamlAuthenticator { } protected boolean isRole(AttributeType attribute) { - return deployment.getRoleAttributeNames().contains(attribute.getName()) || deployment.getRoleAttributeFriendlyNames().contains(attribute.getFriendlyName()); + return (attribute.getName() != null && deployment.getRoleAttributeNames().contains(attribute.getName())) || (attribute.getFriendlyName() != null && deployment.getRoleAttributeNames().contains(attribute.getFriendlyName())); } protected AuthOutcome handleLogoutResponse(SAMLDocumentHolder holder, StatusResponseType responseType, String relayState) { diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java index 4540b253bd..681e405a99 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java @@ -64,7 +64,6 @@ public interface SamlDeployment { String getLogoutPage(); Set getRoleAttributeNames(); - Set getRoleAttributeFriendlyNames(); enum PrincipalNamePolicy { FROM_NAME_ID, diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java index 84764e3b4d..956ab869e2 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java @@ -134,6 +134,8 @@ public class IDP implements Serializable { } private String entityID; + private String signatureAlgorithm; + private String signatureCanonicalizationMethod; private SingleSignOnService singleSignOnService; private SingleLogoutService singleLogoutService; private List keys; @@ -169,4 +171,21 @@ public class IDP implements Serializable { public void setKeys(List keys) { this.keys = keys; } + + public String getSignatureAlgorithm() { + return signatureAlgorithm; + } + + public void setSignatureAlgorithm(String signatureAlgorithm) { + this.signatureAlgorithm = signatureAlgorithm; + } + + public String getSignatureCanonicalizationMethod() { + return signatureCanonicalizationMethod; + } + + public void setSignatureCanonicalizationMethod(String signatureCanonicalizationMethod) { + this.signatureCanonicalizationMethod = signatureCanonicalizationMethod; + } + } diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/SP.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/SP.java index bd48ba19a6..fadfe21743 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/SP.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/SP.java @@ -41,9 +41,6 @@ public class SP implements Serializable { private String nameIDPolicyFormat; private PrincipalNameMapping principalNameMapping; private Set roleAttributes; - private Set roleFriendlyAttributes; - private String signatureAlgorithm; - private String signatureCanonicalizationMethod; private IDP idp; public String getEntityID() { @@ -102,14 +99,6 @@ public class SP implements Serializable { this.roleAttributes = roleAttributes; } - public Set getRoleFriendlyAttributes() { - return roleFriendlyAttributes; - } - - public void setRoleFriendlyAttributes(Set roleFriendlyAttributes) { - this.roleFriendlyAttributes = roleFriendlyAttributes; - } - public IDP getIdp() { return idp; } @@ -126,19 +115,4 @@ public class SP implements Serializable { this.logoutPage = logoutPage; } - public String getSignatureAlgorithm() { - return signatureAlgorithm; - } - - public void setSignatureAlgorithm(String signatureAlgorithm) { - this.signatureAlgorithm = signatureAlgorithm; - } - - public String getSignatureCanonicalizationMethod() { - return signatureCanonicalizationMethod; - } - - public void setSignatureCanonicalizationMethod(String signatureCanonicalizationMethod) { - this.signatureCanonicalizationMethod = signatureCanonicalizationMethod; - } } diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java index 0e0542cf3b..fdb8284675 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java @@ -39,10 +39,10 @@ public class ConfigXmlConstants { public static final String ROLE_MAPPING_ELEMENT = "RoleMapping"; public static final String ATTRIBUTE_ELEMENT = "Attribute"; - public static final String FRIENDLY_ATTRIBUTE_ELEMENT = "FriendlyAttribute"; public static final String NAME_ATTR = "name"; public static final String IDP_ELEMENT = "IDP"; + public static final String SIGNATURES_REQUIRED_ATTR = "signaturesRequired"; public static final String SINGLE_SIGN_ON_SERVICE_ELEMENT = "SingleSignOnService"; public static final String SINGLE_LOGOUT_SERVICE_ELEMENT = "SingleLogoutService"; public static final String SIGN_REQUEST_ATTR = "signRequest"; diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java index b72cb41649..0421fda4b2 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java @@ -41,10 +41,10 @@ public class DeploymentBuilder { deployment.setForceAuthentication(sp.isForceAuthentication()); deployment.setNameIDPolicyFormat(sp.getNameIDPolicyFormat()); deployment.setLogoutPage(sp.getLogoutPage()); - deployment.setSignatureCanonicalizationMethod(sp.getSignatureCanonicalizationMethod()); + deployment.setSignatureCanonicalizationMethod(sp.getIdp().getSignatureCanonicalizationMethod()); deployment.setSignatureAlgorithm(SignatureAlgorithm.RSA_SHA256); - if (sp.getSignatureAlgorithm() != null) { - deployment.setSignatureAlgorithm(SignatureAlgorithm.valueOf(sp.getSignatureAlgorithm())); + if (sp.getIdp().getSignatureAlgorithm() != null) { + deployment.setSignatureAlgorithm(SignatureAlgorithm.valueOf(sp.getIdp().getSignatureAlgorithm())); } if (sp.getPrincipalNameMapping() != null) { SamlDeployment.PrincipalNamePolicy policy = SamlDeployment.PrincipalNamePolicy.valueOf(sp.getPrincipalNameMapping().getPolicy()); @@ -52,7 +52,6 @@ public class DeploymentBuilder { deployment.setPrincipalAttributeName(sp.getPrincipalNameMapping().getAttributeName()); } deployment.setRoleAttributeNames(sp.getRoleAttributes()); - deployment.setRoleFriendlyAttributeNames(sp.getRoleFriendlyAttributes()); if (sp.getSslPolicy() != null) { SslRequired ssl = SslRequired.valueOf(sp.getSslPolicy()); deployment.setSslRequired(ssl); diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java index 96485d55ef..fc08e449a3 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java @@ -30,6 +30,10 @@ public class IDPXmlParser extends AbstractParser { } idp.setEntityID(entityID); + + boolean signaturesRequired = StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNATURES_REQUIRED_ATTR); + idp.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR)); + idp.setSignatureAlgorithm(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR)); while (xmlEventReader.hasNext()) { XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader); if (xmlEvent == null) @@ -47,11 +51,11 @@ public class IDPXmlParser extends AbstractParser { break; String tag = StaxParserUtil.getStartElementName(startElement); if (tag.equals(ConfigXmlConstants.SINGLE_SIGN_ON_SERVICE_ELEMENT)) { - IDP.SingleSignOnService sso = parseSingleSignOnService(xmlEventReader); + IDP.SingleSignOnService sso = parseSingleSignOnService(xmlEventReader, signaturesRequired); idp.setSingleSignOnService(sso); } else if (tag.equals(ConfigXmlConstants.SINGLE_LOGOUT_SERVICE_ELEMENT)) { - IDP.SingleLogoutService slo = parseSingleLogoutService(xmlEventReader); + IDP.SingleLogoutService slo = parseSingleLogoutService(xmlEventReader, signaturesRequired); idp.setSingleLogoutService(slo); } else if (tag.equals(ConfigXmlConstants.KEYS_ELEMENT)) { @@ -66,25 +70,25 @@ public class IDPXmlParser extends AbstractParser { return idp; } - protected IDP.SingleLogoutService parseSingleLogoutService(XMLEventReader xmlEventReader) throws ParsingException { + protected IDP.SingleLogoutService parseSingleLogoutService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException { IDP.SingleLogoutService slo = new IDP.SingleLogoutService(); StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader); - slo.setSignRequest(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR)); - slo.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR)); - slo.setValidateRequestSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR)); + slo.setSignRequest(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired)); + slo.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired)); + slo.setValidateRequestSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR, signaturesRequired)); slo.setRequestBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR)); slo.setResponseBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR)); - slo.setSignResponse(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR)); + slo.setSignResponse(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR, signaturesRequired)); slo.setPostBindingUrl(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR)); slo.setRedirectBindingUrl(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.REDIRECT_BINDING_URL_ATTR)); return slo; } - protected IDP.SingleSignOnService parseSingleSignOnService(XMLEventReader xmlEventReader) throws ParsingException { + protected IDP.SingleSignOnService parseSingleSignOnService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException { IDP.SingleSignOnService sso = new IDP.SingleSignOnService(); StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader); - sso.setSignRequest(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR)); - sso.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR)); + sso.setSignRequest(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired)); + sso.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired)); sso.setRequestBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR)); sso.setResponseBinding(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR)); sso.setBindingUrl(StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR)); diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java index 787af6993d..6fbd8d037f 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/KeyXmlParser.java @@ -7,6 +7,8 @@ import org.keycloak.saml.common.util.StaxParserUtil; import javax.xml.namespace.QName; import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; import javax.xml.stream.events.EndElement; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java index 089dc787b5..f0104707b4 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java @@ -37,8 +37,6 @@ public class SPXmlParser extends AbstractParser { sp.setSslPolicy(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SSL_POLICY_ATTR)); sp.setLogoutPage(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.LOGOUT_PAGE_ATTR)); sp.setNameIDPolicyFormat(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.NAME_ID_POLICY_FORMAT_ATTR)); - sp.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR)); - sp.setSignatureAlgorithm(StaxParserUtil.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR)); sp.setForceAuthentication(StaxParserUtil.getBooleanAttributeValue(startElement, ConfigXmlConstants.FORCE_AUTHENTICATION_ATTR)); while (xmlEventReader.hasNext()) { XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader); @@ -91,7 +89,6 @@ public class SPXmlParser extends AbstractParser { StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader); StaxParserUtil.validate(startElement, ConfigXmlConstants.ROLE_MAPPING_ELEMENT); Set roleAttributes = new HashSet<>(); - Set roleFriendlyAttributes = new HashSet<>(); while (xmlEventReader.hasNext()) { XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader); if (xmlEvent == null) @@ -116,21 +113,12 @@ public class SPXmlParser extends AbstractParser { } roleAttributes.add(attributeValue); - } else if (tag.equals(ConfigXmlConstants.FRIENDLY_ATTRIBUTE_ELEMENT)) { - StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader); - String attributeValue = StaxParserUtil.getAttributeValue(element, ConfigXmlConstants.NAME_ATTR); - if (attributeValue == null) { - throw new ParsingException("RoleMapping FriendlyAttribute element must have the name attribute set"); - - } - roleFriendlyAttributes.add(attributeValue); } else { StaxParserUtil.bypassElementBlock(xmlEventReader, tag); } } sp.setRoleAttributes(roleAttributes); - sp.setRoleFriendlyAttributes(roleFriendlyAttributes); } diff --git a/saml/client-adapter/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd b/saml/client-adapter/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd new file mode 100755 index 0000000000..b9e0799e97 --- /dev/null +++ b/saml/client-adapter/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/saml/client-adapter/core/src/test/java/org/keycloak/test/adapters/saml/XmlParserTest.java b/saml/client-adapter/core/src/test/java/org/keycloak/test/adapters/saml/XmlParserTest.java index c49cdf1f24..c92fec666c 100755 --- a/saml/client-adapter/core/src/test/java/org/keycloak/test/adapters/saml/XmlParserTest.java +++ b/saml/client-adapter/core/src/test/java/org/keycloak/test/adapters/saml/XmlParserTest.java @@ -7,7 +7,15 @@ import org.keycloak.adapters.saml.config.Key; import org.keycloak.adapters.saml.config.KeycloakSamlAdapter; import org.keycloak.adapters.saml.config.SP; import org.keycloak.adapters.saml.config.parsers.KeycloakSamlAdapterXMLParser; +import org.keycloak.saml.common.util.StaxParserUtil; +import javax.xml.XMLConstants; +import javax.xml.stream.XMLEventReader; +import javax.xml.transform.stax.StAXSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; import java.io.InputStream; /** @@ -16,6 +24,37 @@ import java.io.InputStream; */ public class XmlParserTest { + @Test + public void testValidation() throws Exception { + { + InputStream schema = KeycloakSamlAdapterXMLParser.class.getResourceAsStream("/schema/keycloak_saml_adapter_1_6.xsd"); + InputStream is = getClass().getResourceAsStream("/keycloak-saml.xml"); + Assert.assertNotNull(is); + Assert.assertNotNull(schema); + StaxParserUtil.validate(is, schema); + } + { + InputStream sch = KeycloakSamlAdapterXMLParser.class.getResourceAsStream("/schema/keycloak_saml_adapter_1_6.xsd"); + InputStream doc = getClass().getResourceAsStream("/keycloak-saml2.xml"); + Assert.assertNotNull(doc); + Assert.assertNotNull(sch); + try { + SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema = factory.newSchema(new StreamSource(sch)); + Validator validator = schema.newValidator(); + StreamSource source = new StreamSource(doc); + source.setSystemId("/keycloak-saml2.xml"); + validator.validate(source); + } catch (Exception e) { + e.printStackTrace(); + } + + + } + + + } + @Test public void testXmlParser() throws Exception { InputStream is = getClass().getResourceAsStream("/keycloak-saml.xml"); @@ -48,11 +87,11 @@ public class XmlParserTest { Assert.assertEquals("attribute", sp.getPrincipalNameMapping().getAttributeName()); Assert.assertTrue(sp.getRoleAttributes().size() == 1); Assert.assertTrue(sp.getRoleAttributes().contains("member")); - Assert.assertTrue(sp.getRoleFriendlyAttributes().size() == 1); - Assert.assertTrue(sp.getRoleFriendlyAttributes().contains("memberOf")); IDP idp = sp.getIdp(); Assert.assertEquals("idp", idp.getEntityID()); + Assert.assertEquals("RSA", idp.getSignatureAlgorithm()); + Assert.assertEquals("canon", idp.getSignatureCanonicalizationMethod()); Assert.assertTrue(idp.getSingleSignOnService().isSignRequest()); Assert.assertTrue(idp.getSingleSignOnService().isValidateResponseSignature()); Assert.assertEquals("post", idp.getSingleSignOnService().getRequestBinding()); diff --git a/saml/client-adapter/core/src/test/resources/keycloak-saml.xml b/saml/client-adapter/core/src/test/resources/keycloak-saml.xml index 242dc8e50f..5f881975e7 100755 --- a/saml/client-adapter/core/src/test/resources/keycloak-saml.xml +++ b/saml/client-adapter/core/src/test/resources/keycloak-saml.xml @@ -1,9 +1,7 @@ - + @@ -24,9 +22,12 @@ - - + + + + + + + + + + + + private pem + + + public pem + + + + + + + + + + + + + + cert pem + + + + + + \ No newline at end of file diff --git a/saml/client-adapter/wildfly/wildfly9-subsystem/src/main/resources/subsystem-templates/keycloak-adapter.xml b/saml/client-adapter/wildfly/wildfly9-subsystem/src/main/resources/subsystem-templates/keycloak-adapter.xml new file mode 100755 index 0000000000..8677d317e2 --- /dev/null +++ b/saml/client-adapter/wildfly/wildfly9-subsystem/src/main/resources/subsystem-templates/keycloak-adapter.xml @@ -0,0 +1,7 @@ + + + + org.keycloak.keycloak-saml-adapter-subsystem + + + diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java b/saml/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java index 79417293a1..1fbec6fafd 100755 --- a/saml/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java +++ b/saml/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java @@ -27,13 +27,16 @@ import org.keycloak.saml.common.exceptions.ParsingException; import org.keycloak.saml.common.ErrorCodes; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.xml.sax.SAXException; +import javax.xml.XMLConstants; import javax.xml.namespace.QName; import javax.xml.stream.Location; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Characters; import javax.xml.stream.events.EndElement; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; @@ -41,7 +44,11 @@ import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.stax.StAXSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; +import java.io.IOException; import java.io.InputStream; /** @@ -54,7 +61,18 @@ public class StaxParserUtil { private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); - protected static Validator validator = null; + public static void validate(InputStream doc, InputStream sch) throws ParsingException { + try { + XMLEventReader xmlEventReader = StaxParserUtil.getXMLEventReader(doc); + SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema = factory.newSchema(new StreamSource(sch)); + Validator validator = schema.newValidator(); + validator.validate(new StAXSource(xmlEventReader)); + } catch (Exception e) { + throw logger.parserException(e); + } + + } /** * Bypass an entire XML element block from startElement to endElement @@ -75,6 +93,29 @@ public class StaxParserUtil { } } + /** + * Advances reader if character whitespace encountered + * + * @param xmlEventReader + * @param xmlEvent + * @return + */ + public static boolean wasWhitespacePeeked(XMLEventReader xmlEventReader, XMLEvent xmlEvent) { + if (xmlEvent.isCharacters()) { + Characters chars = xmlEvent.asCharacters(); + String data = chars.getData(); + if (data == null || data.trim().equals("")) { + try { + xmlEventReader.nextEvent(); + return true; + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + } + return false; + } + /** * Given an {@code Attribute}, get its trimmed value * @@ -113,11 +154,23 @@ public class StaxParserUtil { * @return false if attribute not set */ public static boolean getBooleanAttributeValue(StartElement startElement, String tag) { + return getBooleanAttributeValue(startElement, tag, false); + } + + /** + * Get the Attribute value + * + * @param startElement + * @param tag localpart of the qname of the attribute + * + * @return false if attribute not set + */ + public static boolean getBooleanAttributeValue(StartElement startElement, String tag, boolean defaultValue) { String result = null; Attribute attr = startElement.getAttributeByName(new QName(tag)); if (attr != null) result = getAttributeValue(attr); - if (result == null) return false; + if (result == null) return defaultValue; return Boolean.valueOf(result); } diff --git a/testsuite/integration/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml b/testsuite/integration/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml index f5b05df8c0..8460a13d76 100755 --- a/testsuite/integration/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml +++ b/testsuite/integration/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml @@ -16,18 +16,13 @@ - - + - - +