renepardon / laravel-saml2
一个基于OneLogin工具包的Laravel包,用于Saml2集成作为SP(服务提供者),比simplesamlphp轻量得多。
Requires
- php: >=7.1
- ext-openssl: *
- illuminate/support: >=5.5
- onelogin/php-saml: ^3.0.0
Requires (Dev)
- laravel/framework: 5.5.*
- mockery/mockery: 0.9.*
- phpunit/phpunit: ^7.0
README
一个基于OneLogin v3工具包的Laravel包,用于Saml2集成作为SP(服务提供者),比simplesamlphp SP更轻量且易于安装。它不需要独立的路由或会话存储即可工作!
本库的目的是尽可能简单。我们不会干扰Laravel用户、认证、会话等。我们更倾向于限制自己只做具体任务。请用户在IDP进行身份验证并处理响应。SLO请求的情况也是如此。
要求
- laravel >= 5.5
- PHP >= 7.1
安装 - Composer
您可以通过composer安装此包。
composer require renepardon/laravel-saml2
然后使用 php artisan vendor:publish --provider="Aacotroneo\Saml2\Saml2ServiceProvider"
发布配置文件。这将添加 app/config/saml2_settings.php
文件。此配置几乎直接由 OneLogin 处理,因此您可以在那里找到更多参考,但这里将涵盖真正必要的内容。还有一些关于路由的其他配置,您可以查看,它们相当直接。
配置
一旦您将saml2_settings.php发布到您自己的文件中,您需要配置您的SP和IDP(远程服务器)。此配置与OneLogin使用的配置之间唯一的真正区别是,SP entityId、assertionConsumerService URL和singleLogoutService URL由库注入。它们分别来自路由'saml_metadata'、'saml_acs'和'saml_sls'。
请记住,您不需要实现这些路由,但您需要将它们添加到IDP配置中。例如,如果您使用simplesamlphp,请将以下内容添加到/metadata/sp-remote.php:
$metadata['http://laravel_url/saml2/metadata'] = array( 'AssertionConsumerService' => 'http://laravel_url/saml2/acs', 'SingleLogoutService' => 'http://laravel_url/saml2/sls', //the following two affect what the $Saml2user->getUserId() will return 'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', 'simplesaml.nameidattribute' => 'uid' );
您可以通过实际导航到 'http://laravel_url/saml2/metadata' 来检查该元数据。
用法
当您想要用户登录时,只需调用 Saml2Auth::login()
或重定向到路由 'saml2_login'。只需记住,它不使用任何会话存储,因此如果您要求它登录,它将重定向到IDP,无论用户是否已登录。例如,您可以将认证中间件更改为以下内容:
public function handle($request, Closure $next) { if ($this->auth->guest()) { if ($request->ajax()) { return response('Unauthorized.', 401); } else { return Saml2::login(URL::full()); //return redirect()->guest('auth/login'); } } return $next($request); }
从Laravel 5.3开始,您可以在 app/Exceptions/Handler.php
中更改您的未认证方法。
protected function unauthenticated($request, AuthenticationException $exception) { if ($request->expectsJson()) { return response()->json(['error' => 'Unauthenticated.'], 401); } return Saml2Auth::login(); }
Saml2::login 将将用户重定向到IDP,并返回到库在 /saml2/acs 上提供的服务端点。这将处理响应并在准备好时触发一个事件。您的下一步是处理该事件。您只需登录用户或拒绝即可。
Event::listen('Aacotroneo\Saml2\Events\Saml2LoginEvent', function (Saml2LoginEvent $event) { $messageId = $event->getSaml2Auth()->getLastMessageId(); // your own code preventing reuse of a $messageId to stop replay attacks $user = $event->getSaml2User(); $userData = [ 'id' => $user->getUserId(), 'attributes' => $user->getAttributes(), 'assertion' => $user->getRawSamlAssertion() ]; $laravelUser = //find user by ID or attribute //if it does not exist create it and go on or show an error message Auth::login($laravelUser); });
身份验证持久性
注意Session中身份验证持久性所需的必要Laravel中间件。
例如,它可以
# in App\Http\Kernel
protected $middlewareGroups = [
'web' => [
...
],
'api' => [
...
],
'saml' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
],
并在 config/saml2_settings.php
/**
* which middleware group to use for the saml routes
* Laravel 5.2 will need a group which includes StartSession
*/
'routesMiddleware' => ['saml'],
注销
现在用户有两种注销方式。
- 1 - 在您的应用程序中注销:在这种情况下,您应该首先通知IDP,以便它关闭全局会话。
- 2 - 从全局SSO会话注销。在这种情况下,IDP将在 /saml2/slo 端点(已提供)上通知您
对于情况1,调用 Saml2Auth::logout();
或将用户重定向到执行此操作的 'saml_logout' 路由。不要立即关闭会话,因为您需要从IDP接收响应确认(重定向)。该响应将由库在 /saml2/sls 上处理,并为您触发一个完成操作的事件。
对于案例2,您只会接收到事件。案例1和案例2都会接收到相同的事件。
请注意,对于案例2,您可能需要手动保存会话以使注销生效(因为会话是由中间件保存的,但在发生之前OneLogin库会重定向回您的身份提供者)
Event::listen('Aacotroneo\Saml2\Events\Saml2LogoutEvent', function ($event) { Auth::logout(); Session::save(); });
就这些了。欢迎提问、提交PR或建议,或者打开问题。