おでんはじめました。

required ちくわぶ and 巾着,optional はんぺん.

コンソールアプリで Azure AD B2C の ROPC フローを試してみた

コンソールアプリを使って Azure AD B2C の ROPC フローを試してみました。

ROPC フローとは

Azure AD B2C は通常はブラウザや WebView を介してサインインをおこないますが、ROPC フローはユーザー名とパスワードを直接処理することでユーザーをサインインすることができるフローです。

また、ROPC フローは作成済みのユーザー情報を使ってサインイン、サインアウトをすることはできますが、新規のユーザーを作成することはできません。

docs.microsoft.com

ROPC フローはサインイン時にユーザー情報がむき出しになるなどの理由から非推奨となっているので注意が必要です。

ROPC フローは "使用しない" ことをお勧めします。 ほとんどのシナリオでは、より安全な代替手段を利用でき、推奨されます。 このフローでは、アプリケーションで非常に高い信頼度が要求されるため、他のフローには存在しないリスクが伴います。 他のもっと安全なフローを使用できない場合にのみ、このフローを使用する必要があります。

(補足)コンソールアプリではブラウザを使った認証を使用できない(ただし Graph API の場合使用可能)

Azure AD B2C のコンソールアプリは http://localhostURI へリダイレクトされるため、ブラウザや WebView を使用する(「サインアップとサインイン」などの)フローの認証を使用することができません。

アプリの登録時に、http://localhost をリダイレクト URI として構成します (B2C では現在サポートされていません)

docs.microsoft.com

同じ MSAL ライブラリを使う場合でも、Graph API の場合はブラウザによる認証を使ったコンソールアプリを作成することができます。

github.com

Azure AD B2C の環境を作成する

ということで、Azure AD B2C で ROPC フローの環境を作成していきます。

docs.microsoft.com

Azure AD B2C のテナントを作成する

(ドキュメントにある Azure AD B2C を先に作るより)リソースグループから Azure AD B2C テナントを作成すると、テナントへのリンクが減る分少し簡単になります。

docs.microsoft.com

アプリの登録をする

作成した Azure AD B2C テナントから「アプリの登録」→「新規登録」でアプリケーションを登録します。

「認証」を選択して、「アクセス トークン (暗黙的なフローに使用)」にチェック、「パブリック クライアント フローを許可する」で「はい」を選択します。

f:id:masatoru:20210306210431p:plain

ユーザーフローを作成する

テナントに戻り、「新しいユーザーフフロー」→「リソース所有者のパスワード資格情報 (ROPC) を使用してサインインする」→「作成」を選択します。

f:id:masatoru:20210306223322p:plain

ユーザーフロー名を入力して「作成」を選択します。

MSAL で使う場合は、( Scope にアプリケーションIDを指定する方法が機能しないので)API を公開してスコープに追加する必要があるのでさらに下記を実行します。

  • API の公開」→「Scope の追加」→「スコープ名」を api(任意)で「スコープの追加」を選択

  • API のアクセス許可」→「自分の API」→「アクセス許可の追加」

  • 「"組織"名に管理者の同意を与えます」→「はい」

C# で使用するときに)スコープ名に https://{テナント名}.onmicrosoft.com/{クライアントID}/{作成したスコープ名} を追加します。

The identifier URI of the backend App Registration and scope name are concatenated to obtain the scope used in the next step.

github.com

C# で動かしてみる

C# と MSAL ライブラリーを使用して、作成した ROPC フローでサインインをおこないます。 今回のサンプルはこちらに置いてあります。 github.com

入力画面に Sharpromt を使う

メールアドレスとパスワードの入力は @shibayanSharpromt を使ってます。Sharpromt を使うと簡単にコンソールでの入力画面を作成できます。

var username = Sharprompt.Prompt.Input<string>("Input username.");
var password = Sharprompt.Prompt.Password("Input password.");

実行するとこんな感じです。

f:id:masatoru:20210306193920p:plain

github.com

MSAL を使ってサインインを実装する

MSAL ライブラリーを使ってサインインをする場合、

  1. Azure AD B2C の情報から IPublicClientApplication を作成する

  2. キャッシュがあればそっちでログインを試みる

  3. キャッシュがなければ(例外が発生するので)通常でログインする

  4. 成功すれば、AuthenticationResult から id token を取得する

という流れになります。

App = PublicClientApplicationBuilder.Create(ClientID)
    .WithB2CAuthority(Authority)
    .Build();

AuthenticationResult result = null;
var accounts = await App.GetAccountsAsync();
var account = accounts.FirstOrDefault();

try
{
    result = await App.AcquireTokenSilent(Scopes, account)
        .ExecuteAsync();
}
catch (MsalUiRequiredException)
{
    try
    {
        result = await App.AcquireTokenByUsernamePassword(Scopes, username, passwordText)
            .ExecuteAsync();
    }
    catch (MsalUiRequiredException ex)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine(ex.Message);
        Console.ResetColor();
    }
    catch (MsalUiRequiredException ex)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine(ex.Message);
        Console.ResetColor();
    }
    // AADB2C90225: The username or password provided in the request are invalid.
    catch (MsalServiceException ex)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine(ex.Message);
        Console.ResetColor();
    }
}

// Cache empty or no token for account in the cache, attempt by username/password
if (result != null)
{
    Console.WriteLine($"IdToken: {result.IdToken}");
    Console.WriteLine($"AccessToken: {result.AccessToken}");
}

実行結果です。

f:id:masatoru:20210306211311p:plain

ちなみに、サンプルを実行して Fiddler で覗いて見るとがっつりパスワードが見えちゃってます(のでくれぐれもご注意ください)。

f:id:masatoru:20210306202504p:plain

最後に

ROPC フローはあくまでも非推奨となっていますが、この仕様を理解した上で手軽に社内ツールを作成する場合などは有効な方法かなと思います。

それでは、Happy B2C Life!!