diff --git a/lib/SimpleSAML/XML/Signer.php b/lib/SimpleSAML/XML/Signer.php index b9bb9fce8b2477a1d0a5ec877e624b4a17451f0a..42ddfa350bb4ee9ec5b672b3e3b2c9b14b381151 100644 --- a/lib/SimpleSAML/XML/Signer.php +++ b/lib/SimpleSAML/XML/Signer.php @@ -123,14 +123,22 @@ class Signer * to the cert-directory. * @param string|null $pass The passphrase on the private key. Pass no value or NULL if the private * key is unencrypted. + * @param bool $full_path Whether the filename found in the configuration contains the + * full path to the private key or not. Default to false. * @throws \Exception */ - public function loadPrivateKey($file, $pass = null) + public function loadPrivateKey($file, $pass = null, $full_path = false) { assert('is_string($file)'); assert('is_string($pass) || is_null($pass)'); + assert('is_bool($full_path)'); + + if (!$full_path) { + $keyFile = Config::getCertPath($file); + } else { + $keyFile = $file; + } - $keyFile = Config::getCertPath($file); if (!file_exists($keyFile)) { throw new \Exception('Could not find private key file "' . $keyFile . '".'); } @@ -178,13 +186,21 @@ class Signer * * @param string $file The file which contains the certificate. The path is assumed to be relative to * the cert-directory. + * @param bool $full_path Whether the filename found in the configuration contains the + * full path to the private key or not. Default to false. * @throws \Exception */ - public function loadCertificate($file) + public function loadCertificate($file, $full_path = false) { assert('is_string($file)'); + assert('is_bool($full_path)'); + + if (!$full_path) { + $certFile = Config::getCertPath($file); + } else { + $certFile = $file; + } - $certFile = Config::getCertPath($file); if (!file_exists($certFile)) { throw new \Exception('Could not find certificate file "' . $certFile . '".'); } @@ -216,13 +232,21 @@ class Signer * are added. * * @param string $file The file which contains the certificate, relative to the cert-directory. + * @param bool $full_path Whether the filename found in the configuration contains the + * full path to the private key or not. Default to false. * @throws \Exception */ - public function addCertificate($file) + public function addCertificate($file, $full_path = false) { assert('is_string($file)'); + assert('is_bool($full_path)'); + + if (!$full_path) { + $certFile = Config::getCertPath($file); + } else { + $certFile = $file; + } - $certFile = Config::getCertPath($file); if (!file_exists($certFile)) { throw new \Exception('Could not find extra certificate file "' . $certFile . '".'); } @@ -268,9 +292,12 @@ class Signer $options['id_name'] = $this->idAttrName; } - $objXMLSecDSig->addReferenceList(array($node), XMLSecurityDSig::SHA1, + $objXMLSecDSig->addReferenceList( + array($node), + XMLSecurityDSig::SHA1, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N), - $options); + $options + ); $objXMLSecDSig->sign($this->privateKey); diff --git a/tests/lib/SimpleSAML/XML/SignerTest.php b/tests/lib/SimpleSAML/XML/SignerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..359836b8b8d6b6a2dfec24751a011621f011c68e --- /dev/null +++ b/tests/lib/SimpleSAML/XML/SignerTest.php @@ -0,0 +1,239 @@ +<?php + +namespace SimpleSAML\Test\Utils; + +use \SimpleSAML_Configuration as Configuration; +use \SimpleSAML\XML\Signer; + +use \org\bovigo\vfs\vfsStream; + +/** + * Tests for SimpleSAML\XML\Signer. + */ +class SignerTest extends \PHPUnit_Framework_TestCase +{ + // openssl genrsa -out private.pem 2048 + private $private_key = <<<'NOWDOC' +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA5LoQYYPfKdHnSnuXI+SiHfUd648Ub0sn2YO81rmnwJ168Ol/ +FZODrGpm8tsRUTz5R9uXXSnwhnWwVJW4ckiZORcp1bEUGI0zXYR387yF3Ih87UFV +KdqodrDXNN6Id7Xrw65AVa4gjwLN2DNBF3JnjbH7zKtnqhb7u2Qer7Lidhvw4WxY +lC9t8c+Kv3xoJOgDvlG1gRaYTZv7pxTpBA7W1YnJpOj3xiXetVmAxRcGyB0Jc8aB +nc1WoUBGudSvjvuc01kJ+rurjgklGEFjVP9AjPfcVkdcFTXc+ECets++AmZc/kk4 +Y6RKCn3fOJlL5L0RxVSJ8obnBcS7H4rZYordfwIDAQABAoIBAH364cTkPompPIyw +0AmMB6MafFVfZHD8Y0GSJvPaJESaOLny0fWPX4oavQNsl/g37lGe6Jr+26Ujs3CT +WplP1V01new+cYQoWa9bpDoSj2RtpOmE/6Ri9EETnCVZoK7W+7m3A2Zt1y8N61T2 +vhZtBA5uhvMvQZTUvehz99bsX4GPTUilYHCPEq4IPkfhCMGigv/c0lWtFQhOoNUF +BjZHezH4Z/qQolIaHpzFZT0K0e7VD4gomBegGsIqPuEJ0gProCjULqA0O5QT4gQX +IT52pUJuU0061d4JOfDcgDI3NT2SmBBMfig71n/R88eMn0azWKN4rn4/3QjxRW3q +tdjL0UECgYEA/ynTXtuL7G5zOezKirakuSlSbHu/3TJ+tdG5p7WOLqWADUzgqss+ +k7rxxFUxw40dBpC0LfYP5YMhXi4cBiNoT5EWhT53x/UxCilXHuz5uYcrt/Wyaqa0 +mZuyIPYuw/yTASEBUE/sE1DU82PD3IlkPmqfgEyW6j8CVyLqo/LxMWECgYEA5XoM +aVB5jhYk8jxy0APWn4jSTm2zpTBZpzHmqTPL19B4Es18XoU+ehWA8rWGQFFwbl1f +TTUBE1hlS9MgMMI8MK6S1Qrhi7mVrHuMaMbp0ilwDBjv+4DSqlDGDoCSLCLrDkkl +c0uDLLFGHkfDjNmk3uiSxPZvrUiVVuwJYLGNGt8CgYEAyvjWbsptz7E8b4Nwyk7n +UXMRYcI+qRIVwUQHTuUZKPn1lp7kyHfMW2+GCgtK/qctw58v9K+bjZJ15JkBKdDY +lRJwu6UpWyIr1E12Q9919qMTn84OEtBxMQ+s7pNmN/ieZ3N9vAkXXXYbL1DY6IFS +AGSIZGKIWeWtUusvgyMpwYECgYEArGDIHfxTs0YzLrv1ywh3GpQe1sdVYUs2rX+w +s32zLETvTcCKIj6ZNgAdQzTUyk/i0yTUyBx+2FdYkGLiFX5y1Gbu6ZYo41rfchfE +25hAYJy8DHpXG2gj18ihXpd6NilsxOhxd3BL8zCfaXOjE5USYlf2mHo+Xb7eX9Mj +ID1/r6UCgYBos8plM27v5BzI8gghUlkFAFLmmccJXQHCUlUhT1+d8FTMEhTZGjZk +94a7cc/ps+6UCp6hOqJ2d6w+cfteWZWP0zMcoxr2JAO9lYekIlUafoZ+mhJCCqoC +ENg4/K7BqpAlRzCf28gUiL53wOut2CadGIoSvj0UR/Mh2eM64jTgSQ== +-----END RSA PRIVATE KEY----- +NOWDOC; + + // openssl req -new -x509 -key private.pem -out public1.pem -days 3650 + private $certificate1 = <<<'NOWDOC' +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAIonjtIRUcfJMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTcwNjE1MTcyMTI4WhcNMjcwNjEzMTcyMTI4WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA5LoQYYPfKdHnSnuXI+SiHfUd648Ub0sn2YO81rmnwJ168Ol/FZODrGpm +8tsRUTz5R9uXXSnwhnWwVJW4ckiZORcp1bEUGI0zXYR387yF3Ih87UFVKdqodrDX +NN6Id7Xrw65AVa4gjwLN2DNBF3JnjbH7zKtnqhb7u2Qer7Lidhvw4WxYlC9t8c+K +v3xoJOgDvlG1gRaYTZv7pxTpBA7W1YnJpOj3xiXetVmAxRcGyB0Jc8aBnc1WoUBG +udSvjvuc01kJ+rurjgklGEFjVP9AjPfcVkdcFTXc+ECets++AmZc/kk4Y6RKCn3f +OJlL5L0RxVSJ8obnBcS7H4rZYordfwIDAQABo1AwTjAdBgNVHQ4EFgQUZHjC+k2X +pMchyKojQngj5zOsZacwHwYDVR0jBBgwFoAUZHjC+k2XpMchyKojQngj5zOsZacw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAETjO0RltSYxFdxmIqVIg +7N6yKptUr46YkWY877HWmCLExHwFLTvewUvbgx7ASYA0YMErnAaVrT9IqCDbOUF+ +RCBovVuiAwwKcvag0C8nKg7rfx7KDr2E8vVV+2WzSpDECtLrpTmrPaje8TlFv8NW +hMk80osVxnGmI7UewiMzfpRuA4tEKFxHhoQG5LVinWRTMKw6EYmrSKGLdQt/27zj +xDe0oOS2DDIYbU/oWCqLtlTlzVqrNM7ig9HKcT0Xxgf5rwTDDzNf/dpM/Nt8DWFY +YmLDnUolf8d/M/kglX1x5IRSN+GxTCgV8i6dIF9EPtBW/AfMz99ojmW+WOgfOLnm +vg== +-----END CERTIFICATE----- +NOWDOC; + + // openssl req -new -x509 -key private.pem -out public2.pem -days 3650 + private $certificate2 = <<<'NOWDOC' +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAJ6gIIeYjdQSMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTcwNjE1MTcyMTM0WhcNMjcwNjEzMTcyMTM0WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA5LoQYYPfKdHnSnuXI+SiHfUd648Ub0sn2YO81rmnwJ168Ol/FZODrGpm +8tsRUTz5R9uXXSnwhnWwVJW4ckiZORcp1bEUGI0zXYR387yF3Ih87UFVKdqodrDX +NN6Id7Xrw65AVa4gjwLN2DNBF3JnjbH7zKtnqhb7u2Qer7Lidhvw4WxYlC9t8c+K +v3xoJOgDvlG1gRaYTZv7pxTpBA7W1YnJpOj3xiXetVmAxRcGyB0Jc8aBnc1WoUBG +udSvjvuc01kJ+rurjgklGEFjVP9AjPfcVkdcFTXc+ECets++AmZc/kk4Y6RKCn3f +OJlL5L0RxVSJ8obnBcS7H4rZYordfwIDAQABo1AwTjAdBgNVHQ4EFgQUZHjC+k2X +pMchyKojQngj5zOsZacwHwYDVR0jBBgwFoAUZHjC+k2XpMchyKojQngj5zOsZacw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA1CqpKLeYLkgRym2qeMhU +5lKlXAYX5b0eM2SOCCjfpEnRqp2PTU/E83H0MOY6i47OfHp3LKNUj4Kze2DD+S6A +llpmLfuLXZ/CB19sByzMrcEyUQo4mfqvKyzLhUTgygGczyocwRRZgnw1e+VwMtpf +mgXnldomDT8CUsM2v3Xb52+JPGSCs16lRYZkgDCQEpHU4+VQxwGAGpj13NM+sidR +ymj443jgpF6XUviaGiaS292rXMO/tW7veA1UZ2/eTKu5PF9RqDmYLiGatY1qp4tr +QjBeEjMtDCs9Rqaety/UIaL4ZfOKffLKsKb2mjM/ew+QTwTLDg9RVv5vv2jbZrw7 +Nw== +-----END CERTIFICATE----- +NOWDOC; + + const ROOTDIRNAME = 'testdir'; + const DEFAULTCERTDIR = 'certdir'; + const PRIVATEKEY = 'privatekey.pem'; + const CERTIFICATE1 = 'certificate1.pem'; + const CERTIFICATE2 = 'certificate2.pem'; + + public function setUp() + { + $this->root = vfsStream::setup( + self::ROOTDIRNAME, + null, + array( + self::DEFAULTCERTDIR => array( + self::PRIVATEKEY => $this->private_key, + self::CERTIFICATE1 => $this->certificate1, + self::CERTIFICATE2 => $this->certificate2, + ), + ) + ); + $this->root_directory = vfsStream::url(self::ROOTDIRNAME); + + $this->certdir = $this->root_directory.DIRECTORY_SEPARATOR.self::DEFAULTCERTDIR; + $this->privatekey_file = $this->certdir.DIRECTORY_SEPARATOR.self::PRIVATEKEY; + $this->certificate_file1 = $this->certdir.DIRECTORY_SEPARATOR.self::CERTIFICATE1; + $this->certificate_file2 = $this->certdir.DIRECTORY_SEPARATOR.self::CERTIFICATE2; + + $this->config = Configuration::loadFromArray(array( + 'certdir' => $this->certdir, + ), '[ARRAY]', 'simplesaml'); + } + + public function tearDown() + { + $this->clearInstance($this->config, '\SimpleSAML_Configuration', array()); + } + + public function testSignerBasic() + { + $res = new Signer(array()); + + $this->assertNotNull($res); + } + + public function testSignBasic() + { + $node = new \DOMDocument(); + $node->loadXML('<?xml version="1.0"?><node>value</node>'); + $element = $node->getElementsByTagName("node")->item(0); + + $doc = new \DOMDocument(); + $insertInto = $doc->appendChild(new \DOMElement('insert')); + + $signer = new Signer(array()); + $signer->loadPrivateKey($this->privatekey_file, null, true); + $signer->sign($element, $insertInto); + + $res = $doc->saveXML(); + + $this->assertContains('DigestValue', $res); + $this->assertContains('SignatureValue', $res); + } + + private static function getCertificateValue($certificate) + { + $replacements = array( + "-----BEGIN CERTIFICATE-----", + "-----END CERTIFICATE-----", + "\n", + ); + + return str_replace($replacements, "", $certificate); + } + + public function testSignWithCertificate() + { + $node = new \DOMDocument(); + $node->loadXML('<?xml version="1.0"?><node>value</node>'); + $element = $node->getElementsByTagName("node")->item(0); + + $doc = new \DOMDocument(); + $insertInto = $doc->appendChild(new \DOMElement('insert')); + + $signer = new Signer(array()); + $signer->loadPrivateKey($this->privatekey_file, null, true); + $signer->loadCertificate($this->certificate_file1, true); + $signer->sign($element, $insertInto); + + $res = $doc->saveXML(); + + $expected = self::getCertificateValue($this->certificate1); + + $this->assertContains('X509Certificate', $res); + $this->assertContains($expected, $res); + } + + public function testSignWithMultiCertificate() + { + $node = new \DOMDocument(); + $node->loadXML('<?xml version="1.0"?><node>value</node>'); + $element = $node->getElementsByTagName("node")->item(0); + + $doc = new \DOMDocument(); + $insertInto = $doc->appendChild(new \DOMElement('insert')); + + $signer = new Signer(array()); + $signer->loadPrivateKey($this->privatekey_file, null, true); + $signer->loadCertificate($this->certificate_file1, true); + $signer->addCertificate($this->certificate_file2, true); + $signer->sign($element, $insertInto); + + $res = $doc->saveXML(); + + $expected1 = self::getCertificateValue($this->certificate1); + $expected2 = self::getCertificateValue($this->certificate2); + + $this->assertContains('X509Certificate', $res); + $this->assertContains($expected1, $res); + $this->assertContains($expected2, $res); + } + + public function testSignMissingPrivateKey() + { + $node = new \DOMDocument(); + $node->loadXML('<?xml version="1.0"?><node>value</node>'); + $element = $node->getElementsByTagName("node")->item(0); + + $doc = new \DOMDocument(); + $insertInto = $doc->appendChild(new \DOMElement('insert')); + + $signer = new Signer(array()); + + $this->setExpectedException('\Exception'); + $signer->sign($element, $insertInto); + } + + protected function clearInstance($service, $className, $value = null) + { + $reflectedClass = new \ReflectionClass($className); + $reflectedInstance = $reflectedClass->getProperty('instance'); + $reflectedInstance->setAccessible(true); + $reflectedInstance->setValue($service, $value); + $reflectedInstance->setAccessible(false); + } +} diff --git a/tests/modules/consent/lib/Auth/Process/ConsentTest.php b/tests/modules/consent/lib/Auth/Process/ConsentTest.php index ce864179fa61a549feccf4d54f9b0962a99ce0ef..e83659d22e054db22ba453e60a5372ac2af2f56b 100644 --- a/tests/modules/consent/lib/Auth/Process/ConsentTest.php +++ b/tests/modules/consent/lib/Auth/Process/ConsentTest.php @@ -8,8 +8,14 @@ namespace SimpleSAML\Test\Module\consent\Auth\Process; +use \SimpleSAML_Configuration as Configuration; + class ConsentTest extends \PHPUnit_Framework_TestCase { + public function setUp() + { + $this->config = Configuration::loadFromArray(array(), '[ARRAY]', 'simplesaml'); + } /** * Helper function to run the filter with a given configuration. diff --git a/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php b/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php index c88def979a42701ebf2d72897652af67edad1058..bb3d065db979d757aa9a474c55706ade050578c3 100644 --- a/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php +++ b/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php @@ -2,6 +2,8 @@ namespace SimpleSAML\Test\Module\saml\Auth\Source; +use \SimpleSAML_Configuration as Configuration; + /** * Custom Exception to throw to terminate a TestCase. */ @@ -121,6 +123,8 @@ class SP_Test extends \PHPUnit_Framework_TestCase ), ), ); + + $this->config = Configuration::loadFromArray(array(), '[ARRAY]', 'simplesaml'); }