performer / php-saml
OneLogin PHP SAML 工具包
Requires
- php: >=5.3.2
- ext-dom: *
- ext-mcrypt: *
- ext-openssl: *
Requires (Dev)
- pdepend/pdepend: 1.1.0
- phploc/phploc: *
- phpunit/phpunit: 3.7.31
- satooshi/php-coveralls: 1.0.1
- sebastian/phpcpd: *
- squizlabs/php_codesniffer: *
Suggests
- 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)
README
使用此库将 SAML 支持添加到您的 PHP 软件。忘记那些复杂的库,使用 OneLogin Inc. 提供和支持的开源库。
为什么要在我的软件中添加 SAML 支持?
SAML 是一种基于 XML 的网络浏览器单点登录标准,由 OASIS 安全服务技术委员会定义。该标准自 2002 年以来一直存在,但近年来由于其优势而越来越受欢迎。
- 可用性 - 从门户或内网一键访问、深度链接、消除密码和自动续期会话使用户的生活更加便捷。
- 安全性 - 基于强大的数字签名进行身份验证和完整性,SAML 是一个安全的单点登录协议,世界上最大和最注重安全的公司都依赖它。
- 速度 - SAML 很快。只需一次浏览器重定向即可安全地将用户登录到应用程序。
- 钓鱼防护 - 如果您没有应用程序的密码,您就不会被欺骗在假登录页面上输入它。
- 对 IT 友好 - SAML 简化了 IT 的生活,因为它集中身份验证、提供更大的可见性并简化目录集成。
- 机会 - B2B 云供应商应支持 SAML 以促进其产品的集成。
一般描述
OneLogin 的 SAML PHP 工具包允许您在 PHP 应用程序上构建 SP(服务提供商)并将其连接到任何 IdP(身份提供者)。
支持
- SSO 和 SLO(SP 初始化和 IdP 初始化)。
- 断言和 nameId 加密。
- 断言签名。
- 消息签名:AuthNRequest、LogoutRequest、LogoutResponses。
- 启用断言消费者服务端点。
- 启用单点登出服务端点。
- 发布 SP 元数据(可以签名)。
主要功能
- saml2int - 实现 SAML 2.0 Web 浏览器 SSO 配置文件。
- 无会话 - 忘记那些 SP 和最终应用程序之间的常见冲突,此工具包将会话委托给最终应用程序。
- 易于使用 - 开发人员将被允许编写高级和低级编程,提供 2 个易于使用的 API。
- 经过测试 - 经彻底测试。
- 受欢迎 - OneLogin 的客户使用它。许多 PHP SAML 插件使用它。
使用此指南在 OneLogin 中集成您的 PHP 工具包:https://developers.onelogin.com/page/saml-toolkit-for-php
安装
依赖关系
php >= 5.3.3
和一些核心扩展,如php-xml
、php-date
、php-zlib
。openssl
。安装 openssl 库。它处理 x509 证书。mcrypt
。如果您将要处理加密数据(如nameID
、assertions
),请安装该库及其 php 驱动程序。gettext
。安装该库及其 php 驱动程序。它处理翻译。
由于 PHP 5.3 已正式不再支持,我们建议您使用较新的 PHP 版本。
代码
选项 1. 从 github 下载
此工具包托管在 github 上。您可以从中下载
- 最新发布版:https://github.com/onelogin/php-saml/releases/latest
- 主仓库:https://github.com/onelogin/php-saml/tree/master
将库的核心复制到PHP应用程序中。(每个应用程序都有自己的结构,所以请花时间找到最佳的PHP SAML工具包位置)。请参阅“添加SAML支持到我的应用的指南”以了解如何操作。
选项2. Composer
工具包支持composer。您可以在https://packagist.org.cn/packages/onelogin/php-saml找到onelogin/php-saml
包。
要将SAML工具包导入到您当前的PHP项目中,请执行
composer require onelogin/php-saml
安装完成后,您将在vendor/
文件夹中找到一个名为onelogin
的新文件夹,并在其中包含php-saml
。请确保您包括由composer提供的自动加载器。它可以在vendor/autoload.php
中找到。
重要 在此选项中,x509证书必须存储在vendor/onelogin/php-saml/certs
中,设置文件存储在vendor/onelogin/php-saml
中。
当使用composer update
或类似命令更新包时,您的设置可能会被删除。因此,强烈建议您不要使用设置文件,而是直接将设置作为数组传递给构造函数(本文件稍后解释)。如果您不采用此方法,则在更新包时,您的设置可能会被删除。
兼容性
此2.0版本有一个新的库。工具包仍然兼容。
您用于添加SAML支持的旧代码将继续工作,只需加载lib/Saml
文件夹中的文件即可。(注意,compatibility.php
文件会这样做)。
旧-demo文件夹包含使用工具包旧版本(v.1)的旧应用程序的代码。请查看。
有时旧代码中类的名称可能略有不同,如果是这种情况,您必须将它们更改为OneLogin_Saml_Settings
、OneLogin_Saml_Response
、OneLogin_Saml_AuthRequest
或OneLogin_Saml_Metadata
。
我们建议您将旧代码迁移到新版本,以便能够使用新库Saml2的新功能。
命名空间
如果您正在使用像Symfony2这样的包含命名空间的框架,请记住,对类的调用必须通过在开头添加反斜杠(\
)来执行,例如,要使用静态方法getSelfURLNoQuery,请使用
\OneLogin_Saml2_Utils::getSelfURLNoQuery()
安全警告
在生产环境中,strict
参数必须设置为"true"
。否则,您的环境将不安全,并可能遭受攻击。
入门
了解工具包
新的OneLogin SAML工具包包含不同的文件夹(certs
、endpoints
、extlib
、lib
、demo
等)和一些文件。
让我们先描述一下文件夹
certs/
SAML需要x.509证书来签名和加密元素,如NameID
、Message
、Assertion
、Metadata
。
如果我们的环境需要签名或加密支持,此文件夹可能包含SP将使用的x509证书和私钥
sp.crt
- SP的公共证书sp.key
- SP的私钥
或者我们也可以在设置文件的$settings['sp']['x509cert']
和$settings['sp']['privateKey']
中提供这些数据。
有时我们可能需要在SP发布的元数据上添加签名,在这种情况下,我们可以使用前面提到的x.509证书或使用新的x.509证书:metadata.crt
和metadata.key
。
extlib/
此文件夹包含工具包使用的第三方库。目前仅使用xmlseclibs
(作者Robert Richards,BSD许可证),该库处理xml元素的签名和加密。
lib/
此文件夹包含工具包的核心,即库
Saml
文件夹包含工具包v.1的修改版本,允许旧代码继续工作。(此库提供以保持向后兼容性)。Saml2
文件夹包含后面章节中描述的新版本类和方法。
doc/
此文件夹包含工具包的API文档。
endpoints/
工具包有三个端点
metadata.php
- SP元数据发布的地方。acs.php
- 断言消费者服务。处理SAML响应。sls.php
- 单一注销服务。处理注销请求和注销响应。
您可以使用工具包提供的文件,或在添加SAML支持到您的应用程序时创建自己的端点文件。请注意,这些端点文件使用工具包基本文件夹的设置文件。
locale/
Locale 文件夹包含一些翻译:作为概念验证的 en_US
和 es_ES
。目前没有翻译,但最终我们将本地化消息并支持多种语言。
其他重要文件
settings_example_example.php
- 创建包含工具包基本配置信息的settings.php文件时要使用的模板。advanced_settings_example.php
- 创建包含与安全性、联系人以及与SP关联的组织的额外配置信息的advanced_settings.php文件时要使用的模板。_toolkit_loader.php
- 此文件加载工具包库(SAML2库)。compatibility
- 导入该文件以使旧代码与新工具包兼容(加载SAML库)。
杂项
tests/
- 包含工具包的单元测试。demo1/
- 包含具有SAML支持的简单PHP应用程序示例。阅读其中的Readme.txt
获取更多信息。demo2/
- 包含另一个示例。demo-old/
- 包含使用工具包旧版本代码的示例,以演示向后兼容性。
工作原理
设置
首先,我们需要配置工具包。SP的信息、IdP的信息,以及在某些情况下,配置高级安全问题,如签名和加密。
有两种方式提供设置信息
- 使用位于工具包基本文件夹中的
settings.php
文件。 - 使用设置数据的数组,并将其直接提供给类的构造函数。
有一个模板文件,settings_example.php
,因此您可以复制此文件,重命名并编辑它。
<?php $settings = array ( // If 'strict' is True, then the PHP Toolkit will reject unsigned // or unencrypted messages if it expects them to be signed or encrypted. // Also it will reject the messages if the SAML standard is not strictly // followed: Destination, NameId, Conditions ... are validated too. 'strict' => false, // Enable debug mode (to print errors). 'debug' => false, // Service Provider Data that we are deploying. '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 ( // URL Location where the <Response> from the IdP will be returned 'url' => '', // SAML protocol binding to be used when returning the <Response> // message. OneLogin Toolkit supports this endpoint for the // HTTP-POST binding only. 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', ), // Specifies info about where and how the <Logout Response> message MUST be // returned to the requester, in this case our SP. 'singleLogoutService' => array ( // URL Location where the <Response> from the IdP will be returned 'url' => '', // SAML protocol binding to be used when returning the <Response> // message. OneLogin Toolkit supports the HTTP-Redirect binding // only for this endpoint. 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', ), // Specifies the constraints on the name identifier to be used to // represent the requested subject. // Take a look on lib/Saml2/Constants.php to see the NameIdFormat supported. 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', // Usually x509cert and privateKey of the SP are provided by files placed at // the certs folder. But we can also provide them with the following parameters 'x509cert' => '', 'privateKey' => '', ), // Identity Provider Data that we want connected with our SP. 'idp' => array ( // Identifier of the IdP entity (must be a URI) 'entityId' => '', // SSO endpoint info of the IdP. (Authentication Request protocol) 'singleSignOnService' => array ( // URL Target of the IdP where the Authentication Request Message // will be sent. 'url' => '', // SAML protocol binding to be used when returning the <Response> // message. OneLogin Toolkit supports the HTTP-Redirect binding // only for this endpoint. 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', ), // SLO endpoint info of the IdP. 'singleLogoutService' => array ( // URL Location of the IdP where SLO Request will be sent. 'url' => '', // SAML protocol binding to be used when returning the <Response> // message. OneLogin Toolkit supports the HTTP-Redirect binding // only for this endpoint. 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', ), // Public x509 certificate of the IdP 'x509cert' => '', /* * Instead of use the whole x509cert you can use a fingerprint in order to * validate a SAMLResponse. * (openssl x509 -noout -fingerprint -in "idp.crt" to generate it, * or add for example the -sha256 , -sha384 or -sha512 parameter) * * If a fingerprint is provided, then the certFingerprintAlgorithm is required in order to * let the toolkit know which algorithm was used. Possible values: sha1, sha256, sha384 or sha512 * 'sha1' is the default value. * * Notice that if you want to validate any SAML Message sent by the HTTP-Redirect binding, you * will need to provide the whole x509cert. */ // 'certFingerprint' => '', // 'certFingerprintAlgorithm' => 'sha1', ), );
除了所需的设置数据(IdP、SP)之外,还可以定义其他信息。与存在用于基本信息的模板一样,工具包基本文件夹中还有一个名为 advanced_settings_example.php
的模板,您可以复制并重命名为 advanced_settings.php
。
<?php $advancedSettings = array ( // Security settings 'security' => array ( /** signatures and encryptions offered */ // Indicates that the nameID of the <samlp:logoutRequest> sent by this SP // will be encrypted. 'nameIdEncrypted' => false, // Indicates whether the <samlp:AuthnRequest> messages sent by this SP // will be signed. [Metadata of the SP will offer this info] 'authnRequestsSigned' => false, // Indicates whether the <samlp:logoutRequest> messages sent by this SP // will be signed. 'logoutRequestSigned' => false, // Indicates whether the <samlp:logoutResponse> messages sent by this SP // will be signed. 'logoutResponseSigned' => false, /* Sign the Metadata False || True (use sp certs) || array ( keyFileName => 'metadata.key', certFileName => 'metadata.crt' ) */ 'signMetadata' => false, /** signatures and encryptions required **/ // Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest> // and <samlp:LogoutResponse> elements received by this SP to be signed. 'wantMessagesSigned' => false, // Indicates a requirement for the <saml:Assertion> elements received by // this SP to be signed. [Metadata of the SP will offer this info] 'wantAssertionsSigned' => false, // Indicates a requirement for the NameID received by // this SP to be encrypted. 'wantNameIdEncrypted' => false, // Authentication context. // Set to false and no AuthContext will be sent in the AuthNRequest, // Set true or don't present thi 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'), 'requestedAuthnContext' => true, // Indicates if the SP will validate all received xmls. // (In order to validate the xml, 'strict' and 'wantXMLValidation' must be true). 'wantXMLValidation' => true, // Algorithm that the toolkit will use on signing process. Options: // 'http://www.w3.org/2000/09/xmldsig#rsa-sha1' // 'http://www.w3.org/2000/09/xmldsig#dsa-sha1' // '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', ), // Contact information template, it is recommended to suply a // technical and support contacts. 'contactPerson' => array ( 'technical' => array ( 'givenName' => '', 'emailAddress' => '' ), 'support' => array ( 'givenName' => '', 'emailAddress' => '' ), ), // Organization information template, the info in en_US lang is // recomended, add more if required. 'organization' => array ( 'en-US' => array( 'name' => '', 'displayname' => '', 'url' => '' ), ), );
在安全部分,您可以设置SP将如何处理消息和断言。联系IdP的管理员,并询问IdP期望什么,并决定SP将处理哪些验证以及SP将有什么要求,并将这些要求传达给IdP的管理员。
一旦我们知道可以配置哪些类型的数据,让我们谈谈工具包内部如何处理设置。
描述的设置文件(settings.php
和 advanced_settings.php
)如果构造函数中没有提供包含设置信息的其他数组,则由工具包加载。让我们看一些示例。
// Initializes toolkit with settings.php & advanced_settings files. $auth = new OneLogin_Saml2_Auth(); //or $settings = new OneLogin_Saml2_Settings(); // Initializes toolkit with the array provided. $auth = new OneLogin_Saml2_Auth($settingsInfo); //or $settings = new OneLogin_Saml2_Settings($settingsInfo);
您可以在包含构造函数执行的文件中声明 $settingsInfo
,或者将它们放在任何文件中,然后加载该文件以获取我们将在以下示例中看到的可用数组。
<?php require_once 'custom_settings.php'; // The custom_settings.php contains a // $settingsInfo array. $auth = new OneLogin_Saml2_Auth($settingsInfo);
如何加载库
为了使用工具库,您需要导入位于工具库基本目录中的 _toolkit_loader.php
文件。您可以按以下方式加载此文件
<?php define("TOOLKIT_PATH", '/var/www/php-saml/'); require_once(TOOLKIT_PATH . '_toolkit_loader.php');
在此行之后,我们将能够使用工具库中的类(及其方法)(因为已加载了外部和 Saml2 库文件)。
如果您为 PHP-SAML 工具库的版本 1 编写了 SAML 应用程序的代码,则需要加载 compatibility.php
文件,该文件加载 SAML 库文件,以及 _toolkit_loader.php
。
该 SAML 库使用最新版本工具库的新类和方法,但保留旧类、方法和旧流程,以完成相同的功能。
我们强烈建议迁移旧代码并使用新工具库的新 API,因为有很多新功能您无法用旧代码处理。
启动 SSO
为了向 IdP 发送 AuthNRequest
<?php define("TOOLKIT_PATH", '/var/www/php-saml/'); require_once(TOOLKIT_PATH . '_toolkit_loader.php'); // We load the SAML2 lib $auth = new OneLogin_Saml2_Auth(); // Constructor of the SP, loads settings.php // and advanced_settings.php $auth->login(); // Method that sent the AuthNRequest
根据 advanced_settings.php
('authnRequestsSigned'
)中的安全信息,AuthNRequest
将以签名或未签名的方式发送。
然后,IdP 将返回 SAML 响应给用户的客户端。然后,客户端会带着这些信息被转发到 SP 的属性消费者服务。如果我们没有在登录方法中设置 'url' 参数,并且我们使用工具库提供的默认 ACS(endpoints/acs.php
),则 ACS 端点将重定向用户到启动 SSO 请求的文件。
我们可以设置一个 'returnTo'
URL 以更改工作流程并重定向用户到另一个 PHP 文件。
$newTargetUrl = 'http://example.com/consume2.php'; $auth = new OneLogin_Saml2_Auth(); $auth->login($newTargetUrl);
登录方法可以接收其他四个可选参数
$parameters
- 一个参数数组,将在 HTTP-Redirect 中的GET
中添加。$forceAuthn
- 当为 true 时,AuthNRequest
将设置ForceAuthn='true'
$isPassive
- 当为 true 时,AuthNRequest
将设置Ispassive='true'
$strict
- 如果我们想保留(返回 URL 字符串),则为 true;如果我们要重定向,则为 false
如果需要匹配未来的 SAMLResponse ID 和要发送的 AuthNRequest ID,则必须提取并保存该 AuthNRequest ID。
$ssoBuiltUrl = $auth->login(null, array(), false, false, true); $_SESSION['AuthNRequestID'] = $auth->getLastRequestID(); header('Pragma: no-cache'); header('Cache-Control: no-cache, must-revalidate'); header('Location: ' . $ssoBuiltUrl); exit();
SP 端点
与 SP 相关有三个重要视图:元数据视图、ACS 视图和 SLS 视图。工具库在 endpoints 目录中提供了这些视图的示例。
SP 元数据 endpoints/metadata.php
此代码将根据我们在设置文件中提供的信息提供我们的 SP 的 XML 元数据文件。
<?php define("TOOLKIT_PATH", '/var/www/php-saml/'); require_once dirname(TOOLKIT_PATH.'/_toolkit_loader.php'; try { $auth = new OneLogin_Saml2_Auth(); $settings = $auth->getSettings(); $metadata = $settings->getSPMetadata(); $errors = $settings->validateMetadata($metadata); if (empty($errors)) { header('Content-Type: text/xml'); echo $metadata; } else { throw new OneLogin_Saml2_Error( 'Invalid SP metadata: '.implode(', ', $errors), OneLogin_Saml2_Error::METADATA_SP_INVALID ); } } catch (Exception $e) { echo $e->getMessage(); }
getSPMetadata
将返回基于 advanced_settings.php
('signMetadata'
)中的安全信息已签名或未签名的元数据。
在暴露 XML 元数据之前,将进行一次检查以确保要提供的信息有效。
除了使用 Auth 对象外,您还可以直接使用
$settings = new OneLogin_Saml2_Settings($settingsInfo, true);
来获取设置对象,并通过使用 true 参数来避免 IdP 设置验证。
属性消费者服务(ACS)endpoints/acs.php
此代码处理 IdP 通过用户的客户端转发给 SP 的 SAML 响应。
<?php session_start(); // IMPORTANT: This is required in order to be able // to store the user data in the session. define("TOOLKIT_PATH", '/var/www/php-saml/'); require_once dirname(TOOLKIT_PATH.'/_toolkit_loader.php'; $auth = new OneLogin_Saml2_Auth(); if (isset($_SESSION) && isset($_SESSION['AuthNRequestID'])) { $requestID = $_SESSION['AuthNRequestID']; } else { $requestID = null; } $auth->processResponse($requestID); $errors = $auth->getErrors(); if (!empty($errors)) { print_r('<p>'.implode(', ', $errors).'</p>'); exit(); } if (!$auth->isAuthenticated()) { echo "<p>Not authenticated</p>"; exit(); } $_SESSION['samlUserdata'] = $auth->getAttributes(); $_SESSION['samlNameId'] = $auth->getNameId(); if (isset($_POST['RelayState']) && OneLogin_Saml2_Utils::getSelfURL() != $_POST['RelayState']) { $auth->redirectTo($_POST['RelayState']); } $attributes = $_SESSION['samlUserdata']; $nameId = $_SESSION['samlNameId']; echo '<h1>Identified user: '. htmlentities($nameId) .'</h1>'; if (!empty($attributes)) { echo '<h2>'._('User attributes:').'</h2>'; echo '<table><thead><th>'._('Name').'</th><th>'._('Values').'</th></thead><tbody>'; foreach ($attributes as $attributeName => $attributeValues) { echo '<tr><td>' . htmlentities($attributeName) . '</td><td><ul>'; foreach ($attributeValues as $attributeValue) { echo '<li>' . htmlentities($attributeValue) . '</li>'; } echo '</ul></td></tr>'; } echo '</tbody></table>'; } else { echo _('No attributes found.'); }
SAML 响应被处理并检查是否存在错误。它还验证用户是否已认证,并将用户数据存储在会话中。
在此点有两个可能的方案
-
如果没有提供
RelayState
,我们可以在该视图中显示用户数据或按需显示。 -
如果提供了
RelayState
,则进行重定向。
注意,我们在重定向之前将用户数据保存在会话中,以便在 RelayState
视图中可用用户数据。
getAttributes
方法
为了检索属性,我们可以使用
$attributes = $auth->getAttributes();
使用此方法,我们可以获取SAML响应断言中IdP提供的所有用户数据。
如果我们执行 print_r($attributes)
,我们可能会得到
Array ( [cn] => Array ( [0] => John ) [sn] => Array ( [0] => Doe ) [mail] => Array ( [0] => john.doe@example.com ) [groups] => Array ( [0] => users [1] => members ) )
每个属性名称都可以用作 $attributes
的索引来获取值。每个属性值都是一个数组 - 单值属性是一个只有一个元素的数组。
以下代码是等效的
$attributes = $auth->getAttributes(); print_r($attributes['cn']);
print_r($auth->getAttribute('cn'));
在尝试获取属性之前,请检查用户是否已认证。如果用户未认证或SAML断言中没有属性,则将返回空数组。例如,如果我们调用 getAttributes
在 $auth->processResponse
之前,则 getAttributes()
将返回空数组。
单点登出服务(SLS)endpoints/sls.php
此代码处理登出请求和登出响应。
<?php session_start(); // IMPORTANT: This is required in order to be able // to close the user session. define("TOOLKIT_PATH", '/var/www/php-saml/'); require_once dirname(TOOLKIT_PATH.'/_toolkit_loader.php'; $auth = new OneLogin_Saml2_Auth(); if (isset($_SESSION) && isset($_SESSION['LogoutRequestID'])) { $requestID = $_SESSION['LogoutRequestID']; } else { $requestID = null; } $auth->processSLO(false, $requestID); $errors = $auth->getErrors(); if (empty($errors)) { print_r('Sucessfully logged out'); } else { print_r(implode(', ', $errors)); }
如果SLS端点收到登出响应,将验证响应并关闭会话
// part of the processSLO method $logoutResponse = new OneLogin_Saml2_LogoutResponse($this->_settings, $_GET['SAMLResponse']); if (!$logoutResponse->isValid($requestId)) { $this->_errors[] = 'invalid_logout_response'; } else if ($logoutResponse->getStatus() !== OneLogin_Saml2_Constants::STATUS_SUCCESS) { $this->_errors[] = 'logout_not_success'; } else { if (!$keepLocalSession) { OneLogin_Saml2_Utils::deleteLocalSession(); } }
如果SLS端点收到登出请求,则验证请求,关闭会话并向IdP的SLS端点发送登出响应。
// part of the processSLO method $decoded = base64_decode($_GET['SAMLRequest']); $request = gzinflate($decoded); if (!OneLogin_Saml2_LogoutRequest::isValid($this->_settings, $request)) { $this->_errors[] = 'invalid_logout_request'; } else { if (!$keepLocalSession) { OneLogin_Saml2_Utils::deleteLocalSession(); } $inResponseTo = $request->id; $responseBuilder = new OneLogin_Saml2_LogoutResponse($this->_settings); $responseBuilder->build($inResponseTo); $logoutResponse = $responseBuilder->getResponse(); $parameters = array('SAMLResponse' => $logoutResponse); if (isset($_GET['RelayState'])) { $parameters['RelayState'] = $_GET['RelayState']; } $security = $this->_settings->getSecurityData(); if (isset($security['logoutResponseSigned']) && $security['logoutResponseSigned']) { $signature = $this->buildResponseSignature($logoutResponse, $parameters['RelayState'], $security['signatureAlgorithm']); $parameters['SigAlg'] = $security['signatureAlgorithm']; $parameters['Signature'] = $signature; } $this->redirectTo($this->getSLOurl(), $parameters); }
如果您不是使用默认PHP会话,或者需要手动销毁会话,可以将回调方法传递给 processSLO
方法作为第四个参数
$keepLocalSession = False; $callback = function () { // Destroy user session }; $auth->processSLO($keepLocalSession, null, false, $callback);
如果我们不想让 processSLO
销毁会话,请将一个true参数传递给 processSLO
方法
$keepLocalSession = True; $auth->processSLO($keepLocalSession);
启动SLO
为了向IdP发送登出请求
<?php define("TOOLKIT_PATH", '/var/www/php-saml/'); require_once(TOOLKIT_PATH . '_toolkit_loader.php'); $auth = new OneLogin_Saml2_Auth(); $auth->logout(); // Method that sent the Logout Request.
此外,还可以设置三个可选参数
$name_id
- 将用于构建登出请求。如果未设置name_id
参数,并且auth对象处理了带有NameId
的SAML响应,则将使用此NameId
。$session_index
- 识别用户会话的SessionIndex。$strict
- 如果我们想要停留(返回URL字符串),则为False以重定向。
根据 advanced_settings.php
('logoutRequestSigned'
)中的安全信息,登出请求将签名或未签名地发送。
IdP将通过用户的客户端返回登出响应到SP的单点登出服务。如果我们没有在登出方法中设置 'url'
参数并使用工具箱提供的默认SLS(endpoints/sls.php
),则SLS端点将重定向用户到启动SLO请求的文件。
我们可以设置一个 'returnTo'
URL来更改工作流程并将用户重定向到其他PHP文件。
$newTargetUrl = 'http://example.com/loggedOut.php'; $auth = new OneLogin_Saml2_Auth(); $auth->logout($newTargetUrl);
如果需要将未来的登出响应ID与要发送的登出请求ID进行匹配,则必须提取并存储该登出请求ID。
$sloBuiltUrl = $auth->logout(null, $paramters, $nameId, $sessionIndex, true); $_SESSION['LogoutRequestID'] = $auth->getLastRequestID(); header('Pragma: no-cache'); header('Cache-Control: no-cache, must-revalidate'); header('Location: ' . $sloBuiltUrl); exit();
初始化SSO请求和处理的视图示例(是acs目标)
我们可以编写一个独特的文件来启动SSO过程,处理响应,获取属性,启动SLO并处理登出响应。
注意:请参阅包含该用例的 demo1
文件夹;在稍后的部分中,我们将更详细地解释demo1用例。
<?php session_start(); // Initialize the session, we do that because // Note that processResponse and processSLO // methods could manipulate/close that session require_once dirname(dirname(__FILE__)).'/_toolkit_loader.php'; // Load Saml2 and // external libs require_once 'settings.php'; // Load the setting info as an Array $auth = new OneLogin_Saml2_Auth($settingsInfo); // Initialize the SP SAML instance if (isset($_GET['sso'])) { // SSO action. Will send an AuthNRequest to the IdP $auth->login(); } else if (isset($_GET['sso2'])) { // Another SSO action $returnTo = $spBaseUrl.'/demo1/attrs.php'; // but set a custom RelayState URL $auth->login($returnTo); } else if (isset($_GET['slo'])) { // SLO action. Will sent a Logout Request to IdP $auth->logout(); } else if (isset($_GET['acs'])) { // Assertion Consumer Service $auth->processResponse(); // Process the Response of the IdP, get the // attributes and put then at // $_SESSION['samlUserdata'] $errors = $auth->getErrors(); // This method receives an array with the errors // that could took place during the process if (!empty($errors)) { print_r('<p>'.implode(', ', $errors).'</p>'); } // This check if the response was if (!$auth->isAuthenticated()) { // sucessfully validated and the user echo "<p>Not authenticated</p>"; // data retrieved or not exit(); } $_SESSION['samlUserdata'] = $auth->getAttributes(); // Retrieves user data if (isset($_POST['RelayState']) && OneLogin_Saml2_Utils::getSelfURL() != $_POST['RelayState']) { $auth->redirectTo($_POST['RelayState']); // Redirect if there is a } // relayState set } else if (isset($_GET['sls'])) { // Single Logout Service $auth->processSLO(); // Process the Logout Request & Logout Response $errors = $auth->getErrors(); // Retrieves possible validation errors if (empty($errors)) { print_r('<p>Sucessfully logged out</p>'); } else { print_r('<p>'.implode(', ', $errors).'</p>'); } } if (isset($_SESSION['samlUserdata'])) { // If there is user data we print it. if (!empty($_SESSION['samlUserdata'])) { $attributes = $_SESSION['samlUserdata']; echo 'You have the following attributes:<br>'; echo '<table><thead><th>Name</th><th>Values</th></thead><tbody>'; foreach ($attributes as $attributeName => $attributeValues) { echo '<tr><td>' . htmlentities($attributeName) . '</td><td><ul>'; foreach ($attributeValues as $attributeValue) { echo '<li>' . htmlentities($attributeValue) . '</li>'; } echo '</ul></td></tr>'; } echo '</tbody></table>'; } else { // If there is not user data, we notify echo "<p>You don't have any attribute</p>"; } echo '<p><a href="?slo" >Logout</a></p>'; // Print some links with possible } else { // actions echo '<p><a href="?sso" >Login</a></p>'; echo '<p><a href="?sso2" >Login and access to attrs.php page</a></p>'; }
主要类和方法
以下是可以调用的主要类和方法。
旧Saml库
让我们开始描述SAML库的类和方法,这是一个旧v.1工具包的演变,它被提供以保持向后兼容性。大多数它们使用新SAML2库的类和方法。
OneLogin_Saml_AuthRequest - AuthRequest.php
具有受保护的属性 $auth
,一个 OneLogin_Saml2_Auth
对象。
OneLogin_Saml_AuthRequest
- 构建OneLogin_Saml2_Auth
,初始化SP SAML实例。getRedirectUrl($returnTo)
- 获取包含压缩AuthRequest消息的SSO URL。
OneLogin_Saml_Response - Response.php
OneLogin_Saml_Response
- 构造函数用于处理SAML响应,内部初始化SP SAML实例和OneLogin_Saml2_Response
。get_saml_attributes
- 获取包含登录用户数据的数组。
OneLogin_Saml_Settings - Settings.php
一个简单的类,用于构建工具包v1.0中使用的设置对象。
OneLogin_Saml_Metadata - Metadata.php
OneLogin_Saml_Metadata
- 构造函数根据SP的设置构建元数据XML信息。getXml
- 包含SP元数据信息的XML。
OneLogin_Saml_XmlSec - XmlSec.php
一个辅助类,包含验证SAML响应的方法:validateNumAssertions
、validateTimestamps
、isValid
(使用前两种方法并验证SAML响应的签名)。
Saml2库
现在我们来描述SAML2库中的类和方法。
OneLogin_Saml2_Auth - Auth.php
OneLogin PHP工具包的主要类
OneLogin_Saml2_Auth
- 初始化SP SAML实例login
- 启动SSO过程。logout
- 启动SLO过程。processResponse
- 处理由IdP发送的SAML响应。processSLO
- 处理由IdP发送的SAML注销响应/注销请求。redirectTo
- 将用户重定向到通过参数传递的URL或我们定义的SSO请求中的URL。isAuthenticated
- 检查用户是否已认证。getAttributes
- 返回SAML属性集。getAttribute
- 返回请求的SAML属性getNameId
- 返回nameIDgetSessionIndex
- 从AuthnStatement获取SessionIndex。getErrors
- 返回是否有错误getSSOurl
- 获取SSO URL。getSLOurl
- 获取SLO URL。getLastRequestID
- 最后生成的SAML消息的ID。buildRequestSignature
- 生成SAML请求的签名。buildResponseSignature
- 生成SAML响应的签名。getSettings
- 返回设置信息setStrict
- 设置严格模式启用/禁用
OneLogin_Saml2_AuthnRequest - AuthnRequest.php
SAML 2认证请求类
OneLogin_Saml2_AuthnRequest
- 构造AuthnRequest
对象。getRequest
- 返回压缩、base64编码、未签名的AuthnRequest
。getId
- 返回AuthNRequest
ID。
OneLogin_Saml2_Response - Response.php
SAML 2认证响应类
OneLogin_Saml2_Response
- 构造SAML响应对象。isValid
- 使用证书确定SAML响应是否有效。checkStatus
- 检查状态是否成功。getAudiences
- 获取受众。getIssuers
- 获取发行者(来自响应和断言)getNameIdData
- 获取由IdP提供的NameID数据。getNameId
- 获取由IdP提供的NameID。getSessionNotOnOrAfter
- 从AuthnStatement获取SessionNotOnOrAfter。getSessionIndex
- 从AuthnStatement获取SessionIndex。getAttributes
- 从AttributeStatement元素获取属性。validateNumAssertions
- 验证文档只包含单个断言(加密或未加密)。validateTimestamps
- 验证文档根据条件元素仍然有效。getError
- 执行验证过程后,如果失败,此方法返回原因
OneLogin_Saml2_LogoutRequest - LogoutRequest.php
SAML 2注销请求类
OneLogin_Saml2_LogoutRequest
- 构造注销请求对象。getRequest
- 返回压缩、base64编码、未签名的注销请求getID
- 返回登出请求的ID。(如果您有该对象,您可以通过id属性访问它)getNameIdData
- 获取登出请求的NameID数据。getNameId
- 获取登出请求的NameID。getIssuer
- 获取登出请求的发行者。getSessionIndexes
- 从登出请求中获取SessionIndexes。isValid
- 检查接收到的登出请求是否有效。getError
- 执行验证过程后,如果失败,此方法返回原因
OneLogin_Saml2_LogoutResponse - LogoutResponse.php
SAML 2登出响应类
OneLogin_Saml2_LogoutResponse
- 构造一个登出响应对象(从设置中初始化参数,如果提供则加载登出响应)getIssuer
- 获取登出响应的发行者。getStatus
- 获取登出响应的状态。isValid
- 判断SAML登出响应是否有效build
- 生成一个登出响应对象。getResponse
- 返回一个登出响应对象。getError
- 执行验证过程后,如果失败,此方法返回原因
OneLogin_Saml2_Settings - Settings.php
OneLogin PHP工具包的配置
OneLogin_Saml2_Settings
- 初始化设置:设置不同文件夹的路径,并从设置文件或提供的数组/对象中加载设置信息checkSettings
- 检查设置信息。getBasePath
- 返回基本路径。getCertPath
- 返回证书路径。getLibPath
- 返回库路径。getExtLibPath
- 返回外部库路径。getSchemasPath
- 返回模式路径。checkSPCerts
- 检查SP的x509证书是否存在且有效。getSPkey
- 返回SP的x509私钥。getSPcert
- 返回SP的x509公钥。getIdPData
- 获取IdP数据。getSPData
获取SP数据。getSecurityData
- 获取安全数据。getContacts
- 获取联系数据。getOrganization
- 获取组织数据。getSPMetadata
- 获取SP元数据。XML表示形式。validateMetadata
- 验证XML SP元数据。formatIdPCert
- 格式化IdP证书。formatSPCert
- 格式化SP证书。formatSPKey
- 格式化SP私钥。getErrors
- 返回一个包含错误信息的数组,当设置正常时数组为空。getLastErrorReason
* 返回最后错误的理由setStrict
- 启用或禁用严格模式。isStrict
- 返回是否启用了'严格'模式。isDebugActive
- 返回是否启用了调试。
OneLogin_Saml2_Metadata - Metadata.php
一个包含与SP元数据相关功能的类
builder
- 根据设置生成SP的元数据。signmetadata
- 使用提供的密钥/证书签名元数据addX509KeyDescriptors
- 将x509描述符(签名/加密)添加到元数据中
OneLogin_Saml2_Utils - Utils.php
一个包含多个方法的辅助类
validateXML
- 此函数尝试根据指定的模式验证XML字符串。formatCert
- 返回一个x509证书(如果需要则添加头部和尾部)。formatPrivateKey
- 返回一个RSA私钥(如果需要则添加头部和尾部)。redirect
- 执行到提供的url的重定向(或返回目标url)。isHTTPS
- 检查是否为https或http。getSelfHost
- 返回当前主机。getSelfURLhost
- 返回协议 + 当前主机 + 端口(如果与常见端口不同)。getSelfURLNoQuery
- 返回当前主机 + 当前视图的URL。getSelfURL
- 返回当前主机 + 当前视图 + 查询的 URL。generateUniqueID
- 生成一个唯一的字符串(例如,用作断言的 ID)。parseTime2SAML
- 将 UNIX 时间戳转换为 SAML2 时间戳,格式为yyyy-mm-ddThh:mm:ss(.s+)?Z
。parseSAML2Time
- 将格式为yyyy-mm-ddThh:mm:ss(.s+)?Z
的 SAML2 时间戳转换为 UNIX 时间戳。忽略亚秒部分。parseDuration
- 解释相对于给定时间戳的 ISO8601 持续时间值。getExpireTime
- 比较两个日期并返回最早的一个。query
- 从 DOMDocument 中提取节点。isSessionStarted
- 检查会话是否已启动。deleteLocalSession
- 删除本地会话。calculateX509Fingerprint
- 计算一个 x509cert 的指纹。formatFingerPrint
- 格式化一个指纹。generateNameId
- 生成一个nameID
。getStatus
- 从响应中获取状态。decryptElement
- 解密一个加密的元素。castKey
- 将XMLSecurityKey
转换为正确的算法。addSign
- 向元素(消息或断言)添加签名密钥和发送者证书。validateSign
- 验证签名(消息或断言)。
有关更多信息,请查看源代码;每个方法都有文档,并提供了关于做什么以及如何使用它的详细信息。请确保还检查文档文件夹,其中提供了有关 SAML 和 SAML2 的类和方法的 HTML 文档。
工具包中包含的演示
该工具包包括三个演示应用程序,以教授如何使用该工具包,请查看它。
在测试之前,演示需要配置得很好的 SP 和 IdP。
演示1
SP 设置
Onelogin 的 PHP Toolkit 允许您以两种方式提供设置信息
- 使用位于工具包基本文件夹中的
settings.php
文件。 - 使用设置数据数组。
在这个演示中,我们使用名为 $settingsInfo
的设置数组以第二种方式提供数据。此数组使用包含的 settings_example.php
作为模板来创建 settings.php
设置并将其存储在 demo1/
文件夹中。配置 SP 部分,然后检查 IdP 的元数据并完成 IdP 信息。
如果您检查 index.php
文件的代码,您将看到 settings.php
文件被忽略,并使用位于工具包基本文件夹中的 _toolkit_loader.php
加载库。
注意,在这个演示中,可以定义在工具包基本文件夹中的 setting.php
文件被忽略,并且使用位于工具包基本文件夹中的 _toolkit_loader.php
加载库。
IdP 设置
一旦 SP 配置完成,SP 的元数据就会发布在 metadata.php
文件中。根据这些信息配置 IdP。
工作原理
-
首次访问
index.php
视图时,您可以选择登录并返回到同一视图或登录并重定向到attrs.php
视图。 -
当您点击
第一个链接中的 2.1,我们访问 (
index.php?sso
),向 IdP 发送一个AuthNRequest
,在 IdP 进行身份验证,然后通过用户的客户端将响应发送到 SP,特别是断言消费者服务视图:index.php?acs
。注意设置了RelayState
参数,指向启动过程的 URL,即index.php
视图。第二个链接中的 2.2 我们访问 (
attrs.php
) 与 2.1 中描述的过程相同,区别在于RelayState
设置为attrs.php
。 -
在 ACS (
index.php?acs
) 处处理 SAML 响应,如果响应无效,则在此处停止处理并显示消息。否则,我们将重定向到 RelayState 视图。a)index.php
或 b)attrs.php
。 -
我们在应用程序中登录,并显示了用户属性。此时,我们可以测试单次注销功能。
-
可以通过两种方式测试单次注销功能。
5.1 由SP发起的SLO。在SP上单击“注销”链接,之后向IdP发送注销请求,关闭IdP上的会话,并通过客户端向SP发送注销响应(发送到单次注销服务端点)。SP的SLS端点(
index.php?sls
)处理注销响应,如果有效,关闭本地应用程序的用户会话。请注意,SLO工作流程始于SP并结束于SP。5.2 由IdP发起的SLO。在这种情况下,操作发生在IdP端,注销过程在idP处启动,向SP发送注销请求(SLS端点,
index.php?sls
)。SP的SLS端点处理注销请求,如果有效,关闭本地应用程序中用户会话,并向IdP发送注销响应(发送到IdP的SLS端点)。IdP接收注销响应,处理它并关闭IdP的会话。请注意,SLO工作流程始于IdP并结束于IdP。
请注意,所有SAML请求和响应都在一个唯一的文件中处理,即index.php
文件,以及如何使用GET
参数来了解必须执行的操作。
Demo2
SP 设置
Onelogin 的 PHP Toolkit 允许您以两种方式提供设置信息
- 使用位于工具包基本文件夹中的
settings.php
文件。 - 使用设置数据数组。
第一种是demo2应用程序的情况。应在工具包的基本文件夹中定义setting.php
文件和setting_extended.php
文件。查看setting_example.php
和advanced_settings_example.php
,了解如何构建它们。
在这种情况下,作为属性消费服务和单次注销服务,我们将使用位于端点文件夹中的文件(acs.php
和sls.php
)。
IdP 设置
一旦配置了SP,SP的元数据将发布在metadata.php
文件中。基于这些信息,配置IdP。
工作原理
在demo1中,我们看到了所有SAML请求和响应都由一个唯一的文件处理,即index.php
文件。此demo1使用高级编程。
在demo2中,我们有几个视图:index.php
、sso.php
、slo.php
、consume.php
和metadata.php
。正如我们所说的,我们将使用工具包中定义的端点(端点文件夹中的acs.php
和sls.php
)。此demo2使用低级编程。
请注意,SSO操作可以在index.php
或sso.php
中启动。
发生的SAML工作流程与demo1中定义的工作流程类似,只是改变了目标。
-
第一次访问
index.php
或sso.php
时,会自动向IdP发送AuthNRequest
(因为发送了原始url作为RelayState
)。我们在IdP处进行身份验证,然后向SP发送Response
,到ACS端点,在这种情况下是端点文件夹中的acs.php
。 -
在ACS中处理SAML响应,如果响应无效,则在此停止处理并显示消息。否则,我们将重定向到
RelayState
视图(sso.php
或index.php
)。sso.php
检测用户是否已登录,并将其重定向到index.php
,因此我们将最终停留在index.php
。 -
我们已经登录到应用程序,并显示了用户属性(如果有的话)。此时,我们可以测试单次注销功能。
-
可以通过两种方式测试单次注销功能。
4.1 由服务提供者(SP)发起的SLO。在SP上点击“登出”链接后,我们将重定向到
slo.php
视图,并在那里向身份提供者(IdP)发送登出请求。在IdP上关闭会话,并向SP发送登出响应(发送到单点登出服务端点)。在这种情况下,SP的SLS端点处理登出响应,如果有效,则关闭本地应用的会话。请注意,SLO工作流始于SP并结束于SP。5.2 由身份提供者(IdP)发起的SLO。在这种情况下,操作发生在IdP端,登出过程在IdP端启动,向SP发送登出请求(端点文件夹中的SLS端点
sls.php
)。SP的SLS端点处理登出请求,如果有效,则关闭本地应用的会话,并向IdP发送登出响应(发送到IdP的SLS端点)。IdP收到登出响应,处理它并关闭IdP的会话。请注意,SLO工作流始于IdP并结束于IdP。
旧版演示
SP 设置
本演示使用工具包的版本1的旧样式。必须向 AuthRequest
的构造函数提供一个 OneLogin_Saml_Settings
类的实例。
在demo-old文件夹中,您将找到一个 example_settings.php
文件,可以用作您自己的 settings.php
文件的模板。
在该模板中,SAML设置分为两部分,应用特定的(const_assertion_consumer_service_url
、const_issuer
、const_name_identifier_format
)和用户/账户特定的(idp_sso_target_url
、x509certificate
)。您需要在此处添加自己的代码来识别用户或用户来源(例如,通过subdomain
、ip_address
等)。
IdP 设置
配置SP后,SP的元数据将在 metadata.php
文件中发布。之后,根据该信息配置IdP。
工作原理
在 metadata.php
视图中发布了SP的元数据。
index.php
文件在需要由应用程序发起SAML对话时充当发起者。这被称为服务提供者发起的SAML。服务提供者创建SAML身份验证请求并将其发送到身份提供者(IdP)。
consume.php
是ACS端点。接收SAML断言。在响应验证后,将通过 getNameId()
或 getAttributes()
使用户数据和nameID可用。
由于php工具包的版本1不支持SLO,因此在本demo-old中不展示如何处理SLO。