Arduino と RFID を使用したユーザー認証
以前の記事では Arduino を使い始め、最終的には気象観測所のデータを表示できるようになりました。 この記事ではさらに掘り下げ、InterSystems Caché アプリケーションに対して RFID カードと Arduino を介した認証をセットアップします。
認証の委任
Caché には認証コードの書き込みを許可することで、認証を委任するための仕組みがあります。 この仕組みを有効にするには、次の手順を実行する必要があります。
- Caché で委任認証を有効にします([SMP] → [System Administration] → [Security] → [System Security] → [Authentication/CSP Session Options] を開き、[Allow Delegated authentication] ボックスにチェックを入れて設定を保存します)。
- 関連するサービスかアプリケーションの委任認証を有効にします(前者の場合は [SMP] → [Menu] → [Manage Services] → [Service] → [Allowed Authentication Methods] → [Delegated] を選択 → [Save]、後者の場合は [SMP] → [Menu] → [Manage Web Applications] → [Application] → [Allowed Authentication Methods] → [Delegated] を選択 → [Save])。
仕組み
委任認証は、委任認証が有効になっているサービスや Web アプリケーションに対してユーザーが認証される際に発生します。
- ZAUTHENTICATE ルーチンが呼び出されます。 このルーチンのコードはユーザーによって書かれたものであり、OS への呼び出しを含む任意の Caché ObjectScript コードである可能性があります。
- 次のステップは、ZAUTHENTICATE の呼び出しが成功したかどうかによって決まります。
- ZAUTHENTICATE の呼び出しが成功し、ユーザーが ZAUTHENTICATE で認証されたのが初めてだった場合は「委任されたユーザー」が作成されます。 ZAUTHENTICATE がロールやその他の権限をユーザーに割り当てた場合は、それらがユーザープロパティになります。
- ZAUTHENTICATE の呼び出しが成功し、ユーザーが ZAUTHENTICATE で認証されたのが初めてではなかった場合はそのユーザーのレコードが更新されます。
- ZAUTHENTICATE の呼び出しが成功しなかった場合、ユーザーはアクセスエラーを受け取ります。
- インスタンスとサービスで 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é の認証システムを使えば、任意のユーザー認証ロジックを実装できます。
リンク
- ドキュメント
- GitHub リポジトリ
- SAMPLES ネームスペースには ZAUTHENTICATE ルーチンの例も含まれています