サーバ側でカスタム認証を有効にする

目次

  概要
  Web認証サーバのアドレス登録
  Web認証サーバへ認証要求を送信する
  Web認証サーバからの結果について、クライアントに送信する
  サーバを起動する


概要

Web認証サーバの認証制御結果を MUN サーバのカスタム認証に適用する

  ここでは、先の シンプルな認証用Webサーバを作る で示した Web 認証サーバを使うことを前提条件として
  MUN サーバのプログラムにカスタム認証処理を組み込む方法について説明します。


Web認証サーバのアドレス登録

サーバ起動スクリプトに、Web認証サーバのアドレスを登録する

  まず、MUNサーバの起動スクリプト(またはサーバ構成ファイル)に対し、カスタム認証を実行するWebサーバのアドレスを登録します。
  下記のうち、ご利用されている MUN サーバのプラットフォームに合わせて、カーソルクリックしてください。

  ご利用されている MUN サーバの開発言語に合わせて、カーソルクリックしてください。
1. 頒布している MUN サーバパッケージの解凍先ディレクトリ内の server/cpp/mun.props ファイルを
  テキストエディタで開きます。
2. 98 行目付近にある、CUSTOM_AUTH_SERVER_ADDR のプロパティ値について、ご利用されるWeb認証サーバのアドレスについて、
<CUSTOM_AUTH_SERVER_ADDR>"http://〇〇〇〇〇/〇〇〇〇〇"</CUSTOM_AUTH_SERVER_ADDR>
  または
<CUSTOM_AUTH_SERVER_ADDR>"https://〇〇〇〇〇/〇〇〇〇〇"</CUSTOM_AUTH_SERVER_ADDR>
  の形式で記載します。
  例えば、認証サーバのアドレスが http://192.168.1.253/index.php の場合、以下のように記述します。
3. 変更内容を反映させるため、一旦 mun_proxy の VisualStudio プロジェクトについてアプリケーションごと閉じて、再度開き直してください。
1. 頒布している MUN サーバパッケージの解凍先ディレクトリ内の server/csharp/appsettings.json ファイルをテキストエディタで開きます。
2. 46 行目付近にある、CUSTOM_AUTH_SERVER_ADDR のプロパティ値について、ご利用されるWeb認証サーバのアドレスについて、
"CUSTOM_AUTH_SERVER_ADDR": "http://〇〇〇〇〇/〇〇〇〇〇",
  または
"CUSTOM_AUTH_SERVER_ADDR": "https://〇〇〇〇〇/〇〇〇〇〇",
  の形式で記載します。
  例えば、認証サーバのアドレスが http://192.168.1.253/index.php の場合、以下のように記述します。
3. 変更内容を反映させるため、一旦 mun_proxy の VisualStudio プロジェクトについてアプリケーションごと閉じて、再度開き直してください。

  ご利用されている MUN サーバの開発言語に合わせて、カーソルクリックしてください。
1. 頒布している MUN サーバパッケージのデプロイ先の server/cpp/server.sh ファイルをテキストエディタ系ツールで開きます。
2. 188 行目付近にある、CUSTOM_AUTH_SERVER_ADDR のパラメータ値について、ご利用されるWeb認証サーバのアドレスについて、
CUSTOM_AUTH_SERVER_ADDR="http://〇〇〇〇〇/〇〇〇〇〇"
  または
CUSTOM_AUTH_SERVER_ADDR="https://〇〇〇〇〇/〇〇〇〇〇"
  の形式で記載します。
  例えば、認証サーバのアドレスが http://192.168.1.253/index.php の場合、以下のように記述します。
1. 頒布している MUN サーバパッケージの解凍先ディレクトリ内の server/csharp/appsettings.json ファイルをテキストエディタで開きます。
2. 46 行目付近にある、CUSTOM_AUTH_SERVER_ADDR のプロパティ値について、ご利用されるWeb認証サーバのアドレスについて、
"CUSTOM_AUTH_SERVER_ADDR": "http://〇〇〇〇〇/〇〇〇〇〇",
  または
"CUSTOM_AUTH_SERVER_ADDR": "https://〇〇〇〇〇/〇〇〇〇〇",
  の形式で記載します。
  例えば、認証サーバのアドレスが http://192.168.1.253/index.php の場合、以下のように記述します。
3. 変更内容を反映させるため、一旦 mun_proxy の VisualStudio プロジェクトについてアプリケーションごと閉じて、再度開き直してください。

  ご利用されている MUN サーバの開発言語に合わせて、カーソルクリックしてください。
1. 頒布している MUN サーバパッケージのデプロイ先の server/cpp/server.sh ファイルをテキストエディタ系ツールで開きます。
2. 188 行目付近にある、CUSTOM_AUTH_SERVER_ADDR のパラメータ値について、ご利用されるWeb認証サーバのアドレスについて、
CUSTOM_AUTH_SERVER_ADDR="http://〇〇〇〇〇/〇〇〇〇〇"
  または
CUSTOM_AUTH_SERVER_ADDR="https://〇〇〇〇〇/〇〇〇〇〇"
  の形式で記載します。
  例えば、認証サーバのアドレスが http://192.168.1.253/index.php の場合、以下のように記述します。
1. 頒布している MUN サーバパッケージの解凍先ディレクトリ内の server/csharp/appsettings.json ファイルをテキストエディタで開きます。
2. 46 行目付近にある、CUSTOM_AUTH_SERVER_ADDR のプロパティ値について、ご利用されるWeb認証サーバのアドレスについて、
"CUSTOM_AUTH_SERVER_ADDR": "http://〇〇〇〇〇/〇〇〇〇〇",
  または
"CUSTOM_AUTH_SERVER_ADDR": "https://〇〇〇〇〇/〇〇〇〇〇",
  の形式で記載します。
  例えば、認証サーバのアドレスが http://192.168.1.253/index.php の場合、以下のように記述します。
3. 変更内容を反映させるため、一旦 mun_proxy の VisualStudio プロジェクトについてアプリケーションごと閉じて、再度開き直してください。


Web認証サーバへ認証要求を送信する

MUN クライアントから接続要求を受信したら、mun_proxy からWebサーバに認証要求を送信する

  続けて、mun_proxy サーバ処理内の Recv_Proxy_Check() について、MUNクライアント側からの認証要求があった場合、
  認証データに必要な情報を Web認証サーバに送信する処理に書き換えます。

  下記のうち、ご利用されている MUN サーバの開発言語に合わせて、カーソルクリックしてください。

先の 認証モジュールを利用するためのサーバコードのページで示した通り、MUNクライアントからサーバに接続したときに
MunProxyDatabase::Recv_Proxy_Check() 関数で認証処理を実行します。

現状外部のWebサーバによるカスタム認証を組み込んでおらず、ほぼ無認証で許可していますが、
カスタム認証の場合無認証許可を削除する必要があります。以下のコードは削除してください。

この上で、MUN クライアントから受信した「認証に必要な適切なパラメータ」を取得し、Web認証サーバに対して情報を送信する処理について、
// TODO : カスタム認証サーバ処理が有効の場合、カスタム認証サーバにリクエストを送信する
と記載されている箇所を置き換える形で、以下のコードを記述しましょう。
            // カスタム認証に必要な情報を request から抽出する
            bool    ret = false;
            if (request.isUseCustomAuth != 0 && s_ProxyCheckResponse.result == STREAM::RESULT_SUCCESS)
            {
                std::string username = "";
                std::string password = "";
                for (uint16 index = 0; index < request.customAuthParametersLen; ++index) {
                    // "username" および "password" の情報を取得する
                    std::string key = request.customAuthParameters[index].key.text;
                    STREAM::Binary bin = request.customAuthParameters[index].value.data;
                    if (key == "username") {
                        // uint8  type = bin.data[0];
                        uint16 len = *(uint16 *)&bin.data[1];
                        const char * data = reinterpret_cast<const char*>(&bin.data[3]);
                        username = std::string(data, len);
                    }
                    else if (key == "password") {
                        // uint8  type = bin.data[0];
                        uint16 len = *(uint16 *)&bin.data[1];
                        const char * data = reinterpret_cast<const char*>(&bin.data[3]);
                        password = std::string(data, len);
                    }
                }

                // カスタム認証サーバにデータを送信する
                std::string getParam = "?username=" + username + "&password=" + password;
                ret = MunProxySessionToCustomAuthServer::OpSend(
                    pMunClient,                                             // MUN クライアントの接続情報
                    (request.isUseClientCustomAuthServerAddress == 0),      // サーバ側で設定した認証サーバを利用するかどうか
                    request.customAuthServerAddress.text,                   // クライアント側で設定した認証サーバのサーバアドレス
                    (request.isIgnoreCustomAuthError != 0),                 // 認証サーバ処理内のエラーを無視するかどうか
                    getParam,                                               // WebサーバへのGETパラメータ
                    ""                                                      // WebサーバへのPOSTパラメータ
                );
            }

            // カスタム認証サーバへの処理を通していない場合、ここで接続失敗の旨を MUN クライアントに送信
            if (!ret)
            {
                // 認証に失敗したので、クライアントUIDを削除
                RemoveMunClient(pMunClient);

                // エラー情報として、送信データを生成する
                s_ProxyCheckResponse.clientUid = 0;
                s_ProxyCheckResponse.result = STREAM::RESULT_FAILURE;
                s_ProxyCheckResponse.authServerRawData.text = "";

                // デバッグ表示
                MRSEXT_LOG_DEBUG("proxy_check failed. result=%d, proxyClientUId=%d",
                    s_ProxyCheckResponse.result, s_ProxyCheckResponse.clientUid);

                // 送信バッファにパッキング
                static MunBuffer buffer;
                buffer.Unread(0xFFFFFFFF);
                buffer.Unwrite(0xFFFFFFFF);
                if (s_ProxyCheckResponse.Pack(buffer)) {
                    // 認証結果を送信
                    MunProxySessionToClient::Send_Relay_Anything(pMunClient,
                        s_ProxyCheckResponse.payloadType,
                        buffer);
                }
            }

MUN クライアント側から送られてくる「認証のための各種データ」については、request.customAuthParameters にハッシュ情報として入っています。

  ・ request.customAuthParameters[].key.text でハッシュキー(文字列)
  ・ request.customAuthParameters[].value.data.data でハッシュの値 (文字列)

この情報を使い、「username」と「password」のハッシュキーに対する値を取得し、
MunProsySessionToCustomAuthServer::OpSend() 関数で、Web認証サーバにリクエストを送信します。

先の 認証モジュールを利用するためのサーバコードのページで示した通り、MUNクライアントからサーバに接続したときに
MunProxyDatabase.Recv_Proxy_Check() メソッドで認証処理を実行します。

現状外部のWebサーバによるカスタム認証を組み込んでおらず、ほぼ無認証で許可していますが、
カスタム認証の場合無認証許可を削除する必要があります。以下のコードは削除してください。

この上で、MUN クライアントから受信した「認証に必要な適切なパラメータ」を取得し、Web認証サーバに対して情報を送信する処理について、
// TODO : カスタム認証サーバ処理が有効の場合、カスタム認証サーバにリクエストを送信する
と記載されている箇所を置き換える形で、以下のコードを記述しましょう。
                    // カスタム認証処理に必要な情報を request から抽出する
                    bool ret = false;
                    if (request.isUseCustomAuth != 0 && s_ProxyCheckResponse.result == (Int32)mun.STREAM.ERRORCODE_ID.RESULT_SUCCESS)
                    {
                        string username = "";
                        string password = "";
                        for (UInt16 index = 0; index < request.customAuthParametersLen; ++index)
                        {
                            // "username" および "password" の情報を取得する
                            string key = request.customAuthParameters[index].key.text;
                            mun.STREAM.Binary bin = request.customAuthParameters[index].value.data;
                            if (key == "username")
                            {
                                // UInt8  type = bin.data[0];
                                UInt16 len = Convert.ToUInt16(bin.data[1] + bin.data[2] * 256);
                                byte[] data = new byte[len];
                                Array.Copy(bin.data, 3, data, 0, len);
                                username = System.Text.Encoding.UTF8.GetString(data);
                            }
                            else if (key == "password")
                            {
                                // UInt8  type = bin.data[0];
                                UInt16 len = Convert.ToUInt16(bin.data[1] + bin.data[2] * 256);
                                byte[] data = new byte[len];
                                Array.Copy(bin.data, 3, data, 0, len);
                                password = System.Text.Encoding.UTF8.GetString(data);
                            }
                        }
                     
                        // カスタム認証サーバにデータを送信する
                        string getParam = "?username=" + username + "&password=" + password;
                        ret = MunProxySessionToCustomAuthServer.OpSend(
                            pMunClient,                                         // MUN クライアントの接続情報
                            (request.isUseClientCustomAuthServerAddress == 0),  // サーバ側で設定した認証サーバを利用するかどうか
                            request.customAuthServerAddress.text,               // クライアント側で設定した認証サーバのWebサーバアドレス
                            (request.isIgnoreCustomAuthError != 0),             // 認証サーバ処理内のエラーを無視するかどうか
                            getParam,                                           // WebサーバへのGETパラメータ
                            ""                                                  // WebサーバへのPOSTパラメータ
                        );
                    }
                     
                    // カスタム認証サーバへの処理を通していない場合、ここで接続失敗の旨を MUN クライアントに送信
                    if (!ret)
                    {
                        // 認証に失敗したので、クライアントUIDを削除
                        RemoveMunClient(ref pMunClient);
                     
                        // エラー情報として、送信データを生成する
                        s_ProxyCheckResponse.clientUid = 0;
                        s_ProxyCheckResponse.result = (Int32)mun.STREAM.ERRORCODE_ID.RESULT_FAILURE;
                        s_ProxyCheckResponse.authServerRawData.text = "";
                     
                        // デバッグ表示
                        mun.MunLogger.MRSEXT_LOG_DEBUG($"proxy_check done. " +
                                                       $"result={s_ProxyCheckResponse.result}, " +
                                                       $"proxyClientUId={s_ProxyCheckResponse.clientUid}"
                                                       , m_DeclaringType);
                     
                        // 送信バッファにパッキング
                        mrs.Buffer buffer = new mrs.Buffer();
                        buffer.Unread(0xFFFFFFFF);
                        buffer.Unwrite(0xFFFFFFFF);
                        if (s_ProxyCheckResponse.Pack(ref buffer))
                        {
                            // 認証結果を送信
                            MunProxySessionToClient.Send_Relay_Anything(pMunClient, s_ProxyCheckResponse.payloadType, ref buffer);
                        }
                    }

MUN クライアント側から送られてくる「認証のための各種データ」については、request.customAuthParameters にハッシュ情報として入っています。

  ・ request.customAuthParameters[].key.text でハッシュキー(文字列)
  ・ request.customAuthParameters[].value.data.data でハッシュの値 (文字列)

この情報を使い、「username」と「password」のハッシュキーに対する値を取得し、
MunProsySessionToCustomAuthServer::OpSend() 関数で、Web認証サーバにリクエストを送信します。


Web認証サーバからの結果について、クライアントに送信する

mun_proxy サーバが Web 認証サーバから認証結果を取得した場合の処理の記述

  Web 認証サーバから認証結果を取得したら、その結果を受けて MUN クライアントに認証結果の可否を渡します。

  下記のうち、ご利用されている MUN サーバの開発言語に合わせて、カーソルクリックしてください。
MunProxyDatabase::Recv_Proxy_Check() 関数に対して以下のように実装することで、
先の シンプルな認証用Webサーバを作る で示した Web 認証サーバの結果の是非を判断し、
MUN クライアントに結果を通知することができます。
/**
 * @brief   カスタム認証サーバから認証処理結果を受信したときの処理.
 * @param   pMunClient      MUN クライアント接続モジュール.
 * @param   authResult      認証処理に伴う取得データ.
 */
void    MunProxyDatabase::Recv_Proxy_CheckResult(MrsConnection pMunClient, std::string authResult)
{
    int32   result = STREAM::RESULT_FAILURE;

    // リザルト結果の中に「"result":"OK"」が含まれているかどうかを取得    
    std::string::size_type pos_ok = authResult.find("\"result\":\"OK\"");
    if (pos_ok != std::string::npos) {
        result = STREAM::RESULT_SUCCESS;
    }
    else {
        result = STREAM::RESULT_FAILURE_PROXY_DENYED_CUSTOM_AUTH;

        // 認証に失敗したので、クライアントUIDを削除    
        RemoveMunClient(pMunClient);

        // リザルト結果の中に「"result":"FAILED"」が含まれているかどうかを取得
        std::string::size_type pos_failed = authResult.find("\"result\":\"FAILED\"");
        if (pos_failed == std::string::npos) {
            // 想定外のリザルト結果が返ってきている
            MRSEXT_LOG_ERR("Invalid response from auth-server : " + authResult);
        }
    }

    // 送信データの生成
    s_ProxyCheckResponse.clientUid = GetMunClient(pMunClient);
    s_ProxyCheckResponse.result = result;
    s_ProxyCheckResponse.authServerRawData.text = authResult;

    // 送信バッファをまとめる
    static MunBuffer buffer;
    buffer.Unread(0xFFFFFFFF);
    buffer.Unwrite(0xFFFFFFFF);
    if (s_ProxyCheckResponse.Pack(buffer)) {
        // 認証結果を送信
        MunProxySessionToClient::Send_Relay_Anything(pMunClient, s_ProxyCheckResponse.payloadType, buffer);
    }
}


先のシンプルな認証用Webサーバを作る で示した Web 認証サーバにより

  ・ 認証に成功した場合、「{"result":"OK"}」の文字列を返す
  ・ 認証に失敗した場合、「{"result":"FAILED"}」の文字列を返す

ように指定していますので、認証結果として受け取った authResult の文字列情報として、
上記のうちのどちらが返ってきているかを std::string::find() を使って検索して判別します。

認証に失敗している場合には、事前に登録しているクライアント識別用ユニークIDの削除処理(RemoveMunClient())を実行します。

s_ProxyCheckResponse.result に、認証に成功していれば STREAM::RESULT_SUCCESS を格納し、
失敗していれば STREAM::RESULT_FAILURE_PROXY_DENYED_CUSTOM_AUTH を格納した上で、
MunProxySessionToClient::Send_Relay_Anything() で MUN クライアントに結果を通知します。
MunProxyDatabase.Recv_Proxy_Check() メソッドに対し以下のように実装することで、
先の シンプルな認証用Webサーバを作る で示した Web 認証サーバの結果に対し、
認証の是非を判断し、MUN クライアントに結果を通知することができます。
        /**
         * @brief    カスタム認証サーバから認証処理結果を受信したときの処理.
         * @param    pMunClient        MUN クライアント接続モジュール.
         * @param    authResult        認証処理に伴う取得データ.
         */
        public static void Recv_Proxy_CheckResult(MrsConnection pMunClient, string authResult)
        {
            // TODO : カスタム認証サーバからの認証結果により、認証の可否判定をする
            Int32   result = (Int32)mun.STREAM.ERRORCODE_ID.RESULT_FAILURE;
         
            // リザルト結果の中に「"result":"OK"」が含まれているかどうかを取得    
            Int32 pos_ok = authResult.IndexOf("\"result\":\"OK\"");
            if (pos_ok >= 0) {
                result = (Int32)mun.STREAM.ERRORCODE_ID.RESULT_SUCCESS;
            }
            else {
                result = (Int32)mun.STREAM.ERRORCODE_ID.RESULT_FAILURE_PROXY_DENYED_CUSTOM_AUTH;
         
                // 認証に失敗したので、クライアントUIDを削除    
                RemoveMunClient(ref pMunClient);
         
                // リザルト結果の中に「"result":"FAILED"」が含まれているかどうかを取得
                Int32 pos_failed = authResult.IndexOf("\"result\":\"FAILED\"");
                if (pos_failed < 0) {
                    // 想定外のリザルト結果が返ってきている
                    mun.MunLogger.MRSEXT_LOG_ERR($"Invalid response from auth-server : {authResult}", m_DeclaringType);
                }
            }
         
            // 送信データの生成
            s_ProxyCheckResponse.clientUid = GetMunClient(ref pMunClient);
            s_ProxyCheckResponse.result = result;
            s_ProxyCheckResponse.authServerRawData.text = authResult;
         
            // 送信バッファをまとめる
            mrs.Buffer buffer = new mrs.Buffer();
            buffer.Unread(0xFFFFFFFF);
            buffer.Unwrite(0xFFFFFFFF);
            if (s_ProxyCheckResponse.Pack(ref buffer)) {
                // 認証結果を送信
                MunProxySessionToClient.Send_Relay_Anything(pMunClient, s_ProxyCheckResponse.payloadType, ref buffer);
            }
        }


先のシンプルな認証用Webサーバを作る で示した Web 認証サーバにより

  ・ 認証に成功した場合、「{"result":"OK"}」の文字列を返す
  ・ 認証に失敗した場合、「{"result":"FAILED"}」の文字列を返す

ように指定していますので、認証結果として受け取った authResult の文字列情報として、
上記のうちのどちらが返ってきているかを string.IndexOf() を使って検索して判別します。

認証に失敗している場合には、事前に登録しているクライアント識別用ユニークIDの削除処理(RemoveMunClient())を実行します。

s_ProxyCheckResponse.result について、認証に成功していれば mun.STREAM.ERRORCODE_ID.RESULT_SUCCESS を格納し、
失敗していれば mun.STREAM.ERRORCODE_ID.RESULT_FAILURE_PROXY_DENYED_CUSTOM_AUTH を格納した上で、
MunProxySessionToClient.Send_Relay_Anything() で MUN クライアントに結果を通知します。


サーバを起動する

MUNサーバとWeb認証サーバを起動させる

  ここまでの対応でひとまずサーバ側の設定は完了しました。
  サーバを起動させて、カスタム認証制御を利用できる環境を整えましょう。

  上述の内容で MUN サーバに改変を加えていますので、改めて MUN サーバのビルド を行ない、
  続けて MUN サーバの実行 を行ないます。

  Web 認証サーバについては Web認証サーバを起動する に記載した内容に基づき、
  MUN サーバ側からアクセス可能な状態に構築してください。