SSOの問題:SSOまたはSIGパラメータが欠落

こんにちは。Discourse SSOで問題が発生しています。何が間違っているのでしょうか?私のコードは他のプラットフォームから問題なく抽出できます。しかし、nonceが取得できません。

<?php

// エラーログを有効にしてデバッグする
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

// 初期化ファイルを読み込む
require_once '/init.php'; // Platformの設定に基づいてこのパスを更新してください

// Discourse Connectの秘密鍵とペイロードを返すURL
$sso_secret = 'keyhere'; // Discourseの共有秘密鍵に置き換えてください
$discourse_url = 'https://urlhere.com/session/sso_login'; // DiscourseのURLに置き換えてください

// Platformユーザーのログイン状態を確認するためにセッションを開始する
session_start();

// ユーザーがログインしているか確認する
if (!isset($_SESSION['uid'])) {
    // ユーザーがログインしていない場合は、Platformログインページにリダイレクトする
    header('Location: /clientarea.php');
    exit;
}

// デバッグ:受信したリクエストパラメータをログに記録する
error_log("Received GET parameters: " . print_r($_GET, true));

// Discourseから'sso'と'sig'パラメータを受信したか確認する
if (!isset($_GET['sso']) || !isset($_GET['sig'])) {
    error_log("Missing SSO or SIG parameters.");
    header('Location: /clientarea.php');
    exit;
}

// 秘密鍵を使用してSSO署名を検証する
$sso = $_GET['sso'];
$sig = $_GET['sig'];
$expected_sig = hash_hmac('sha256', $sso, $sso_secret);

if ($sig !== $expected_sig) {
    error_log("Invalid SSO signature. Expected: $expected_sig, Received: $sig");
    header('Location: /clientarea.php');
    exit;
}

// Platformクライアントの詳細を取得する
$clientDetails = localAPI('getclientsdetails', ['clientid' => $_SESSION['uid']], 'admin');
if ($clientDetails['result'] !== 'success' || !isset($clientDetails['userid'])) {
    error_log("Failed to fetch Platform client details.");
    header('Location: /clientarea.php');
    exit;
}

// ユーザー詳細を抽出する
$userId = $clientDetails['userid'];
$email = $clientDetails['email'];
$firstName = $clientDetails['firstname'];
$lastName = $clientDetails['lastname'];
$username = $firstName . ' ' . $lastName;

// SSOペイロードをデコードする
$sso_payload = base64_decode($sso);
parse_str($sso_payload, $sso_params);

if (!isset($sso_params['nonce'])) {
    error_log("Nonce is missing from SSO payload.");
    header('Location: /clientarea.php');
    exit;
}

// ユーザー詳細を含む返信SSOペイロードを準備する
$return_payload = [
    'nonce' => $sso_params['nonce'],
    'email' => $email,
    'external_id' => $userId,
    'username' => $username,
    'name' => $firstName . ' ' . $lastName,
    'admin' => 0, // ユーザーが管理者であれば1に設定、そうでなければ0のままにする
    'moderator' => 0 // ユーザーがモデレーターであれば1に設定、そうでなければ0のままにする
];

// 返信ペイロードをBase64エンコードする
$query_string = http_build_query($return_payload);
$encoded_payload = base64_encode($query_string);

// エンコードされたペイロードをDiscourse秘密鍵で署名する
$return_sig = hash_hmac('sha256', $encoded_payload, $sso_secret);

// デバッグ:ペイロードと署名をログに記録する
error_log("Return Payload: " . print_r($return_payload, true));
error_log("Encoded Payload: $encoded_payload");
error_log("Return Signature: $return_sig");

// 署名されたペイロードでDiscourseにリダイレクトする
header("Location: $discourse_url?sso=" . urlencode($encoded_payload) . "&sig=" . urlencode($return_sig));
exit;

?>

エラーログ:

[25-Sep-2024 14:50:17 UTC] Missing SSO or SIG parameters.
[25-Sep-2024 14:53:59 UTC] Received GET parameters: Array
(
[sso] => nonce_from_discourse
)

[25-Sep-2024 14:53:59 UTC] Missing SSO or SIG parameters.

なぜかわかりません。

私もよくわかりません。DiscourseサイトでDiscourseConnectが設定されていますか?ユーザーはこのコードが処理するURLにどのようにアクセスしていますか?

ブラウザのインスペクターを開き、ネットワークタブを表示した状態で認証プロセスを進めると、何が起こっているかについての詳細が得られるかもしれません。

返信ありがとうございます。

WHMCSとの連携を試みています。コード内の設定はすべて適切に行い、Discourse内の設定も有効にしました。

一部の応答は取得できますが、sig がありません。両システム間で不一致があるように見えるため、デコードエラーの可能性があると考えています。

これは私の専門分野ではないのですが、なんとかまとめようと最善を尽くしていますが、2日間頭を悩ませています。どこが間違っているのか分かりません。

できる限りのデバッグを試み、Discourseを再構築しました。ステップバイステップでログを記録しました。ChatGPTも試しました。WordPressプラグインのコードと比較しました。お手上げ状態です。

何かが正しく設定されていない可能性が高いです。一歩引いて考えてみてください。現在、ローカル環境でSSOプロバイダーサイトを設定していませんが、これで部分的に役立つかもしれません。

Discourseで、次の設定が構成されていることを確認してください。

discourse connect url 設定は、投稿したコードを処理しているURLに設定する必要があります。

discourse connect secret 設定は、10文字以上の文字列に設定してください。投稿したコードに7文字の文字列 keyhere がハードコードされていることに注意してください。コードを実行する際にその値を変更していると仮定します。Discourseに入力したものと同じ値に設定してください。

これでDiscourseサイトからログアウトしてください。ブラウザのWebインスペクターを開き、ネットワークタブに移動します。Discourseの「ログイン」ボタンをクリックします。以下のスクリーンショットの最初の2つのリクエストと同様のリクエストが表示されるはずです。

最初のリクエストは http://forum.example.com/session/sso?return_path=%2F になります。

次リクエストは https://example.com/?sso=<discourseから送信されたssoペイロード>&sig=<sso署名> になるはずです。

example.comforum.example.com は、使用している実際のドメインに設定する必要があります。

すべてが正しく構成されていれば、ssosig パラメータの値が、ここで設定した変数に割り当てられると予想されます。

$sso = $_GET['sso'];
$sig = $_GET['sig'];

私なら、残りのコードはコメントアウトし、ペイロードを受信して変数に割り当てることができることを確認するだけにするでしょう。

DiscourseConnectが有効になっている場合、/u/admin-login ルートにアクセスすることでDiscourseサイトに再度ログインできます。DiscourseサイトのRailsコンソールにアクセスできる場合は、RailsコンソールからDiscourseConnectを無効にすることでもログインできます。

SiteSetting.enable_discourse_connect = false

投稿したコードのさらに下の方にエラーがある可能性があります。例えば、期待される署名を生成する前に、sso パラメータの値に対して urldecode を呼び出す必要があると思います。WP Discourseプラグインがどのように処理しているか確認してください。

上記の関数における$payloadは、単にssoクエリパラメータの値であり、ここでサニタイズされた後です: wp-discourse/lib/sso-provider/discourse-sso.php at main · discourse/wp-discourse · GitHub

「いいね!」 1