LoginSignup
12
12

More than 1 year has passed since last update.

【Laravel】SAML認証を実装する

Posted at

この記事に書いてあること

LaravelアプリケーションにSAML認証方式のSSO(シングルサインオン)を実装する

前提条件

Laravel側での認証機能が既に作成されていることが必須です。

シングルサインオンとは?

1度のユーザー認証によって複数のシステム(業務アプリケーションやクラウドサービスなど)の利用が可能になる仕組みです

SAML認証とは?

SAML(Security Assertion Markup Language)とは、SSO(シングルサインオン)環境を構築できるプロトコル(規約)のひとつです。
SSO環境を構築する方法として、有名なものにOAuth2.0認証やOpenID Connect認証などがあります。

認証方式による細かな違いは他の技術記事などで確認してください。

また、SAML認証はOASISによって2002年に策定されたXMLベースの標準規格です。
現在の主流バージョンは2.0です。

実装するために使うライブラリ

SAML認証を実装するにはライブラリを使ってしまうのが簡単かつ安全です。

有名なライブラリにOneLoginが提供するOpen-Source SAML Toolkitsがあるのですが、今回はそれを基盤として作られているLaravel-saml2を使います。

インストール - Composer

composer require aacotroneo/laravel-saml2

Laravel5.5以下のバージョンの場合、サービスプロバイダを追加します。

config/app.php
'providers' => [
        ...
    	Aacotroneo\Saml2\Saml2ServiceProvider::class,
]

設定ファイルの公開

下記コマンドで設定ファイルを作成します。

php artisan vendor:publish --provider="Aacotroneo\Saml2\Saml2ServiceProvider"

config/saml2_settings.php
config/saml2/mytestidp1_idp_settings.php

が追加されます。
後ほど、これらのファイルをカスタマイズしていきます。

IdPにSPのメタ情報を登録

LaravelのSAMLメタ情報を確認し、IdP側に登録(登録方法や必要な情報は各サービスを確認)

ちなみに、ここまで新しいルーティング情報が追加されている。
メタ情報は下記ルーティングのうちsaml2/{idpName}/metadataから確認可能です。
![saml.png](https://image.docbase.io/uploads/0a9e4e84-4a1d-4546-8671-b57bf7899702.png =WxH)

{idpName}の箇所はconfig/saml2_settings.phpの10行目に設定されている値が入る。この値は自分で任意のものに変更可能。

config/saml2_settings.php
<?php
return $settings = array(
    省略
    'idpNames' => ['test'],
    省略

つまり上記のようにtestとなっている場合は、saml2/test/metadataにアクセスするとxml形式のメタ情報が取得できる。このメタ情報からentityIDやACSのURLなども確認できるが、デフォルト設定は以下の通り。

ACS の URL
https://{laravel_url}/saml2/{idpName}/acs

エンティティ ID]
https://{laravel_url}/saml2/{idpName}/metadata

Laravel(SP)にIdPメタ情報を設定

ここらへんの設定は本家のOneLoginプロジェクトに由来するので、もしわからないことがあれば、こちらのドキュメントを参照する

各環境に合わせてentityId、singleSignOnService、singleLogoutService、x509certを指定します。
例として、GoogleをIdPとして利用した場合を紹介します。

IdPメタ情報はconfig/saml2/〇〇_idp_settings.phpに設定していきます。

まず変数の値を変更。この変数が同ファイルの63行目以降で使われます。

config/saml2/〇〇_idp_settings.php
<?php

//GOOGLEに変更
$this_idp_env_id = 'GOOGLE';

.envに実際のメタ情報を追加
stackoverflowの回答によると、GoogleはSLOをサポートしていないようなので、とりあえずhttps://accounts.google.com/Logoutをデフォルト値として設定しています。

.env
# SAML2 環境設定
SAML2_GOOGLE_IDP_ENTITYID=https://accounts.google.com/o/saml2?idpid=****
SAML2_GOOGLE_IDP_SSO_URL=https://accounts.google.com/o/saml2/idp?idpid=****
SAML2_GOOGLE_IDP_SL_URL=https://accounts.google.com/Logout
SAML2_GOOGLE_IDP_x509=****

先ほど、変数と.envで追加したメタ情報はconfig/saml2/〇〇_idp_settings.phpの63行目以降で使われることになります。

config/saml2/〇〇_idp_settings.php
    // Identity Provider Data that we want connect with our SP
    'idp' => array(
        // Identifier of the IdP entity  (must be a URI)
        'entityId' => env('SAML2_'.$this_idp_env_id.'_IDP_ENTITYID', $idp_host . '/saml2/idp/metadata.php'),
        // SSO endpoint info of the IdP. (Authentication Request protocol)
        'singleSignOnService' => array(
            // URL Target of the IdP where the SP will send the Authentication Request Message,
            // using HTTP-Redirect binding.
            'url' => env('SAML2_'.$this_idp_env_id.'_IDP_SSO_URL', $idp_host . '/saml2/idp/SSOService.php'),
        ),
        // SLO endpoint info of the IdP.
        'singleLogoutService' => array(
            // URL Location of the IdP where the SP will send the SLO Request,
            // using HTTP-Redirect binding.
            'url' => env('SAML2_'.$this_idp_env_id.'_IDP_SL_URL', $idp_host . '/saml2/idp/SingleLogoutService.php'),
        ),
        // Public x509 certificate of the IdP
        'x509cert' => env('SAML2_'.$this_idp_env_id.'_IDP_x509', '***'),
        /*
         *  Instead of use the whole x509cert you can use a fingerprint
         *  (openssl x509 -noout -fingerprint -in "idp.crt" to generate it)
         */
        // 'certFingerprint' => '',
    ),

SAML認証のroutesMiddlewareを追加

Kernel.php に新規ミドルウェアグループsamlを追加
VerifyCsrfTokenを入れるとログインセッションが作られないとのことなので注意

app\Http\Kernel.php
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
         // samlグループを追加
        'saml' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

config\saml2_settings.phpにmiddlewareを反映させます。

config\saml2_settings.php
    'routesMiddleware' => ['saml'],

SAML認証とLaravelAuthの連携

app/Providers/EventServiceProvider.phpのbootメソッドの中に、Samlログイン時のイベントリスナを登録します
こうすることで、SAMLログイン時にLaravelのAuthでもログインするようになります。

app/Providers/EventServiceProvider.php
   public function boot()
    {
        parent::boot();

        //SAML2 のログインイベント
        Event::listen('Aacotroneo\Saml2\Events\Saml2LoginEvent', function (Saml2LoginEvent $event) {
            $messageId = $event->getSaml2Auth()->getLastMessageId();
            $user = $event->getSaml2User();

            // 属性からUserモデルを取得する
            $userData = [
                'id' => $user->getUserId(),
                'attributes' => $user->getAttributes(),
                'assertion' => $user->getRawSamlAssertion()
            ];
            $laravelUser = User::where('email',$userData['attributes']['emailAddress'])->first();

            if ($laravelUser) {
                Auth::login($laravelUser);
                return;
            } else {
                abort(401, 'Authorization Required');
                return;
            }
        });
    }

ログイン画面の設置

ログイン先はライブラリで生成されたルートである
https://{laravel_url}/saml2/{idpName}/login
なので、ログインボタンのリンク先を変更する

resources/views/welcome.blade.php
<div class="data-form">
    <div class="button-area">
        <a class="button size-l" href="/saml2/google/login">ログイン</a>
    </div>
</div>
12
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
12