前回の続き、SSO(シングルサインオン)導入について書いていこうと思います。

シングルサインオンとは エクステックでは、社内システムとしてオープンソースのCRMを使用しております。今回、この社内システムに対して「シングルサインオン」を導入した手順についてご紹介したいと思います。 まずは前提知識として、シングルサインオンとはどういうものか、について簡単にご紹介。シングル...
プロトコル
前回、SSOの流れを説明いたしましたが、SSOを実現するためのプロトコルを決める必要があります。いくつかの選択肢がありますが、代表的なものを記載します。
・SAML 古くからある企業向けSSOプロトコル(XMLベース、SaaS連携に多い)
・OpenID Connect(OIDC) モダンなWeb・モバイル対応の認証プロトコル(OAuth 2.0ベース、JSON)
・OAuth 2.0 ユーザーに代わってAPIアクセスを許可するプロトコル(認可が目的)
・Kerberos 社内ネットワーク用のWindows系SSOプロトコル
今回はMicrosoft AD認証を考えていますので、推奨としているOIDCかOAuth 2.0が候補。また、PHPのWebアプリであれば、ライブラリが豊富で扱いやすいOIDCの選択が良いように思えます。
前回、SSOの全体構成と流れを記載しましたが、OIDCがサポートする部分について書いておきたいと思います。
ユーザー
↓
SSOポータル / SP
↓
(未認証時 / 認証済の場合はアプリ利用開始)
↓
IdP(Identity Provider) ★Microsoft ADがカバー
↓
ユーザーストア ★Microsoft ADがカバー
↓
トークン発行 ★OIDC開始
↓
SPにリダイレクト戻り ★OIDCコアプロトコル
↓
SPで認証成功 ★OIDCでIDトークンを検証
↓
アプリ利用開始
という事で、OIDCを組み込んでいきます。
その前にMicrosoft EntraID でアプリを登録します。
登録の手順はこんな感じです
- Microsoft Entra 管理センター にログイン
- 「アプリの登録」 > 「新規登録」 で、今回対象のアプリを登録
- リダイレクト URI(Web)として、コールバックのURLを登録(今回は<アプリケーションURL>/oidc-callback.phpとする)
- 登録後、「クライアントID」(アプリケーションID)、「ディレクトリID」(テナントID)の値を控える(後で使う)
- 「証明書とシークレット」→「新しいクライアントシークレット」を作成し、値を控える(後で使う)
- 「APIのアクセス許可」→「Microsoft Graph」→「openid」「email」「profile」を追加
それではいよいよ、PHPアプリケーションにSSOの組み込みです。
OIDC ライブラリ導入
まずはOIDC ライブラリを導入します。有名どころで、jumbojett/OpenID-Connect-PHP を使用する事にします。
composer require jumbojett/openid-connect-php
で、さくっとライブラリの導入終了です。
PHPの組み込み
次に、PHPアプリケーションの組み込みです。とは言っても、実装する内容はそれほど多くありません。次の2つを組み込めば、ほぼ完了です。
oidc-login.php(ログイン開始)
<?php use Jumbojett\OpenIDConnectClient; // Azure ADの設定 $tenantId = '<テナントID>'; $clientId = '<クライアントID>'; $clientSecret = '<クライアントシークレット>'; $redirectUri = '<アプリケーションURL>/oidc-callback.php'; try { $oidc = new OpenIDConnectClient("https://login.microsoftonline.com/$tenantId/v2.0", $clientId, $clientSecret); echo "OIDC クライアント作成成功"; $oidc->setRedirectURL($redirectUri); $oidc->addScope(['openid', 'profile', 'email']); $oidc->authenticate(); echo "認証成功!"; } catch (Exception $e) { echo "エラー発生: " . $e->getMessage(); }
oidc-callback.php(認証後の処理)
<?php require_once __DIR__ . '/vendor/autoload.php'; session_start(); use Jumbojett\OpenIDConnectClient; // OIDC設定 $tenantId = '<テナントID>'; $clientId = '<クライアントID>'; $clientSecret = '<クライアントシークレット>'; $redirectUri = '<アプリケーションURL>/oidc-callback.php'; try { $oidc = new OpenIDConnectClient("https://login.microsoftonline.com/$tenantId/v2.0", $clientId, $clientSecret); $oidc->setRedirectURL($redirectUri); $oidc->addScope(['openid', 'profile', 'email']); $oidc->authenticate(); $idToken = $oidc->getIdToken(); $tokenParts = explode('.', $idToken); $payload = base64_decode(strtr($tokenParts[1], '-_', '+/')); $payloadData = json_decode($payload); //UPNをメールアドレスとしてアプリケーションに登録済み $email = $payloadData->upn; if (!$email) { throw new Exception("メールアドレスが取得できませんでした。"); } // メールアドレスでアプリケーションのユーザーを検索 $sql = '<メールアドレスでアプリケーションのユーザーを検索>'; $result = $adb->pquery($sql, array($email, mb_strstr($email, '@', true))); if ($adb->num_rows($result) > 0) { $userId = $adb->query_result($result, 0, 'id'); $username = $adb->query_result($result, 0, 'user_name'); // セッションにユーザー情報をセット $_SESSION['authenticated_user_id'] = $userid; // ログイン成功後にリダイレクト header('Location: index.php'); exit; } else { // ユーザーが存在しない場合の処理 echo "ユーザーが見つかりません。管理者にお問い合わせください。"; exit; } } catch (Exception $e) { echo "エラー発生: " . $e->getMessage(); }
後は、アプリケーションのログイン画面や社内のポータルサイトに、「Microsoft ID でログイン」ボタンを追加し、oidc-login.phpへ誘導すればOKです。
ざっくりですが、こんな感じでSSOの組み込みが完了しました。
流れさえわかっていれば、それほど難しい内容ではないですね。