juhedata/laravel-samlidp

使用SAML 2.0将您的Laravel应用程序打造为身份提供者。

v2.0.5 2020-03-13 23:42 UTC

README

Latest Version on Packagist Total Downloads

Laravel SAML IdP

此包允许您使用SAML 2.0标准实现自己的身份提供者(idP),用于与支持SAML 2.0服务提供者(SP)一起使用。

该组件可以让你实现基于SAML 2.0协议的IDP端(IDP端提供身份验证,用户在此登录)。

版本

1.0

  • 需要Laravel 5.X

2.0

  • 需要PHP 7.2+
  • 需要Laravel 6.X

安装

使用composer安装此组件

用composer安装本组件:

composer require juhedata/laravel-samlidp:^2.0

发布配置

发布配置文件

php artisan vendor:publish --tag="samlidp_config"

文件系统配置

文件系统配置

// config/filesystem.php

'disks' => [

        ...

        'samlidp' => [
            'driver' => 'local',
            'root' => storage_path() . '/samlidp',
        ]
],

使用以下命令为您的小型身份提供者生成自签证书。如果您将证书名称或密钥名称更改为除默认名称以外的任何名称,您需要更新config/samlidp.php配置文件以反映这些新文件名。

用以下命令生成自签证书

php artisan samlidp:cert [--days <days> --keyname <name> --certname <name>]
Options:
  --days=<days>      Days to add for the expiration date [default: 7800]
  --keyname=<name>   Name of the certificate key file [default: key.pem]
  --certname=<name>  Name of the certificate file [default: cert.pem]

用法

在您的登录视图中,例如 resources/views/auth/login.blade.php,在CSRF directive后添加SAMLRequest directive

在登录页面(如resources/views/auth/login.blade.php),在CSRF directive后增加SAMLRequest directive

@csrf
@samlidp

SAMLRequest directive会在HTTP请求发送SAMLRequest时自动填充隐藏输入,从而启动SAML身份验证尝试。要启动SAML身份验证,需要对登录和重定向过程进行干预。这通过在身份验证时触发的Laravel事件来完成。

SAMLRequest directive会自动检查当前的HTTP请求是否包含SAML相关的参数,如果有,则将SAML相关的参数补充到登录表单中。相关中间件将处理表单中的SAML请求,并将用户重定向到SP。

配置

发布配置文件后,您需要设置您的服务提供者。服务提供者的密钥是对Consumer Service (ACS) URL的base 64编码。您可以从您的服务提供者处获取此信息,但您需要将URL进行base 64编码并将其放入配置中。这是由于配置点表示法。

您可以使用以下命令帮助生成新的SAML服务提供者

一个idP可以对应多个SP,以下命令生成SP配置代码:

php artisan samlidp:sp

config/samlidp.php文件中的示例SP

可参考config/samlidp.php文件中的SP配置示例:

<?php

return [
    // The URI to your login page
    'login_uri' => 'login',
    // The URI to the saml metadata file, this describes your idP
    'issuer_uri' => 'saml/metadata',
    // List of all Service Providers
    'sp' => [
        // Base64 encoded ACS URL
        'aHR0cHM6Ly9teWZhY2Vib29rd29ya3BsYWNlLmZhY2Vib29rLmNvbS93b3JrL3NhbWwucGhw' => [
            // ACS URL of the Service Provider
            'destination' => 'https://example.com/saml/acs',
            // Simple Logout URL of the Service Provider
            'logout' => 'https://example.com/saml/sls',
        ]
    ]

];

在SLO完成后注销IDP

如果您希望在SLO完成后注销IDP,请将LOGOUT_AFTER_SLO.env中设置为true并执行IDP的注销操作。

// .env

LOGOUT_AFTER_SLO=true

在注销后重定向到SLO发起者

如果您希望用户通过SLO发起的SP返回,您可以为/saml/logout路由提供额外的查询参数,例如

https://idp.com/saml/logout?redirect_to=mysp.com

所有SP都注销后,用户将被重定向到mysp.com。为了正确工作,您需要在config/samlidp.php配置文件中添加sp_slo_redirects选项,例如

<?php

// config/samlidp.php

return [
    // If you need to redirect after SLO depending on SLO initiator
    // key is beginning of HTTP_REFERER value from SERVER, value is redirect path
    'sp_slo_redirects' => [
        'mysp.com' => 'https://mysp.com',
    ],

];

属性(可选)

服务提供者可能需要发送更多附加属性通过断言。甚至可能它们需要相同的信息,但作为不同的Claim Type。

SP可能需要提供更多的属性。

默认情况下,此包将发送以下Claim Types

ClaimTypes::EMAIL_ADDRESS 作为 auth()->user()->email ClaimTypes::GIVEN_NAME 作为 auth()->user()->name

这是因为Laravel迁移默认情况下只提供SAML 2.0可用的email和name字段。

要添加额外的Claim Types,您可以订阅Assertion事件

CodeGreenCreative\SamlIdp\Events\Assertion

订阅事件

可以通过订阅相关事件,向SP传递更多属性:

在您的App\Providers\EventServiceProvider类中,将以下内容添加到已存在的$listen属性...

App\Providers\EventServiceProvider 中订阅这个事件:CodeGreenCreative\SamlIdp\Events\Assertion

protected $listen = [
    'App\Events\Event' => [
        'App\Listeners\EventListener',
    ],
    'CodeGreenCreative\SamlIdp\Events\Assertion' => [
        'App\Listeners\SamlAssertionAttributes'
    ]
];

示例监听器

监听器示例:

<?php

namespace App\Listeners;

use LightSaml\ClaimTypes;
use LightSaml\Model\Assertion\Attribute;
use CodeGreenCreative\SamlIdp\Events\Assertion;

class SamlAssertionAttributes
{
    public function handle(Assertion $event)
    {
        $event->attribute_statement
            ->addAttribute(new Attribute(ClaimTypes::PPID, auth()->user()->id))
            ->addAttribute(new Attribute(ClaimTypes::NAME, auth()->user()->name));
    }
}