記事
· 2020年12月7日 10m read

Arduino と RFID を使用したユーザー認証

    以前の記事では Arduino を使い始め、最終的には気象観測所のデータを表示できるようになりました。 この記事ではさらに掘り下げ、InterSystems Caché アプリケーションに対して RFID カードと Arduino を介した認証をセットアップします。

 

認証の委任

Caché には認証コードの書き込みを許可することで、認証を委任するための仕組みがあります。 この仕組みを有効にするには、次の手順を実行する必要があります。

  • ZAUTHENTICATE ルーチンにユーザー認証コードを記述します。 このルーチンにはユーザー名/パスワードの取得、それらの検証と権限の割り当て、パスワード変更、トークン生成の 4 つのエントリポイントがあります。 詳細については、以下をお読みください。
    1. Caché で委任認証を有効にします([SMP] → [System Administration] → [Security] → [System Security] → [Authentication/CSP Session Options] を開き、[Allow Delegated authentication] ボックスにチェックを入れて設定を保存します)。
    2. 関連するサービスかアプリケーションの委任認証を有効にします(前者の場合は [SMP] → [Menu] → [Manage Services] → [Service] → [Allowed Authentication Methods] → [Delegated] を選択 → [Save]、後者の場合は [SMP] → [Menu] → [Manage Web Applications] → [Application] → [Allowed Authentication Methods] → [Delegated] を選択 → [Save])。

    仕組み

    委任認証は、委任認証が有効になっているサービスや Web アプリケーションに対してユーザーが認証される際に発生します。

    1. ZAUTHENTICATE ルーチンが呼び出されます。 このルーチンのコードはユーザーによって書かれたものであり、OS への呼び出しを含む任意の Caché ObjectScript コードである可能性があります。
    2. 次のステップは、ZAUTHENTICATE の呼び出しが成功したかどうかによって決まります。
    • ZAUTHENTICATE の呼び出しが成功し、ユーザーが ZAUTHENTICATE で認証されたのが初めてだった場合は「委任されたユーザー」が作成されます。 ZAUTHENTICATE がロールやその他の権限をユーザーに割り当てた場合は、それらがユーザープロパティになります。
    • ZAUTHENTICATE の呼び出しが成功し、ユーザーが ZAUTHENTICATE で認証されたのが初めてではなかった場合はそのユーザーのレコードが更新されます。
    • ZAUTHENTICATE の呼び出しが成功しなかった場合、ユーザーはアクセスエラーを受け取ります。
    1. インスタンスとサービスで 2 要素認証が有効になっている場合は、ユーザーの電話番号と事業者の検索が開始されます。 これらの情報が入力されている場合は、2 要素認証が実行されます。 入力されていない場合は、ユーザーは認証されません。

    ユーザー情報の出処は?

    次のように、アプリケーション/サービスで有効になっている認証方法に応じた 2 つの認証方法があります。

    • 委任: ユーザー名/パスワードは ZAUTHENTICATE ルーチン(GetCredentials エントリポイント)から取得され、ZAUTHENTICATE を使用して検証されます(ユーザータイプ: 委任)。
    • 委任およびパスワード: ユーザー名/パスワードは GetCredentials から取得されますが、標準の Caché ツールを使用してチェックされます(ユーザータイプ: Caché)。

    次に、ZAUTHENTICATE ルーチンとそのエントリポイントを見てみましょう。

    ZAUTHENTICATE

    これはメインルーチンであり、次の 4 つのエントリポイントで構成されています。

    GetCredentials

    このエントリポイントはサービスで委任認証が有効になっている場合に呼び出され、ユーザーにユーザー名/パスワードの入力を求める代わりに呼び出されます。 このルーチンのコードは、ユーザー名とパスワードを(何らかの方法で)取得します。 その後、(このエントリポイントの外部で)受信したユーザー名とパスワードはユーザーから通常の方法で入力されたかのように認証されます。 ユーザー名とパスワードは、キーボードからの入力、API、外部デバイスを使用したスキャンなど、任意の方法で取得できます。 この記事では、RFID カードを使用した認証を実装します。

    このエントリポイントはステータスを返します。ステータスがエラーの場合は監査ログに記録され、認証試行は拒否されます。 ただし、エラーステータス $SYSTEM.Status.Error($$$GetCredentialsFailed) が返された場合は、例外的に通常のユーザー名/パスワードの入力が続きます。 シグネチャは次のとおりです。

    GetCredentials(ServiceName, Namespace, Username, Password, Credentials) Public { }

    説明:

    • ServiceName – 接続が確立されるサービスの名前
    • Namespace – ネームスペース(接続時に指定されている場合)
    • Username – ユーザー名
    • Password – パスワード
    • Credentials – 現在使用されていません

    このエントリポイントの重要な機能について説明します。 委任認証とパスワード認証の両方がサービスやアプリケーションで有効になっている場合、ユーザー名とパスワードは GetCredentials エントリポイントを介して受信されますが、それらの情報は標準のパスワード認証に使用されます(ユーザーが手動で入力した場合と同じ)。また、認証が成功した場合のユーザーは委任ユーザーではなく通常の Cache ユーザーになります。

    ZAUTHENTICATE

    初回認証が成功すると、ZAUTHENTICATE はロールやその他のユーザープロパティを定義します。 初回認証以外の場合はプロパティが更新されます(例えば、Roles はログインのたびに指定する必要があります)。 そのために、Properties 配列のプロパティを定型化したコードで設定する必要があります。 シグネチャは以下のとおりです。

    ZAUTHENTICATE(ServiceName, Namespace, Username, Password, Credentials, Properties) Public { }

    Properties 配列の説明:

    • Properties("Comment") — コメント
    • Properties("FullName") — 氏名
    • Properties("NameSpace") — 初期ネームスペース
    • Properties("Roles") — カンマ区切りのロールのリスト
    • Properties("Routine") — 初期ルーチン
    • Properties("Password") — パスワード
    • Properties("Username") — ユーザー名
    • Properties("PhoneNumber") — ユーザーの電話番号
    • Properties("PhoneProvider") — 電話会社
    • Properties("AutheEnabled") — 標準の 2 要素認証を有効化します(この目的のために、$$$AutheTwoFactorSMS に等しい値を設定する必要があります)

    ChangePassword

    ユーザーパスワードを変更するためのエントリポイントです。シグネチャは次のとおりです。

    ChangePassword(Username, NewPassword, OldPassword, Status) Public { }

    説明:

    • NewPassword — 新しいパスワード
    • OldPassword — 古いパスワード
    • Status — パスワード変更の結果

    SendTwoFactorToken

    標準の 2 要素認証で使用されるものです。 リクエストの形式と認証トークンを指定します。 シグネチャは以下のとおりです。

    SendTwoFactorToken(Username, ServiceName,Namespace,Application,Credentials,SecurityToken,TwoFactorTimeout,UserPhoneNumber) Public { }
    

    説明:

    • Application — ユーザーが接続している CSP アプリケーションまたはルーチン
    • SecurityToken — ユーザーに送信されるトークン
    • TwoFactorTimeout — トークンの有効期限が切れる時間
    • UserPhoneNumber — ユーザーの電話番号


    まずは簡単な例から始めましょう。Windows での Caché ターミナルを担う %Service_Console サービスは、ユーザー名とパスワードの入力をユーザーに要求します。 このサービスに対して委任認証を有効にしましょう。 以下は、ユーザーにユーザー名とパスワードの入力を要求する ZAUTHENTICATE ルーチン(%SYS ネームスペース内)です。

    ZAUTHENTICATE(ServiceName, Namespace, Username, Password, Credentials, Properties) PUBLIC {
        #Include %occStatus
        Quit $$$OK
    }
    GetCredentials(ServiceName, Namespace, Username, Password, Credentials) Public {
        #Include %occErrors
        #Include %occStatus
        Do ##class(%Prompt).GetString("USER:",.Username)
        Do ##class(%Prompt).GetString("PASS:",.Password)
        Quit $$$OK
    }

    ターミナルの場合、これは通常のユーザー名認証と同じように見えます。

    >USER: _SYSTEM
    >PASS: SYS

    RFID

    それでは、RFID による認証を見てみましょう。 考え方は単純で、Caché が暗号化されたユーザー名とパスワードをカードに書き込み、認証中に Caché がカードをスキャンして復号化し、受け取ったユーザー名とパスワードを認証に使用するというものです。

    まず、Arduino Uno と RFID-RC522 モジュールの回路図をご覧ください。

    MF522 ライブラリを使用した C のコードはここにあります。 このコードでは、COM ポート経由で次の 2 つのコマンドを受信できます。

    • Get – RFID カードのブロック 2 / 4 / 5 / 6 の内容が COM ポートに渡されます
    • Set@bloc2@bloc4@bloc5@bloc6 — ブロック 2 / 4 / 5 / 6 の値が受信したデータに置き換えられます

    Caché 側には Arduino.Delegate クラスがあり、その中に次の 2 つの対応するエントリポイントがあります。

    • SetCredentials — ユーザー名とパスワードの入力を取得し、それをシステムに格納されているキーを使用して AES 暗号化で暗号化し、RFID カードに書き込みます。
    • GetCredentials — カードから暗号化テキストを受信して復号化し、ユーザー名、パスワード、および操作のステータスを返します。

    また、GetCredentials を使用して Arduino.Delegated クラスを呼び出す ZAUTHENTICATE ルーチンは以下のとおりです。

    ZAUTHENTICATE(ServiceName, Namespace, Username, Password, Credentials, Properties) PUBLIC {
        #Include %occStatus
        Quit $$$OK
    }
    GetCredentials(ServiceName, Namespace, Username, Password, Credentials) Public {
        #Include %occErrors
        #Include %occStatus
        Quit ##class(Arduino.Delegated).GetCredentials(.Username, .Password)
    }
    

    これで準備完了です! 組み立て後のデバイスは次のようになります。

    次のようにターミナルでシステム暗号化キーを設定します(%SYS ネームスペースと Arduino.Delegated クラスを使用できる必要があります)。

    Do ##class(Arduino.Delegated).InitEncryption(Key, IV)
    

    ここで、Key は暗号化キー、IV は初期化ベクトルです。 これらは、ユーザー名とパスワードを暗号化するために使用されます。 コマンドを使用して認証するには、Arduino を Caché に接続し、カードに情報を書き込みます。

    Do ##class(Arduino.Delegated).SetCredentials("_SYSTEM", "SYS")
    

    適切なサービスまたは Web アプリケーション(端末やシステム管理ポータルなど)で委任認証とパスワード認証を有効にすると、カードを RFID カードリーダーにかざすことで認証できるようになります。

    考えられる機能強化

    • マネージド暗号化キーを使用してユーザー名とパスワードを暗号化すると、セキュリティを強化できます。
    • 2 要素認証を使用すると、セキュリティを強化できます。具体的には、先にユーザー名とパスワードのペアを取得してから、ユーザーに固有のキーが格納されているカードを読み取ります。 次に、受信したキーをシステムに格納されている特定ユーザーのキーで確認する必要があります。 任意のユーザーデータを格納する方法は、InterSystems のコミュニティで議論されています
    • それぞれ 15 文字を超えるユーザー名とパスワードを格納する機能を追加します。

    まとめ

    柔軟性の高い Caché の認証システムを使えば、任意のユーザー認証ロジックを実装できます。

    リンク

    ディスカッション (0)2
    続けるにはログインするか新規登録を行ってください