qbnk/php-saml

这是OneLogin PHP SAML工具包的一个克隆版本,修改后支持无缝更改签名证书。

v4.1.0 2022-04-05 13:20 UTC

README

Build Status Coverage Status License

使用此库将SAML支持添加到您的PHP软件中。忘记那些复杂的库,使用由OneLogin Inc.提供和支持的开源库。

警告

版本3.4.0引入了'rejectUnsolicitedResponsesWithInResponseTo'设置参数,默认禁用,允许使未请求的SAMLResponse无效。此版本还将拒绝SAMLResponse,如果提供requestId给验证器但SAMLResponse不包含InResponseTo属性。另外,还有一个额外的设置参数'destinationStrictlyMatches',默认禁用,将强制目标URL严格匹配处理SAMLResponse的地址。

版本3.3.1将xmlseclibs更新到3.0.4(CVE-2019-3465),但php-saml没有直接受到影响,因为它实现了额外的检查,防止利用该漏洞。

版本3.3.0默认启用严格模式

将php-saml更新到3.1.0,此版本包括与XEE攻击相关的安全补丁。

此版本与PHP 7.X兼容,不包括xmlseclibs(您需要通过composer安装它,依赖关系在composer.json中描述)

安全指南

如果您认为您发现了此工具包中的安全漏洞,请带描述报告至 https://www.onelogin.com/security。我们遵循负责任的披露指南,并与您合作迅速找到解决方案。

为什么要在我的软件中添加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 插件也在使用它。

使用本指南将您的 PHP 工具包集成到 OneLogin: https://developers.onelogin.com/page/saml-toolkit-for-php

安装

依赖项

  • php >= 5.4 以及一些核心扩展,如 php-xmlphp-datephp-zlib
  • openssl。安装 openssl 库。它处理 x509 证书。
  • gettext。安装该库及其 php 驱动程序。它处理翻译。
  • curl。如果您计划使用 IdP 元数据解析器,请安装该库及其 php 驱动程序。

代码

选项 1. 从 github 克隆仓库

git clone git@github.com:onelogin/php-saml.git

然后拉取 3.X.X 分支/标签

选项 2. 从 github 下载

工具包托管在 github 上。您可以从以下位置下载它:

搜索 3.X.X 版本

将库的核心复制到 PHP 应用程序内部。(每个应用程序都有其结构,因此请花时间找到 PHP SAML 工具包的最佳位置)。请参阅“将 SAML 支持添加到我的应用的指南”以了解详情。

请注意,压缩文件仅包含主要文件。如果您计划使用演示,请使用选项 1。

选项 3. Composer

工具包支持 composer。您可以在 https://packagist.org.cn/packages/onelogin/php-saml 找到 onelogin/php-saml 包。

要将 saml 工具包导入到您的当前 PHP 项目中,请执行

composer require onelogin/php-saml

请记住选择 3.X.X 分支

安装完成后,您将在 vendor/ 文件夹中找到一个名为 onelogin 的新文件夹,并在其中找到 php-saml。请确保您包含 composer 提供的自动加载器。它位于 vendor/autoload.php

重要 在此选项中,x509 证书必须存储在 vendor/onelogin/php-saml/certs 中,设置文件存储在 vendor/onelogin/php-saml 中。

当使用 composer update 或类似命令更新包时,您的设置可能会被删除。因此,强烈建议您不要使用设置文件,而是直接将设置作为数组传递给构造函数(本文件稍后解释)。如果您不使用此方法,当使用 composer update 或类似命令更新包时,您的设置可能会被删除。

兼容性

此 3.X.X 支持 PHP 7.X,但也可以与 PHP >=5.4 一起使用(出于安全原因,建议使用 5.6.24+)。

命名空间

如果您正在使用像 Symfony 这样的包含命名空间的框架,请记住,必须通过在开头添加反斜杠(\)来调用类,例如,要使用静态方法 getSelfURLNoQuery,请使用

\OneLogin\Saml2\Utils::getSelfURLNoQuery()

安全警告

在生产环境中,strict 参数 必须 设置为 "true",并且 security 下的 signatureAlgorithmdigestAlgorithm 必须设置为除 SHA1 之外的内容(请参阅 https://shattered.io/)。否则,您的环境不安全,将容易受到攻击。

在生产环境中,我们还强烈建议在设置中注册 IdP 证书而不是使用指纹方法。指纹是散列,因此最终容易受到碰撞攻击,这可能导致签名验证绕过。其他 SAML 工具包已弃用该机制,我们保持该机制以保持兼容性,并且也可以在测试环境中使用。

入门指南

了解工具包

新的OneLogin SAML工具包包含不同的文件夹(如certsendpointslibdemo等)和一些文件。

让我们先描述一下这些文件夹

certs/

SAML需要x509证书来签名和加密如NameIDMessageAssertionMetadata等元素。

如果我们的环境需要签名或加密支持,这个文件夹可能包含SP将使用的x509证书和私钥

  • sp.crt - SP的公钥证书
  • sp.key - SP的私钥

或者我们也可以在设置文件中提供这些数据,在$settings['sp']['x509cert']$settings['sp']['privateKey']

有时我们可能需要在SP发布的元数据上添加签名,在这种情况下,我们可以使用前面提到的x509证书,或者使用新的x.509证书:metadata.crtmetadata.key

如果您正在进行密钥轮换过程并希望在服务提供者元数据上发布该x509证书,请使用sp_new.crt

src/

这个文件夹包含了工具包的核心,即库文件

  • Saml2文件夹包含后续章节中描述的新版本类和方法。

doc/

这个文件夹包含了工具包的API文档。

endpoints/

工具包有三个端点

  • metadata.php - SP元数据的发布位置。
  • acs.php - 断言消费者服务。处理SAML响应。
  • sls.php - 单一登出服务。处理登出请求和登出响应。

您可以使用工具包提供的文件,或者在添加SAML支持到您的应用程序时创建自己的端点文件。请注意,这些端点文件使用工具包基本文件夹的设置文件。

locale/

Locale文件夹包含一些翻译:作为概念证明的en_USes_ES。目前还没有翻译,但我们将最终本地化消息并支持多种语言。

其他重要文件

  • settings_example.php - 用于创建包含工具包基本配置信息的settings.php文件的模板。
  • advanced_settings_example.php - 用于创建包含与安全、联系人以及与SP关联的组织的额外配置信息的advanced_settings.php文件的模板。
  • _toolkit_loader.php - 此文件加载工具包库(SAML2库)。

杂项

  • tests/ - 包含工具包的单元测试。
  • demo1/ - 包含一个具有SAML支持的简单PHP应用程序的示例。请阅读其中的Readme.txt以获取更多信息。
  • demo2/ - 包含另一个示例。

工作原理

设置

首先,我们需要配置工具包。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' => true,

    // Enable debug mode (to print errors).
    'debug' => false,

    // 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/
    'baseurl' => null,

    // 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',
        ),
        // If you need to specify requested attributes, set a
        // attributeConsumingService. nameFormat, attributeValue and
        // friendlyName can be omitted
        "attributeConsumingService"=> array(
                "serviceName" => "SP test",
                "serviceDescription" => "Test Service",
                "requestedAttributes" => array(
                    array(
                        "name" => "",
                        "isRequired" => false,
                        "nameFormat" => "",
                        "friendlyName" => "",
                        "attributeValue" => array()
                    )
                )
        ),
        // 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' => '',

        /*
         * 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 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' => '',
            // URL location of the IdP where SLO Response will be sent (ResponseLocation)
            // if not set, url for the SLO Request will be used
            'responseUrl' => '',
            // 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, 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)
         *
         *  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',

        /* 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>',
        //      )
        // ),
    ),
);

除了必需的设置数据(IdP、SP)之外,还可以定义额外信息。与基本信息的模板一样,在工具包基本文件夹中还有一个用于高级信息的模板,名为advanced_settings_example.php,您可以复制并重命名为advanced_settings.php

<?php

$advancedSettings = array(

    // Compression settings
    'compress' => array(
        'requests' => true,
        'responses' => true
    ),
    // 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'
                                               )
                                      || array (
                                                    'x509cert' => '',
                                                    'privateKey' => ''
                                               )
        */
        '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 encrypted.
        'wantAssertionsEncrypted' => 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 element on the SAMLResponse
        // received by this SP to be present.
        'wantNameId' => true,

        // 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 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').
        '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,

        // If true, SAMLResponses with an empty value at its Destination
        // attribute will not be rejected for this fact.
        'relaxDestinationValidation' => false,

        // If true, Destination URL should strictly match to the address to
        // which the response has been sent.
        // Notice that if 'relaxDestinationValidation' is true an empty Destintation
        // will be accepted.
        'destinationStrictlyMatches' => false,

        // If true, SAMLResponses with an InResponseTo value will be rejectd if not
        // AuthNRequest ID provided to the validation method.
        'rejectUnsolicitedResponsesWithInResponseTo' => false,

        // 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'
        // 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'
        // 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
        'lowercaseUrlencoding' => false,
    ),

    // Contact information template, it is recommended to supply 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' => ''
        ),
    ),
);

压缩设置允许您指示身份提供者(IdP)是否可以接受使用 gzip('请求' 和 '响应')压缩的数据。但如果我们在 getRequestgetResponse 方法中提供了一个 $deflate 布尔参数,它将优先于压缩设置。

在安全部分,您可以设置服务提供者(SP)处理消息和断言的方式。联系 IdP 的管理员,询问 IdP 的期望值,并决定 SP 将进行哪些验证以及 SP 将有哪些要求,并将这些信息传达给 IdP 的管理员。

一旦我们知道了可以配置的数据类型,让我们谈谈设置在工具包中的处理方式。

描述的设置文件(settings.phpadvanced_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);

如何加载库

为了使用工具包库,如果您的项目支持 composer,您只需使用 composer 安装它(见安装部分)即可完成。

如果您的项目不使用 composer,您需要导入位于工具包基本文件夹中的 _toolkit_loader.php 文件。您可以按以下方式加载此文件。

<?php

define("TOOLKIT_PATH", '/var/www/php-saml/');
require_once(TOOLKIT_PATH . '_toolkit_loader.php');

在这行之后,我们将能够使用工具包的类(及其方法)(因为外部和 Saml2 库文件已加载)。

该工具包依赖于 xmlseclibs 3.X.X 分支,您需要获取其代码并将其放置在您的项目中,并使用 _toolkit_loader.php 文件包含 xmlseclibs。

启动单点登录(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
  • $setNameIdPolicy - 当为 true 时,AuthNRequest 将设置一个 nameIdPolicy 元素。
  • $nameIdValueReq - 指示 IdP 应该认证的主体。

如果需要在将来 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);
unset($_SESSION['AuthNRequestID']);

$errors = $auth->getErrors();

if (!empty($errors)) {
    echo '<p>' . implode(', ', $errors) . '</p>';
    exit();
}

if (!$auth->isAuthenticated()) {
    echo "<p>Not authenticated</p>";
    exit();
}

$_SESSION['samlUserdata'] = $auth->getAttributes();
$_SESSION['samlNameId'] = $auth->getNameId();
$_SESSION['samlNameIdFormat'] = $auth->getNameIdFormat();
$_SESSION['samlNameidNameQualifier'] = $auth->getNameIdNameQualifier();
$_SESSION['samlNameidSPNameQualifier'] = $auth->getNameIdSPNameQualifier();
$_SESSION['samlSessionIndex'] = $auth->getSessionIndex();

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响应,并检查是否存在错误。它还验证用户是否已认证,并将userdata存储在会话中。

在此阶段,有两种可能的方案

  1. 如果没有提供RelayState,我们可以显示用户数据在此视图或我们想要的任何方式。

  2. 如果提供了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)) {
    echo 'Sucessfully logged out';
} else {
    echo 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.

还有八个可选参数可以设置

  • $returnTo - 用户登出后应返回的目标URL。
  • $parameters - 要添加到GET中的额外参数。
  • $name_id - 将用于构建登出请求。如果未设置name_id参数且auth对象处理了包含NameId的SAML响应,则将使用此NameId
  • $session_index - 用于标识用户会话的SessionIndex。
  • $stay - 如果我们想停留(返回URL字符串),则为true;如果为假,则重定向。
  • $nameIdFormat - 将在登出请求中设置NameID格式。
  • $nameIdNameQualifier - 将在登出请求中设置NameID NameQualifier。
  • $nameIdSPNameQualifier - 将在登出请求中设置NameID SP NameQualifier。

根据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);

带有所有参数的更复杂注销

$auth = new OneLogin\Saml2\Auth();
$returnTo = null;
$parameters = array();
$nameId = null;
$sessionIndex = null;
$nameIdFormat = null;
$nameIdNameQualifier = null;
$nameIdSPNameQualifier = null;

if (isset($_SESSION['samlNameId'])) {
    $nameId = $_SESSION['samlNameId'];
}
if (isset($_SESSION['samlSessionIndex'])) {
    $sessionIndex = $_SESSION['samlSessionIndex'];
}
if (isset($_SESSION['samlNameIdFormat'])) {
    $nameIdFormat = $_SESSION['samlNameIdFormat'];
}
if (isset($_SESSION['samlNameIdNameQualifier'])) {
    $nameIdNameQualifier = $_SESSION['samlNameIdNameQualifier'];
}
if (isset($_SESSION['samlNameIdSPNameQualifier'])) {
    $nameIdSPNameQualifier = $_SESSION['samlNameIdSPNameQualifier'];
}
$auth->logout($returnTo, $parameters, $nameId, $sessionIndex, false, $nameIdFormat, $nameIdNameQualifier, $nameIdSPNameQualifier);

如果需要将未来的注销响应ID与要发送的注销请求ID进行匹配,则必须提取并存储该注销请求ID。

$sloBuiltUrl = $auth->logout(null, $parameters, $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(__DIR__) . '/_toolkit_loader.php'; // Load Saml2 and xmlseclibs
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)) {
        echo '<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)) {
        echo '<p>Sucessfully logged out</p>';
    } else {
        echo '<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>';
}

URL猜测方法

php-saml工具包在OneLogin\Saml2\Utils中使用一系列方法来猜测处理SAML消息的URL。

  • getSelfHost 返回当前主机。
  • getSelfPort 返回请求使用的端口号。
  • isHTTPS 检查协议是https还是http。
  • getSelfURLhost 返回协议 + 当前主机 + 端口(如果不同于常用端口)。
  • getSelfURL 返回当前主机 + 当前视图 + 查询。
  • getSelfURLNoQuery 返回当前主机 + 当前视图的URL。
  • getSelfRoutedURLNoQuery 返回当前主机 + 当前视图的路由URL。

getSelfURLNoQuery和getSelfRoutedURLNoQuery用于计算当前URL,以便验证SAML元素,如目的地或收件人。

当PHP应用程序位于代理或负载均衡器后面时,我们可以执行setProxyVars(true)setSelfPort,并且isHTTPS将负责处理$_SERVER["HTTP_X_FORWARDED_PORT"]$_SERVER['HTTP_X_FORWARDED_PROTO']变量(否则它们将被忽略)。

此外,开发人员可以使用setSelfProtocolsetSelfHostsetSelfPortgetBaseURLPath来定义要由isHTTPSgetSelfHostgetSelfPortgetBaseURLPath返回的特定值。并定义一个setBasePath,用于在getSelfURLgetSelfRoutedURLNoQuery中使用,以替换从$_SERVER["REQUEST_URI"]中提取的数据。

在设置中,开发人员将能够设置一个'baseurl'参数,该参数将自动使用setBaseURL来设置setSelfProtocolsetSelfHostsetSelfPortsetBaseURLPath的值。

在负载均衡器后面工作

当在带有SSL卸载的负载均衡器后面工作时,断言请求URL和SAML响应的目的地属性可能会失败。

您可以通过配置服务器使其了解代理并返回请求的原URL来解决这个问题。

或者,可以使用前面部分中描述的方法。

SP密钥轮换

如果您计划更新SP的x509cert和privateKey,您可以定义新的x509cert为$settings['sp']['x509certNew'],它将发布在SP元数据中,以便身份提供者可以读取它们并准备轮换。

具有多个证书的IdP

在某些场景中,IdP使用不同的证书进行签名/加密,或者处于密钥轮换阶段,并且多个证书已发布在IdP元数据中。

为了处理这种情况,工具包提供了$settings['idp']['x509certMulti']参数。

当使用该参数时,工具包将忽略'x509cert''certFingerprint'值。

x509certMulti 是一个包含2个键的数组

  • signing。一个包含证书的数组,用于验证IdP签名
  • encryption。一个包含一个唯一证书的数组,用于加密发送给IdP的数据

重放攻击

为了避免重放攻击,您可以存储已处理SAML消息的ID,以避免重复处理。由于消息会过期并且由于这个事实而失效,因此您不需要存储这些ID超过您目前接受的时效。

使用Auth对象的getLastMessageId/getLastAssertionId方法获取最后处理的消息/断言的ID。

主要类和方法

下面描述了可以调用的主要类和方法。

Saml2库

现在让我们描述SAML2库的类和方法。

OneLogin\Saml2\Auth - Auth.php

OneLogin PHP工具包的主要类

  • Auth - 初始化SP SAML实例
  • login - 启动SSO流程。
  • logout - 启动SLO流程。
  • processResponse - 处理IdP发送的SAML响应。
  • processSLO - 处理IdP发送的SAML注销响应/注销请求。
  • redirectTo - 将用户重定向到通过参数传递的URL或我们定义的SSO请求的URL。
  • isAuthenticated - 检查用户是否已认证。
  • getAttributes - 返回SAML属性的集合。
  • getAttribute - 返回请求的SAML属性
  • getNameId - 返回nameID
  • getNameIdFormat - 获取IdP提供的NameID格式。
  • getNameIdNameQualifier - 获取SAML响应字符串提供的NameID NameQualifier。
  • getNameIdNameSPQualifier - 获取SAML响应字符串提供的NameID SP NameQualifier。
  • getSessionIndex - 从AuthnStatement获取SessionIndex。
  • getErrors - 返回是否有错误
  • getSSOurl - 获取SSO URL。
  • getSLOurl - 获取SLO URL。
  • getLastRequestID - 生成到最后一个请求SAML消息的ID。
  • buildRequestSignature - 为SAML请求生成签名
  • buildResponseSignature - 为SAML响应生成签名
  • getSettings - 返回设置信息
  • setStrict - 设置严格模式激活/禁用
  • getLastRequestID - 获取由服务提供商生成的最后一个AuthNRequest或LogoutRequest的ID。
  • getLastRequestXML - 返回最近构造/处理的XML SAML请求(AuthNRequest,LogoutRequest)
  • getLastResponseXML - 返回最近构造/处理的XML SAML响应(SAMLResponse,LogoutResponse)。如果SAMLResponse包含加密的断言,则解密它。
OneLogin\Saml2\AuthnRequest - AuthnRequest.php

SAML 2认证请求类

  • AuthnRequest - 构造AuthnRequest对象。
  • getRequest - 返回压缩、base64编码、未签名的AuthnRequest
  • getId - 返回AuthNRequest ID。
  • getXML - 返回作为请求一部分发送的XML。
OneLogin\Saml2\Response - Response.php

SAML 2认证响应类

  • Response - 构造SAML响应对象。
  • isValid - 使用证书确定SAML响应是否有效。
  • checkStatus - 检查状态是否成功。
  • getAudiences - 获取受众。
  • getIssuers - 获取发行者(从响应和断言中获取)
  • getNameIdData - 从IdP的SAML响应中获取NameID数据。
  • getNameId - 从IdP的SAML响应中获取NameID。
  • getNameIdFormat - 获取IdP提供的NameID格式。
  • getNameIdNameQualifier - 获取SAML响应字符串提供的NameID NameQualifier。
  • getNameIdNameSPQualifier - 获取SAML响应字符串提供的NameID SP NameQualifier。
  • getSessionNotOnOrAfter - 从AuthnStatement中获取SessionNotOnOrAfter。
  • getSessionIndex - 从AuthnStatement获取SessionIndex。
  • getAttributes - 从AttributeStatement元素中获取属性。
  • validateNumAssertions - 验证文档只包含一个断言(加密或未加密)。
  • validateTimestamps - 验证文档根据条件元素仍然有效。
  • getError - 执行验证过程后,如果失败,此方法返回原因。
  • getXMLDocument - 返回SAML响应文档(如果包含加密的断言,则解密它)。
OneLogin\Saml2\LogoutRequest - LogoutRequest.php

SAML 2注销请求类

  • LogoutRequest - 构造注销请求对象。
  • getRequest - 返回注销请求,已解压、base64编码、未签名。
  • getID - 返回注销请求的ID。(如果您有对象,可以访问id属性)
  • getNameIdData - 获取注销请求的NameID数据。
  • getNameId - 获取注销请求的NameID。
  • getIssuer - 获取注销请求的发行者。
  • getSessionIndexes - 获取注销请求中的SessionIndexes。
  • isValid - 检查收到的注销请求是否有效。
  • getError - 执行验证过程后,如果失败,此方法返回原因。
  • getXML - 返回请求或接收到的SP中的XML。
OneLogin\Saml2\LogoutResponse - LogoutResponse.php

SAML 2注销响应类

  • LogoutResponse - 构造注销响应对象(从设置中初始化参数,如果提供则加载注销响应)
  • getIssuer - 获取注销响应的发行者。
  • getStatus - 获取注销响应的状态。
  • isValid - 确定SAML注销响应是否有效
  • build - 生成注销响应对象。
  • getResponse - 返回注销响应对象。
  • getError - 执行验证过程后,如果失败,此方法返回原因。
  • getXML - 返回作为响应部分发送的XML或接收到的SP中的XML。
OneLogin\Saml2\Settings - Settings.php

OneLogin PHP工具箱的配置

  • Settings - 初始化设置:设置不同文件夹的路径,从设置文件或提供的数组/对象中加载设置信息
  • checkSettings - 检查设置信息。
  • getBasePath - 返回基本路径。
  • getCertPath - 返回证书路径。
  • getLibPath - 返回库路径。
  • getExtLibPath - 返回外部库路径。
  • getSchemasPath - 返回模式路径。
  • checkSPCerts - 检查SP的x509证书是否存在且有效。
  • getSPkey - 返回SP的x509私钥。
  • getSPcert - 返回SP的x509公钥。
  • getSPcertNew - 返回SP未来的x509公钥。
  • getIdPData - 获取IdP数据。
  • getSPData获取SP数据。
  • getSecurityData - 获取安全数据。
  • getContacts - 获取联系数据。
  • getOrganization - 获取组织数据。
  • getSPMetadata - 获取SP元数据。XML表示形式。
  • validateMetadata - 验证XML SP元数据。
  • formatIdPCert - 格式化IdP证书。
  • formatSPCert - 格式化SP证书。
  • formatSPCertNew - 格式化新的SP证书。
  • formatSPKey - 格式化SP私钥。
  • getErrors - 返回包含错误信息的数组,当设置正常时数组为空。
  • getLastErrorReason - 返回最后一个错误的原因。
  • getBaseURL - 如果设置了,则返回设置的baseurl。
  • setBaseURL - 设置baseurl值。
  • 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 - 计算x509证书的指纹。
  • formatFingerPrint - 格式化指纹。
  • generateNameId - 生成nameID
  • getStatus - 从响应中获取状态。
  • decryptElement - 解密加密的元素。
  • castKey - 将XMLSecurityKey转换为正确的算法。
  • addSign - 将签名密钥和发送者证书添加到元素(消息或断言)中。
  • validateSign - 验证签名(消息或断言)。
OneLogin\Saml2\IdPMetadataParser - IdPMetadataParser.php

一个包含多个方法以检索和处理IdP元数据的辅助类。

  • parseRemoteXML - 从URL获取IdP元数据信息。
  • parseFileXML - 从文件获取IdP元数据信息。
  • parseXML - 从XML获取IdP元数据信息。
  • injectIntoSettings - 将元数据信息注入到php-saml设置数组中。

有关更多信息,请查看源代码;每个方法都有文档,并提供有关其功能和使用方法的详细信息。请确保还检查doc文件夹,其中提供了有关SAML和SAML2的类和方法的HTML文档。

工具包中包含的示例

该工具包包括三个示例应用程序,用于说明如何使用工具包,请查看它。

示例需要在使用之前正确配置SP和IdP。

Demo1

SP设置

Onelogin的PHP工具包允许您以两种方式提供设置信息。

  • 使用位于工具包基本文件夹中的settings.php文件。
  • 使用设置数据数组。

在这个示例中,我们采用第二种方式提供数据,使用名为$settingsInfo的设置数组。此数组使用包含为模板的settings_example.php来创建settings.php设置,并将其存储在demo1/文件夹中。配置SP部分,然后审查IdP的元数据,并完成IdP信息。

如果您检查index.php文件的代码,您将看到settings.php文件被加载,以便使用$settingsInfo变量来初始化Setting类。

注意,在这个示例中,位于工具包基础目录中的可能定义的setting.php文件被忽略,并且使用位于工具包基础目录中的_toolkit_loader.php来加载库。

IdP设置

一旦配置了SP,SP的元数据就会发布在metadata.php文件中。根据该信息配置IdP。

工作原理

  1. 第一次访问index.php视图时,您可以选择登录并返回同一视图或登录并重定向到attrs.php视图。

  2. 当您点击

    第一个链接中的2.1时,我们访问到(index.php?sso),向IdP发送一个AuthNRequest,在IdP进行身份验证后,通过用户的客户端将响应发送到SP,具体是Assertion Consumer Service视图:index.php?acs。注意,将RelayState参数设置为启动过程的url,即index.php视图。

    第二个链接中的2.2,我们访问到(attrs.php),与2.1中描述的过程相同,不同之处在于将RelayState设置为attrs.php

  3. SAML响应在ACS(index.php?acs)中处理,如果响应无效,则在此停止处理并显示消息。否则,我们将重定向到RelayState视图。a) index.php或b) attrs.php

  4. 我们登录到应用程序,并显示用户属性。在此阶段,我们可以测试单点登出功能。

  5. 单点登出功能可以通过两种方式测试。

    5.1 SP启动SLO。在SP上单击“登出”链接,之后向IdP发送一个登出请求,关闭IdP上的会话,并通过客户端回复SP一个登出响应(发送到单点登出服务端点)。SP的SLS端点(index.php?sls)处理登出响应,如果有效,则关闭本地应用程序的用户会话。注意,SLO工作流从SP开始并结束。

    5.2 IdP启动SLO。在这种情况下,操作发生在IdP端,登出过程在IdP处启动,向SP发送一个登出请求(SLS端点,index.php?sls)。SP的SLS端点处理登出请求,如果有效,则关闭本地应用程序的用户会话,并向IdP发送一个登出响应(发送到IdP的SLS端点)。IdP接收登出响应,处理它并关闭IdP上的会话。注意,SLO工作流从IdP开始并结束。

请注意,所有SAML请求和响应都由一个文件处理,即index.php文件,以及如何使用GET参数来知道必须执行的操作。

演示2

SP设置

Onelogin的PHP工具包允许您以两种方式提供设置信息。

  • 使用位于工具包基本文件夹中的settings.php文件。
  • 使用设置数据数组。

第一个是演示2应用程序的情况。应在工具包的基础目录中定义setting.php文件和setting_extended.php文件。审查setting_example.phpadvanced_settings_example.php,了解如何构建它们。

在这种情况下,作为属性消费服务(Attribute Consume Service)和单点登出服务(Single Logout Service),我们将使用位于端点文件夹中的文件(acs.phpsls.php)。

IdP设置

一旦服务提供者(SP)配置完毕,SP的元数据将发布在 metadata.php 文件中。根据这些信息,配置身份提供者(IdP)。

工作原理

在demo1中,我们看到了所有SAML请求和响应是如何在一个独特的文件 index.php 中处理的。这个demo1使用高级编程。

在demo2中,我们有几个视图:index.phpsso.phpslo.phpconsume.phpmetadata.php。正如我们所说的,我们将使用工具包中定义的端点(端点文件夹中的 acs.phpsls.php)。这个demo2使用低级编程。

请注意,SSO操作可以在 index.phpsso.php 中启动。

发生的SAML工作流程与demo1中定义的工作流程类似,只是改变了目标。

  1. 当您第一次访问 index.phpsso.php 时,会自动向IdP发送一个 AuthNRequest,(因为发送了原始url作为 RelayState)。我们在IdP处进行身份验证,然后向SP发送一个 Response,到端点,在这个例子中是端点文件夹中的 acs.php

  2. SAML响应在ACS中处理,如果 Response 无效,则在此处停止处理并显示消息。否则,我们被重定向到 RelayState 视图(sso.phpindex.php)。sso.php 检测用户是否已登录,并将其重定向到 index.php,因此最终我们将处于 index.php

  3. 我们登录到应用程序,并显示用户属性(如果有的话)。在此阶段,我们可以测试单点登出功能。

  4. 单点登出功能可以通过两种方式测试。

    4.1 由SP启动的SLO。在SP上点击“登出”链接,然后我们被重定向到 slo.php 视图,在那里向IdP发送一个登出请求,关闭IdP处的会话,并回复SP一个登出响应(发送到单点登出服务端点)。在这种情况下,SP的SLS端点处理登出响应,如果有效,关闭本地应用程序的用户会话。请注意,SLO工作流程在SP处开始和结束。

    4.2 由IdP启动的SLO。在这种情况下,操作在IdP侧进行,登出过程在IdP处启动,向SP发送一个登出请求(端点文件夹的SLS端点 sls.php)。SP的SLS端点处理登出请求,如果有效,关闭本地应用程序中用户的会话,并发送一个登出响应到IdP(到IdP的SLS端点)。IdP接收登出响应,处理它并关闭IdP的会话。请注意,SLO工作流程在IdP处开始和结束。