update to php-saml 3.0.0 without mcrypt dependecy

Signed-off-by: Bjoern Schiessle <bjoern@schiessle.org>
This commit is contained in:
Björn Schiessle 2018-10-04 15:36:44 +02:00
parent a0e05af6c8
commit a9fbc8703e
No known key found for this signature in database
GPG Key ID: 2378A753E2BF04F6
62 changed files with 5050 additions and 3582 deletions

View File

@ -4,7 +4,7 @@
"classmap-authoritative": true
},
"require": {
"onelogin/php-saml": "2.10.5",
"onelogin/php-saml": "^3.0",
"firebase/php-jwt": "^4.0"
}
}

82
3rdparty/composer.lock generated vendored
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c0b54acdb5e61d572c6c95652de525ed",
"content-hash": "f3e661f8388070704bd9b01b48752bf0",
"packages": [
{
"name": "firebase/php-jwt",
@ -51,57 +51,91 @@
},
{
"name": "onelogin/php-saml",
"version": "2.10.5",
"version": "v3.0.0",
"source": {
"type": "git",
"url": "https://github.com/onelogin/php-saml.git",
"reference": "3319d7707f342e38291eee6b01a4a5f8df1b333b"
"reference": "920c2240e48c9a74aad4129720f48fbf3d5fee47"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/onelogin/php-saml/zipball/3319d7707f342e38291eee6b01a4a5f8df1b333b",
"reference": "3319d7707f342e38291eee6b01a4a5f8df1b333b",
"url": "https://api.github.com/repos/onelogin/php-saml/zipball/920c2240e48c9a74aad4129720f48fbf3d5fee47",
"reference": "920c2240e48c9a74aad4129720f48fbf3d5fee47",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-mcrypt": "*",
"ext-openssl": "*",
"php": ">=5.3.2"
"php": ">=5.4",
"robrichards/xmlseclibs": "^3.0"
},
"require-dev": {
"pdepend/pdepend": "1.1.0",
"phploc/phploc": "*",
"phpunit/phpunit": "4.8",
"satooshi/php-coveralls": "1.0.1",
"sebastian/phpcpd": "*",
"squizlabs/php_codesniffer": "*"
"pdepend/pdepend": "^2.5.0",
"php-coveralls/php-coveralls": "^1.0.2 || ^2.0",
"phploc/phploc": "^2.1 || ^3.0 || ^4.0",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1",
"sebastian/phpcpd": "^2.0 || ^3.0 || ^4.0",
"squizlabs/php_codesniffer": "^3.1.1"
},
"suggest": {
"ext-curl": "Install curl lib to be able to use the IdPMetadataParser for parsing remote XMLs",
"ext-gettext": "Install gettext and php5-gettext libs to handle translations",
"ext-mcrypt": "Install mcrypt and php5-mcrypt libs in order to support encryption",
"lib-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)"
"ext-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)"
},
"type": "library",
"autoload": {
"classmap": [
"extlib/xmlseclibs",
"lib/Saml",
"lib/Saml2"
]
"psr-4": {
"OneLogin\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "OneLogin PHP SAML Toolkit",
"homepage": "https://onelogin.zendesk.com/hc/en-us/sections/200245634-SAML-Toolkits",
"homepage": "https://developers.onelogin.com/saml/php",
"keywords": [
"SAML2",
"onelogin",
"saml"
],
"time": "2017-03-13T09:56:49+00:00"
"time": "2018-10-02T16:02:37+00:00"
},
{
"name": "robrichards/xmlseclibs",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/robrichards/xmlseclibs.git",
"reference": "1f4de0c0d121922aafd8c62c2a9f5e528830cf38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/1f4de0c0d121922aafd8c62c2a9f5e528830cf38",
"reference": "1f4de0c0d121922aafd8c62c2a9f5e528830cf38",
"shasum": ""
},
"require": {
"ext-openssl": "*",
"php": ">= 5.4"
},
"type": "library",
"autoload": {
"psr-4": {
"RobRichards\\XMLSecLibs\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "A PHP library for XML Security",
"homepage": "https://github.com/robrichards/xmlseclibs",
"keywords": [
"security",
"signature",
"xml",
"xmldsig"
],
"time": "2018-09-27T13:24:13+00:00"
}
],
"packages-dev": [],

View File

@ -10,23 +10,20 @@ return array(
'Firebase\\JWT\\ExpiredException' => $vendorDir . '/firebase/php-jwt/src/ExpiredException.php',
'Firebase\\JWT\\JWT' => $vendorDir . '/firebase/php-jwt/src/JWT.php',
'Firebase\\JWT\\SignatureInvalidException' => $vendorDir . '/firebase/php-jwt/src/SignatureInvalidException.php',
'OneLogin_Saml2_Auth' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Auth.php',
'OneLogin_Saml2_AuthnRequest' => $vendorDir . '/onelogin/php-saml/lib/Saml2/AuthnRequest.php',
'OneLogin_Saml2_Constants' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Constants.php',
'OneLogin_Saml2_Error' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Error.php',
'OneLogin_Saml2_LogoutRequest' => $vendorDir . '/onelogin/php-saml/lib/Saml2/LogoutRequest.php',
'OneLogin_Saml2_LogoutResponse' => $vendorDir . '/onelogin/php-saml/lib/Saml2/LogoutResponse.php',
'OneLogin_Saml2_Metadata' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Metadata.php',
'OneLogin_Saml2_Response' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Response.php',
'OneLogin_Saml2_Settings' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Settings.php',
'OneLogin_Saml2_Utils' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Utils.php',
'OneLogin_Saml2_ValidationError' => $vendorDir . '/onelogin/php-saml/lib/Saml2/Error.php',
'OneLogin_Saml_AuthRequest' => $vendorDir . '/onelogin/php-saml/lib/Saml/AuthRequest.php',
'OneLogin_Saml_Metadata' => $vendorDir . '/onelogin/php-saml/lib/Saml/Metadata.php',
'OneLogin_Saml_Response' => $vendorDir . '/onelogin/php-saml/lib/Saml/Response.php',
'OneLogin_Saml_Settings' => $vendorDir . '/onelogin/php-saml/lib/Saml/Settings.php',
'OneLogin_Saml_XmlSec' => $vendorDir . '/onelogin/php-saml/lib/Saml/XmlSec.php',
'XMLSecEnc' => $vendorDir . '/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php',
'XMLSecurityDSig' => $vendorDir . '/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php',
'XMLSecurityKey' => $vendorDir . '/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php',
'OneLogin\\Saml2\\Auth' => $vendorDir . '/onelogin/php-saml/src/Saml2/Auth.php',
'OneLogin\\Saml2\\AuthnRequest' => $vendorDir . '/onelogin/php-saml/src/Saml2/AuthnRequest.php',
'OneLogin\\Saml2\\Constants' => $vendorDir . '/onelogin/php-saml/src/Saml2/Constants.php',
'OneLogin\\Saml2\\Error' => $vendorDir . '/onelogin/php-saml/src/Saml2/Error.php',
'OneLogin\\Saml2\\IdPMetadataParser' => $vendorDir . '/onelogin/php-saml/src/Saml2/IdPMetadataParser.php',
'OneLogin\\Saml2\\LogoutRequest' => $vendorDir . '/onelogin/php-saml/src/Saml2/LogoutRequest.php',
'OneLogin\\Saml2\\LogoutResponse' => $vendorDir . '/onelogin/php-saml/src/Saml2/LogoutResponse.php',
'OneLogin\\Saml2\\Metadata' => $vendorDir . '/onelogin/php-saml/src/Saml2/Metadata.php',
'OneLogin\\Saml2\\Response' => $vendorDir . '/onelogin/php-saml/src/Saml2/Response.php',
'OneLogin\\Saml2\\Settings' => $vendorDir . '/onelogin/php-saml/src/Saml2/Settings.php',
'OneLogin\\Saml2\\Utils' => $vendorDir . '/onelogin/php-saml/src/Saml2/Utils.php',
'OneLogin\\Saml2\\ValidationError' => $vendorDir . '/onelogin/php-saml/src/Saml2/ValidationError.php',
'RobRichards\\XMLSecLibs\\Utils\\XPath' => $vendorDir . '/robrichards/xmlseclibs/src/Utils/XPath.php',
'RobRichards\\XMLSecLibs\\XMLSecEnc' => $vendorDir . '/robrichards/xmlseclibs/src/XMLSecEnc.php',
'RobRichards\\XMLSecLibs\\XMLSecurityDSig' => $vendorDir . '/robrichards/xmlseclibs/src/XMLSecurityDSig.php',
'RobRichards\\XMLSecLibs\\XMLSecurityKey' => $vendorDir . '/robrichards/xmlseclibs/src/XMLSecurityKey.php',
);

View File

@ -6,5 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'RobRichards\\XMLSecLibs\\' => array($vendorDir . '/robrichards/xmlseclibs/src'),
'OneLogin\\' => array($vendorDir . '/onelogin/php-saml/src'),
'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'),
);

View File

@ -7,6 +7,14 @@ namespace Composer\Autoload;
class ComposerStaticInitcc75f134f7630c1ee3a8e4d7c86f3bcc
{
public static $prefixLengthsPsr4 = array (
'R' =>
array (
'RobRichards\\XMLSecLibs\\' => 23,
),
'O' =>
array (
'OneLogin\\' => 9,
),
'F' =>
array (
'Firebase\\JWT\\' => 13,
@ -14,6 +22,14 @@ class ComposerStaticInitcc75f134f7630c1ee3a8e4d7c86f3bcc
);
public static $prefixDirsPsr4 = array (
'RobRichards\\XMLSecLibs\\' =>
array (
0 => __DIR__ . '/..' . '/robrichards/xmlseclibs/src',
),
'OneLogin\\' =>
array (
0 => __DIR__ . '/..' . '/onelogin/php-saml/src',
),
'Firebase\\JWT\\' =>
array (
0 => __DIR__ . '/..' . '/firebase/php-jwt/src',
@ -25,25 +41,22 @@ class ComposerStaticInitcc75f134f7630c1ee3a8e4d7c86f3bcc
'Firebase\\JWT\\ExpiredException' => __DIR__ . '/..' . '/firebase/php-jwt/src/ExpiredException.php',
'Firebase\\JWT\\JWT' => __DIR__ . '/..' . '/firebase/php-jwt/src/JWT.php',
'Firebase\\JWT\\SignatureInvalidException' => __DIR__ . '/..' . '/firebase/php-jwt/src/SignatureInvalidException.php',
'OneLogin_Saml2_Auth' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml2/Auth.php',
'OneLogin_Saml2_AuthnRequest' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml2/AuthnRequest.php',
'OneLogin_Saml2_Constants' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml2/Constants.php',
'OneLogin_Saml2_Error' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml2/Error.php',
'OneLogin_Saml2_LogoutRequest' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml2/LogoutRequest.php',
'OneLogin_Saml2_LogoutResponse' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml2/LogoutResponse.php',
'OneLogin_Saml2_Metadata' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml2/Metadata.php',
'OneLogin_Saml2_Response' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml2/Response.php',
'OneLogin_Saml2_Settings' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml2/Settings.php',
'OneLogin_Saml2_Utils' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml2/Utils.php',
'OneLogin_Saml2_ValidationError' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml2/Error.php',
'OneLogin_Saml_AuthRequest' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml/AuthRequest.php',
'OneLogin_Saml_Metadata' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml/Metadata.php',
'OneLogin_Saml_Response' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml/Response.php',
'OneLogin_Saml_Settings' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml/Settings.php',
'OneLogin_Saml_XmlSec' => __DIR__ . '/..' . '/onelogin/php-saml/lib/Saml/XmlSec.php',
'XMLSecEnc' => __DIR__ . '/..' . '/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php',
'XMLSecurityDSig' => __DIR__ . '/..' . '/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php',
'XMLSecurityKey' => __DIR__ . '/..' . '/onelogin/php-saml/extlib/xmlseclibs/xmlseclibs.php',
'OneLogin\\Saml2\\Auth' => __DIR__ . '/..' . '/onelogin/php-saml/src/Saml2/Auth.php',
'OneLogin\\Saml2\\AuthnRequest' => __DIR__ . '/..' . '/onelogin/php-saml/src/Saml2/AuthnRequest.php',
'OneLogin\\Saml2\\Constants' => __DIR__ . '/..' . '/onelogin/php-saml/src/Saml2/Constants.php',
'OneLogin\\Saml2\\Error' => __DIR__ . '/..' . '/onelogin/php-saml/src/Saml2/Error.php',
'OneLogin\\Saml2\\IdPMetadataParser' => __DIR__ . '/..' . '/onelogin/php-saml/src/Saml2/IdPMetadataParser.php',
'OneLogin\\Saml2\\LogoutRequest' => __DIR__ . '/..' . '/onelogin/php-saml/src/Saml2/LogoutRequest.php',
'OneLogin\\Saml2\\LogoutResponse' => __DIR__ . '/..' . '/onelogin/php-saml/src/Saml2/LogoutResponse.php',
'OneLogin\\Saml2\\Metadata' => __DIR__ . '/..' . '/onelogin/php-saml/src/Saml2/Metadata.php',
'OneLogin\\Saml2\\Response' => __DIR__ . '/..' . '/onelogin/php-saml/src/Saml2/Response.php',
'OneLogin\\Saml2\\Settings' => __DIR__ . '/..' . '/onelogin/php-saml/src/Saml2/Settings.php',
'OneLogin\\Saml2\\Utils' => __DIR__ . '/..' . '/onelogin/php-saml/src/Saml2/Utils.php',
'OneLogin\\Saml2\\ValidationError' => __DIR__ . '/..' . '/onelogin/php-saml/src/Saml2/ValidationError.php',
'RobRichards\\XMLSecLibs\\Utils\\XPath' => __DIR__ . '/..' . '/robrichards/xmlseclibs/src/Utils/XPath.php',
'RobRichards\\XMLSecLibs\\XMLSecEnc' => __DIR__ . '/..' . '/robrichards/xmlseclibs/src/XMLSecEnc.php',
'RobRichards\\XMLSecLibs\\XMLSecurityDSig' => __DIR__ . '/..' . '/robrichards/xmlseclibs/src/XMLSecurityDSig.php',
'RobRichards\\XMLSecLibs\\XMLSecurityKey' => __DIR__ . '/..' . '/robrichards/xmlseclibs/src/XMLSecurityKey.php',
);
public static function getInitializer(ClassLoader $loader)

View File

@ -46,58 +46,94 @@
},
{
"name": "onelogin/php-saml",
"version": "2.10.5",
"version_normalized": "2.10.5.0",
"version": "v3.0.0",
"version_normalized": "3.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/onelogin/php-saml.git",
"reference": "3319d7707f342e38291eee6b01a4a5f8df1b333b"
"reference": "920c2240e48c9a74aad4129720f48fbf3d5fee47"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/onelogin/php-saml/zipball/3319d7707f342e38291eee6b01a4a5f8df1b333b",
"reference": "3319d7707f342e38291eee6b01a4a5f8df1b333b",
"url": "https://api.github.com/repos/onelogin/php-saml/zipball/920c2240e48c9a74aad4129720f48fbf3d5fee47",
"reference": "920c2240e48c9a74aad4129720f48fbf3d5fee47",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-mcrypt": "*",
"ext-openssl": "*",
"php": ">=5.3.2"
"php": ">=5.4",
"robrichards/xmlseclibs": "^3.0"
},
"require-dev": {
"pdepend/pdepend": "1.1.0",
"phploc/phploc": "*",
"phpunit/phpunit": "4.8",
"satooshi/php-coveralls": "1.0.1",
"sebastian/phpcpd": "*",
"squizlabs/php_codesniffer": "*"
"pdepend/pdepend": "^2.5.0",
"php-coveralls/php-coveralls": "^1.0.2 || ^2.0",
"phploc/phploc": "^2.1 || ^3.0 || ^4.0",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1",
"sebastian/phpcpd": "^2.0 || ^3.0 || ^4.0",
"squizlabs/php_codesniffer": "^3.1.1"
},
"suggest": {
"ext-curl": "Install curl lib to be able to use the IdPMetadataParser for parsing remote XMLs",
"ext-gettext": "Install gettext and php5-gettext libs to handle translations",
"ext-mcrypt": "Install mcrypt and php5-mcrypt libs in order to support encryption",
"lib-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)"
"ext-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)"
},
"time": "2017-03-13T09:56:49+00:00",
"time": "2018-10-02T16:02:37+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
"extlib/xmlseclibs",
"lib/Saml",
"lib/Saml2"
]
"psr-4": {
"OneLogin\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "OneLogin PHP SAML Toolkit",
"homepage": "https://onelogin.zendesk.com/hc/en-us/sections/200245634-SAML-Toolkits",
"homepage": "https://developers.onelogin.com/saml/php",
"keywords": [
"SAML2",
"onelogin",
"saml"
]
},
{
"name": "robrichards/xmlseclibs",
"version": "3.0.2",
"version_normalized": "3.0.2.0",
"source": {
"type": "git",
"url": "https://github.com/robrichards/xmlseclibs.git",
"reference": "1f4de0c0d121922aafd8c62c2a9f5e528830cf38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/1f4de0c0d121922aafd8c62c2a9f5e528830cf38",
"reference": "1f4de0c0d121922aafd8c62c2a9f5e528830cf38",
"shasum": ""
},
"require": {
"ext-openssl": "*",
"php": ">= 5.4"
},
"time": "2018-09-27T13:24:13+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"RobRichards\\XMLSecLibs\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "A PHP library for XML Security",
"homepage": "https://github.com/robrichards/xmlseclibs",
"keywords": [
"security",
"signature",
"xml",
"xmldsig"
]
}
]

View File

@ -1,7 +0,0 @@
service_name: travis-ci
src_dir: lib
coverage_clover: tests/build/logs/clover.xml
json_path: tests/build/logs/coveralls-upload.json

View File

@ -1,14 +0,0 @@
*.swp
*~
.DS_Store
/settings.php
/demo1/settings.php
/demo-old/settings.php
/certs/sp.key
/certs/sp.crt
/certs/metadata.key
/certs/metadata.crt
/tests/build
/vendor
/composer.lock
/.idea

View File

@ -1,36 +0,0 @@
language: php
php:
- 5.6
- 5.5
- 5.4
# - 5.3
- 7.0
env:
- TRAVIS=true
matrix:
fast_finish: true
before_install:
- composer self-update || true
- composer install --prefer-source --no-interaction
before_script:
- phpenv config-rm xdebug.ini
script:
- vendor/bin/phpunit --bootstrap tests/bootstrap.php --configuration tests/phpunit.xml
- php vendor/bin/phpcpd --exclude tests --exclude vendor .
- php vendor/bin/phploc . --exclude vendor
- php vendor/bin/phploc lib/.
- mkdir -p tests/build/dependences
- php vendor/bin/pdepend --summary-xml=tests/build/logs/dependence-summary.xml --jdepend-chart=tests/build/dependences/jdepend.svg --overview-pyramid=tests/build/dependences/pyramid.svg lib/.
- php vendor/bin/phpcs --standard=tests/ZendModStandard lib/Saml2 demo1 demo2 demo-old endpoints tests/src
after_script:
- export TRAVIS=https://travis-ci.org/onelogin/php-saml
- echo $TRAVIS
- echo $TRAVIS_JOB_ID
- php vendor/bin/coveralls --config .coveralls.yml -v

View File

@ -1,5 +1,35 @@
CHANGELOG
=========
v.3.0.0 (pending)
* Remove mcrypt dependency. Compatible with PHP 7.2
* xmlseclibs now is not part of the toolkit and need to be installed from original source
v.2.12.0
* Improve Time management. Use DateTime/DateTimeZone classes.
* Escape error messages in debug mode
* Improve phpdoc
* Add an extra filter to the url to be used on redirection
* [#242](https://github.com/onelogin/php-saml/pull/242) Document that SHA-1 must not be used
* [#250](https://github.com/onelogin/php-saml/pull/250) Fixed issue with IdPMetadataParser only keeping 1 certificate when multiple certificates of a single type were provided.
* [#263](https://github.com/onelogin/php-saml/issues/263) Fix incompatibility with ADFS on SLO. When on php saml settings NameID Format is set as unspecified but the SAMLResponse has no NameID Format, no NameID Format should be specified on LogoutRequest.
v.2.11.0
* [#236](https://github.com/onelogin/php-saml/pull/236) Exclude unnecesary files from Composer production downloads
* [#226](https://github.com/onelogin/php-saml/pull/226) Add possibility to handle nameId NameQualifier attribute in SLO Request
* Improve logout documentation on Readme.
* Improve multi-certificate support
v.2.10.7
* Fix IdPMetadataParser. The SingleLogoutService retrieved method was wrong
* [#201](https://github.com/onelogin/php-saml/issues/201) Fix issues with SP entity_id, acs url and sls url that contains &
v.2.10.6
* [#206](https://github.com/onelogin/php-saml/pull/206)Be able to register future SP x509cert on the settings and publish it on SP metadata
* [#206](https://github.com/onelogin/php-saml/pull/206) Be able to register more than 1 Identity Provider x509cert, linked with an specific use (signing or encryption)
* [#206](https://github.com/onelogin/php-saml/pull/206) Support the ability to parse IdP XML metadata (remote url or file) and be able to inject the data obtained on the settings.
v.2.10.5
* Be able to get at the auth object the last processed ID
* Improve NameID Format support

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,28 @@
<?php
// Create an __autoload function
// Create an __autoload function
// (can conflicts other autoloaders)
// http://php.net/manual/en/language.oop5.autoload.php
$libDir = dirname(__FILE__) . '/lib/Saml2/';
$extlibDir = dirname(__FILE__) . '/extlib/';
// Load composer
if (file_exists('vendor/autoload.php')) {
require 'vendor/autoload.php';
// Load composer vendor folder if any
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
require __DIR__ . '/vendor/autoload.php';
}
// Load now external libs
require_once $extlibDir . 'xmlseclibs/xmlseclibs.php';
/*
// Load xmlseclibs
$xmlseclibsSrcDir = '';
include_once $xmlseclibsSrcDir.'/XMLSecEnc.php';
include_once $xmlseclibsSrcDir.'/XMLSecurityDSig.php';
include_once $xmlseclibsSrcDir.'/XMLSecurityKey.php';
include_once $xmlseclibsSrcDir.'/Utils/XPath.php';
*/
// Load php-saml
$libDir = __DIR__ . '/src/Saml2/';
$folderInfo = scandir($libDir);
@ -22,4 +31,4 @@ foreach ($folderInfo as $element) {
include_once $libDir.$element;
}
}

View File

@ -1,18 +1,18 @@
<?php
$advancedSettings = array (
$advancedSettings = array(
// Compression settings
// Compression settings
// Handle if the getRequest/getResponse methods will return the Request/Response deflated.
// But if we provide a $deflate boolean parameter to the getRequest or getResponse
// method it will have priority over the compression settings.
'compress' => array (
'compress' => array(
'requests' => true,
'responses' => true
),
// Security settings
'security' => array (
'security' => array(
/** signatures and encryptions offered */
@ -33,7 +33,7 @@ $advancedSettings = array (
'logoutResponseSigned' => false,
/* Sign the Metadata
False || True (use sp certs) || array (
False || True (use sp certs) || array(
keyFileName => 'metadata.key',
certFileName => 'metadata.crt'
)
@ -66,7 +66,7 @@ $advancedSettings = array (
// Authentication context.
// Set to false and no AuthContext will be sent in the AuthNRequest,
// Set true or don't present this parameter and you will get an AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
// Set an array with the possible auth context values: array ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509'),
// Set an array with the possible auth context values: array('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509'),
'requestedAuthnContext' => false,
// Allows the authn comparison parameter to be set, defaults to 'exact' if
@ -87,14 +87,16 @@ $advancedSettings = array (
// 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
// 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'
// 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'
'signatureAlgorithm' => 'http://www.w3.org/2000/09/xmldsig#rsa-sha1',
// Notice that rsa-sha1 is a deprecated algorithm and should not be used
'signatureAlgorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
// Algorithm that the toolkit will use on digest process. Options:
// 'http://www.w3.org/2000/09/xmldsig#sha1'
// 'http://www.w3.org/2001/04/xmlenc#sha256'
// 'http://www.w3.org/2001/04/xmldsig-more#sha384'
// 'http://www.w3.org/2001/04/xmlenc#sha512'
'digestAlgorithm' => 'http://www.w3.org/2000/09/xmldsig#sha1',
// Notice that sha1 is a deprecated algorithm and should not be used
'digestAlgorithm' => 'http://www.w3.org/2001/04/xmlenc#sha256',
// ADFS URL-Encodes SAML data as lowercase, and the toolkit by default uses
// uppercase. Turn it True for ADFS compatibility on signature verification
@ -102,19 +104,19 @@ $advancedSettings = array (
),
// Contact information template, it is recommended to suply a technical and support contacts
'contactPerson' => array (
'technical' => array (
'contactPerson' => array(
'technical' => array(
'givenName' => '',
'emailAddress' => ''
),
'support' => array (
'support' => array(
'givenName' => '',
'emailAddress' => ''
),
),
// Organization information template, the info in en_US lang is recomended, add more if required
'organization' => array (
'organization' => array(
'en-US' => array(
'name' => '',
'displayname' => '',

View File

@ -1,12 +0,0 @@
<?php
/**
* Compability with the old PHP Toolkit
*/
define('ONELOGIN_SAML_DIR', 'lib/Saml/');
require_once ONELOGIN_SAML_DIR . 'AuthRequest.php';
require_once ONELOGIN_SAML_DIR . 'Response.php';
require_once ONELOGIN_SAML_DIR . 'Settings.php';
require_once ONELOGIN_SAML_DIR . 'XmlSec.php';
require_once ONELOGIN_SAML_DIR . 'Metadata.php';

View File

@ -2,15 +2,12 @@
"name": "onelogin/php-saml",
"description": "OneLogin PHP SAML Toolkit",
"license": "MIT",
"version": "2.10.5",
"homepage": "https://onelogin.zendesk.com/hc/en-us/sections/200245634-SAML-Toolkits",
"homepage": "https://developers.onelogin.com/saml/php",
"keywords": ["saml", "saml2", "onelogin"],
"autoload": {
"classmap": [
"extlib/xmlseclibs",
"lib/Saml",
"lib/Saml2"
]
"psr-4": {
"OneLogin\\": "src/"
}
},
"support": {
"email": "sixto.garcia@onelogin.com",
@ -18,22 +15,20 @@
"source": "https://github.com/onelogin/php-saml/"
},
"require": {
"php": ">=5.3.2",
"ext-openssl": "*",
"ext-dom": "*",
"ext-mcrypt": "*"
"php": ">=5.4",
"robrichards/xmlseclibs": "^3.0"
},
"require-dev": {
"phpunit/phpunit": "4.8",
"satooshi/php-coveralls": "1.0.1",
"sebastian/phpcpd": "*",
"phploc/phploc": "*",
"pdepend/pdepend" : "1.1.0",
"squizlabs/php_codesniffer": "*"
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1",
"php-coveralls/php-coveralls": "^1.0.2 || ^2.0",
"sebastian/phpcpd": "^2.0 || ^3.0 || ^4.0",
"phploc/phploc": "^2.1 || ^3.0 || ^4.0",
"pdepend/pdepend": "^2.5.0",
"squizlabs/php_codesniffer": "^3.1.1"
},
"suggest": {
"lib-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)",
"ext-mcrypt": "Install mcrypt and php5-mcrypt libs in order to support encryption",
"ext-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)",
"ext-curl": "Install curl lib to be able to use the IdPMetadataParser for parsing remote XMLs",
"ext-gettext": "Install gettext and php5-gettext libs to handle translations"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +0,0 @@
<?php
class OneLogin_Saml_AuthRequest
{
/**
* @var OneLogin_Saml2_Auth object
*/
protected $auth;
/**
* Constructs the OneLogin_Saml2_Auth, initializing
* the SP SAML instance.
*
* @param array|object $settings SAML Toolkit Settings
*/
public function __construct($settings)
{
$this->auth = new OneLogin_Saml2_Auth($settings);
}
/**
* Obtains the SSO URL containing the AuthRequest
* message deflated.
*
* @param string|null $returnTo
*
* @return string
*
* @throws OneLogin_Saml2_Error
*/
public function getRedirectUrl($returnTo = null)
{
$settings = $this->auth->getSettings();
$authnRequest = new OneLogin_Saml2_AuthnRequest($settings);
$parameters = array('SAMLRequest' => $authnRequest->getRequest());
if (!empty($returnTo)) {
$parameters['RelayState'] = $returnTo;
} else {
$parameters['RelayState'] = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
}
$url = OneLogin_Saml2_Utils::redirect($this->auth->getSSOurl(), $parameters, true);
return $url;
}
/**
* @return string
*/
protected function _generateUniqueID()
{
return OneLogin_Saml2_Utils::generateUniqueID();
}
/**
* @return string
*/
protected function _getTimestamp()
{
$defaultTimezone = date_default_timezone_get();
date_default_timezone_set('UTC');
$timestamp = strftime("%Y-%m-%dT%H:%M:%SZ");
date_default_timezone_set($defaultTimezone);
return $timestamp;
}
}

View File

@ -1,39 +0,0 @@
<?php
class OneLogin_Saml_Metadata
{
const VALIDITY_SECONDS = 604800; // 1 week
protected $_settings;
/**
* @param array|object|null $settings Setting data
*/
public function __construct($settings = null)
{
$auth = new OneLogin_Saml2_Auth($settings);
$this->_settings = $auth->getSettings();
}
/**
* @return string
*
* @throws OneLogin_Saml2_Error
*/
public function getXml()
{
return $this->_settings->getSPMetadata();
}
/**
* @return string
*/
protected function _getMetadataValidTimestamp()
{
$timeZone = date_default_timezone_get();
date_default_timezone_set('UTC');
$time = strftime("%Y-%m-%dT%H:%M:%SZ", time() + self::VALIDITY_SECONDS);
date_default_timezone_set($timeZone);
return $time;
}
}

View File

@ -1,39 +0,0 @@
<?php
class OneLogin_Saml_Response extends OneLogin_Saml2_Response
{
/**
* Constructor that process the SAML Response,
* Internally initializes an SP SAML instance
* and an OneLogin_Saml2_Response.
*
* @param array|object $oldSettings Settings
* @param string $assertion SAML Response
*/
public function __construct($oldSettings, $assertion)
{
$auth = new OneLogin_Saml2_Auth($oldSettings);
$settings = $auth->getSettings();
parent::__construct($settings, $assertion);
}
/**
* Retrieves an Array with the logged user data.
*
* @return array
*/
public function get_saml_attributes()
{
return $this->getAttributes();
}
/**
* Retrieves the nameId
*
* @return string
*/
public function get_nameid()
{
return $this->getNameId();
}
}

View File

@ -1,80 +0,0 @@
<?php
/**
* Holds SAML settings for the SamlResponse and SamlAuthRequest classes.
*
* These settings need to be filled in by the user prior to being used.
*/
class OneLogin_Saml_Settings
{
const NAMEID_EMAIL_ADDRESS = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress';
const NAMEID_X509_SUBJECT_NAME = 'urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName';
const NAMEID_WINDOWS_DOMAIN_QUALIFIED_NAME = 'urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName';
const NAMEID_KERBEROS = 'urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos';
const NAMEID_ENTITY = 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity';
const NAMEID_TRANSIENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient';
const NAMEID_PERSISTENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent';
/**
* The URL to submit SAML authentication requests to.
* @var string
*/
public $idpSingleSignOnUrl = '';
/**
* The URL to submit SAML Logout Request to.
* @var string
*/
public $idpSingleLogOutUrl = '';
/**
* The x509 certificate used to authenticate the request.
* @var string
*/
public $idpPublicCertificate = '';
/**
* The URL where to the SAML Response/SAML Assertion will be posted.
* @var string
*/
public $spReturnUrl = '';
/**
* The name of the application.
* @var string
*/
public $spIssuer = 'php-saml';
/**
* Specifies what format to return the authentication token, i.e, the email address.
* @var string
*/
public $requestedNameIdFormat = self::NAMEID_EMAIL_ADDRESS;
/**
* @return array<string,array> Values (compatibility with the new version)
*/
public function getValues()
{
$values = array();
$values['sp'] = array();
$values['sp']['entityId'] = $this->spIssuer;
$values['sp']['assertionConsumerService'] = array(
'url' => $this->spReturnUrl,
);
$values['sp']['NameIDFormat'] = $this->requestedNameIdFormat;
$values['idp'] = array();
$values['idp']['entityId'] = $this->idpSingleSignOnUrl;
$values['idp']['singleSignOnService'] = array(
'url' => $this->idpSingleSignOnUrl,
);
$values['idp']['singleLogoutService'] = array(
'url' => $this->idpSingleLogOutUrl,
);
$values['idp']['x509cert'] = $this->idpPublicCertificate;
return $values;
}
}

View File

@ -1,110 +0,0 @@
<?php
/**
* Determine if the SAML response is valid using a provided x509 certificate.
*/
class OneLogin_Saml_XmlSec
{
/**
* A SamlResponse class provided to the constructor.
* @var OneLogin_Saml_Settings
*/
protected $_settings;
/**
* The document to be tested.
* @var DomDocument
*/
protected $_document;
/**
* Construct the SamlXmlSec object.
*
* @param OneLogin_Saml_Settings $settings A SamlResponse settings object containing the necessary
* x509 certicate to test the document.
* @param OneLogin_Saml_Response $response The document to test.
*/
public function __construct(OneLogin_Saml_Settings $settings, OneLogin_Saml_Response $response)
{
$this->_settings = $settings;
$this->_document = clone $response->document;
}
/**
* Verify that the document only contains a single Assertion
*
* @return bool TRUE if the document passes.
*/
public function validateNumAssertions()
{
$rootNode = $this->_document;
$assertionNodes = $rootNode->getElementsByTagName('Assertion');
return ($assertionNodes->length == 1);
}
/**
* Verify that the document is still valid according
*
* @return bool
*/
public function validateTimestamps()
{
$rootNode = $this->_document;
$timestampNodes = $rootNode->getElementsByTagName('Conditions');
for ($i = 0; $i < $timestampNodes->length; $i++) {
$nbAttribute = $timestampNodes->item($i)->attributes->getNamedItem("NotBefore");
$naAttribute = $timestampNodes->item($i)->attributes->getNamedItem("NotOnOrAfter");
if ($nbAttribute && strtotime($nbAttribute->textContent) > time()) {
return false;
}
if ($naAttribute && strtotime($naAttribute->textContent) <= time()) {
return false;
}
}
return true;
}
/**
* @return bool
*
* @throws Exception
*/
public function isValid()
{
$singleAssertion = $this->validateNumAssertions();
if (!$singleAssertion) {
throw new Exception('Multiple assertions are not supported');
}
$validTimestamps = $this->validateTimestamps();
if (!$validTimestamps) {
throw new Exception('Timing issues (please check your clock settings)');
}
$objXMLSecDSig = new XMLSecurityDSig();
$objDSig = $objXMLSecDSig->locateSignature($this->_document);
if (!$objDSig) {
throw new Exception('Cannot locate Signature Node');
}
$objXMLSecDSig->canonicalizeSignedInfo();
$objXMLSecDSig->idKeys = array('ID');
$objKey = $objXMLSecDSig->locateKey();
if (!$objKey) {
throw new Exception('We have no idea about the key');
}
try {
$objXMLSecDSig->validateReference();
} catch (Exception $e) {
throw new Exception('Reference Validation Failed');
}
XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig);
$objKey->loadKey($this->_settings->idpPublicCertificate, false, true);
return ($objXMLSecDSig->verify($objKey) === 1);
}
}

View File

@ -1,6 +0,0 @@
{
"php-saml": {
"version": "2.10.5",
"released": "13/03/2017"
}
}

View File

@ -1,26 +0,0 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "test"
msgstr "test"
msgid "test2: %s"
msgstr "test2: %s"
#: index.php:15 endpoints/acs.php:35
msgid "User attributes:"
msgstr ""
#: index.php:16 endpoints/acs.php:36
msgid "Name"
msgstr ""
#: index.php:16 endpoints/acs.php:36
msgid "Values"
msgstr ""
#: index.php:26 endpoints/acs.php:46
msgid "Attributes not found"
msgstr ""

View File

@ -1,27 +0,0 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "test"
msgstr "prueba"
msgid "test2: %s"
msgstr "prueba2: %s"
#: index.php:15 endpoints/acs.php:35
msgid "User attributes:"
msgstr "Atributos del usuario:"
#: index.php:16 endpoints/acs.php:36
msgid "Name"
msgstr "Nombre"
#: index.php:16 endpoints/acs.php:36
msgid "Values"
msgstr "Valores"
#: index.php:26 endpoints/acs.php:46
msgid "Attributes not found"
msgstr "Atributos no encontrados"

View File

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<phpdoc>
<title>OneLogin's SAML PHP Toolkit</title>
<parser>
<default-package-name>OneLogin_SAML_Toolkit</default-package-name>
<target>docs/Saml3</target>
</parser>
<extensions>
<extension>php</extension>
</extensions>
<transformer>
<target>docs/Saml3</target>
</transformer>
<transformations>
<template name="onelogin" />
<!-- <template name="clean" /> -->
</transformations>
<files>
<directory>lib/Saml2/*</directory>
<ignore>lib/Saml/*</ignore>
<ignore>tests/*</ignore>
<ignore>demo1/*</ignore>
<ignore>demo2/*</ignore>
<ignore>demo-old/*</ignore>
<ignore>endpoints/*</ignore>
<ignore>extlib/*</ignore>
<ignore>locale/*</ignore>
<ignore>docs/*</ignore>
<ignore>vendor/*</ignore>
<ignore>compatibility.php</ignore>
<ignore>_toolkit_loader.php</ignore>
<ignore>settings.php</ignore>
<ignore>settings_example.php</ignore>
<ignore>advanced_settings.php</ignore>
<ignore>advanced_settings_example</ignore>
</files>
</phpdoc>

View File

@ -1,6 +1,6 @@
<?php
$settings = array (
$settings = array(
// If 'strict' is True, then the PHP Toolkit will reject unsigned
// or unencrypted messages if it expects them signed or encrypted
// Also will reject the messages if not strictly follow the SAML
@ -10,19 +10,19 @@ $settings = array (
// Enable debug mode (to print errors)
'debug' => false,
// Set a BaseURL to be used instead of try to guess
// Set a BaseURL to be used instead of try to guess
// the BaseURL of the view that process the SAML Message.
// Ex. http://sp.example.com/
// http://example.com/sp/
// http://example.com/sp/
'baseurl' => null,
// Service Provider Data that we are deploying
'sp' => array (
'sp' => array(
// Identifier of the SP entity (must be a URI)
'entityId' => '',
// Specifies info about where and how the <AuthnResponse> message MUST be
// returned to the requester, in this case our SP.
'assertionConsumerService' => array (
'assertionConsumerService' => array(
// URL Location where the <Response> from the IdP will be returned
'url' => '',
// SAML protocol binding to be used when returning the <Response>
@ -32,7 +32,7 @@ $settings = array (
),
// If you need to specify requested attributes, set a
// attributeConsumingService. nameFormat, attributeValue and
// friendlyName can be omitted. Otherwise remove this section.
// friendlyName can be omitted. Otherwise remove this section.
"attributeConsumingService"=> array(
"ServiceName" => "SP test",
"serviceDescription" => "Test Service",
@ -48,7 +48,7 @@ $settings = array (
),
// Specifies info about where and how the <Logout Response> message MUST be
// returned to the requester, in this case our SP.
'singleLogoutService' => array (
'singleLogoutService' => array(
// URL Location where the <Response> from the IdP will be returned
'url' => '',
// SAML protocol binding to be used when returning the <Response>
@ -65,14 +65,23 @@ $settings = array (
// the certs folder. But we can also provide them with the following parameters
'x509cert' => '',
'privateKey' => '',
/*
* Key rollover
* If you plan to update the SP x509cert and privateKey
* you can define here the new x509cert and it will be
* published on the SP metadata so Identity Providers can
* read them and get ready for rollover.
*/
// 'x509certNew' => '',
),
// Identity Provider Data that we want connect with our SP
'idp' => array (
'idp' => array(
// Identifier of the IdP entity (must be a URI)
'entityId' => '',
// SSO endpoint info of the IdP. (Authentication Request protocol)
'singleSignOnService' => array (
'singleSignOnService' => array(
// URL Target of the IdP where the SP will send the Authentication Request Message
'url' => '',
// SAML protocol binding to be used when returning the <Response>
@ -81,7 +90,7 @@ $settings = array (
'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
),
// SLO endpoint info of the IdP.
'singleLogoutService' => array (
'singleLogoutService' => array(
// URL Location of the IdP where the SP will send the SLO Request
'url' => '',
// SAML protocol binding to be used when returning the <Response>
@ -92,7 +101,10 @@ $settings = array (
// Public x509 certificate of the IdP
'x509cert' => '',
/*
* Instead of use the whole x509cert you can use a fingerprint
* Instead of use the whole x509cert you can use a fingerprint in
* order to validate the SAMLResponse, but we don't recommend to use
* that method on production since is exploitable by a collision
* attack.
* (openssl x509 -noout -fingerprint -in "idp.crt" to generate it,
* or add for example the -sha256 , -sha384 or -sha512 parameter)
*
@ -102,5 +114,21 @@ $settings = array (
*/
// 'certFingerprint' => '',
// 'certFingerprintAlgorithm' => 'sha1',
/* In some scenarios the IdP uses different certificates for
* signing/encryption, or is under key rollover phase and more
* than one certificate is published on IdP metadata.
* In order to handle that the toolkit offers that parameter.
* (when used, 'x509cert' and 'certFingerprint' values are
* ignored).
*/
// 'x509certMulti' => array(
// 'signing' => array(
// 0 => '<cert1-string>',
// ),
// 'encryption' => array(
// 0 => '<cert2-string>',
// )
// ),
),
);

View File

@ -1,15 +1,33 @@
<?php
/**
* This file is part of php-saml.
*
* (c) OneLogin Inc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package OneLogin
* @author OneLogin Inc <saml-info@onelogin.com>
* @license MIT https://github.com/onelogin/php-saml/blob/master/LICENSE
* @link https://github.com/onelogin/php-saml
*/
namespace OneLogin\Saml2;
use RobRichards\XMLSecLibs\XMLSecurityKey;
use Exception;
/**
* Main class of OneLogin's PHP Toolkit
*
*/
class OneLogin_Saml2_Auth
class Auth
{
/**
* Settings data.
*
* @var OneLogin_Saml2_Settings
* @var Settings
*/
private $_settings;
@ -20,6 +38,13 @@ class OneLogin_Saml2_Auth
*/
private $_attributes = array();
/**
* User attributes data with FriendlyName index.
*
* @var array
*/
private $_attributesWithFriendlyName = array();
/**
* NameID
*
@ -34,6 +59,20 @@ class OneLogin_Saml2_Auth
*/
private $_nameidFormat;
/**
* NameID NameQualifier
*
* @var string
*/
private $_nameidNameQualifier;
/**
* NameID SP NameQualifier
*
* @var string
*/
private $_nameidSPNameQualifier;
/**
* If user is authenticated.
*
@ -54,7 +93,7 @@ class OneLogin_Saml2_Auth
* SessionNotOnOrAfter. When the user is logged, this stored it
* from the AuthnStatement of the SAML Response
*
* @var DateTime
* @var int|null
*/
private $_sessionExpiration;
@ -76,7 +115,7 @@ class OneLogin_Saml2_Auth
* The NotOnOrAfter value of the valid SubjectConfirmationData
* node (if any) of the last assertion processed
*
* @var DateTime
* @var int
*/
private $_lastAssertionNotOnOrAfter;
@ -88,11 +127,18 @@ class OneLogin_Saml2_Auth
private $_errors = array();
/**
* Reason of the last error.
* Last error object.
*
* @var string
* @var Error|null
*/
private $_errorReason;
private $_lastErrorException;
/**
* Last error.
*
* @var string|null
*/
private $_lastError;
/**
* Last AuthNRequest ID or LogoutRequest ID generated by this Service Provider
@ -114,24 +160,27 @@ class OneLogin_Saml2_Auth
* (SAMLResponse, LogoutResponse). If the SAMLResponse was
* encrypted, by default tries to return the decrypted XML
*
* @var string
* @var string|\DomDocument|null
*/
private $_lastResponse;
/**
* Initializes the SP SAML instance.
*
* @param array|object|null $oldSettings Setting data (You can provide a OneLogin_Saml_Settings, the settings object of the Saml folder implementation)
* @param array|null $settings Setting data
*
* @throws Exception
* @throws Error
*/
public function __construct($oldSettings = null)
public function __construct(array $settings = null)
{
$this->_settings = new OneLogin_Saml2_Settings($oldSettings);
$this->_settings = new Settings($settings);
}
/**
* Returns the settings info
*
* @return OneLogin_Saml2_Settings The settings data.
* @return Settings The settings data.
*/
public function getSettings()
{
@ -143,14 +192,14 @@ class OneLogin_Saml2_Auth
*
* @param bool $value Strict parameter
*
* @return array The settings data.
* @throws Error
*/
public function setStrict($value)
{
if (! (is_bool($value))) {
throw new OneLogin_Saml2_Error(
if (!is_bool($value)) {
throw new Error(
'Invalid value passed to setStrict()',
OneLogin_Saml2_Error::SETTINGS_INVALID_SYNTAX
Error::SETTINGS_INVALID_SYNTAX
);
}
@ -162,21 +211,25 @@ class OneLogin_Saml2_Auth
*
* @param string|null $requestId The ID of the AuthNRequest sent by this SP to the IdP
*
* @throws OneLogin_Saml2_Error
* @throws Error
* @throws ValidationError
*/
public function processResponse($requestId = null)
{
$this->_errors = array();
$this->_errorReason = null;
if (isset($_POST) && isset($_POST['SAMLResponse'])) {
$this->_lastError = $this->_lastErrorException = null;
if (isset($_POST['SAMLResponse'])) {
// AuthnResponse -- HTTP_POST Binding
$response = new OneLogin_Saml2_Response($this->_settings, $_POST['SAMLResponse']);
$response = new Response($this->_settings, $_POST['SAMLResponse']);
$this->_lastResponse = $response->getXMLDocument();
if ($response->isValid($requestId)) {
$this->_attributes = $response->getAttributes();
$this->_attributesWithFriendlyName = $response->getAttributesWithFriendlyName();
$this->_nameid = $response->getNameId();
$this->_nameidFormat = $response->getNameIdFormat();
$this->_nameidNameQualifier = $response->getNameIdNameQualifier();
$this->_nameidSPNameQualifier = $response->getNameIdSPNameQualifier();
$this->_authenticated = true;
$this->_sessionIndex = $response->getSessionIndex();
$this->_sessionExpiration = $response->getSessionNotOnOrAfter();
@ -185,13 +238,14 @@ class OneLogin_Saml2_Auth
$this->_lastAssertionNotOnOrAfter = $response->getAssertionNotOnOrAfter();
} else {
$this->_errors[] = 'invalid_response';
$this->_errorReason = $response->getError();
$this->_lastErrorException = $response->getErrorException();
$this->_lastError = $response->getError();
}
} else {
$this->_errors[] = 'invalid_binding';
throw new OneLogin_Saml2_Error(
throw new Error(
'SAML Response not found, Only supported HTTP_POST Binding',
OneLogin_Saml2_Error::SAML_RESPONSE_NOT_FOUND
Error::SAML_RESPONSE_NOT_FOUND
);
}
}
@ -199,55 +253,58 @@ class OneLogin_Saml2_Auth
/**
* Process the SAML Logout Response / Logout Request sent by the IdP.
*
* @param bool $keepLocalSession When false will destroy the local session, otherwise will keep it
* @param string|null $requestId The ID of the LogoutRequest sent by this SP to the IdP
* @param bool $retrieveParametersFromServer
* @param callable $cbDeleteSession
* @param bool $stay True if we want to stay (returns the url string) False to redirect
* @param bool $keepLocalSession When false will destroy the local session, otherwise will keep it
* @param string|null $requestId The ID of the LogoutRequest sent by this SP to the IdP
* @param bool $retrieveParametersFromServer True if we want to use parameters from $_SERVER to validate the signature
* @param callable $cbDeleteSession Callback to be executed to delete session
* @param bool $stay True if we want to stay (returns the url string) False to redirect
*
* @return string|void
* @return string|null
*
* @throws OneLogin_Saml2_Error
* @throws Error
*/
public function processSLO($keepLocalSession = false, $requestId = null, $retrieveParametersFromServer = false, $cbDeleteSession = null, $stay = false)
{
$this->_errors = array();
$this->_errorReason = null;
if (isset($_GET) && isset($_GET['SAMLResponse'])) {
$logoutResponse = new OneLogin_Saml2_LogoutResponse($this->_settings, $_GET['SAMLResponse']);
$this->_lastError = $this->_lastErrorException = null;
if (isset($_GET['SAMLResponse'])) {
$logoutResponse = new LogoutResponse($this->_settings, $_GET['SAMLResponse']);
$this->_lastResponse = $logoutResponse->getXML();
if (!$logoutResponse->isValid($requestId, $retrieveParametersFromServer)) {
$this->_errors[] = 'invalid_logout_response';
$this->_errorReason = $logoutResponse->getError();
} else if ($logoutResponse->getStatus() !== OneLogin_Saml2_Constants::STATUS_SUCCESS) {
$this->_lastErrorException = $logoutResponse->getErrorException();
$this->_lastError = $logoutResponse->getError();
} else if ($logoutResponse->getStatus() !== Constants::STATUS_SUCCESS) {
$this->_errors[] = 'logout_not_success';
} else {
$this->_lastMessageId = $logoutResponse->id;
if (!$keepLocalSession) {
if ($cbDeleteSession === null) {
OneLogin_Saml2_Utils::deleteLocalSession();
Utils::deleteLocalSession();
} else {
call_user_func($cbDeleteSession);
}
}
}
} else if (isset($_GET) && isset($_GET['SAMLRequest'])) {
$logoutRequest = new OneLogin_Saml2_LogoutRequest($this->_settings, $_GET['SAMLRequest']);
} else if (isset($_GET['SAMLRequest'])) {
$logoutRequest = new LogoutRequest($this->_settings, $_GET['SAMLRequest']);
$this->_lastRequest = $logoutRequest->getXML();
if (!$logoutRequest->isValid($retrieveParametersFromServer)) {
$this->_errors[] = 'invalid_logout_request';
$this->_errorReason = $logoutRequest->getError();
$this->_lastErrorException = $logoutRequest->getErrorException();
$this->_lastError = $logoutRequest->getError();
} else {
if (!$keepLocalSession) {
if ($cbDeleteSession === null) {
OneLogin_Saml2_Utils::deleteLocalSession();
Utils::deleteLocalSession();
} else {
call_user_func($cbDeleteSession);
}
}
$inResponseTo = $logoutRequest->id;
$this->_lastMessageId = $logoutRequest->id;
$responseBuilder = new OneLogin_Saml2_LogoutResponse($this->_settings);
$responseBuilder = new LogoutResponse($this->_settings);
$responseBuilder->build($inResponseTo);
$this->_lastResponse = $responseBuilder->getXML();
@ -269,9 +326,9 @@ class OneLogin_Saml2_Auth
}
} else {
$this->_errors[] = 'invalid_binding';
throw new OneLogin_Saml2_Error(
throw new Error(
'SAML LogoutRequest/LogoutResponse not found. Only supported HTTP_REDIRECT Binding',
OneLogin_Saml2_Error::SAML_LOGOUTMESSAGE_NOT_FOUND
Error::SAML_LOGOUTMESSAGE_NOT_FOUND
);
}
}
@ -283,17 +340,18 @@ class OneLogin_Saml2_Auth
* @param string $url The target URL to redirect the user.
* @param array $parameters Extra parameters to be passed as part of the url
* @param bool $stay True if we want to stay (returns the url string) False to redirect
*
* @return string|null
*/
public function redirectTo($url = '', $parameters = array(), $stay = false)
public function redirectTo($url = '', array $parameters = array(), $stay = false)
{
assert('is_string($url)');
assert('is_array($parameters)');
assert(is_string($url));
if (empty($url) && isset($_REQUEST['RelayState'])) {
$url = $_REQUEST['RelayState'];
}
return OneLogin_Saml2_Utils::redirect($url, $parameters, $stay);
return Utils::redirect($url, $parameters, $stay);
}
/**
@ -316,6 +374,17 @@ class OneLogin_Saml2_Auth
return $this->_attributes;
}
/**
* Returns the set of SAML attributes indexed by FriendlyName
*
* @return array Attributes of the user.
*/
public function getAttributesWithFriendlyName()
{
return $this->_attributesWithFriendlyName;
}
/**
* Returns the nameID
*
@ -336,6 +405,26 @@ class OneLogin_Saml2_Auth
return $this->_nameidFormat;
}
/**
* Returns the nameID NameQualifier
*
* @return string The nameID NameQualifier of the assertion
*/
public function getNameIdNameQualifier()
{
return $this->_nameidNameQualifier;
}
/**
* Returns the nameID SP NameQualifier
*
* @return string The nameID SP NameQualifier of the assertion
*/
public function getNameIdSPNameQualifier()
{
return $this->_nameidSPNameQualifier;
}
/**
* Returns the SessionIndex
*
@ -349,7 +438,7 @@ class OneLogin_Saml2_Auth
/**
* Returns the SessionNotOnOrAfter
*
* @return DateTime|null The SessionNotOnOrAfter of the assertion
* @return int|null The SessionNotOnOrAfter of the assertion
*/
public function getSessionExpiration()
{
@ -369,11 +458,22 @@ class OneLogin_Saml2_Auth
/**
* Returns the reason for the last error
*
* @return string Error reason
* @return string|null Error reason
*/
public function getLastErrorReason()
{
return $this->_errorReason;
return $this->_lastError;
}
/**
* Returns the last error
*
* @return Exception|null Error
*/
public function getLastErrorException()
{
return $this->_lastErrorException;
}
/**
@ -385,7 +485,7 @@ class OneLogin_Saml2_Auth
*/
public function getAttribute($name)
{
assert('is_string($name)');
assert(is_string($name));
$value = null;
if (isset($this->_attributes[$name])) {
@ -394,23 +494,40 @@ class OneLogin_Saml2_Auth
return $value;
}
/**
* Returns the requested SAML attribute indexed by FriendlyName
*
* @param string $friendlyName The requested attribute of the user.
*
* @return array|null Requested SAML attribute ($friendlyName).
*/
public function getAttributeWithFriendlyName($friendlyName)
{
assert(is_string($friendlyName));
$value = null;
if (isset($this->_attributesWithFriendlyName[$friendlyName])) {
return $this->_attributesWithFriendlyName[$friendlyName];
}
return $value;
}
/**
* Initiates the SSO process.
*
* @param string|null $returnTo The target URL the user should be returned to after login.
* @param array $parameters Extra parameters to be added to the GET
* @param bool $forceAuthn When true the AuthNReuqest will set the ForceAuthn='true'
* @param bool $isPassive When true the AuthNReuqest will set the Ispassive='true'
* @param bool $forceAuthn When true the AuthNRequest will set the ForceAuthn='true'
* @param bool $isPassive When true the AuthNRequest will set the Ispassive='true'
* @param bool $stay True if we want to stay (returns the url string) False to redirect
* @param bool $setNameIdPolicy When true the AuthNReuqest will set a nameIdPolicy element
* @param bool $setNameIdPolicy When true the AuthNRequest will set a nameIdPolicy element
*
* @return If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters
* @return string|null If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters
*
* @throws Error
*/
public function login($returnTo = null, $parameters = array(), $forceAuthn = false, $isPassive = false, $stay = false, $setNameIdPolicy = true)
public function login($returnTo = null, array $parameters = array(), $forceAuthn = false, $isPassive = false, $stay = false, $setNameIdPolicy = true)
{
assert('is_array($parameters)');
$authnRequest = new OneLogin_Saml2_AuthnRequest($this->_settings, $forceAuthn, $isPassive, $setNameIdPolicy);
$authnRequest = new AuthnRequest($this->_settings, $forceAuthn, $isPassive, $setNameIdPolicy);
$this->_lastRequest = $authnRequest->getXML();
$this->_lastRequestID = $authnRequest->getId();
@ -421,7 +538,7 @@ class OneLogin_Saml2_Auth
if (!empty($returnTo)) {
$parameters['RelayState'] = $returnTo;
} else {
$parameters['RelayState'] = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
$parameters['RelayState'] = Utils::getSelfRoutedURLNoQuery();
}
$security = $this->_settings->getSecurityData();
@ -436,26 +553,25 @@ class OneLogin_Saml2_Auth
/**
* Initiates the SLO process.
*
* @param string|null $returnTo The target URL the user should be returned to after logout.
* @param array $parameters Extra parameters to be added to the GET
* @param string|null $nameId The NameID that will be set in the LogoutRequest.
* @param string|null $sessionIndex The SessionIndex (taken from the SAML Response in the SSO process).
* @param bool $stay True if we want to stay (returns the url string) False to redirect
* @param string|null $nameIdFormat The NameID Format will be set in the LogoutRequest.
* @param string|null $returnTo The target URL the user should be returned to after logout.
* @param array $parameters Extra parameters to be added to the GET
* @param string|null $nameId The NameID that will be set in the LogoutRequest.
* @param string|null $sessionIndex The SessionIndex (taken from the SAML Response in the SSO process).
* @param bool $stay True if we want to stay (returns the url string) False to redirect
* @param string|null $nameIdFormat The NameID Format will be set in the LogoutRequest.
* @param string|null $nameIdNameQualifier The NameID NameQualifier will be set in the LogoutRequest.
*
* @return If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters
* @return string|null If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters
*
* @throws OneLogin_Saml2_Error
* @throws Error
*/
public function logout($returnTo = null, $parameters = array(), $nameId = null, $sessionIndex = null, $stay = false, $nameIdFormat = null)
public function logout($returnTo = null, array $parameters = array(), $nameId = null, $sessionIndex = null, $stay = false, $nameIdFormat = null, $nameIdNameQualifier = null, $nameIdSPNameQualifier = null)
{
assert('is_array($parameters)');
$sloUrl = $this->getSLOurl();
if (empty($sloUrl)) {
throw new OneLogin_Saml2_Error(
throw new Error(
'The IdP does not support Single Log Out',
OneLogin_Saml2_Error::SAML_SINGLE_LOGOUT_NOT_SUPPORTED
Error::SAML_SINGLE_LOGOUT_NOT_SUPPORTED
);
}
@ -466,7 +582,7 @@ class OneLogin_Saml2_Auth
$nameIdFormat = $this->_nameidFormat;
}
$logoutRequest = new OneLogin_Saml2_LogoutRequest($this->_settings, null, $nameId, $sessionIndex, $nameIdFormat);
$logoutRequest = new LogoutRequest($this->_settings, null, $nameId, $sessionIndex, $nameIdFormat, $nameIdNameQualifier, $nameIdSPNameQualifier);
$this->_lastRequest = $logoutRequest->getXML();
$this->_lastRequestID = $logoutRequest->id;
@ -477,7 +593,7 @@ class OneLogin_Saml2_Auth
if (!empty($returnTo)) {
$parameters['RelayState'] = $returnTo;
} else {
$parameters['RelayState'] = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
$parameters['RelayState'] = Utils::getSelfRoutedURLNoQuery();
}
$security = $this->_settings->getSecurityData();
@ -504,7 +620,7 @@ class OneLogin_Saml2_Auth
/**
* Gets the SLO url.
*
* @return string The url of the Single Logout Service
* @return string|null The url of the Single Logout Service
*/
public function getSLOurl()
{
@ -529,46 +645,18 @@ class OneLogin_Saml2_Auth
/**
* Generates the Signature for a SAML Request
*
* @param string $samlRequest The SAML Request
* @param string $relayState The RelayState
* @param string $samlRequest The SAML Request
* @param string $relayState The RelayState
* @param string $signAlgorithm Signature algorithm method
*
* @return string A base64 encoded signature
*
* @throws Exception
* @throws OneLogin_Saml2_Error
* @throws Error
*/
public function buildRequestSignature($samlRequest, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA1)
public function buildRequestSignature($samlRequest, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA256)
{
$key = $this->_settings->getSPkey();
if (empty($key)) {
throw new OneLogin_Saml2_Error(
"Trying to sign the SAML Request but can't load the SP private key",
OneLogin_Saml2_Error::PRIVATE_KEY_NOT_FOUND
);
}
$key = $this->_settings->getSPkey();
$objKey = new XMLSecurityKey($signAlgorithm, array('type' => 'private'));
$objKey->loadKey($key, false);
$security = $this->_settings->getSecurityData();
if ($security['lowercaseUrlencoding']) {
$msg = 'SAMLRequest='.rawurlencode($samlRequest);
if (isset($relayState)) {
$msg .= '&RelayState='.rawurlencode($relayState);
}
$msg .= '&SigAlg=' . rawurlencode($signAlgorithm);
} else {
$msg = 'SAMLRequest='.urlencode($samlRequest);
if (isset($relayState)) {
$msg .= '&RelayState='.urlencode($relayState);
}
$msg .= '&SigAlg=' . urlencode($signAlgorithm);
}
$signature = $objKey->signData($msg);
return base64_encode($signature);
return $this->buildMessageSignature($samlRequest, $relayState, $signAlgorithm, "SAMLRequest");
}
/**
@ -581,16 +669,37 @@ class OneLogin_Saml2_Auth
* @return string A base64 encoded signature
*
* @throws Exception
* @throws OneLogin_Saml2_Error
* @throws Error
*/
public function buildResponseSignature($samlResponse, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA1)
public function buildResponseSignature($samlResponse, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA256)
{
return $this->buildMessageSignature($samlResponse, $relayState, $signAlgorithm, "SAMLResponse");
}
/**
* Generates the Signature for a SAML Message
*
* @param string $samlMessage The SAML Message
* @param string $relayState The RelayState
* @param string $signAlgorithm Signature algorithm method
* @param string $type "SAMLRequest" or "SAMLResponse"
*
* @return string A base64 encoded signature
*
* @throws Exception
* @throws Error
*/
private function buildMessageSignature($samlMessage, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA256, $type="SAMLRequest")
{
$key = $this->_settings->getSPkey();
if (empty($key)) {
throw new OneLogin_Saml2_Error(
"Trying to sign the SAML Response but can't load the SP private key",
OneLogin_Saml2_Error::PRIVATE_KEY_NOT_FOUND
);
if ($type == "SAMLRequest") {
$errorMsg = "Trying to sign the SAML Request but can't load the SP private key";
} else {
$errorMsg = "Trying to sign the SAML Response but can't load the SP private key";
}
throw new Error($errorMsg, Error::PRIVATE_KEY_NOT_FOUND);
}
$objKey = new XMLSecurityKey($signAlgorithm, array('type' => 'private'));
@ -598,13 +707,13 @@ class OneLogin_Saml2_Auth
$security = $this->_settings->getSecurityData();
if ($security['lowercaseUrlencoding']) {
$msg = 'SAMLResponse='.rawurlencode($samlResponse);
$msg = $type.'='.rawurlencode($samlMessage);
if (isset($relayState)) {
$msg .= '&RelayState='.rawurlencode($relayState);
}
$msg .= '&SigAlg=' . rawurlencode($signAlgorithm);
} else {
$msg = 'SAMLResponse='.urlencode($samlResponse);
$msg = $type.'='.urlencode($samlMessage);
if (isset($relayState)) {
$msg .= '&RelayState='.urlencode($relayState);
}
@ -631,7 +740,7 @@ class OneLogin_Saml2_Auth
}
/**
* @return The NotOnOrAfter value of the valid
* @return int The NotOnOrAfter value of the valid
* SubjectConfirmationData node (if any)
* of the last assertion processed
*/
@ -644,7 +753,7 @@ class OneLogin_Saml2_Auth
* Returns the most recently-constructed/processed
* XML SAML request (AuthNRequest, LogoutRequest)
*
* @return string The Request XML
* @return string|null The Request XML
*/
public function getLastRequestXML()
{
@ -657,7 +766,7 @@ class OneLogin_Saml2_Auth
* If the SAMLResponse was encrypted, by default tries
* to return the decrypted XML.
*
* @return string The Response XML
* @return string|null The Response XML
*/
public function getLastResponseXML()
{
@ -669,7 +778,7 @@ class OneLogin_Saml2_Auth
$response = $this->_lastResponse->saveXML();
}
}
return $response;
}
}

View File

@ -1,26 +1,42 @@
<?php
/**
* This file is part of php-saml.
*
* (c) OneLogin Inc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package OneLogin
* @author OneLogin Inc <saml-info@onelogin.com>
* @license MIT https://github.com/onelogin/php-saml/blob/master/LICENSE
* @link https://github.com/onelogin/php-saml
*/
namespace OneLogin\Saml2;
/**
* SAML 2 Authentication Request
*
*/
class OneLogin_Saml2_AuthnRequest
class AuthnRequest
{
/**
* Object that represents the setting info
* @var OneLogin_Saml2_Settings
*
* @var Settings
*/
protected $_settings;
/**
* SAML AuthNRequest string
*
* @var string
*/
private $_authnRequest;
/**
* SAML AuthNRequest ID.
*
* @var string
*/
private $_id;
@ -28,12 +44,12 @@ class OneLogin_Saml2_AuthnRequest
/**
* Constructs the AuthnRequest object.
*
* @param OneLogin_Saml2_Settings $settings Settings
* @param bool $forceAuthn When true the AuthNReuqest will set the ForceAuthn='true'
* @param bool $isPassive When true the AuthNReuqest will set the Ispassive='true'
* @param bool $setNameIdPolicy When true the AuthNReuqest will set a nameIdPolicy
* @param Settings $settings SAML Toolkit Settings
* @param bool $forceAuthn When true the AuthNReuqest will set the ForceAuthn='true'
* @param bool $isPassive When true the AuthNReuqest will set the Ispassive='true'
* @param bool $setNameIdPolicy When true the AuthNReuqest will set a nameIdPolicy
*/
public function __construct(OneLogin_Saml2_Settings $settings, $forceAuthn = false, $isPassive = false, $setNameIdPolicy = true)
public function __construct(\OneLogin\Saml2\Settings $settings, $forceAuthn = false, $isPassive = false, $setNameIdPolicy = true)
{
$this->_settings = $settings;
@ -41,14 +57,14 @@ class OneLogin_Saml2_AuthnRequest
$idpData = $this->_settings->getIdPData();
$security = $this->_settings->getSecurityData();
$id = OneLogin_Saml2_Utils::generateUniqueID();
$issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time());
$id = Utils::generateUniqueID();
$issueInstant = Utils::parseTime2SAML(time());
$nameIdPolicyStr = '';
if ($setNameIdPolicy) {
$nameIDPolicyFormat = $spData['NameIDFormat'];
if (isset($security['wantNameIdEncrypted']) && $security['wantNameIdEncrypted']) {
$nameIDPolicyFormat = OneLogin_Saml2_Constants::NAMEID_ENCRYPTED;
$nameIDPolicyFormat = Constants::NAMEID_ENCRYPTED;
}
$nameIdPolicyStr = <<<NAMEIDPOLICY
@ -93,7 +109,6 @@ ISPASSIVE;
$requestedAuthnStr = '';
if (isset($security['requestedAuthnContext']) && $security['requestedAuthnContext'] !== false) {
$authnComparison = 'exact';
if (isset($security['requestedAuthnContextComparison'])) {
$authnComparison = $security['requestedAuthnContextComparison'];
@ -114,6 +129,8 @@ REQUESTEDAUTHN;
}
}
$spEntityId = htmlspecialchars($spData['entityId'], ENT_QUOTES);
$acsUrl = htmlspecialchars($spData['assertionConsumerService']['url'], ENT_QUOTES);
$request = <<<AUTHNREQUEST
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
@ -124,8 +141,8 @@ REQUESTEDAUTHN;
IssueInstant="$issueInstant"
Destination="{$idpData['singleSignOnService']['url']}"
ProtocolBinding="{$spData['assertionConsumerService']['binding']}"
AssertionConsumerServiceURL="{$spData['assertionConsumerService']['url']}">
<saml:Issuer>{$spData['entityId']}</saml:Issuer>
AssertionConsumerServiceURL="{$acsUrl}">
<saml:Issuer>{$spEntityId}</saml:Issuer>
{$nameIdPolicyStr}
{$requestedAuthnStr}
</samlp:AuthnRequest>
@ -139,6 +156,8 @@ AUTHNREQUEST;
* Returns deflated, base64 encoded, unsigned AuthnRequest.
*
* @param bool|null $deflate Whether or not we should 'gzdeflate' the request body before we return it.
*
* @return string
*/
public function getRequest($deflate = null)
{

View File

@ -1,11 +1,26 @@
<?php
/**
* This file is part of php-saml.
*
* (c) OneLogin Inc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package OneLogin
* @author OneLogin Inc <saml-info@onelogin.com>
* @license MIT https://github.com/onelogin/php-saml/blob/master/LICENSE
* @link https://github.com/onelogin/php-saml
*/
namespace OneLogin\Saml2;
/**
* Constants of OneLogin PHP Toolkit
*
* Defines all required constants
*/
class OneLogin_Saml2_Constants
class Constants
{
// Value added to the current time in time condition validations
const ALLOWED_CLOCK_DRIFT = 180; // 3 min in seconds

View File

@ -0,0 +1,66 @@
<?php
/**
* This file is part of php-saml.
*
* (c) OneLogin Inc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package OneLogin
* @author OneLogin Inc <saml-info@onelogin.com>
* @license MIT https://github.com/onelogin/php-saml/blob/master/LICENSE
* @link https://github.com/onelogin/php-saml
*/
namespace OneLogin\Saml2;
use Exception;
/**
* Error class of OneLogin PHP Toolkit
*
* Defines the Error class
*/
class Error extends Exception
{
// Errors
const SETTINGS_FILE_NOT_FOUND = 0;
const SETTINGS_INVALID_SYNTAX = 1;
const SETTINGS_INVALID = 2;
const METADATA_SP_INVALID = 3;
const SP_CERTS_NOT_FOUND = 4;
// SP_CERTS_NOT_FOUND is deprecated, use CERT_NOT_FOUND instead
const CERT_NOT_FOUND = 4;
const REDIRECT_INVALID_URL = 5;
const PUBLIC_CERT_FILE_NOT_FOUND = 6;
const PRIVATE_KEY_FILE_NOT_FOUND = 7;
const SAML_RESPONSE_NOT_FOUND = 8;
const SAML_LOGOUTMESSAGE_NOT_FOUND = 9;
const SAML_LOGOUTREQUEST_INVALID = 10;
const SAML_LOGOUTRESPONSE_INVALID = 11;
const SAML_SINGLE_LOGOUT_NOT_SUPPORTED = 12;
const PRIVATE_KEY_NOT_FOUND = 13;
const UNSUPPORTED_SETTINGS_OBJECT = 14;
/**
* Constructor
*
* @param string $msg Describes the error.
* @param int $code The code error (defined in the error class).
* @param array|null $args Arguments used in the message that describes the error.
*/
public function __construct($msg, $code = 0, $args = array())
{
assert(is_string($msg));
assert(is_int($code));
if (!isset($args)) {
$args = array();
}
$params = array_merge(array($msg), $args);
$message = call_user_func_array('sprintf', $params);
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,237 @@
<?php
/**
* This file is part of php-saml.
*
* (c) OneLogin Inc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package OneLogin
* @author OneLogin Inc <saml-info@onelogin.com>
* @license MIT https://github.com/onelogin/php-saml/blob/master/LICENSE
* @link https://github.com/onelogin/php-saml
*/
namespace OneLogin\Saml2;
use DOMDocument;
use Exception;
/**
* IdP Metadata Parser of OneLogin PHP Toolkit
*/
class IdPMetadataParser
{
/**
* Get IdP Metadata Info from URL
*
* @param string $url URL where the IdP metadata is published
* @param string $entityId Entity Id of the desired IdP, if no
* entity Id is provided and the XML
* metadata contains more than one
* IDPSSODescriptor, the first is returned
* @param string $desiredNameIdFormat If available on IdP metadata, use that nameIdFormat
* @param string $desiredSSOBinding Parse specific binding SSO endpoint
* @param string $desiredSLOBinding Parse specific binding SLO endpoint
*
* @return array metadata info in php-saml settings format
*/
public static function parseRemoteXML($url, $entityId = null, $desiredNameIdFormat = null, $desiredSSOBinding = Constants::BINDING_HTTP_REDIRECT, $desiredSLOBinding = Constants::BINDING_HTTP_REDIRECT)
{
$metadataInfo = array();
try {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
$xml = curl_exec($ch);
if ($xml !== false) {
$metadataInfo = self::parseXML($xml, $entityId, $desiredNameIdFormat, $desiredSSOBinding, $desiredSLOBinding);
} else {
throw new Exception(curl_error($ch), curl_errno($ch));
}
} catch (Exception $e) {
}
return $metadataInfo;
}
/**
* Get IdP Metadata Info from File
*
* @param string $filepath File path
* @param string $entityId Entity Id of the desired IdP, if no
* entity Id is provided and the XML
* metadata contains more than one
* IDPSSODescriptor, the first is returned
* @param string $desiredNameIdFormat If available on IdP metadata, use that nameIdFormat
* @param string $desiredSSOBinding Parse specific binding SSO endpoint
* @param string $desiredSLOBinding Parse specific binding SLO endpoint
*
* @return array metadata info in php-saml settings format
*/
public static function parseFileXML($filepath, $entityId = null, $desiredNameIdFormat = null, $desiredSSOBinding = Constants::BINDING_HTTP_REDIRECT, $desiredSLOBinding = Constants::BINDING_HTTP_REDIRECT)
{
$metadataInfo = array();
try {
if (file_exists($filepath)) {
$data = file_get_contents($filepath);
$metadataInfo = self::parseXML($data, $entityId, $desiredNameIdFormat, $desiredSSOBinding, $desiredSLOBinding);
}
} catch (Exception $e) {
}
return $metadataInfo;
}
/**
* Get IdP Metadata Info from URL
*
* @param string $xml XML that contains IdP metadata
* @param string $entityId Entity Id of the desired IdP, if no
* entity Id is provided and the XML
* metadata contains more than one
* IDPSSODescriptor, the first is returned
* @param string $desiredNameIdFormat If available on IdP metadata, use that nameIdFormat
* @param string $desiredSSOBinding Parse specific binding SSO endpoint
* @param string $desiredSLOBinding Parse specific binding SLO endpoint
*
* @return array metadata info in php-saml settings format
*
* @throws Exception
*/
public static function parseXML($xml, $entityId = null, $desiredNameIdFormat = null, $desiredSSOBinding = Constants::BINDING_HTTP_REDIRECT, $desiredSLOBinding = Constants::BINDING_HTTP_REDIRECT)
{
$metadataInfo = array();
$dom = new DOMDocument();
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
try {
$dom = Utils::loadXML($dom, $xml);
if (!$dom) {
throw new Exception('Error parsing metadata');
}
$customIdPStr = '';
if (!empty($entityId)) {
$customIdPStr = '[@entityID="' . $entityId . '"]';
}
$idpDescryptorXPath = '//md:EntityDescriptor' . $customIdPStr . '/md:IDPSSODescriptor';
$idpDescriptorNodes = Utils::query($dom, $idpDescryptorXPath);
if (isset($idpDescriptorNodes) && $idpDescriptorNodes->length > 0) {
$metadataInfo['idp'] = array();
$idpDescriptor = $idpDescriptorNodes->item(0);
if (empty($entityId) && $idpDescriptor->parentNode->hasAttribute('entityID')) {
$entityId = $idpDescriptor->parentNode->getAttribute('entityID');
}
if (!empty($entityId)) {
$metadataInfo['idp']['entityId'] = $entityId;
}
$ssoNodes = Utils::query($dom, './md:SingleSignOnService[@Binding="'.$desiredSSOBinding.'"]', $idpDescriptor);
if ($ssoNodes->length < 1) {
$ssoNodes = Utils::query($dom, './md:SingleSignOnService', $idpDescriptor);
}
if ($ssoNodes->length > 0) {
$metadataInfo['idp']['singleSignOnService'] = array(
'url' => $ssoNodes->item(0)->getAttribute('Location'),
'binding' => $ssoNodes->item(0)->getAttribute('Binding')
);
}
$sloNodes = Utils::query($dom, './md:SingleLogoutService[@Binding="'.$desiredSLOBinding.'"]', $idpDescriptor);
if ($sloNodes->length < 1) {
$sloNodes = Utils::query($dom, './md:SingleLogoutService', $idpDescriptor);
}
if ($sloNodes->length > 0) {
$metadataInfo['idp']['singleLogoutService'] = array(
'url' => $sloNodes->item(0)->getAttribute('Location'),
'binding' => $sloNodes->item(0)->getAttribute('Binding')
);
}
$keyDescriptorCertSigningNodes = Utils::query($dom, './md:KeyDescriptor[not(contains(@use, "encryption"))]/ds:KeyInfo/ds:X509Data/ds:X509Certificate', $idpDescriptor);
$keyDescriptorCertEncryptionNodes = Utils::query($dom, './md:KeyDescriptor[not(contains(@use, "signing"))]/ds:KeyInfo/ds:X509Data/ds:X509Certificate', $idpDescriptor);
if (!empty($keyDescriptorCertSigningNodes) || !empty($keyDescriptorCertEncryptionNodes)) {
$metadataInfo['idp']['x509certMulti'] = array();
if (!empty($keyDescriptorCertSigningNodes)) {
$idpInfo['x509certMulti']['signing'] = array();
foreach ($keyDescriptorCertSigningNodes as $keyDescriptorCertSigningNode) {
$metadataInfo['idp']['x509certMulti']['signing'][] = Utils::formatCert($keyDescriptorCertSigningNode->nodeValue, false);
}
}
if (!empty($keyDescriptorCertEncryptionNodes)) {
$idpInfo['x509certMulti']['encryption'] = array();
foreach ($keyDescriptorCertEncryptionNodes as $keyDescriptorCertEncryptionNode) {
$metadataInfo['idp']['x509certMulti']['encryption'][] = Utils::formatCert($keyDescriptorCertEncryptionNode->nodeValue, false);
}
}
$idpCertdata = $metadataInfo['idp']['x509certMulti'];
if ((count($idpCertdata) == 1 and
((isset($idpCertdata['signing']) and count($idpCertdata['signing']) == 1) or (isset($idpCertdata['encryption']) and count($idpCertdata['encryption']) == 1))) or
((isset($idpCertdata['signing']) && count($idpCertdata['signing']) == 1) && isset($idpCertdata['encryption']) && count($idpCertdata['encryption']) == 1 && strcmp($idpCertdata['signing'][0], $idpCertdata['encryption'][0]) == 0)) {
if (isset($metadataInfo['idp']['x509certMulti']['signing'][0])) {
$metadataInfo['idp']['x509cert'] = $metadataInfo['idp']['x509certMulti']['signing'][0];
} else {
$metadataInfo['idp']['x509cert'] = $metadataInfo['idp']['x509certMulti']['encryption'][0];
}
unset($metadataInfo['idp']['x509certMulti']);
}
}
$nameIdFormatNodes = Utils::query($dom, './md:NameIDFormat', $idpDescriptor);
if ($nameIdFormatNodes->length > 0) {
$metadataInfo['sp']['NameIDFormat'] = $nameIdFormatNodes->item(0)->nodeValue;
if (!empty($desiredNameIdFormat)) {
foreach ($nameIdFormatNodes as $nameIdFormatNode) {
if (strcmp($nameIdFormatNode->nodeValue, $desiredNameIdFormat) == 0) {
$metadataInfo['sp']['NameIDFormat'] = $nameIdFormatNode->nodeValue;
break;
}
}
}
}
}
} catch (Exception $e) {
throw new Exception('Error parsing metadata. '.$e->getMessage());
}
return $metadataInfo;
}
/**
* Inject metadata info into php-saml settings array
*
* @param array $settings php-saml settings array
* @param array $metadataInfo array metadata info
*
* @return array settings
*/
public static function injectIntoSettings($settings, $metadataInfo)
{
if (isset($metadataInfo['idp']) && isset($settings['idp'])) {
if (isset($metadataInfo['idp']['x509certMulti']) && !empty($metadataInfo['idp']['x509certMulti']) && isset($settings['idp']['x509cert'])) {
unset($settings['idp']['x509cert']);
}
if (isset($metadataInfo['idp']['x509cert']) && !empty($metadataInfo['idp']['x509cert']) && isset($settings['idp']['x509certMulti'])) {
unset($settings['idp']['x509certMulti']);
}
}
return array_replace_recursive($settings, $metadataInfo);
}
}

View File

@ -1,51 +1,76 @@
<?php
/**
* This file is part of php-saml.
*
* (c) OneLogin Inc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package OneLogin
* @author OneLogin Inc <saml-info@onelogin.com>
* @license MIT https://github.com/onelogin/php-saml/blob/master/LICENSE
* @link https://github.com/onelogin/php-saml
*/
namespace OneLogin\Saml2;
use RobRichards\XMLSecLibs\XMLSecurityKey;
use DOMDocument;
use Exception;
/**
* SAML 2 Logout Request
*
*/
class OneLogin_Saml2_LogoutRequest
class LogoutRequest
{
/**
* Contains the ID of the Logout Request
* @var string
*/
* Contains the ID of the Logout Request
*
* @var string
*/
public $id;
/**
* Object that represents the setting info
* @var OneLogin_Saml2_Settings
*
* @var Settings
*/
protected $_settings;
/**
* SAML Logout Request
*
* @var string
*/
protected $_logoutRequest;
/**
* After execute a validation process, this var contains the cause
* @var string
*/
* After execute a validation process, this var contains the cause
*
* @var Exception
*/
private $_error;
/**
* Constructs the Logout Request object.
*
* @param OneLogin_Saml2_Settings $settings Settings
* @param string|null $request A UUEncoded Logout Request.
* @param string|null $nameId The NameID that will be set in the LogoutRequest.
* @param string|null $sessionIndex The SessionIndex (taken from the SAML Response in the SSO process).
* @param string|null $nameIdFormat The NameID Format will be set in the LogoutRequest.
* @param Settings $settings Settings
* @param string|null $request A UUEncoded Logout Request.
* @param string|null $nameId The NameID that will be set in the LogoutRequest.
* @param string|null $sessionIndex The SessionIndex (taken from the SAML Response in the SSO process).
* @param string|null $nameIdFormat The NameID Format will be set in the LogoutRequest.
* @param string|null $nameIdNameQualifier The NameID NameQualifier will be set in the LogoutRequest.
* @param string|null $nameIdSPNameQualifier The NameID SP NameQualifier will be set in the LogoutRequest.
*/
public function __construct(OneLogin_Saml2_Settings $settings, $request = null, $nameId = null, $sessionIndex = null, $nameIdFormat = null)
public function __construct(\OneLogin\Saml2\Settings $settings, $request = null, $nameId = null, $sessionIndex = null, $nameIdFormat = null, $nameIdNameQualifier = null, $nameIdSPNameQualifier = null)
{
$this->_settings = $settings;
$baseURL = $this->_settings->getBaseURL();
if (!empty($baseURL)) {
OneLogin_Saml2_Utils::setBaseURL($baseURL);
Utils::setBaseURL($baseURL);
}
if (!isset($request) || empty($request)) {
@ -53,37 +78,56 @@ class OneLogin_Saml2_LogoutRequest
$idpData = $this->_settings->getIdPData();
$security = $this->_settings->getSecurityData();
$id = OneLogin_Saml2_Utils::generateUniqueID();
$id = Utils::generateUniqueID();
$this->id = $id;
$nameIdValue = OneLogin_Saml2_Utils::generateUniqueID();
$issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time());
$issueInstant = Utils::parseTime2SAML(time());
$cert = null;
if (isset($security['nameIdEncrypted']) && $security['nameIdEncrypted']) {
$cert = $idpData['x509cert'];
$existsMultiX509Enc = isset($idpData['x509certMulti']) && isset($idpData['x509certMulti']['encryption']) && !empty($idpData['x509certMulti']['encryption']);
if ($existsMultiX509Enc) {
$cert = $idpData['x509certMulti']['encryption'][0];
} else {
$cert = $idpData['x509cert'];
}
}
if (!empty($nameId)) {
if (empty($nameIdFormat)) {
if (empty($nameIdFormat)
&& $spData['NameIDFormat'] != Constants::NAMEID_UNSPECIFIED) {
$nameIdFormat = $spData['NameIDFormat'];
}
$spNameQualifier = null;
} else {
$nameId = $idpData['entityId'];
$nameIdFormat = OneLogin_Saml2_Constants::NAMEID_ENTITY;
$spNameQualifier = $spData['entityId'];
$nameIdFormat = Constants::NAMEID_ENTITY;
}
$nameIdObj = OneLogin_Saml2_Utils::generateNameId(
/* From saml-core-2.0-os 8.3.6, when the entity Format is used:
"The NameQualifier, SPNameQualifier, and SPProvidedID attributes MUST be omitted.
*/
if (!empty($nameIdFormat) && $nameIdFormat == Constants::NAMEID_ENTITY) {
$nameIdNameQualifier = null;
$nameIdSPNameQualifier = null;
}
// NameID Format UNSPECIFIED omitted
if (!empty($nameIdFormat) && $nameIdFormat == Constants::NAMEID_UNSPECIFIED) {
$nameIdFormat = null;
}
$nameIdObj = Utils::generateNameId(
$nameId,
$spNameQualifier,
$nameIdSPNameQualifier,
$nameIdFormat,
$cert
$cert,
$nameIdNameQualifier
);
$sessionIndexStr = isset($sessionIndex) ? "<samlp:SessionIndex>{$sessionIndex}</samlp:SessionIndex>" : "";
$spEntityId = htmlspecialchars($spData['entityId'], ENT_QUOTES);
$logoutRequest = <<<LOGOUTREQUEST
<samlp:LogoutRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
@ -92,7 +136,7 @@ class OneLogin_Saml2_LogoutRequest
Version="2.0"
IssueInstant="{$issueInstant}"
Destination="{$idpData['singleLogoutService']['url']}">
<saml:Issuer>{$spData['entityId']}</saml:Issuer>
<saml:Issuer>{$spEntityId}</saml:Issuer>
{$nameIdObj}
{$sessionIndexStr}
</samlp:LogoutRequest>
@ -106,12 +150,11 @@ LOGOUTREQUEST;
} else {
$logoutRequest = $decoded;
}
$this->id = self::getID($logoutRequest);
$this->id = static::getID($logoutRequest);
}
$this->_logoutRequest = $logoutRequest;
}
/**
* Returns the Logout Request defated, base64encoded, unsigned
*
@ -140,6 +183,8 @@ LOGOUTREQUEST;
* @param string|DOMDocument $request Logout Request Message
*
* @return string ID
*
* @throws OneLogin_Saml2_Error
*/
public static function getID($request)
{
@ -147,7 +192,15 @@ LOGOUTREQUEST;
$dom = $request;
} else {
$dom = new DOMDocument();
$dom = OneLogin_Saml2_Utils::loadXML($dom, $request);
$dom = Utils::loadXML($dom, $request);
}
if (false === $dom) {
throw new Error(
"LogoutRequest could not be processed",
Error::SAML_LOGOUTREQUEST_INVALID
);
}
$id = $dom->documentElement->getAttribute('ID');
@ -162,7 +215,9 @@ LOGOUTREQUEST;
*
* @return array Name ID Data (Value, Format, NameQualifier, SPNameQualifier)
*
* @throws Error
* @throws Exception
* @throws ValidationError
*/
public static function getNameIdData($request, $key = null)
{
@ -170,38 +225,38 @@ LOGOUTREQUEST;
$dom = $request;
} else {
$dom = new DOMDocument();
$dom = OneLogin_Saml2_Utils::loadXML($dom, $request);
$dom = Utils::loadXML($dom, $request);
}
$encryptedEntries = OneLogin_Saml2_Utils::query($dom, '/samlp:LogoutRequest/saml:EncryptedID');
$encryptedEntries = Utils::query($dom, '/samlp:LogoutRequest/saml:EncryptedID');
if ($encryptedEntries->length == 1) {
$encryptedDataNodes = $encryptedEntries->item(0)->getElementsByTagName('EncryptedData');
$encryptedData = $encryptedDataNodes->item(0);
if (empty($key)) {
throw new OneLogin_Saml2_Error(
throw new Error(
"Private Key is required in order to decrypt the NameID, check settings",
OneLogin_Saml2_Error::PRIVATE_KEY_NOT_FOUND
Error::PRIVATE_KEY_NOT_FOUND
);
}
$seckey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type'=>'private'));
$seckey->loadKey($key);
$nameId = OneLogin_Saml2_Utils::decryptElement($encryptedData, $seckey);
$nameId = Utils::decryptElement($encryptedData, $seckey);
} else {
$entries = OneLogin_Saml2_Utils::query($dom, '/samlp:LogoutRequest/saml:NameID');
$entries = Utils::query($dom, '/samlp:LogoutRequest/saml:NameID');
if ($entries->length == 1) {
$nameId = $entries->item(0);
}
}
if (!isset($nameId)) {
throw new OneLogin_Saml2_ValidationError(
throw new ValidationError(
"NameID not found in the Logout Request",
OneLogin_Saml2_ValidationError::NO_NAMEID
ValidationError::NO_NAMEID
);
}
@ -223,6 +278,10 @@ LOGOUTREQUEST;
* @param string|null $key The SP key
*
* @return string Name ID Value
*
* @throws Error
* @throws Exception
* @throws ValidationError
*/
public static function getNameId($request, $key = null)
{
@ -236,6 +295,8 @@ LOGOUTREQUEST;
* @param string|DOMDocument $request Logout Request Message
*
* @return string|null $issuer The Issuer
*
* @throws Exception
*/
public static function getIssuer($request)
{
@ -243,11 +304,11 @@ LOGOUTREQUEST;
$dom = $request;
} else {
$dom = new DOMDocument();
$dom = OneLogin_Saml2_Utils::loadXML($dom, $request);
$dom = Utils::loadXML($dom, $request);
}
$issuer = null;
$issuerNodes = OneLogin_Saml2_Utils::query($dom, '/samlp:LogoutRequest/saml:Issuer');
$issuerNodes = Utils::query($dom, '/samlp:LogoutRequest/saml:Issuer');
if ($issuerNodes->length == 1) {
$issuer = $issuerNodes->item(0)->textContent;
}
@ -263,6 +324,8 @@ LOGOUTREQUEST;
* @param string|DOMDocument $request Logout Request Message
*
* @return array The SessionIndex value
*
* @throws Exception
*/
public static function getSessionIndexes($request)
{
@ -270,11 +333,11 @@ LOGOUTREQUEST;
$dom = $request;
} else {
$dom = new DOMDocument();
$dom = OneLogin_Saml2_Utils::loadXML($dom, $request);
$dom = Utils::loadXML($dom, $request);
}
$sessionIndexes = array();
$sessionIndexNodes = OneLogin_Saml2_Utils::query($dom, '/samlp:LogoutRequest/samlp:SessionIndex');
$sessionIndexNodes = Utils::query($dom, '/samlp:LogoutRequest/samlp:SessionIndex');
foreach ($sessionIndexNodes as $sessionIndexNode) {
$sessionIndexes[] = $sessionIndexNode->textContent;
}
@ -284,14 +347,19 @@ LOGOUTREQUEST;
/**
* Checks if the Logout Request recieved is valid.
*
* @param bool $retrieveParametersFromServer True if we want to use parameters from $_SERVER to validate the signature
*
* @return bool If the Logout Request is or not valid
*
* @throws Exception
* @throws ValidationError
*/
public function isValid($retrieveParametersFromServer = false)
{
$this->_error = null;
try {
$dom = new DOMDocument();
$dom = OneLogin_Saml2_Utils::loadXML($dom, $this->_logoutRequest);
$dom = Utils::loadXML($dom, $this->_logoutRequest);
$idpData = $this->_settings->getIdPData();
$idPEntityId = $idpData['entityId'];
@ -300,24 +368,24 @@ LOGOUTREQUEST;
$security = $this->_settings->getSecurityData();
if ($security['wantXMLValidation']) {
$res = OneLogin_Saml2_Utils::validateXML($dom, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive());
$res = Utils::validateXML($dom, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive());
if (!$res instanceof DOMDocument) {
throw new OneLogin_Saml2_ValidationError(
throw new ValidationError(
"Invalid SAML Logout Request. Not match the saml-schema-protocol-2.0.xsd",
OneLogin_Saml2_ValidationError::INVALID_XML_FORMAT
ValidationError::INVALID_XML_FORMAT
);
}
}
$currentURL = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
$currentURL = Utils::getSelfRoutedURLNoQuery();
// Check NotOnOrAfter
if ($dom->documentElement->hasAttribute('NotOnOrAfter')) {
$na = OneLogin_Saml2_Utils::parseSAML2Time($dom->documentElement->getAttribute('NotOnOrAfter'));
$na = Utils::parseSAML2Time($dom->documentElement->getAttribute('NotOnOrAfter'));
if ($na <= time()) {
throw new OneLogin_Saml2_ValidationError(
throw new ValidationError(
"Could not validate timestamp: expired. Check system clock.",
OneLogin_Saml2_ValidationError::RESPONSE_EXPIRED
ValidationError::RESPONSE_EXPIRED
);
}
}
@ -325,106 +393,76 @@ LOGOUTREQUEST;
// Check destination
if ($dom->documentElement->hasAttribute('Destination')) {
$destination = $dom->documentElement->getAttribute('Destination');
if (!empty($destination)) {
if (strpos($destination, $currentURL) === false) {
throw new OneLogin_Saml2_ValidationError(
"The LogoutRequest was received at $currentURL instead of $destination",
OneLogin_Saml2_ValidationError::WRONG_DESTINATION
);
}
if (!empty($destination) && strpos($destination, $currentURL) === false) {
throw new ValidationError(
"The LogoutRequest was received at $currentURL instead of $destination",
ValidationError::WRONG_DESTINATION
);
}
}
$nameId = $this->getNameId($dom, $this->_settings->getSPkey());
$nameId = static::getNameId($dom, $this->_settings->getSPkey());
// Check issuer
$issuer = $this->getIssuer($dom);
$issuer = static::getIssuer($dom);
if (!empty($issuer) && $issuer != $idPEntityId) {
throw new OneLogin_Saml2_ValidationError(
throw new ValidationError(
"Invalid issuer in the Logout Request",
OneLogin_Saml2_ValidationError::WRONG_ISSUER
ValidationError::WRONG_ISSUER
);
}
if ($security['wantMessagesSigned']) {
if (!isset($_GET['Signature'])) {
throw new OneLogin_Saml2_ValidationError(
"The Message of the Logout Request is not signed and the SP require it",
OneLogin_Saml2_ValidationError::NO_SIGNED_MESSAGE
);
}
if ($security['wantMessagesSigned'] && !isset($_GET['Signature'])) {
throw new ValidationError(
"The Message of the Logout Request is not signed and the SP require it",
ValidationError::NO_SIGNED_MESSAGE
);
}
}
if (isset($_GET['Signature'])) {
if (!isset($_GET['SigAlg'])) {
$signAlg = XMLSecurityKey::RSA_SHA1;
} else {
$signAlg = $_GET['SigAlg'];
}
if ($retrieveParametersFromServer) {
$signedQuery = 'SAMLRequest='.OneLogin_Saml2_Utils::extractOriginalQueryParam('SAMLRequest');
if (isset($_GET['RelayState'])) {
$signedQuery .= '&RelayState='.OneLogin_Saml2_Utils::extractOriginalQueryParam('RelayState');
}
$signedQuery .= '&SigAlg='.OneLogin_Saml2_Utils::extractOriginalQueryParam('SigAlg');
} else {
$signedQuery = 'SAMLRequest='.urlencode($_GET['SAMLRequest']);
if (isset($_GET['RelayState'])) {
$signedQuery .= '&RelayState='.urlencode($_GET['RelayState']);
}
$signedQuery .= '&SigAlg='.urlencode($signAlg);
}
if (!isset($idpData['x509cert']) || empty($idpData['x509cert'])) {
throw new OneLogin_Saml2_Error(
"In order to validate the sign on the Logout Request, the x509cert of the IdP is required",
OneLogin_Saml2_Error::CERT_NOT_FOUND
);
}
$cert = $idpData['x509cert'];
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
$objKey->loadKey($cert, false, true);
if ($signAlg != XMLSecurityKey::RSA_SHA1) {
try {
$objKey = OneLogin_Saml2_Utils::castKey($objKey, $signAlg, 'public');
} catch (Exception $e) {
throw new OneLogin_Saml2_ValidationError(
"Invalid signAlg in the recieved Logout Request",
OneLogin_Saml2_ValidationError::INVALID_SIGNATURE
);
}
}
if ($objKey->verifySignature($signedQuery, base64_decode($_GET['Signature'])) !== 1) {
throw new OneLogin_Saml2_ValidationError(
$signatureValid = Utils::validateBinarySign("SAMLRequest", $_GET, $idpData, $retrieveParametersFromServer);
if (!$signatureValid) {
throw new ValidationError(
"Signature validation failed. Logout Request rejected",
OneLogin_Saml2_ValidationError::INVALID_SIGNATURE
ValidationError::INVALID_SIGNATURE
);
}
}
return true;
} catch (Exception $e) {
$this->_error = $e->getMessage();
$this->_error = $e;
$debug = $this->_settings->isDebugActive();
if ($debug) {
echo $this->_error;
echo htmlentities($this->_error->getMessage());
}
return false;
}
}
/* After execute a validation process, if fails this method returns the cause
/**
* After execute a validation process, if fails this method returns the Exception of the cause
*
* @return string Cause
* @return Exception Cause
*/
public function getErrorException()
{
return $this->_error;
}
/**
* After execute a validation process, if fails this method returns the cause
*
* @return null|string Error reason
*/
public function getError()
{
return $this->_error;
$errorMsg = null;
if (isset($this->_error)) {
$errorMsg = htmlentities($this->_error->getMessage());
}
return $errorMsg;
}
/**

View File

@ -1,55 +1,82 @@
<?php
/**
* This file is part of php-saml.
*
* (c) OneLogin Inc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package OneLogin
* @author OneLogin Inc <saml-info@onelogin.com>
* @license MIT https://github.com/onelogin/php-saml/blob/master/LICENSE
* @link https://github.com/onelogin/php-saml
*/
namespace OneLogin\Saml2;
use DOMDocument;
use DOMNodeList;
use Exception;
/**
* SAML 2 Logout Response
*
*/
class OneLogin_Saml2_LogoutResponse
class LogoutResponse
{
/**
* Contains the ID of the Logout Response
* @var string
*/
* Contains the ID of the Logout Response
*
* @var string
*/
public $id;
/**
* Object that represents the setting info
* @var OneLogin_Saml2_Settings
*
* @var Settings
*/
protected $_settings;
/**
* The decoded, unprocessed XML response provided to the constructor.
* @var string
*
* @var string|null
*/
protected $_logoutResponse;
/**
* A DOMDocument class loaded from the SAML LogoutResponse.
* @var DomDocument
*
* @var DOMDocument
*/
public $document;
/**
* After execute a validation process, if it fails, this var contains the cause
* @var string
*/
* After execute a validation process, if it fails, this var contains the cause
*
* @var Exception|null
*/
private $_error;
/**
* Constructs a Logout Response object (Initialize params from settings and if provided
* load the Logout Response.
*
* @param OneLogin_Saml2_Settings $settings Settings.
* @param Settings $settings Settings.
* @param string|null $response An UUEncoded SAML Logout response from the IdP.
*
* @throws Error
* @throws Exception
*
*/
public function __construct(OneLogin_Saml2_Settings $settings, $response = null)
public function __construct(\OneLogin\Saml2\Settings $settings, $response = null)
{
$this->_settings = $settings;
$baseURL = $this->_settings->getBaseURL();
if (!empty($baseURL)) {
OneLogin_Saml2_Utils::setBaseURL($baseURL);
Utils::setBaseURL($baseURL);
}
if ($response) {
@ -61,7 +88,14 @@ class OneLogin_Saml2_LogoutResponse
$this->_logoutResponse = $decoded;
}
$this->document = new DOMDocument();
$this->document = OneLogin_Saml2_Utils::loadXML($this->document, $this->_logoutResponse);
$this->document = Utils::loadXML($this->document, $this->_logoutResponse);
if (false === $this->document) {
throw new Error(
"LogoutResponse could not be processed",
Error::SAML_LOGOUTRESPONSE_INVALID
);
}
if ($this->document->documentElement->hasAttribute('ID')) {
$this->id = $this->document->documentElement->getAttribute('ID');
@ -87,7 +121,7 @@ class OneLogin_Saml2_LogoutResponse
/**
* Gets the Status of the Logout Response.
*
* @return string The Status
* @return string|null The Status
*/
public function getStatus()
{
@ -102,12 +136,12 @@ class OneLogin_Saml2_LogoutResponse
/**
* Determines if the SAML LogoutResponse is valid
*
* @param string|null $requestId The ID of the LogoutRequest sent by this SP to the IdP
* @param bool $retrieveParametersFromServer
* @param string|null $requestId The ID of the LogoutRequest sent by this SP to the IdP
* @param bool $retrieveParametersFromServer True if we want to use parameters from $_SERVER to validate the signature
*
* @return bool Returns if the SAML LogoutResponse is or not valid
*
* @throws Exception
*
* @throws ValidationError
*/
public function isValid($requestId = null, $retrieveParametersFromServer = false)
{
@ -120,11 +154,11 @@ class OneLogin_Saml2_LogoutResponse
$security = $this->_settings->getSecurityData();
if ($security['wantXMLValidation']) {
$res = OneLogin_Saml2_Utils::validateXML($this->document, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive());
$res = Utils::validateXML($this->document, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive());
if (!$res instanceof DOMDocument) {
throw new OneLogin_Saml2_ValidationError(
throw new ValidationError(
"Invalid SAML Logout Response. Not match the saml-schema-protocol-2.0.xsd",
OneLogin_Saml2_ValidationError::INVALID_XML_FORMAT
ValidationError::INVALID_XML_FORMAT
);
}
}
@ -133,9 +167,9 @@ class OneLogin_Saml2_LogoutResponse
if (isset($requestId) && $this->document->documentElement->hasAttribute('InResponseTo')) {
$inResponseTo = $this->document->documentElement->getAttribute('InResponseTo');
if ($requestId != $inResponseTo) {
throw new OneLogin_Saml2_ValidationError(
throw new ValidationError(
"The InResponseTo of the Logout Response: $inResponseTo, does not match the ID of the Logout request sent by the SP: $requestId",
OneLogin_Saml2_ValidationError::WRONG_INRESPONSETO
ValidationError::WRONG_INRESPONSETO
);
}
}
@ -143,93 +177,48 @@ class OneLogin_Saml2_LogoutResponse
// Check issuer
$issuer = $this->getIssuer();
if (!empty($issuer) && $issuer != $idPEntityId) {
throw new OneLogin_Saml2_ValidationError(
throw new ValidationError(
"Invalid issuer in the Logout Response",
OneLogin_Saml2_ValidationError::WRONG_ISSUER
ValidationError::WRONG_ISSUER
);
}
$currentURL = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
$currentURL = Utils::getSelfRoutedURLNoQuery();
// Check destination
if ($this->document->documentElement->hasAttribute('Destination')) {
$destination = $this->document->documentElement->getAttribute('Destination');
if (!empty($destination)) {
if (strpos($destination, $currentURL) === false) {
throw new OneLogin_Saml2_ValidationError(
"The LogoutResponse was received at $currentURL instead of $destination",
OneLogin_Saml2_ValidationError::WRONG_DESTINATION
);
}
if (!empty($destination) && strpos($destination, $currentURL) === false) {
throw new ValidationError(
"The LogoutResponse was received at $currentURL instead of $destination",
ValidationError::WRONG_DESTINATION
);
}
}
if ($security['wantMessagesSigned']) {
if (!isset($_GET['Signature'])) {
throw new OneLogin_Saml2_ValidationError(
"The Message of the Logout Response is not signed and the SP requires it",
OneLogin_Saml2_ValidationError::NO_SIGNED_MESSAGE
);
}
if ($security['wantMessagesSigned'] && !isset($_GET['Signature'])) {
throw new ValidationError(
"The Message of the Logout Response is not signed and the SP requires it",
ValidationError::NO_SIGNED_MESSAGE
);
}
}
if (isset($_GET['Signature'])) {
if (!isset($_GET['SigAlg'])) {
$signAlg = XMLSecurityKey::RSA_SHA1;
} else {
$signAlg = $_GET['SigAlg'];
}
if ($retrieveParametersFromServer) {
$signedQuery = 'SAMLResponse='.OneLogin_Saml2_Utils::extractOriginalQueryParam('SAMLResponse');
if (isset($_GET['RelayState'])) {
$signedQuery .= '&RelayState='.OneLogin_Saml2_Utils::extractOriginalQueryParam('RelayState');
}
$signedQuery .= '&SigAlg='.OneLogin_Saml2_Utils::extractOriginalQueryParam('SigAlg');
} else {
$signedQuery = 'SAMLResponse='.urlencode($_GET['SAMLResponse']);
if (isset($_GET['RelayState'])) {
$signedQuery .= '&RelayState='.urlencode($_GET['RelayState']);
}
$signedQuery .= '&SigAlg='.urlencode($signAlg);
}
if (!isset($idpData['x509cert']) || empty($idpData['x509cert'])) {
throw new OneLogin_Saml2_Error(
"In order to validate the sign on the Logout Response, the x509cert of the IdP is required",
OneLogin_Saml2_Error::CERT_NOT_FOUND
);
}
$cert = $idpData['x509cert'];
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
$objKey->loadKey($cert, false, true);
if ($signAlg != XMLSecurityKey::RSA_SHA1) {
try {
$objKey = OneLogin_Saml2_Utils::castKey($objKey, $signAlg, 'public');
} catch (Exception $e) {
throw new OneLogin_Saml2_ValidationError(
"Invalid signAlg in the recieved Logout Response",
OneLogin_Saml2_ValidationError::INVALID_SIGNATURE
);
}
}
if ($objKey->verifySignature($signedQuery, base64_decode($_GET['Signature'])) !== 1) {
throw new OneLogin_Saml2_ValidationError(
$signatureValid = Utils::validateBinarySign("SAMLResponse", $_GET, $idpData, $retrieveParametersFromServer);
if (!$signatureValid) {
throw new ValidationError(
"Signature validation failed. Logout Response rejected",
OneLogin_Saml2_ValidationError::INVALID_SIGNATURE
ValidationError::INVALID_SIGNATURE
);
}
}
return true;
} catch (Exception $e) {
$this->_error = $e->getMessage();
$this->_error = $e;
$debug = $this->_settings->isDebugActive();
if ($debug) {
echo $this->_error;
echo htmlentities($this->_error->getMessage());
}
return false;
}
@ -238,13 +227,13 @@ class OneLogin_Saml2_LogoutResponse
/**
* Extracts a node from the DOMDocument (Logout Response Menssage)
*
* @param string $query Xpath Expresion
* @param string $query Xpath Expression
*
* @return DOMNodeList The queried node
*/
private function _query($query)
{
return OneLogin_Saml2_Utils::query($this->document, $query);
return Utils::query($this->document, $query);
}
@ -259,9 +248,10 @@ class OneLogin_Saml2_LogoutResponse
$spData = $this->_settings->getSPData();
$idpData = $this->_settings->getIdPData();
$this->id = OneLogin_Saml2_Utils::generateUniqueID();
$issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time());
$this->id = Utils::generateUniqueID();
$issueInstant = Utils::parseTime2SAML(time());
$spEntityId = htmlspecialchars($spData['entityId'], ENT_QUOTES);
$logoutResponse = <<<LOGOUTRESPONSE
<samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
@ -271,7 +261,7 @@ class OneLogin_Saml2_LogoutResponse
Destination="{$idpData['singleLogoutService']['url']}"
InResponseTo="{$inResponseTo}"
>
<saml:Issuer>{$spData['entityId']}</saml:Issuer>
<saml:Issuer>{$spEntityId}</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
</samlp:Status>
@ -289,30 +279,45 @@ LOGOUTRESPONSE;
*/
public function getResponse($deflate = null)
{
$subject = $this->_logoutResponse;
$logoutResponse = $this->_logoutResponse;
if (is_null($deflate)) {
$deflate = $this->_settings->shouldCompressResponses();
}
if ($deflate) {
$subject = gzdeflate($this->_logoutResponse);
$logoutResponse = gzdeflate($this->_logoutResponse);
}
return base64_encode($subject);
return base64_encode($logoutResponse);
}
/* After execute a validation process, if fails this method returns the cause.
/**
* After execute a validation process, if fails this method returns the cause.
*
* @return string Cause
* @return Exception|null Cause
*/
public function getError()
public function getErrorException()
{
return $this->_error;
}
/**
* @return the ID of the Response
*/
/**
* After execute a validation process, if fails this method returns the cause
*
* @return null|string Error reason
*/
public function getError()
{
$errorMsg = null;
if (isset($this->_error)) {
$errorMsg = htmlentities($this->_error->getMessage());
}
return $errorMsg;
}
/**
* @return string the ID of the Response
*/
public function getId()
{
return $this->id;
@ -322,7 +327,7 @@ LOGOUTRESPONSE;
* Returns the XML that will be sent as part of the response
* or that was received at the SP
*
* @return string
* @return string|null
*/
public function getXML()
{

View File

@ -1,11 +1,30 @@
<?php
/**
* This file is part of php-saml.
*
* (c) OneLogin Inc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package OneLogin
* @author OneLogin Inc <saml-info@onelogin.com>
* @license MIT https://github.com/onelogin/php-saml/blob/master/LICENSE
* @link https://github.com/onelogin/php-saml
*/
namespace OneLogin\Saml2;
use RobRichards\XMLSecLibs\XMLSecurityKey;
use RobRichards\XMLSecLibs\XMLSecurityDSig;
use DOMDocument;
use Exception;
/**
* Metadata lib of OneLogin PHP Toolkit
*
*/
class OneLogin_Saml2_Metadata
class Metadata
{
const TIME_VALID = 172800; // 2 days
const TIME_CACHED = 604800; // 1 week
@ -16,11 +35,12 @@ class OneLogin_Saml2_Metadata
* @param array $sp The SP data
* @param bool|string $authnsign authnRequestsSigned attribute
* @param bool|string $wsign wantAssertionsSigned attribute
* @param DateTime|null $validUntil Metadata's valid time
* @param int|null $validUntil Metadata's valid time
* @param int|null $cacheDuration Duration of the cache in seconds
* @param array $contacts Contacts info
* @param array $organization Organization ingo
* @param array $attributes
*
* @return string SAML Metadata XML
*/
public static function builder($sp, $authnsign = false, $wsign = false, $validUntil = null, $cacheDuration = null, $contacts = array(), $organization = array(), $attributes = array())
@ -29,7 +49,7 @@ class OneLogin_Saml2_Metadata
if (!isset($validUntil)) {
$validUntil = time() + self::TIME_VALID;
}
$validUntilTime = gmdate('Y-m-d\TH:i:s\Z', $validUntil);
$validUntilTime = Utils::parseTime2SAML($validUntil);
if (!isset($cacheDuration)) {
$cacheDuration = self::TIME_CACHED;
@ -38,9 +58,10 @@ class OneLogin_Saml2_Metadata
$sls = '';
if (isset($sp['singleLogoutService'])) {
$slsUrl = htmlspecialchars($sp['singleLogoutService']['url'], ENT_QUOTES);
$sls = <<<SLS_TEMPLATE
<md:SingleLogoutService Binding="{$sp['singleLogoutService']['binding']}"
Location="{$sp['singleLogoutService']['url']}" />
Location="{$slsUrl}" />
SLS_TEMPLATE;
}
@ -127,7 +148,7 @@ CONTACT;
$reqAttrAuxStr = '>';
if (is_string($attribute['attributeValue'])) {
$attribute['attributeValue'] = array($attribute['attributeValue']);
}
}
foreach ($attribute['attributeValue'] as $attrValue) {
$reqAttrAuxStr .=<<<ATTRIBUTEVALUE
@ -149,16 +170,18 @@ ATTRIBUTEVALUE;
METADATA_TEMPLATE;
}
$spEntityId = htmlspecialchars($sp['entityId'], ENT_QUOTES);
$acsUrl = htmlspecialchars($sp['assertionConsumerService']['url'], ENT_QUOTES);
$metadata = <<<METADATA_TEMPLATE
<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
validUntil="{$validUntilTime}"
cacheDuration="PT{$cacheDuration}S"
entityID="{$sp['entityId']}">
entityID="{$spEntityId}">
<md:SPSSODescriptor AuthnRequestsSigned="{$strAuthnsign}" WantAssertionsSigned="{$strWsign}" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
{$sls} <md:NameIDFormat>{$sp['NameIDFormat']}</md:NameIDFormat>
<md:AssertionConsumerService Binding="{$sp['assertionConsumerService']['binding']}"
Location="{$sp['assertionConsumerService']['url']}"
Location="{$acsUrl}"
index="1" />
{$strAttributeConsumingService}
</md:SPSSODescriptor>{$strOrganization}{$strContacts}
@ -170,21 +193,23 @@ METADATA_TEMPLATE;
/**
* Signs the metadata with the key/cert provided
*
* @param string $metadata SAML Metadata XML
* @param string $key x509 key
* @param string $cert x509 cert
* @param string $signAlgorithm Signature algorithm method
* @param string $digestAlgorithm Digest algorithm method
* @param string $metadata SAML Metadata XML
* @param string $key x509 key
* @param string $cert x509 cert
* @param string $signAlgorithm Signature algorithm method
* @param string $digestAlgorithm Digest algorithm method
*
* @return string Signed Metadata
*
* @throws Exception
*/
public static function signMetadata($metadata, $key, $cert, $signAlgorithm = XMLSecurityKey::RSA_SHA1, $digestAlgorithm = XMLSecurityDSig::SHA1)
public static function signMetadata($metadata, $key, $cert, $signAlgorithm = XMLSecurityKey::RSA_SHA256, $digestAlgorithm = XMLSecurityDSig::SHA256)
{
return OneLogin_Saml2_Utils::addSign($metadata, $key, $cert, $signAlgorithm, $digestAlgorithm);
return Utils::addSign($metadata, $key, $cert, $signAlgorithm, $digestAlgorithm);
}
/**
* Adds the x509 descriptors (sign/encriptation) to the metadata
* Adds the x509 descriptors (sign/encryption) to the metadata
* The same cert will be used for sign/encrypt
*
* @param string $metadata SAML Metadata XML
@ -192,6 +217,8 @@ METADATA_TEMPLATE;
* @param bool $wantsEncrypted Whether to include the KeyDescriptor for encryption
*
* @return string Metadata with KeyDescriptors
*
* @throws Exception
*/
public static function addX509KeyDescriptors($metadata, $cert, $wantsEncrypted = true)
{
@ -199,7 +226,7 @@ METADATA_TEMPLATE;
$xml->preserveWhiteSpace = false;
$xml->formatOutput = true;
try {
$xml = OneLogin_Saml2_Utils::loadXML($xml, $metadata);
$xml = Utils::loadXML($xml, $metadata);
if (!$xml) {
throw new Exception('Error parsing metadata');
}
@ -207,16 +234,16 @@ METADATA_TEMPLATE;
throw new Exception('Error parsing metadata. '.$e->getMessage());
}
$formatedCert = OneLogin_Saml2_Utils::formatCert($cert, false);
$x509Certificate = $xml->createElementNS(OneLogin_Saml2_Constants::NS_DS, 'X509Certificate', $formatedCert);
$formatedCert = Utils::formatCert($cert, false);
$x509Certificate = $xml->createElementNS(Constants::NS_DS, 'X509Certificate', $formatedCert);
$keyData = $xml->createElementNS(OneLogin_Saml2_Constants::NS_DS, 'ds:X509Data');
$keyData = $xml->createElementNS(Constants::NS_DS, 'ds:X509Data');
$keyData->appendChild($x509Certificate);
$keyInfo = $xml->createElementNS(OneLogin_Saml2_Constants::NS_DS, 'ds:KeyInfo');
$keyInfo = $xml->createElementNS(Constants::NS_DS, 'ds:KeyInfo');
$keyInfo->appendChild($keyData);
$keyDescriptor = $xml->createElementNS(OneLogin_Saml2_Constants::NS_MD, "md:KeyDescriptor");
$keyDescriptor = $xml->createElementNS(Constants::NS_MD, "md:KeyDescriptor");
$SPSSODescriptor = $xml->getElementsByTagName('SPSSODescriptor')->item(0);
$SPSSODescriptor->insertBefore($keyDescriptor->cloneNode(), $SPSSODescriptor->firstChild);

View File

@ -1,11 +1,30 @@
<?php
/**
* This file is part of php-saml.
*
* (c) OneLogin Inc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package OneLogin
* @author OneLogin Inc <saml-info@onelogin.com>
* @license MIT https://github.com/onelogin/php-saml/blob/master/LICENSE
* @link https://github.com/onelogin/php-saml
*/
namespace OneLogin\Saml2;
use RobRichards\XMLSecLibs\XMLSecurityKey;
use RobRichards\XMLSecLibs\XMLSecurityDSig;
use DOMDocument;
use Exception;
/**
* Configuration of the OneLogin PHP Toolkit
*
*/
class OneLogin_Saml2_Settings
class Settings
{
/**
* List of paths.
@ -17,7 +36,7 @@ class OneLogin_Saml2_Settings
/**
* @var string
*/
private $_baseurl;
private $_baseurl;
/**
* Strict. If active, PHP Toolkit will reject unsigned or unencrypted messages
@ -86,9 +105,9 @@ class OneLogin_Saml2_Settings
private $_errors = array();
/**
* Setting errors.
* Valitate SP data only flag
*
* @var array
* @var bool
*/
private $_spValidationOnly = false;
@ -97,44 +116,31 @@ class OneLogin_Saml2_Settings
* - Sets the paths of the different folders
* - Loads settings info from settings file or array/object provided
*
* @param array|object|null $settings SAML Toolkit Settings
* @param array|null $settings SAML Toolkit Settings
* @param bool $spValidationOnly Validate or not the IdP data
*
* @throws OneLogin_Saml2_Error If any settings parameter is invalid
* @throws Exception If OneLogin_Saml2_Settings is incorrectly supplied
* @throws Error If any settings parameter is invalid
* @throws Exception If Settings is incorrectly supplied
*/
public function __construct($settings = null, $spValidationOnly = false)
public function __construct(array $settings = null, $spValidationOnly = false)
{
$this->_spValidationOnly = $spValidationOnly;
$this->_loadPaths();
if (!isset($settings)) {
if (!$this->_loadSettingsFromFile()) {
throw new OneLogin_Saml2_Error(
throw new Error(
'Invalid file settings: %s',
OneLogin_Saml2_Error::SETTINGS_INVALID,
Error::SETTINGS_INVALID,
array(implode(', ', $this->_errors))
);
}
$this->_addDefaultValues();
} else if (is_array($settings)) {
if (!$this->_loadSettingsFromArray($settings)) {
throw new OneLogin_Saml2_Error(
'Invalid array settings: %s',
OneLogin_Saml2_Error::SETTINGS_INVALID,
array(implode(', ', $this->_errors))
);
}
} else if ($settings instanceof OneLogin_Saml2_Settings) {
throw new OneLogin_Saml2_Error(
'Only instances of OneLogin_Saml_Settings are supported.',
OneLogin_Saml2_Error::UNSUPPORTED_SETTINGS_OBJECT,
array(implode(', ', $this->_errors))
);
} else {
if (!$this->_loadSettingsFromArray($settings->getValues())) {
throw new OneLogin_Saml2_Error(
if (!$this->_loadSettingsFromArray($settings)) {
throw new Error(
'Invalid array settings: %s',
OneLogin_Saml2_Error::SETTINGS_INVALID,
Error::SETTINGS_INVALID,
array(implode(', ', $this->_errors))
);
}
@ -143,25 +149,27 @@ class OneLogin_Saml2_Settings
$this->formatIdPCert();
$this->formatSPCert();
$this->formatSPKey();
$this->formatSPCertNew();
$this->formatIdPCertMulti();
}
/**
* Sets the paths of the different folders
* @suppress PhanUndeclaredConstant
*/
private function _loadPaths()
{
$basePath = dirname(dirname(dirname(__FILE__))).'/';
$this->_paths = array (
$basePath = dirname(dirname(__DIR__)) . '/';
$this->_paths = array(
'base' => $basePath,
'config' => $basePath,
'cert' => $basePath.'certs/',
'lib' => $basePath.'lib/',
'extlib' => $basePath.'extlib/'
'lib' => $basePath.'src/'
);
if (defined('ONELOGIN_CUSTOMPATH')) {
$this->_paths['config'] = ONELOGIN_CUSTOMPATH;
$this->_paths['cert'] = ONELOGIN_CUSTOMPATH.'certs/';
$this->_paths['cert'] = ONELOGIN_CUSTOMPATH . 'certs/';
}
}
@ -205,16 +213,6 @@ class OneLogin_Saml2_Settings
return $this->_paths['lib'];
}
/**
* Returns external lib path.
*
* @return string The external library folder path
*/
public function getExtLibPath()
{
return $this->_paths['extlib'];
}
/**
* Returns schema path.
*
@ -232,7 +230,7 @@ class OneLogin_Saml2_Settings
*
* @return bool True if the settings info is valid
*/
private function _loadSettingsFromArray($settings)
private function _loadSettingsFromArray(array $settings)
{
if (isset($settings['sp'])) {
$this->_sp = $settings['sp'];
@ -284,27 +282,31 @@ class OneLogin_Saml2_Settings
* Loads settings info from the settings file
*
* @return bool True if the settings info is valid
* @throws OneLogin_Saml2_Error
*
* @throws Error
*
* @suppress PhanUndeclaredVariable
*/
private function _loadSettingsFromFile()
{
$filename = $this->getConfigPath().'settings.php';
if (!file_exists($filename)) {
throw new OneLogin_Saml2_Error(
throw new Error(
'Settings file not found: %s',
OneLogin_Saml2_Error::SETTINGS_FILE_NOT_FOUND,
Error::SETTINGS_FILE_NOT_FOUND,
array($filename)
);
}
/** @var array $settings */
include $filename;
// Add advance_settings if exists
$advancedFilename = $this->getConfigPath().'advanced_settings.php';
if (file_exists($advancedFilename)) {
/** @var array $advancedSettings */
include $advancedFilename;
$settings = array_merge($settings, $advancedSettings);
}
@ -319,10 +321,10 @@ class OneLogin_Saml2_Settings
private function _addDefaultValues()
{
if (!isset($this->_sp['assertionConsumerService']['binding'])) {
$this->_sp['assertionConsumerService']['binding'] = OneLogin_Saml2_Constants::BINDING_HTTP_POST;
$this->_sp['assertionConsumerService']['binding'] = Constants::BINDING_HTTP_POST;
}
if (isset($this->_sp['singleLogoutService']) && !isset($this->_sp['singleLogoutService']['binding'])) {
$this->_sp['singleLogoutService']['binding'] = OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT;
$this->_sp['singleLogoutService']['binding'] = Constants::BINDING_HTTP_REDIRECT;
}
if (!isset($this->_compress['requests'])) {
@ -335,7 +337,7 @@ class OneLogin_Saml2_Settings
// Related to nameID
if (!isset($this->_sp['NameIDFormat'])) {
$this->_sp['NameIDFormat'] = OneLogin_Saml2_Constants::NAMEID_UNSPECIFIED;
$this->_sp['NameIDFormat'] = Constants::NAMEID_UNSPECIFIED;
}
if (!isset($this->_security['nameIdEncrypted'])) {
$this->_security['nameIdEncrypted'] = false;
@ -391,12 +393,12 @@ class OneLogin_Saml2_Settings
// SignatureAlgorithm
if (!isset($this->_security['signatureAlgorithm'])) {
$this->_security['signatureAlgorithm'] = XMLSecurityKey::RSA_SHA1;
$this->_security['signatureAlgorithm'] = XMLSecurityKey::RSA_SHA256;
}
// DigestAlgorithm
if (!isset($this->_security['digestAlgorithm'])) {
$this->_security['digestAlgorithm'] = XMLSecurityDSig::SHA1;
$this->_security['digestAlgorithm'] = XMLSecurityDSig::SHA256;
}
if (!isset($this->_security['lowercaseUrlencoding'])) {
@ -429,11 +431,9 @@ class OneLogin_Saml2_Settings
*
* @return array $errors Errors found on the settings data
*/
public function checkSettings($settings)
public function checkSettings(array $settings)
{
assert('is_array($settings)');
if (!is_array($settings) || empty($settings)) {
if (empty($settings)) {
$errors = array('invalid_syntax');
} else {
$errors = array();
@ -465,14 +465,12 @@ class OneLogin_Saml2_Settings
if (isset($settings['compress'])) {
if (!is_array($settings['compress'])) {
$errors[] = "invalid_syntax";
} else if (
isset($settings['compress']['requests'])
} else if (isset($settings['compress']['requests'])
&& $settings['compress']['requests'] !== true
&& $settings['compress']['requests'] !== false
) {
$errors[] = "'compress'=>'requests' values must be true or false.";
} else if (
isset($settings['compress']['responses'])
} else if (isset($settings['compress']['responses'])
&& $settings['compress']['responses'] !== true
&& $settings['compress']['responses'] !== false
) {
@ -489,11 +487,9 @@ class OneLogin_Saml2_Settings
*
* @return array $errors Errors found on the IdP settings data
*/
public function checkIdPSettings($settings)
public function checkIdPSettings(array $settings)
{
assert('is_array($settings)');
if (!is_array($settings) || empty($settings)) {
if (empty($settings)) {
return array('invalid_syntax');
}
@ -528,15 +524,16 @@ class OneLogin_Saml2_Settings
$security = $settings['security'];
$existsX509 = isset($idp['x509cert']) && !empty($idp['x509cert']);
$existsMultiX509Sign = isset($idp['x509certMulti']) && isset($idp['x509certMulti']['signing']) && !empty($idp['x509certMulti']['signing']);
$existsMultiX509Enc = isset($idp['x509certMulti']) && isset($idp['x509certMulti']['encryption']) && !empty($idp['x509certMulti']['encryption']);
$existsFingerprint = isset($idp['certFingerprint']) && !empty($idp['certFingerprint']);
if (((isset($security['wantAssertionsSigned']) && $security['wantAssertionsSigned'] == true)
|| (isset($security['wantMessagesSigned']) && $security['wantMessagesSigned'] == true))
&& !($existsX509 || $existsFingerprint)
if (!($existsX509 || $existsFingerprint || $existsMultiX509Sign)
) {
$errors[] = 'idp_cert_or_fingerprint_not_found_and_required';
}
if ((isset($security['nameIdEncrypted']) && $security['nameIdEncrypted'] == true)
&& !($existsX509)
&& !($existsX509 || $existsMultiX509Enc)
) {
$errors[] = 'idp_cert_not_found_and_required';
}
@ -553,11 +550,9 @@ class OneLogin_Saml2_Settings
*
* @return array $errors Errors found on the SP settings data
*/
public function checkSPSettings($settings)
public function checkSPSettings(array $settings)
{
assert('is_array($settings)');
if (!is_array($settings) || empty($settings)) {
if (empty($settings)) {
return array('invalid_syntax');
}
@ -699,6 +694,29 @@ class OneLogin_Saml2_Settings
return $cert;
}
/**
* Returns the x509 public of the SP that is
* planed to be used soon instead the other
* public cert
*
* @return string SP public cert New
*/
public function getSPcertNew()
{
$cert = null;
if (isset($this->_sp['x509certNew']) && !empty($this->_sp['x509certNew'])) {
$cert = $this->_sp['x509certNew'];
} else {
$certFile = $this->_paths['cert'].'sp_new.crt';
if (file_exists($certFile)) {
$cert = file_get_contents($certFile);
}
}
return $cert;
}
/**
* Gets the IdP data.
*
@ -750,20 +768,20 @@ class OneLogin_Saml2_Settings
}
/**
* Should SAML requests be compressed?
*
* @return bool Yes/No as True/False
*/
* Should SAML requests be compressed?
*
* @return bool Yes/No as True/False
*/
public function shouldCompressRequests()
{
return $this->_compress['requests'];
}
/**
* Should SAML responses be compressed?
*
* @return bool Yes/No as True/False
*/
* Should SAML responses be compressed?
*
* @return bool Yes/No as True/False
*/
public function shouldCompressResponses()
{
return $this->_compress['responses'];
@ -772,21 +790,37 @@ class OneLogin_Saml2_Settings
/**
* Gets the SP metadata. The XML representation.
*
* @param bool $alwaysPublishEncryptionCert When 'true', the returned
* metadata will always include an 'encryption' KeyDescriptor. Otherwise,
* the 'encryption' KeyDescriptor will only be included if
* $advancedSettings['security']['wantNameIdEncrypted'] or
* $advancedSettings['security']['wantAssertionsEncrypted'] are enabled.
* @param int|null $validUntil Metadata's valid time
* @param int|null $cacheDuration Duration of the cache in seconds
*
* @return string SP metadata (xml)
* @throws Exception
* @throws OneLogin_Saml2_Error
* @throws Error
*/
public function getSPMetadata()
public function getSPMetadata($alwaysPublishEncryptionCert = false, $validUntil = null, $cacheDuration = null)
{
$metadata = OneLogin_Saml2_Metadata::builder($this->_sp, $this->_security['authnRequestsSigned'], $this->_security['wantAssertionsSigned'], null, null, $this->getContacts(), $this->getOrganization());
$metadata = Metadata::builder($this->_sp, $this->_security['authnRequestsSigned'], $this->_security['wantAssertionsSigned'], $validUntil, $cacheDuration, $this->getContacts(), $this->getOrganization());
$certNew = $this->getSPcertNew();
if (!empty($certNew)) {
$metadata = Metadata::addX509KeyDescriptors(
$metadata,
$certNew,
$alwaysPublishEncryptionCert || $this->_security['wantNameIdEncrypted'] || $this->_security['wantAssertionsEncrypted']
);
}
$cert = $this->getSPcert();
if (!empty($cert)) {
$metadata = OneLogin_Saml2_Metadata::addX509KeyDescriptors(
$metadata = Metadata::addX509KeyDescriptors(
$metadata,
$cert,
$this->_security['wantNameIdEncrypted'] || $this->_security['wantAssertionsEncrypted']
$alwaysPublishEncryptionCert || $this->_security['wantNameIdEncrypted'] || $this->_security['wantAssertionsEncrypted']
);
}
@ -797,25 +831,25 @@ class OneLogin_Saml2_Settings
$certMetadata = $cert;
if (!$keyMetadata) {
throw new OneLogin_Saml2_Error(
throw new Error(
'SP Private key not found.',
OneLogin_Saml2_Error::PRIVATE_KEY_FILE_NOT_FOUND
Error::PRIVATE_KEY_FILE_NOT_FOUND
);
}
if (!$certMetadata) {
throw new OneLogin_Saml2_Error(
throw new Error(
'SP Public cert not found.',
OneLogin_Saml2_Error::PUBLIC_CERT_FILE_NOT_FOUND
Error::PUBLIC_CERT_FILE_NOT_FOUND
);
}
} else {
if (!isset($this->_security['signMetadata']['keyFileName'])
|| !isset($this->_security['signMetadata']['certFileName'])
) {
throw new OneLogin_Saml2_Error(
throw new Error(
'Invalid Setting: signMetadata value of the sp is not valid',
OneLogin_Saml2_Error::SETTINGS_INVALID_SYNTAX
Error::SETTINGS_INVALID_SYNTAX
);
}
$keyFileName = $this->_security['signMetadata']['keyFileName'];
@ -824,19 +858,18 @@ class OneLogin_Saml2_Settings
$keyMetadataFile = $this->_paths['cert'].$keyFileName;
$certMetadataFile = $this->_paths['cert'].$certFileName;
if (!file_exists($keyMetadataFile)) {
throw new OneLogin_Saml2_Error(
throw new Error(
'SP Private key file not found: %s',
OneLogin_Saml2_Error::PRIVATE_KEY_FILE_NOT_FOUND,
Error::PRIVATE_KEY_FILE_NOT_FOUND,
array($keyMetadataFile)
);
}
if (!file_exists($certMetadataFile)) {
throw new OneLogin_Saml2_Error(
throw new Error(
'SP Public cert file not found: %s',
OneLogin_Saml2_Error::PUBLIC_CERT_FILE_NOT_FOUND,
Error::PUBLIC_CERT_FILE_NOT_FOUND,
array($certMetadataFile)
);
}
@ -846,7 +879,7 @@ class OneLogin_Saml2_Settings
$signatureAlgorithm = $this->_security['signatureAlgorithm'];
$digestAlgorithm = $this->_security['digestAlgorithm'];
$metadata = OneLogin_Saml2_Metadata::signMetadata($metadata, $keyMetadata, $certMetadata, $signatureAlgorithm, $digestAlgorithm);
$metadata = Metadata::signMetadata($metadata, $keyMetadata, $certMetadata, $signatureAlgorithm, $digestAlgorithm);
}
return $metadata;
}
@ -856,14 +889,16 @@ class OneLogin_Saml2_Settings
*
* @param string $xml Metadata's XML that will be validate
*
* @return Array The list of found errors
* @return array The list of found errors
*
* @throws Exception
*/
public function validateMetadata($xml)
{
assert('is_string($xml)');
assert(is_string($xml));
$errors = array();
$res = OneLogin_Saml2_Utils::validateXML($xml, 'saml-schema-metadata-2.0.xsd', $this->_debug);
$res = Utils::validateXML($xml, 'saml-schema-metadata-2.0.xsd', $this->_debug);
if (!$res instanceof DOMDocument) {
$errors[] = $res;
} else {
@ -875,13 +910,13 @@ class OneLogin_Saml2_Settings
$validUntil = $cacheDuration = $expireTime = null;
if ($element->hasAttribute('validUntil')) {
$validUntil = OneLogin_Saml2_Utils::parseSAML2Time($element->getAttribute('validUntil'));
$validUntil = Utils::parseSAML2Time($element->getAttribute('validUntil'));
}
if ($element->hasAttribute('cacheDuration')) {
$cacheDuration = $element->getAttribute('cacheDuration');
}
$expireTime = OneLogin_Saml2_Utils::getExpireTime($cacheDuration, $validUntil);
$expireTime = Utils::getExpireTime($cacheDuration, $validUntil);
if (isset($expireTime) && time() > $expireTime) {
$errors[] = 'expired_xml';
}
@ -899,7 +934,26 @@ class OneLogin_Saml2_Settings
public function formatIdPCert()
{
if (isset($this->_idp['x509cert'])) {
$this->_idp['x509cert'] = OneLogin_Saml2_Utils::formatCert($this->_idp['x509cert']);
$this->_idp['x509cert'] = Utils::formatCert($this->_idp['x509cert']);
}
}
/**
* Formats the Multple IdP certs.
*/
public function formatIdPCertMulti()
{
if (isset($this->_idp['x509certMulti'])) {
if (isset($this->_idp['x509certMulti']['signing'])) {
foreach ($this->_idp['x509certMulti']['signing'] as $i => $cert) {
$this->_idp['x509certMulti']['signing'][$i] = Utils::formatCert($cert);
}
}
if (isset($this->_idp['x509certMulti']['encryption'])) {
foreach ($this->_idp['x509certMulti']['encryption'] as $i => $cert) {
$this->_idp['x509certMulti']['encryption'][$i] = Utils::formatCert($cert);
}
}
}
}
@ -909,7 +963,17 @@ class OneLogin_Saml2_Settings
public function formatSPCert()
{
if (isset($this->_sp['x509cert'])) {
$this->_sp['x509cert'] = OneLogin_Saml2_Utils::formatCert($this->_sp['x509cert']);
$this->_sp['x509cert'] = Utils::formatCert($this->_sp['x509cert']);
}
}
/**
* Formats the SP cert.
*/
public function formatSPCertNew()
{
if (isset($this->_sp['x509certNew'])) {
$this->_sp['x509certNew'] = Utils::formatCert($this->_sp['x509certNew']);
}
}
@ -919,7 +983,7 @@ class OneLogin_Saml2_Settings
public function formatSPKey()
{
if (isset($this->_sp['privateKey'])) {
$this->_sp['privateKey'] = OneLogin_Saml2_Utils::formatPrivateKey($this->_sp['privateKey']);
$this->_sp['privateKey'] = Utils::formatPrivateKey($this->_sp['privateKey']);
}
}
@ -937,10 +1001,12 @@ class OneLogin_Saml2_Settings
* Activates or deactivates the strict mode.
*
* @param bool $value Strict parameter
*
* @throws Exception
*/
public function setStrict($value)
{
if (! (is_bool($value))) {
if (!is_bool($value)) {
throw new Exception('Invalid value passed to setStrict()');
}
@ -969,6 +1035,8 @@ class OneLogin_Saml2_Settings
/**
* Set a baseurl value.
*
* @param string $baseurl Base URL.
*/
public function setBaseURL($baseurl)
{
@ -988,11 +1056,11 @@ class OneLogin_Saml2_Settings
/**
* Sets the IdP certificate.
*
* @param string $value IdP certificate
* @param string $cert IdP certificate
*/
public function setIdPCert($cert)
{
$this->_idp['x509cert'] = $cert;
$this->formatIdPCert();
$this->_idp['x509cert'] = $cert;
$this->formatIdPCert();
}
}

View File

@ -1,56 +1,31 @@
<?php
/**
* Error class of OneLogin PHP Toolkit
* This file is part of php-saml.
*
* Defines the Error class
* (c) OneLogin Inc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package OneLogin
* @author OneLogin Inc <saml-info@onelogin.com>
* @license MIT https://github.com/onelogin/php-saml/blob/master/LICENSE
* @link https://github.com/onelogin/php-saml
*/
class OneLogin_Saml2_Error extends Exception
{
// Errors
const SETTINGS_FILE_NOT_FOUND = 0;
const SETTINGS_INVALID_SYNTAX = 1;
const SETTINGS_INVALID = 2;
const METADATA_SP_INVALID = 3;
const SP_CERTS_NOT_FOUND = 4;
// SP_CERTS_NOT_FOUND is deprecated, use CERT_NOT_FOUND instead
const CERT_NOT_FOUND = 4;
const REDIRECT_INVALID_URL = 5;
const PUBLIC_CERT_FILE_NOT_FOUND = 6;
const PRIVATE_KEY_FILE_NOT_FOUND = 7;
const SAML_RESPONSE_NOT_FOUND = 8;
const SAML_LOGOUTMESSAGE_NOT_FOUND = 9;
const SAML_LOGOUTREQUEST_INVALID = 10;
const SAML_LOGOUTRESPONSE_INVALID = 11;
const SAML_SINGLE_LOGOUT_NOT_SUPPORTED = 12;
const PRIVATE_KEY_NOT_FOUND = 13;
const UNSUPPORTED_SETTINGS_OBJECT = 14;
/**
* Constructor
*
* @param string $msg Describes the error.
* @param int $code The code error (defined in the error class).
* @param array|null $args Arguments used in the message that describes the error.
*/
public function __construct($msg, $code = 0, $args = null)
{
assert('is_string($msg)');
assert('is_int($code)');
namespace OneLogin\Saml2;
$message = OneLogin_Saml2_Utils::t($msg, $args);
parent::__construct($message, $code);
}
}
use Exception;
/**
* ValidationError class of OneLogin PHP Toolkit
*
* This class implements another custom Exception handler,
* related to exceptions that happens during validation process.
*/
class OneLogin_Saml2_ValidationError extends Exception
class ValidationError extends Exception
{
# Validation Errors
// Validation Errors
const UNSUPPORTED_SAML_VERSION = 0;
const MISSING_ID = 1;
const WRONG_NUMBER_OF_ASSERTIONS = 2;
@ -109,12 +84,16 @@ class OneLogin_Saml2_ValidationError extends Exception
* @param int $code The code error (defined in the error class).
* @param array|null $args Arguments used in the message that describes the error.
*/
public function __construct($msg, $code = 0, $args = null)
public function __construct($msg, $code = 0, $args = array())
{
assert('is_string($msg)');
assert('is_int($code)');
assert(is_string($msg));
assert(is_int($code));
$message = OneLogin_Saml2_Utils::t($msg, $args);
if (!isset($args)) {
$args = array();
}
$params = array_merge(array($msg), $args);
$message = call_user_func_array('sprintf', $params);
parent::__construct($message, $code);
}

View File

@ -0,0 +1,6 @@
{
"php-saml": {
"version": "3.0.0",
"released": "02/11/2018"
}
}

View File

@ -1,9 +1,70 @@
xmlseclibs.php
??, ??? ????, 2.0.0
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
27, Sep 2018, 3.0.2
Security Improvements:
- OpenSSL is now a requirement rather than suggestion. (Slaven Bacelic)
- Filter input to avoid XPath injection. (Jaime Pérez)
Bug Fixes:
- Fix missing parentheses (Tim van Dijen)
Improvements:
- Use strict comparison operator to compare digest values. (Jaime Pérez)
- Remove call to file_get_contents that doesn't even work. (Jaime Pérez)
- Document potentially dangerous return value behaviour. (Thijs Kinkhorst)
31, Aug 2017, 3.0.1
Bug Fixes:
- Fixed missing () in function call. (Dennis Væversted)
Improvements:
- Add OneLogin to supported software.
- Add .gitattributes to remove unneeded files. (Filippo Tessarotto)
- Fix bug in example code. (Dan Church)
- Travis: add PHP 7.1, move hhvm to allowed failures. (Thijs Kinkhorst)
- Drop failing extract-win-cert test (Thijs Kinkhorst). (Thijs Kinkhorst)
- Add comments to warn about return values of verify(). (Thijs Kinkhorst)
- Fix tests to properly check return code of verify(). (Thijs Kinkhorst)
- Restore support for PHP >= 5.4. (Jaime Pérez)
25, May 2017, 3.0.0
Improvements:
- Remove use of mcrypt (skymeyer)
08, Sep 2016, 2.0.1
Bug Fixes:
- Strip whitespace characters when parsing X509Certificate. fixes #84
(klemen.bratec)
- Certificate 'subject' values can be arrays. fixes #80 (Andreas Stangl)
- HHVM signing node with ID attribute w/out namespace regenerates ID value.
fixes #88 (Milos Tomic)
Improvements:
- Fix typos and add some PHPDoc Blocks. (gfaust-qb)
- Update lightSAML link. (Milos Tomic)
- Update copyright dates.
31, Jul 2015, 2.0.0
Features:
- Namespace support. Classes now in the RobRichards\XMLSecLibs\ namespace.
Improvements:
- Dropped support for PHP 5.2
31, Jul 2015, 1.4.1
Bug Fixes:
- Allow for large digest values that may have line breaks. fixes #62
Features:
- Support for locating specific signature when multiple exist in
document. (griga3k)
Improvements:
- Add optional argument to XMLSecurityDSig to define the prefix to be used,
also allowing for null to use no prefix, for the dsig namespace. fixes #13
- Code cleanup
- Depreciated XMLSecurityDSig::generate_GUID for XMLSecurityDSig::generateGUID
23, Jun 2015, 1.4.0
Features:
- Support for PSR-0 standard.

View File

@ -1,4 +1,4 @@
Copyright (c) 2007-2013, Robert Richards <rrichards@cdatazone.org>.
Copyright (c) 2007-2018, Robert Richards <rrichards@cdatazone.org>.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -28,4 +28,4 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,84 @@
#xmlseclibs
xmlseclibs is a library written in PHP for working with XML Encryption and Signatures.
The author of xmlseclibs is Rob Richards.
# Branches
Both the master and the 2.0 branches are actively maintained.
* master: Removes mcrypt usage requiring 5.4+ (5.6.24+ recommended for security reasons)
* 2.0: Contains namespace support requiring 5.3+
* 1.4: Contains auto-loader support while also maintaining backwards compatiblity with the older 1.3 version using the xmlseclibs.php file. Supports PHP 5.2+
# Requirements
xmlseclibs requires PHP version 5.4 or greater. **5.6.24+ recommended for security reasons**
## How to Install
Install with [`composer.phar`](http://getcomposer.org).
```sh
php composer.phar require "robrichards/xmlseclibs"
```
## Use cases
xmlseclibs is being used in many different software.
* [SimpleSAMLPHP](https://github.com/simplesamlphp/simplesamlphp)
* [LightSAML](https://github.com/lightsaml/lightsaml)
* [OneLogin](https://github.com/onelogin/php-saml)
## Basic usage
The example below shows basic usage of xmlseclibs, with a SHA-256 signature.
```php
use RobRichards\XMLSecLibs\XMLSecurityDSig;
use RobRichards\XMLSecLibs\XMLSecurityKey;
// Load the XML to be signed
$doc = new DOMDocument();
$doc->load('./path/to/file/tobesigned.xml');
// Create a new Security object
$objDSig = new XMLSecurityDSig();
// Use the c14n exclusive canonicalization
$objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
// Sign using SHA-256
$objDSig->addReference(
$doc,
XMLSecurityDSig::SHA256,
array('http://www.w3.org/2000/09/xmldsig#enveloped-signature')
);
// Create a new (private) Security key
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type'=>'private'));
/*
If key has a passphrase, set it using
$objKey->passphrase = '<passphrase>';
*/
// Load the private key
$objKey->loadKey('./path/to/privatekey.pem', TRUE);
// Sign the XML file
$objDSig->sign($objKey);
// Add the associated public key to the signature
$objDSig->add509Cert(file_get_contents('./path/to/file/mycert.pem'));
// Append the signature to the XML
$objDSig->appendSignature($doc->documentElement);
// Save the signed XML
$doc->save('./path/to/signed.xml');
```
## How to Contribute
* [Open Issues](https://github.com/robrichards/xmlseclibs/issues)
* [Open Pull Requests](https://github.com/robrichards/xmlseclibs/pulls)
Mailing List: https://groups.google.com/forum/#!forum/xmlseclibs

View File

@ -0,0 +1,21 @@
{
"name": "robrichards/xmlseclibs",
"description": "A PHP library for XML Security",
"license": "BSD-3-Clause",
"keywords": [
"xml",
"xmldsig",
"signature",
"security"
],
"homepage": "https://github.com/robrichards/xmlseclibs",
"autoload": {
"psr-4": {
"RobRichards\\XMLSecLibs\\": "src"
}
},
"require": {
"php": ">= 5.4",
"ext-openssl": "*"
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace RobRichards\XMLSecLibs\Utils;
class XPath
{
const ALPHANUMERIC = '\w\d';
const NUMERIC = '\d';
const LETTERS = '\w';
const EXTENDED_ALPHANUMERIC = '\w\d\s-_:\.';
const SINGLE_QUOTE = '\'';
const DOUBLE_QUOTE = '"';
const ALL_QUOTES = '[\'"]';
/**
* Filter an attribute value for save inclusion in an XPath query.
*
* @param string $value The value to filter.
* @param string $quotes The quotes used to delimit the value in the XPath query.
*
* @return string The filtered attribute value.
*/
public static function filterAttrValue($value, $quotes = self::ALL_QUOTES)
{
return preg_replace('#'.$quotes.'#', '', $value);
}
/**
* Filter an attribute name for save inclusion in an XPath query.
*
* @param string $name The attribute name to filter.
* @param mixed $allow The set of characters to allow. Can be one of the constants provided by this class, or a
* custom regex excluding the '#' character (used as delimiter).
*
* @return string The filtered attribute name.
*/
public static function filterAttrName($name, $allow = self::EXTENDED_ALPHANUMERIC)
{
return preg_replace('#[^'.$allow.']#', '', $name);
}
}

View File

@ -0,0 +1,510 @@
<?php
namespace RobRichards\XMLSecLibs;
use DOMDocument;
use DOMNode;
use DOMXPath;
use Exception;
use RobRichards\XMLSecLibs\Utils\XPath as XPath;
/**
* xmlseclibs.php
*
* Copyright (c) 2007-2018, Robert Richards <rrichards@cdatazone.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Robert Richards nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @author Robert Richards <rrichards@cdatazone.org>
* @copyright 2007-2018 Robert Richards <rrichards@cdatazone.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class XMLSecEnc
{
const template = "<xenc:EncryptedData xmlns:xenc='http://www.w3.org/2001/04/xmlenc#'>
<xenc:CipherData>
<xenc:CipherValue></xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>";
const Element = 'http://www.w3.org/2001/04/xmlenc#Element';
const Content = 'http://www.w3.org/2001/04/xmlenc#Content';
const URI = 3;
const XMLENCNS = 'http://www.w3.org/2001/04/xmlenc#';
/** @var null|DOMDocument */
private $encdoc = null;
/** @var null|DOMNode */
private $rawNode = null;
/** @var null|string */
public $type = null;
/** @var null|DOMElement */
public $encKey = null;
/** @var array */
private $references = array();
public function __construct()
{
$this->_resetTemplate();
}
private function _resetTemplate()
{
$this->encdoc = new DOMDocument();
$this->encdoc->loadXML(self::template);
}
/**
* @param string $name
* @param DOMNode $node
* @param string $type
* @throws Exception
*/
public function addReference($name, $node, $type)
{
if (! $node instanceOf DOMNode) {
throw new Exception('$node is not of type DOMNode');
}
$curencdoc = $this->encdoc;
$this->_resetTemplate();
$encdoc = $this->encdoc;
$this->encdoc = $curencdoc;
$refuri = XMLSecurityDSig::generateGUID();
$element = $encdoc->documentElement;
$element->setAttribute("Id", $refuri);
$this->references[$name] = array("node" => $node, "type" => $type, "encnode" => $encdoc, "refuri" => $refuri);
}
/**
* @param DOMNode $node
*/
public function setNode($node)
{
$this->rawNode = $node;
}
/**
* Encrypt the selected node with the given key.
*
* @param XMLSecurityKey $objKey The encryption key and algorithm.
* @param bool $replace Whether the encrypted node should be replaced in the original tree. Default is true.
* @throws Exception
*
* @return DOMElement The <xenc:EncryptedData>-element.
*/
public function encryptNode($objKey, $replace = true)
{
$data = '';
if (empty($this->rawNode)) {
throw new Exception('Node to encrypt has not been set');
}
if (! $objKey instanceof XMLSecurityKey) {
throw new Exception('Invalid Key');
}
$doc = $this->rawNode->ownerDocument;
$xPath = new DOMXPath($this->encdoc);
$objList = $xPath->query('/xenc:EncryptedData/xenc:CipherData/xenc:CipherValue');
$cipherValue = $objList->item(0);
if ($cipherValue == null) {
throw new Exception('Error locating CipherValue element within template');
}
switch ($this->type) {
case (self::Element):
$data = $doc->saveXML($this->rawNode);
$this->encdoc->documentElement->setAttribute('Type', self::Element);
break;
case (self::Content):
$children = $this->rawNode->childNodes;
foreach ($children AS $child) {
$data .= $doc->saveXML($child);
}
$this->encdoc->documentElement->setAttribute('Type', self::Content);
break;
default:
throw new Exception('Type is currently not supported');
}
$encMethod = $this->encdoc->documentElement->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:EncryptionMethod'));
$encMethod->setAttribute('Algorithm', $objKey->getAlgorithm());
$cipherValue->parentNode->parentNode->insertBefore($encMethod, $cipherValue->parentNode->parentNode->firstChild);
$strEncrypt = base64_encode($objKey->encryptData($data));
$value = $this->encdoc->createTextNode($strEncrypt);
$cipherValue->appendChild($value);
if ($replace) {
switch ($this->type) {
case (self::Element):
if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) {
return $this->encdoc;
}
$importEnc = $this->rawNode->ownerDocument->importNode($this->encdoc->documentElement, true);
$this->rawNode->parentNode->replaceChild($importEnc, $this->rawNode);
return $importEnc;
case (self::Content):
$importEnc = $this->rawNode->ownerDocument->importNode($this->encdoc->documentElement, true);
while ($this->rawNode->firstChild) {
$this->rawNode->removeChild($this->rawNode->firstChild);
}
$this->rawNode->appendChild($importEnc);
return $importEnc;
}
} else {
return $this->encdoc->documentElement;
}
}
/**
* @param XMLSecurityKey $objKey
* @throws Exception
*/
public function encryptReferences($objKey)
{
$curRawNode = $this->rawNode;
$curType = $this->type;
foreach ($this->references AS $name => $reference) {
$this->encdoc = $reference["encnode"];
$this->rawNode = $reference["node"];
$this->type = $reference["type"];
try {
$encNode = $this->encryptNode($objKey);
$this->references[$name]["encnode"] = $encNode;
} catch (Exception $e) {
$this->rawNode = $curRawNode;
$this->type = $curType;
throw $e;
}
}
$this->rawNode = $curRawNode;
$this->type = $curType;
}
/**
* Retrieve the CipherValue text from this encrypted node.
*
* @throws Exception
* @return string|null The Ciphervalue text, or null if no CipherValue is found.
*/
public function getCipherValue()
{
if (empty($this->rawNode)) {
throw new Exception('Node to decrypt has not been set');
}
$doc = $this->rawNode->ownerDocument;
$xPath = new DOMXPath($doc);
$xPath->registerNamespace('xmlencr', self::XMLENCNS);
/* Only handles embedded content right now and not a reference */
$query = "./xmlencr:CipherData/xmlencr:CipherValue";
$nodeset = $xPath->query($query, $this->rawNode);
$node = $nodeset->item(0);
if (!$node) {
return null;
}
return base64_decode($node->nodeValue);
}
/**
* Decrypt this encrypted node.
*
* The behaviour of this function depends on the value of $replace.
* If $replace is false, we will return the decrypted data as a string.
* If $replace is true, we will insert the decrypted element(s) into the
* document, and return the decrypted element(s).
*
* @param XMLSecurityKey $objKey The decryption key that should be used when decrypting the node.
* @param boolean $replace Whether we should replace the encrypted node in the XML document with the decrypted data. The default is true.
*
* @return string|DOMElement The decrypted data.
*/
public function decryptNode($objKey, $replace=true)
{
if (! $objKey instanceof XMLSecurityKey) {
throw new Exception('Invalid Key');
}
$encryptedData = $this->getCipherValue();
if ($encryptedData) {
$decrypted = $objKey->decryptData($encryptedData);
if ($replace) {
switch ($this->type) {
case (self::Element):
$newdoc = new DOMDocument();
$newdoc->loadXML($decrypted);
if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) {
return $newdoc;
}
$importEnc = $this->rawNode->ownerDocument->importNode($newdoc->documentElement, true);
$this->rawNode->parentNode->replaceChild($importEnc, $this->rawNode);
return $importEnc;
case (self::Content):
if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) {
$doc = $this->rawNode;
} else {
$doc = $this->rawNode->ownerDocument;
}
$newFrag = $doc->createDocumentFragment();
$newFrag->appendXML($decrypted);
$parent = $this->rawNode->parentNode;
$parent->replaceChild($newFrag, $this->rawNode);
return $parent;
default:
return $decrypted;
}
} else {
return $decrypted;
}
} else {
throw new Exception("Cannot locate encrypted data");
}
}
/**
* Encrypt the XMLSecurityKey
*
* @param XMLSecurityKey $srcKey
* @param XMLSecurityKey $rawKey
* @param bool $append
* @throws Exception
*/
public function encryptKey($srcKey, $rawKey, $append=true)
{
if ((! $srcKey instanceof XMLSecurityKey) || (! $rawKey instanceof XMLSecurityKey)) {
throw new Exception('Invalid Key');
}
$strEncKey = base64_encode($srcKey->encryptData($rawKey->key));
$root = $this->encdoc->documentElement;
$encKey = $this->encdoc->createElementNS(self::XMLENCNS, 'xenc:EncryptedKey');
if ($append) {
$keyInfo = $root->insertBefore($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo'), $root->firstChild);
$keyInfo->appendChild($encKey);
} else {
$this->encKey = $encKey;
}
$encMethod = $encKey->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:EncryptionMethod'));
$encMethod->setAttribute('Algorithm', $srcKey->getAlgorith());
if (! empty($srcKey->name)) {
$keyInfo = $encKey->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo'));
$keyInfo->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyName', $srcKey->name));
}
$cipherData = $encKey->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:CipherData'));
$cipherData->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:CipherValue', $strEncKey));
if (is_array($this->references) && count($this->references) > 0) {
$refList = $encKey->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:ReferenceList'));
foreach ($this->references AS $name => $reference) {
$refuri = $reference["refuri"];
$dataRef = $refList->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:DataReference'));
$dataRef->setAttribute("URI", '#' . $refuri);
}
}
return;
}
/**
* @param XMLSecurityKey $encKey
* @return DOMElement|string
* @throws Exception
*/
public function decryptKey($encKey)
{
if (! $encKey->isEncrypted) {
throw new Exception("Key is not Encrypted");
}
if (empty($encKey->key)) {
throw new Exception("Key is missing data to perform the decryption");
}
return $this->decryptNode($encKey, false);
}
/**
* @param DOMDocument $element
* @return DOMNode|null
*/
public function locateEncryptedData($element)
{
if ($element instanceof DOMDocument) {
$doc = $element;
} else {
$doc = $element->ownerDocument;
}
if ($doc) {
$xpath = new DOMXPath($doc);
$query = "//*[local-name()='EncryptedData' and namespace-uri()='".self::XMLENCNS."']";
$nodeset = $xpath->query($query);
return $nodeset->item(0);
}
return null;
}
/**
* Returns the key from the DOM
* @param null|DOMNode $node
* @return null|XMLSecurityKey
*/
public function locateKey($node=null)
{
if (empty($node)) {
$node = $this->rawNode;
}
if (! $node instanceof DOMNode) {
return null;
}
if ($doc = $node->ownerDocument) {
$xpath = new DOMXPath($doc);
$xpath->registerNamespace('xmlsecenc', self::XMLENCNS);
$query = ".//xmlsecenc:EncryptionMethod";
$nodeset = $xpath->query($query, $node);
if ($encmeth = $nodeset->item(0)) {
$attrAlgorithm = $encmeth->getAttribute("Algorithm");
try {
$objKey = new XMLSecurityKey($attrAlgorithm, array('type' => 'private'));
} catch (Exception $e) {
return null;
}
return $objKey;
}
}
return null;
}
/**
* @param null|XMLSecurityKey $objBaseKey
* @param null|DOMNode $node
* @return null|XMLSecurityKey
* @throws Exception
*/
public static function staticLocateKeyInfo($objBaseKey=null, $node=null)
{
if (empty($node) || (! $node instanceof DOMNode)) {
return null;
}
$doc = $node->ownerDocument;
if (!$doc) {
return null;
}
$xpath = new DOMXPath($doc);
$xpath->registerNamespace('xmlsecenc', self::XMLENCNS);
$xpath->registerNamespace('xmlsecdsig', XMLSecurityDSig::XMLDSIGNS);
$query = "./xmlsecdsig:KeyInfo";
$nodeset = $xpath->query($query, $node);
$encmeth = $nodeset->item(0);
if (!$encmeth) {
/* No KeyInfo in EncryptedData / EncryptedKey. */
return $objBaseKey;
}
foreach ($encmeth->childNodes AS $child) {
switch ($child->localName) {
case 'KeyName':
if (! empty($objBaseKey)) {
$objBaseKey->name = $child->nodeValue;
}
break;
case 'KeyValue':
foreach ($child->childNodes AS $keyval) {
switch ($keyval->localName) {
case 'DSAKeyValue':
throw new Exception("DSAKeyValue currently not supported");
case 'RSAKeyValue':
$modulus = null;
$exponent = null;
if ($modulusNode = $keyval->getElementsByTagName('Modulus')->item(0)) {
$modulus = base64_decode($modulusNode->nodeValue);
}
if ($exponentNode = $keyval->getElementsByTagName('Exponent')->item(0)) {
$exponent = base64_decode($exponentNode->nodeValue);
}
if (empty($modulus) || empty($exponent)) {
throw new Exception("Missing Modulus or Exponent");
}
$publicKey = XMLSecurityKey::convertRSA($modulus, $exponent);
$objBaseKey->loadKey($publicKey);
break;
}
}
break;
case 'RetrievalMethod':
$type = $child->getAttribute('Type');
if ($type !== 'http://www.w3.org/2001/04/xmlenc#EncryptedKey') {
/* Unsupported key type. */
break;
}
$uri = $child->getAttribute('URI');
if ($uri[0] !== '#') {
/* URI not a reference - unsupported. */
break;
}
$id = substr($uri, 1);
$query = '//xmlsecenc:EncryptedKey[@Id="'.XPath::filterAttrValue($id, XPAth::DOUBLE_QUOTE).'"]';
$keyElement = $xpath->query($query)->item(0);
if (!$keyElement) {
throw new Exception("Unable to locate EncryptedKey with @Id='$id'.");
}
return XMLSecurityKey::fromEncryptedKeyElement($keyElement);
case 'EncryptedKey':
return XMLSecurityKey::fromEncryptedKeyElement($child);
case 'X509Data':
if ($x509certNodes = $child->getElementsByTagName('X509Certificate')) {
if ($x509certNodes->length > 0) {
$x509cert = $x509certNodes->item(0)->textContent;
$x509cert = str_replace(array("\r", "\n", " "), "", $x509cert);
$x509cert = "-----BEGIN CERTIFICATE-----\n".chunk_split($x509cert, 64, "\n")."-----END CERTIFICATE-----\n";
$objBaseKey->loadKey($x509cert, false, true);
}
}
break;
}
}
return $objBaseKey;
}
/**
* @param null|XMLSecurityKey $objBaseKey
* @param null|DOMNode $node
* @return null|XMLSecurityKey
*/
public function locateKeyInfo($objBaseKey=null, $node=null)
{
if (empty($node)) {
$node = $this->rawNode;
}
return self::staticLocateKeyInfo($objBaseKey, $node);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,749 @@
<?php
namespace RobRichards\XMLSecLibs;
use DOMElement;
use Exception;
/**
* xmlseclibs.php
*
* Copyright (c) 2007-2018, Robert Richards <rrichards@cdatazone.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Robert Richards nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @author Robert Richards <rrichards@cdatazone.org>
* @copyright 2007-2018 Robert Richards <rrichards@cdatazone.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class XMLSecurityKey
{
const TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
const AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc';
const AES192_CBC = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc';
const AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
const RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5';
const RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p';
const DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1';
const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
const RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
const RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384';
const RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';
const HMAC_SHA1 = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1';
/** @var array */
private $cryptParams = array();
/** @var int|string */
public $type = 0;
/** @var mixed|null */
public $key = null;
/** @var string */
public $passphrase = "";
/** @var string|null */
public $iv = null;
/** @var string|null */
public $name = null;
/** @var mixed|null */
public $keyChain = null;
/** @var bool */
public $isEncrypted = false;
/** @var XMLSecEnc|null */
public $encryptedCtx = null;
/** @var mixed|null */
public $guid = null;
/**
* This variable contains the certificate as a string if this key represents an X509-certificate.
* If this key doesn't represent a certificate, this will be null.
* @var string|null
*/
private $x509Certificate = null;
/**
* This variable contains the certificate thumbprint if we have loaded an X509-certificate.
* @var string|null
*/
private $X509Thumbprint = null;
/**
* @param string $type
* @param null|array $params
* @throws Exception
*/
public function __construct($type, $params=null)
{
switch ($type) {
case (self::TRIPLEDES_CBC):
$this->cryptParams['library'] = 'openssl';
$this->cryptParams['cipher'] = 'des-ede3-cbc';
$this->cryptParams['type'] = 'symmetric';
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
$this->cryptParams['keysize'] = 24;
$this->cryptParams['blocksize'] = 8;
break;
case (self::AES128_CBC):
$this->cryptParams['library'] = 'openssl';
$this->cryptParams['cipher'] = 'aes-128-cbc';
$this->cryptParams['type'] = 'symmetric';
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc';
$this->cryptParams['keysize'] = 16;
$this->cryptParams['blocksize'] = 16;
break;
case (self::AES192_CBC):
$this->cryptParams['library'] = 'openssl';
$this->cryptParams['cipher'] = 'aes-192-cbc';
$this->cryptParams['type'] = 'symmetric';
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc';
$this->cryptParams['keysize'] = 24;
$this->cryptParams['blocksize'] = 16;
break;
case (self::AES256_CBC):
$this->cryptParams['library'] = 'openssl';
$this->cryptParams['cipher'] = 'aes-256-cbc';
$this->cryptParams['type'] = 'symmetric';
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
$this->cryptParams['keysize'] = 32;
$this->cryptParams['blocksize'] = 16;
break;
case (self::RSA_1_5):
$this->cryptParams['library'] = 'openssl';
$this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5';
if (is_array($params) && ! empty($params['type'])) {
if ($params['type'] == 'public' || $params['type'] == 'private') {
$this->cryptParams['type'] = $params['type'];
break;
}
}
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
case (self::RSA_OAEP_MGF1P):
$this->cryptParams['library'] = 'openssl';
$this->cryptParams['padding'] = OPENSSL_PKCS1_OAEP_PADDING;
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p';
$this->cryptParams['hash'] = null;
if (is_array($params) && ! empty($params['type'])) {
if ($params['type'] == 'public' || $params['type'] == 'private') {
$this->cryptParams['type'] = $params['type'];
break;
}
}
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
case (self::RSA_SHA1):
$this->cryptParams['library'] = 'openssl';
$this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
$this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
if (is_array($params) && ! empty($params['type'])) {
if ($params['type'] == 'public' || $params['type'] == 'private') {
$this->cryptParams['type'] = $params['type'];
break;
}
}
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
case (self::RSA_SHA256):
$this->cryptParams['library'] = 'openssl';
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
$this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
$this->cryptParams['digest'] = 'SHA256';
if (is_array($params) && ! empty($params['type'])) {
if ($params['type'] == 'public' || $params['type'] == 'private') {
$this->cryptParams['type'] = $params['type'];
break;
}
}
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
case (self::RSA_SHA384):
$this->cryptParams['library'] = 'openssl';
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384';
$this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
$this->cryptParams['digest'] = 'SHA384';
if (is_array($params) && ! empty($params['type'])) {
if ($params['type'] == 'public' || $params['type'] == 'private') {
$this->cryptParams['type'] = $params['type'];
break;
}
}
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
case (self::RSA_SHA512):
$this->cryptParams['library'] = 'openssl';
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';
$this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
$this->cryptParams['digest'] = 'SHA512';
if (is_array($params) && ! empty($params['type'])) {
if ($params['type'] == 'public' || $params['type'] == 'private') {
$this->cryptParams['type'] = $params['type'];
break;
}
}
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
case (self::HMAC_SHA1):
$this->cryptParams['library'] = $type;
$this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1';
break;
default:
throw new Exception('Invalid Key Type');
}
$this->type = $type;
}
/**
* Retrieve the key size for the symmetric encryption algorithm..
*
* If the key size is unknown, or this isn't a symmetric encryption algorithm,
* null is returned.
*
* @return int|null The number of bytes in the key.
*/
public function getSymmetricKeySize()
{
if (! isset($this->cryptParams['keysize'])) {
return null;
}
return $this->cryptParams['keysize'];
}
/**
* Generates a session key using the openssl-extension.
* In case of using DES3-CBC the key is checked for a proper parity bits set.
* @return string
* @throws Exception
*/
public function generateSessionKey()
{
if (!isset($this->cryptParams['keysize'])) {
throw new Exception('Unknown key size for type "' . $this->type . '".');
}
$keysize = $this->cryptParams['keysize'];
$key = openssl_random_pseudo_bytes($keysize);
if ($this->type === self::TRIPLEDES_CBC) {
/* Make sure that the generated key has the proper parity bits set.
* Mcrypt doesn't care about the parity bits, but others may care.
*/
for ($i = 0; $i < strlen($key); $i++) {
$byte = ord($key[$i]) & 0xfe;
$parity = 1;
for ($j = 1; $j < 8; $j++) {
$parity ^= ($byte >> $j) & 1;
}
$byte |= $parity;
$key[$i] = chr($byte);
}
}
$this->key = $key;
return $key;
}
/**
* Get the raw thumbprint of a certificate
*
* @param string $cert
* @return null|string
*/
public static function getRawThumbprint($cert)
{
$arCert = explode("\n", $cert);
$data = '';
$inData = false;
foreach ($arCert AS $curData) {
if (! $inData) {
if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) {
$inData = true;
}
} else {
if (strncmp($curData, '-----END CERTIFICATE', 20) == 0) {
break;
}
$data .= trim($curData);
}
}
if (! empty($data)) {
return strtolower(sha1(base64_decode($data)));
}
return null;
}
/**
* Loads the given key, or - with isFile set true - the key from the keyfile.
*
* @param string $key
* @param bool $isFile
* @param bool $isCert
* @throws Exception
*/
public function loadKey($key, $isFile=false, $isCert = false)
{
if ($isFile) {
$this->key = file_get_contents($key);
} else {
$this->key = $key;
}
if ($isCert) {
$this->key = openssl_x509_read($this->key);
openssl_x509_export($this->key, $str_cert);
$this->x509Certificate = $str_cert;
$this->key = $str_cert;
} else {
$this->x509Certificate = null;
}
if ($this->cryptParams['library'] == 'openssl') {
switch ($this->cryptParams['type']) {
case 'public':
if ($isCert) {
/* Load the thumbprint if this is an X509 certificate. */
$this->X509Thumbprint = self::getRawThumbprint($this->key);
}
$this->key = openssl_get_publickey($this->key);
if (! $this->key) {
throw new Exception('Unable to extract public key');
}
break;
case 'private':
$this->key = openssl_get_privatekey($this->key, $this->passphrase);
break;
case'symmetric':
if (strlen($this->key) < $this->cryptParams['keysize']) {
throw new Exception('Key must contain at least 25 characters for this cipher');
}
break;
default:
throw new Exception('Unknown type');
}
}
}
/**
* ISO 10126 Padding
*
* @param string $data
* @param integer $blockSize
* @throws Exception
* @return string
*/
private function padISO10126($data, $blockSize)
{
if ($blockSize > 256) {
throw new Exception('Block size higher than 256 not allowed');
}
$padChr = $blockSize - (strlen($data) % $blockSize);
$pattern = chr($padChr);
return $data . str_repeat($pattern, $padChr);
}
/**
* Remove ISO 10126 Padding
*
* @param string $data
* @return string
*/
private function unpadISO10126($data)
{
$padChr = substr($data, -1);
$padLen = ord($padChr);
return substr($data, 0, -$padLen);
}
/**
* Encrypts the given data (string) using the openssl-extension
*
* @param string $data
* @return string
*/
private function encryptSymmetric($data)
{
$this->iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->cryptParams['cipher']));
$data = $this->padISO10126($data, $this->cryptParams['blocksize']);
$encrypted = openssl_encrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv);
if (false === $encrypted) {
throw new Exception('Failure encrypting Data (openssl symmetric) - ' . openssl_error_string());
}
return $this->iv . $encrypted;
}
/**
* Decrypts the given data (string) using the openssl-extension
*
* @param string $data
* @return string
*/
private function decryptSymmetric($data)
{
$iv_length = openssl_cipher_iv_length($this->cryptParams['cipher']);
$this->iv = substr($data, 0, $iv_length);
$data = substr($data, $iv_length);
$decrypted = openssl_decrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv);
if (false === $decrypted) {
throw new Exception('Failure decrypting Data (openssl symmetric) - ' . openssl_error_string());
}
return $this->unpadISO10126($decrypted);
}
/**
* Encrypts the given public data (string) using the openssl-extension
*
* @param string $data
* @return string
* @throws Exception
*/
private function encryptPublic($data)
{
if (! openssl_public_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) {
throw new Exception('Failure encrypting Data (openssl public) - ' . openssl_error_string());
}
return $encrypted;
}
/**
* Decrypts the given public data (string) using the openssl-extension
*
* @param string $data
* @return string
* @throws Exception
*/
private function decryptPublic($data)
{
if (! openssl_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
throw new Exception('Failure decrypting Data (openssl public) - ' . openssl_error_string());
}
return $decrypted;
}
/**
* Encrypts the given private data (string) using the openssl-extension
*
* @param string $data
* @return string
* @throws Exception
*/
private function encryptPrivate($data)
{
if (! openssl_private_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) {
throw new Exception('Failure encrypting Data (openssl private) - ' . openssl_error_string());
}
return $encrypted;
}
/**
* Decrypts the given private data (string) using the openssl-extension
*
* @param string $data
* @return string
* @throws Exception
*/
private function decryptPrivate($data)
{
if (! openssl_private_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
throw new Exception('Failure decrypting Data (openssl private) - ' . openssl_error_string());
}
return $decrypted;
}
/**
* Signs the given data (string) using the openssl-extension
*
* @param string $data
* @return string
* @throws Exception
*/
private function signOpenSSL($data)
{
$algo = OPENSSL_ALGO_SHA1;
if (! empty($this->cryptParams['digest'])) {
$algo = $this->cryptParams['digest'];
}
if (! openssl_sign($data, $signature, $this->key, $algo)) {
throw new Exception('Failure Signing Data: ' . openssl_error_string() . ' - ' . $algo);
}
return $signature;
}
/**
* Verifies the given data (string) belonging to the given signature using the openssl-extension
*
* Returns:
* 1 on succesful signature verification,
* 0 when signature verification failed,
* -1 if an error occurred during processing.
*
* NOTE: be very careful when checking the return value, because in PHP,
* -1 will be cast to True when in boolean context. So always check the
* return value in a strictly typed way, e.g. "$obj->verify(...) === 1".
*
* @param string $data
* @param string $signature
* @return int
*/
private function verifyOpenSSL($data, $signature)
{
$algo = OPENSSL_ALGO_SHA1;
if (! empty($this->cryptParams['digest'])) {
$algo = $this->cryptParams['digest'];
}
return openssl_verify($data, $signature, $this->key, $algo);
}
/**
* Encrypts the given data (string) using the regarding php-extension, depending on the library assigned to algorithm in the contructor.
*
* @param string $data
* @return mixed|string
*/
public function encryptData($data)
{
if ($this->cryptParams['library'] === 'openssl') {
switch ($this->cryptParams['type']) {
case 'symmetric':
return $this->encryptSymmetric($data);
case 'public':
return $this->encryptPublic($data);
case 'private':
return $this->encryptPrivate($data);
}
}
}
/**
* Decrypts the given data (string) using the regarding php-extension, depending on the library assigned to algorithm in the contructor.
*
* @param string $data
* @return mixed|string
*/
public function decryptData($data)
{
if ($this->cryptParams['library'] === 'openssl') {
switch ($this->cryptParams['type']) {
case 'symmetric':
return $this->decryptSymmetric($data);
case 'public':
return $this->decryptPublic($data);
case 'private':
return $this->decryptPrivate($data);
}
}
}
/**
* Signs the data (string) using the extension assigned to the type in the constructor.
*
* @param string $data
* @return mixed|string
*/
public function signData($data)
{
switch ($this->cryptParams['library']) {
case 'openssl':
return $this->signOpenSSL($data);
case (self::HMAC_SHA1):
return hash_hmac("sha1", $data, $this->key, true);
}
}
/**
* Verifies the data (string) against the given signature using the extension assigned to the type in the constructor.
*
* Returns in case of openSSL:
* 1 on succesful signature verification,
* 0 when signature verification failed,
* -1 if an error occurred during processing.
*
* NOTE: be very careful when checking the return value, because in PHP,
* -1 will be cast to True when in boolean context. So always check the
* return value in a strictly typed way, e.g. "$obj->verify(...) === 1".
*
* @param string $data
* @param string $signature
* @return bool|int
*/
public function verifySignature($data, $signature)
{
switch ($this->cryptParams['library']) {
case 'openssl':
return $this->verifyOpenSSL($data, $signature);
case (self::HMAC_SHA1):
$expectedSignature = hash_hmac("sha1", $data, $this->key, true);
return strcmp($signature, $expectedSignature) == 0;
}
}
/**
* @deprecated
* @see getAlgorithm()
* @return mixed
*/
public function getAlgorith()
{
return $this->getAlgorithm();
}
/**
* @return mixed
*/
public function getAlgorithm()
{
return $this->cryptParams['method'];
}
/**
*
* @param int $type
* @param string $string
* @return null|string
*/
public static function makeAsnSegment($type, $string)
{
switch ($type) {
case 0x02:
if (ord($string) > 0x7f)
$string = chr(0).$string;
break;
case 0x03:
$string = chr(0).$string;
break;
}
$length = strlen($string);
if ($length < 128) {
$output = sprintf("%c%c%s", $type, $length, $string);
} else if ($length < 0x0100) {
$output = sprintf("%c%c%c%s", $type, 0x81, $length, $string);
} else if ($length < 0x010000) {
$output = sprintf("%c%c%c%c%s", $type, 0x82, $length / 0x0100, $length % 0x0100, $string);
} else {
$output = null;
}
return $output;
}
/**
*
* Hint: Modulus and Exponent must already be base64 decoded
* @param string $modulus
* @param string $exponent
* @return string
*/
public static function convertRSA($modulus, $exponent)
{
/* make an ASN publicKeyInfo */
$exponentEncoding = self::makeAsnSegment(0x02, $exponent);
$modulusEncoding = self::makeAsnSegment(0x02, $modulus);
$sequenceEncoding = self::makeAsnSegment(0x30, $modulusEncoding.$exponentEncoding);
$bitstringEncoding = self::makeAsnSegment(0x03, $sequenceEncoding);
$rsaAlgorithmIdentifier = pack("H*", "300D06092A864886F70D0101010500");
$publicKeyInfo = self::makeAsnSegment(0x30, $rsaAlgorithmIdentifier.$bitstringEncoding);
/* encode the publicKeyInfo in base64 and add PEM brackets */
$publicKeyInfoBase64 = base64_encode($publicKeyInfo);
$encoding = "-----BEGIN PUBLIC KEY-----\n";
$offset = 0;
while ($segment = substr($publicKeyInfoBase64, $offset, 64)) {
$encoding = $encoding.$segment."\n";
$offset += 64;
}
return $encoding."-----END PUBLIC KEY-----\n";
}
/**
* @param mixed $parent
*/
public function serializeKey($parent)
{
}
/**
* Retrieve the X509 certificate this key represents.
*
* Will return the X509 certificate in PEM-format if this key represents
* an X509 certificate.
*
* @return string The X509 certificate or null if this key doesn't represent an X509-certificate.
*/
public function getX509Certificate()
{
return $this->x509Certificate;
}
/**
* Get the thumbprint of this X509 certificate.
*
* Returns:
* The thumbprint as a lowercase 40-character hexadecimal number, or null
* if this isn't a X509 certificate.
*
* @return string Lowercase 40-character hexadecimal number of thumbprint
*/
public function getX509Thumbprint()
{
return $this->X509Thumbprint;
}
/**
* Create key from an EncryptedKey-element.
*
* @param DOMElement $element The EncryptedKey-element.
* @throws Exception
*
* @return XMLSecurityKey The new key.
*/
public static function fromEncryptedKeyElement(DOMElement $element)
{
$objenc = new XMLSecEnc();
$objenc->setNode($element);
if (! $objKey = $objenc->locateKey()) {
throw new Exception("Unable to locate algorithm for this Encrypted Key");
}
$objKey->isEncrypted = true;
$objKey->encryptedCtx = $objenc;
XMLSecEnc::staticLocateKeyInfo($objKey, $element);
return $objKey;
}
}

View File

@ -0,0 +1,47 @@
<?php
/**
* xmlseclibs.php
*
* Copyright (c) 2007-2018, Robert Richards <rrichards@cdatazone.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Robert Richards nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @author Robert Richards <rrichards@cdatazone.org>
* @copyright 2007-2018 Robert Richards <rrichards@cdatazone.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @version 3.0.2
*/
$xmlseclibs_srcdir = dirname(__FILE__) . '/src/';
require $xmlseclibs_srcdir . '/XMLSecurityKey.php';
require $xmlseclibs_srcdir . '/XMLSecurityDSig.php';
require $xmlseclibs_srcdir . '/XMLSecEnc.php';
require $xmlseclibs_srcdir . '/Utils/XPath.php';