diff --git a/config-templates/config.php b/config-templates/config.php index 3d1609c8..b584d7b6 100644 --- a/config-templates/config.php +++ b/config-templates/config.php @@ -41,10 +41,10 @@ $config = array ( 'showerrors' => true, /** - * This option allows you to enable validation of SAML 2.0 messages against their + * This option allows you to enable validation of SAML messages against their * schemas. A warning will be written to the log if validation fails. */ - 'debug.validatesaml2messages' => false, + 'debug.validatesamlmessages' => false, /** * This password must be kept secret, and modified from the default value 123. diff --git a/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php b/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php index ed9ee715..cf7f0bbe 100644 --- a/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php +++ b/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php @@ -20,7 +20,7 @@ class SimpleSAML_Bindings_SAML20_HTTPPost { public function sendResponseUnsigned($response, $idpentityid, $spentityid, $relayState = null, $endpoint = 'AssertionConsumerService') { - SimpleSAML_Utilities::validateSAML2Message($response); + SimpleSAML_Utilities::validateSAMLMessage($response, 'saml20'); $idpmd = $this->metadata->getMetaData($idpentityid, 'saml20-idp-hosted'); $spmd = $this->metadata->getMetaData($spentityid, 'saml20-sp-remote'); @@ -183,7 +183,7 @@ class SimpleSAML_Bindings_SAML20_HTTPPost { } $response = $responsedom->saveXML(); - SimpleSAML_Utilities::validateSAML2Message($response); + SimpleSAML_Utilities::validateSAMLMessage($response, 'saml20'); # openssl genrsa -des3 -out server.key 1024 # openssl rsa -in server.key -out server.pem @@ -231,7 +231,7 @@ class SimpleSAML_Bindings_SAML20_HTTPPost { $samlResponseXML = base64_decode( $rawResponse ); - SimpleSAML_Utilities::validateSAML2Message($samlResponseXML); + SimpleSAML_Utilities::validateSAMLMessage($samlResponseXML, 'saml20'); //error_log("Response is: " . $samlResponseXML); diff --git a/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php b/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php index 2bf82072..c9f610cf 100644 --- a/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php +++ b/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php @@ -180,7 +180,7 @@ class SimpleSAML_Bindings_SAML20_HTTPRedirect { public function sendMessage($request, $localentityid, $remoteentityid, $relayState = null, $endpoint = 'SingleSignOnService', $direction = 'SAMLRequest', $mode = 'SP') { - SimpleSAML_Utilities::validateSAML2Message($request); + SimpleSAML_Utilities::validateSAMLMessage($request, 'saml20'); $redirectURL = $this->getRedirectURL($request, $localentityid, $remoteentityid, $relayState, $endpoint, $direction, $mode); @@ -234,7 +234,7 @@ class SimpleSAML_Bindings_SAML20_HTTPRedirect { throw new Exception('Could not gzinflate base64 decoded SAMLRequest: ' . $error['message'] ); } - SimpleSAML_Utilities::validateSAML2Message($samlRequestXML); + SimpleSAML_Utilities::validateSAMLMessage($samlRequestXML, 'saml20'); $samlRequest = new SimpleSAML_XML_SAML20_AuthnRequest($this->configuration, $this->metadata); @@ -272,7 +272,7 @@ class SimpleSAML_Bindings_SAML20_HTTPRedirect { throw new Exception('Could not gzinflate base64 decoded SAMLRequest: ' . $error['message'] ); } - SimpleSAML_Utilities::validateSAML2Message($samlRequestXML); + SimpleSAML_Utilities::validateSAMLMessage($samlRequestXML, 'saml20'); $samlRequest = new SimpleSAML_XML_SAML20_LogoutRequest($this->configuration, $this->metadata); @@ -311,7 +311,7 @@ class SimpleSAML_Bindings_SAML20_HTTPRedirect { throw new Exception('Could not gzinflate base64 decoded SAMLRequest: ' . $error['message'] ); } - SimpleSAML_Utilities::validateSAML2Message($samlRequestXML); + SimpleSAML_Utilities::validateSAMLMessage($samlRequestXML, 'saml20'); $samlRequest = new SimpleSAML_XML_SAML20_LogoutResponse($this->configuration, $this->metadata); diff --git a/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php b/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php index 37adb633..36af8c22 100644 --- a/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php +++ b/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php @@ -20,6 +20,8 @@ class SimpleSAML_Bindings_Shib13_HTTPPost { public function sendResponseUnsigned($response, $idpentityid, $spentityid, $relayState = null, $endpoint = 'AssertionConsumerService') { + SimpleSAML_Utilities::validateSAMLMessage($response, 'saml11'); + $idpmd = $this->metadata->getMetaData($idpentityid, 'saml20-idp-hosted'); $spmd = $this->metadata->getMetaData($spentityid, 'saml20-sp-remote'); @@ -62,6 +64,8 @@ class SimpleSAML_Bindings_Shib13_HTTPPost { */ public function sendResponse($response, $idpmetaindex, $spentityid, $relayState = null, $claimedacs = null) { + SimpleSAML_Utilities::validateSAMLMessage($response, 'saml11'); + $idpmd = $this->metadata->getMetaData($idpmetaindex, 'shib13-idp-hosted'); $spmd = $this->metadata->getMetaData($spentityid, 'shib13-sp-remote'); @@ -201,6 +205,8 @@ class SimpleSAML_Bindings_Shib13_HTTPPost { $relaystate = $post["TARGET"]; $samlResponseXML = base64_decode( $rawResponse ); + + SimpleSAML_Utilities::validateSAMLMessage($samlResponseXML, 'saml11'); $samlResponse = new SimpleSAML_XML_Shib13_AuthnResponse($this->configuration, $this->metadata); diff --git a/lib/SimpleSAML/Utilities.php b/lib/SimpleSAML/Utilities.php index a46f3117..474cee47 100644 --- a/lib/SimpleSAML/Utilities.php +++ b/lib/SimpleSAML/Utilities.php @@ -793,24 +793,44 @@ class SimpleSAML_Utilities { /** - * This function validates a SAML2 message against its schema. - * A warning will be printed to the log if validation fails. + * This function performs some sanity checks on SAML messages, and optionally validates them + * against their schema. A warning will be printed to the log if validation fails. * * @param $message The message which should be validated. + * @param $type The type of message - can be either 'saml20' or 'saml11'. */ - public static function validateSAML2Message($message) { + public static function validateSAMLMessage($message, $type) { assert('is_string($message)'); + assert($type === 'saml11' || $type === 'saml20'); - $enabled = SimpleSAML_Configuration::getInstance()->getValue('debug.validatesaml2messages', FALSE); - if(!is_bool($enabled)) { - throw new Exception('Expected "debug.validatesaml2messages" to be set to a boolean value.'); + /* A SAML message should not contain a doctype-declaration. */ + if(strpos($message, 'getValue('debug.validatesamlmessages', NULL); + if($enabled === NULL) { + /* Fall back to old configuration option. */ + $enabled = SimpleSAML_Configuration::getInstance()->getValue('debug.validatesaml2messages', FALSE); + if(!is_bool($enabled)) { + throw new Exception('Expected "debug.validatesaml2messages" to be set to a boolean value.'); + } + } elseif(!is_bool($enabled)) { + throw new Exception('Expected "debug.validatesamlmessages" to be set to a boolean value.'); } if(!$enabled) { return; } - $result = self::validateXML($message, 'saml-schema-protocol-2.0.xsd'); + if($type === 'saml11') { + $result = self::validateXML($message, 'oasis-sstc-saml-schema-protocol-1.1.xsd'); + } elseif($type === 'saml20') { + $result = self::validateXML($message, 'saml-schema-protocol-2.0.xsd'); + } else { + throw new Exception('Invalid message type.'); + } + if($result !== '') { SimpleSAML_Logger::warning($result); } diff --git a/schemas/oasis-sstc-saml-schema-assertion-1.1.xsd b/schemas/oasis-sstc-saml-schema-assertion-1.1.xsd new file mode 100644 index 00000000..4cc2bf33 --- /dev/null +++ b/schemas/oasis-sstc-saml-schema-assertion-1.1.xsd @@ -0,0 +1,201 @@ + + + + + + Document identifier: oasis-sstc-saml-schema-assertion-1.1 + Location: http://www.oasis-open.org/committees/documents.php?wg_abbrev=security + Revision history: + V1.0 (November, 2002): + Initial standard schema. + V1.1 (September, 2003): + * Note that V1.1 of this schema has the same XML namespace as V1.0. + Rebased ID content directly on XML Schema types + Added DoNotCacheCondition element and DoNotCacheConditionType + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schemas/oasis-sstc-saml-schema-protocol-1.1.xsd b/schemas/oasis-sstc-saml-schema-protocol-1.1.xsd new file mode 100644 index 00000000..9df108d9 --- /dev/null +++ b/schemas/oasis-sstc-saml-schema-protocol-1.1.xsd @@ -0,0 +1,132 @@ + + + + + + + Document identifier: oasis-sstc-saml-schema-protocol-1.1 + Location: http://www.oasis-open.org/committees/documents.php?wg_abbrev=security + Revision history: + V1.0 (November, 2002): + Initial standard schema. + V1.1 (September, 2003): + * Note that V1.1 of this schema has the same XML namespace as V1.0. + Rebased ID content directly on XML Schema types + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +