サードパーティの SMS ベースの多要素認証のリリース
多要素認証 (MFA) は、ユーザの ID を検証するときのセキュリティを強化し、Salesforce 組織へのアクセスを保護します。SMS ベースの MFA では、パスワードに加え、モバイルデバイスで受信したワンタイムパスワード (OTP) コードの入力がユーザに要求されます。
MFA を実装するには、Twilio や TeleSign のような、サードパーティの SMS または音声配信サービスを Salesforce ログインフローと一緒に利用できます。
SMS ベースの MFA プロセスを詳しく見ていきましょう。
- ユーザがログインすると、ログインフローがランダムな OTP を生成し、音声またはテキストメッセージを介してユーザの携帯電話に送信します。
- ユーザがその OTP を Salesforce アプリケーションに入力します。
- Salesforce がそのコードを検証します。
- コードが有効な場合、Salesforce はユーザのアクセスを許可します。
ログインフローには 4 つのステップがあります。
- レコードを取得— ユーザレコードを照会して携帯電話番号を取得します。
- Apex アクション (従来) — OTP を生成し、サードパーティの SMS 配信サービスを使用してその OTP をユーザのモバイルデバイスに送信します。
- 画面— ユーザに受信した OTP を入力するように促します。
- 決定 — Apex アクションで生成された OTP をユーザが入力した OTP と比較します。等しければ、フローは完了し、ユーザはアプリケーションにリダイレクトされます。等しくなければ、フローは別のコードを生成し、ユーザに再検証を要求します。
フローの設定
この例では、Twilio Apex SDK を使用して SMS 配信操作を実行します。他のクラウドベースの SMS または音声ベンダーでも、サービスにアクセスするための公開 API があれば使用できます。
- Flow Builder を開きます。[設定] で、[クイック検索] ボックスに「フロー」と入力して、[フロー] を選択し、[新規フロー] をクリックします。
- [画面フロー] を選択して、[作成] をクリックします。
- ツールボックスから、[マネージャ] タブを開いて [新規リソース] をクリックします。
- LoginFlow_UserId 入力テキスト変数を作成します。この変数には、ログインイベント中にユーザ ID が入力されます。
- テキスト変数を作成します。
- Mobile (モバイル) — ユーザの携帯番号
- VerificationCode (確認コード) — Apex プラグインで生成された OTP
- Code (コード) — ユーザから収集された OTP
- Status (状況) — プラグイン実行時に返された状況
- ツールボックスから、[要素] タブを開きます。[レコードを取得] 要素をキャンバスに追加し、ログインしようとしているユーザを検索します。
- ユーザの携帯番号を Mobile 入力変数に保存します。
- https://github.com/twilio/twilio-salesforce から Twilio Apex SDK をインストールします。
- SMS プラグインに Twilio Web サービスへの送信 API コールの実行を許可するには、Salesforce で https://api.twilio.com をリモートサイトとして設定します。[設定] で、[クイック検索] ボックスに「リモートサイトの設定」と入力し、[リモートサイトの設定] を選択して Twilio Web サービスの URL を追加します。
- Apex クラスを作成します。
1global class SMSPlugin implements Process.Plugin { 2 3 global Process.PluginDescribeResult describe() { 4 5 Process.PluginDescribeResult result = new Process.PluginDescribeResult(); 6 result.tag='Identity'; 7 result.name='SMS Plugin'; 8 result.description='Multi-factor authentication with SMS'; 9 10 result.inputParameters = new List<Process.PluginDescribeResult.InputParameter> { 11 new Process.PluginDescribeResult.InputParameter('AccountSid', Process.PluginDescribeResult.ParameterType.STRING, true), 12 13 new Process.PluginDescribeResult.InputParameter('Token', Process.PluginDescribeResult.ParameterType.STRING, true), 14 new Process.PluginDescribeResult.InputParameter('To', Process.PluginDescribeResult.ParameterType.STRING, true), 15 new Process.PluginDescribeResult.InputParameter('From', Process.PluginDescribeResult.ParameterType.STRING, true), 16 new Process.PluginDescribeResult.InputParameter('Message', Process.PluginDescribeResult.ParameterType.STRING, true) 17 }; 18 19 result.outputParameters = new List<Process.PluginDescribeResult.OutputParameter> { 20 new Process.PluginDescribeResult.OutputParameter('Status', Process.PluginDescribeResult.ParameterType.STRING), 21 new Process.PluginDescribeResult.OutputParameter('VerificationCode', Process.PluginDescribeResult.ParameterType.STRING) 22 }; 23 24 return result; 25 26 } 27 28 29 global Process.PluginResult invoke(Process.PluginRequest request) { 30 31 Map<String, Object> result = new Map<String, Object>(); 32 String AccountSid = (String)request.inputParameters.get('AccountSid'); 33 String token = (String)request.inputParameters.get('Token'); 34 String To = (String)request.inputParameters.get('To'); 35 String From_a = (String)request.inputParameters.get('From'); 36 String Message = (String)request.inputParameters.get('Message'); 37 if (Message == null) Message = 'Your verification code is: '; 38 39 TwilioRestClient client = new TwilioRestClient(AccountSid, Token); 40 TwilioSMS sms; 41 42 Integer rand = Math.round(Math.random()*100000); 43 String VerificationCode = string.valueOf(rand); 44 String Body = Message + VerificationCode; 45 46 Map<String,String> params = new Map<String,String> { 47 'To' => To, 48 'From' => From_a, 49 'Body' => Body 50 }; 51 52 try { 53 sms = client.getAccount().getSMSMessages().create(params); 54 result.put('Status', sms.getStatus()); 55 } catch(Exception ex) { 56 result.put('Status', 'Failure'); 57 } 58 result.put('VerificationCode', VerificationCode); 59 return new Process.PluginResult(result); 60 } 61} - OTP コードを生成して SMS 経由でユーザの携帯番号に送信する SMS プラグインを作成します。このプラグインは、次の入力を取り込みます。
- AccountSid (アカウント SID) — Twilio アカウント SID (Twilio アカウントのユーザ名)
- Token (トークン) — Twilio 認証トークン (Twilio アカウントのパスワード)
- From (送信者) — SMS の送信者番号
- Message (メッセージ) — 確認コードと一緒にユーザに送信されるメッセージ
- To (送信先) — ユーザの携帯電話番号
このプラグインは、2 つの値を返します。- Status (状況) — SMS 配信操作の状況
- VerificationCode (確認コード) — 生成されてユーザに送信される確認コード
- 受信した確認コードの入力を促す画面要素を作成します。
- 2 つの結果を持つ決定要素を作成します。
- Valid (有効) — 確認コード ({!VerificationCode} に保存) はユーザがコード画面コンポーネントで入力したコードと同じです。
- Invalid (無効) — 有効な結果の条件が満たされないため、結果は無効です。この結果を作成するには、デフォルトの結果の表示ラベルを「Invalid」 (無効) に変更します。
- 要素と要素を接続します。決定を従来の Apex アクションに接続する場合、無効な結果を選択します。
- フローを保存して有効化します。
-
ログインフローをユーザプロファイルに接続します。
- ログアウトし、テストプロファイルに接続されたテストユーザとしてログインします。
フローの拡張
本番リリースでは、この基本フローを拡張することがよくあります。たとえば、次のようなカスタマイズ、検証、ポリシーを追加できます。
- ブランド — 会社のロゴとメッセージを検証画面に追加します。
- 検証 — ユーザレコードに電話番号が含まれているかどうかを検証します。含まれていなければ、ユーザに入力を促します。
- 再試行回数 — ユーザが入力した OTP コードが誤りの場合、ログインフローは新しい OTP コードを生成してユーザに送信します。一般的に、再試行回数を制限したり、検証の試行が複数回失敗したらユーザのログインを一時的にブロックしたりします。
- ポリシー — ユーザが携帯電話番号ではなく固定電話を登録している場合、SMS ではなく音声で OTP を送信します。または、Salesforce にユーザの電話番号が登録されていない場合、メールで OTP コードを送信します。別の方法として、ユーザに検証方法 (Salesforce の時間ベースの OTP や、YubiKey のようなハードウェアベースの OTP など) の入力を要求することもできます。