Azure AD B2CをPHPと使う (4) Laravel用のサンプルを解析、実運用へ

Azure-SamplesにあるLaravel用のサンプルは、現在は公式ドキュメントからのリンクこそないですが、基本的な実装を学ぶには十分でしょう。

トークンの検証部分は、githubのコードを参照すると、

active-directory-b2c-php-webapp-openidconnect/app/Http/Controllers at master · Azure-Samples/active-directory-b2c-php-webapp-openidconnect · GitHub

active-directory-b2c-php-webapp-openidconnect/app/Http/Controllers/

にある、EndpointHandlerクラスとTokenCheckerクラスです。

基本的な流れは、先に書いた記事と同様です。

noopable.hatenablog.jp

 

最新のB2Cと違うのはエンドポイントくらいでしょうか。

 

実運用を考慮

サンプルは上記でよいと思います。

が、このままでは使えないので、実運用に使っていくにはどうするか。

phpseclibは、サンプルの作成については、v1の方が直でクラスをロードしやすいですが、実運用ではv2の方でいいかなと思います。

EndpointHandler

まず、エンドポイントからの情報取得をリクエストがある度に行うのは、レスポンスが著しく悪化しますし、失敗した場合に認証失敗となっていたのではあり得ないと思いますので、キャッシュすること。できれば、キャッシュするだけではなく、実行環境ではcronなどで定期実行しておきたいですね。

キーリストは1時間に1回くらい更新されるそうです。

EndpointHandlerのエンドポイントデータの取得については、エラー処理を入れておきたいところ。

TokenChecker

検証をOPENSSL_ALGO_SHA256に決め打ちなんですが、jwtから取得しなくていいんでしょうか・・・

その他

その他、くせのあるコード部分については、各プロジェクトの規約に合わせて変更する形になるかな、と思います。

 

 

Azure AD B2CをPHPと使う (3) フレームワークの活用について考える

Azure AD B2CのサンプルでLaravel版があったことは以前に書きましたが、それ以外の選択肢について調べました。

いわゆる、プラグインやバンドルでOAuth、SSOを目的としたものであれば対応できるのではないかと考えられます。

 

Symfony バンドル

PHPフルスタックなフレームワークとしてまずはSymfonyについて

ざっと検索した感じでは、2種類のOAuth向けバンドルが有名なんでしょうか。(ご存じの方がいたら教えてください)

github.com

github.com

いずれもOAuth2対応で、その認証にAzureを含んでいることから、Azure AD対応がされていることが推測され、また、その結果としてAzure AD B2Cに対しても多少カスタマイズすれば対応可能なのではないかと思います。

 

Drupal

CMSフレームワークの中間的Drupalでは、Azure AD B2C対応がされています。

Guide to Configure Azure AD B2C as an OAuth Server for Drupal

フレームワークと比べ、必要とあらば作り込みまでできてしまうところがDrupalのようなサイズのCMSの特徴といえるかもしれません。

 

Laravel プラグイン

Laravelには、Laravel Socialiteという有名なプラグインがあるそうで、いわゆるSSO関係を幅広くサポートするプラグインのようです。

laravel.com

そして、これを使った例。

Laravel Socialite でMicrosoft Graph (Office 365アカウント)認証する – hrendoh's tech memo

このブログ記事では、Laravel Socialiteを用いてMS Graph を使用しています。実際これができるのであれば、Azure AD B2Cにも対応できるのではないかと想像します。

 ありますね。

github.com

ほとんど、これでいけるんじゃないか?という気がしますがどうでしょうか。

 

Zend Framework

Zend Framework3では、zend-authenticationの中のアダプターに、LDAPアダプターがあります。Active DirectoryLDAPプロトコルもサポートしているので、認証関係はLDAPアダプターで実現できます。

LDAP - zend-authentication - Zend Framework Docs

また、このLDAPアダプターはMicrosoft Active Directoryについてテストもされているので、Windows 環境でシームレスにWebを扱いたい場合には有力な候補となると思います。

おそらく、Azure AD B2Cにも活用できると思うのですが、Azureの場合、LDAPサーバーはどこを指定すればいいんですかね?

 

OAuthプラグインは必要なのか?

いろいろとみてきましたが、全体設計をシンプルにするならPHPでOAuthを全部受け持つのがよいとは思えないのです。

認証周りはエンドポイントとの通信が多く発生します。そのたびに自前のサーバーを通すのはエコじゃないですよね。ブラウザーとエンドポイント間で認証してもらい、アプリケーションサーバーは検証するだけでほとんどのシナリオは解決可能なはずです。

そうすると、他の機能のために保守が必要であったり、場合によってはセキュリティホールにもなりうるものを使うよりも、シンプルにトークンの検証に特化した方が幸せなような気がします。

そういうわけでSymfonyで、トークンの検証をサポートすればいいのでは?というのが今の雑感です。

symfony.com

実際には、APIにおいてはAuthorizationヘッダーを読んで検証するだけであれば、Authentication Providerではなく別のフックを利用するべきなのかもしれませんが、詳しい方、教えていただけると幸いです。

 

 

Azure AD B2CをPHPと使う (2) SPAから送られてきたトークンを検証する

SPAから送られてきたトークンを検証する

Azure AD B2Cと連携するのにあたり、PHP側のタスクは、

  • 適切なAPI
  • ページの送出

にあろうかと思います。

Azure AD B2Cとの連携という意味では、APIにおいてアクセスしてきたユーザーが適切なトークンを持っているか、つまり、認証を経て当該アクセスをする正当な権限を持っていることを検証することに尽きます。具体的には、IDを保証するトークンと権限を保証するトークンということになるでしょう。

現状でそういったサンプルは見かけないのですが、要件としては、以下のドキュメントとOpenIDのドキュメントを参考に、

トークンの概要 - Azure Active Directory B2C | Microsoft Docs

 

  • 対象ユーザー
  • 期間の開始時刻 および 期限切れ日時
  • 発行者
  • nonce

 

これらを検証することになるでしょう。

トークンには、認証結果を示すIDトークンと承認結果を示すアクセストークンがあり、それぞれ、もしくは、IDトークンのみを検証して、サーバー内でアクセスコントロールを行うか、B2C側に許可情報を付与してアクセストークンも検証することになると思います。せっかく認証機構を外だしするわけですから、アクセストークンもB2Cで管理した方がいいと思いますが、既存のCMSなどと連携する際はIDトークンのみの検証になることも考えられます。

docs.microsoft.com

docs.microsoft.com

 

2015年頃にPHPサンプルがMicrosoftのブログで閲覧できていたのですが、現状は404 not foundになっています。おそらく、out-datedなのでしょう。

その404ページに貼られていたリンクですが、Azure ADのトークン関係で、重要そうなのでメモっておきます。

プライマリ更新トークン (PRT) と Azure AD - Azure Active Directory | Microsoft Docs

 

ところで、当時の仕様通りかどうかはわからないのですが、大きく変更がないとすれば、(というか動いてほしいですが、)当時のサンプルでのフローを追ってみます。

 

トークンの概要 - Azure Active Directory B2C | Microsoft Docs

Azure AD B2C には、OpenID Connect メタデータ エンドポイントがあります。 このエンドポイントを使用すると、アプリケーションは実行時に Azure AD B2C に関する情報を要求できます。 この情報には、エンドポイント、トークンの内容、トークンの署名キーが含まれます。 Azure AD B2C テナントには、ポリシー別の JSON メタデータ ドキュメントが含まれています。 メタデータ ドキュメントは、いくつかの便利な情報が含まれている JSON オブジェクトです。 メタデータには、トークンの署名に使用される公開キーのセットの場所を示す jwks_uri が含まれます。 次に示すのがその場所ですが、メタデータ ドキュメントを使用して jwks_uri を解析することにより、その場所を動的にフェッチするのが最善の方法です。
https://contoso.b2clogin.com/contoso.onmicrosoft.com/b2c_1_signupsignin1/discovery/v2.0/keys

この URL にある JSON ドキュメントには、特定の時点で使用されているすべての公開キー情報が含まれています。 アプリでは、JWT ヘッダーの kid 要求を使用して、特定のトークンの署名に使用される JSON ドキュメント内の公開キーを選択できます。 その後、正しい公開キーと指定されたアルゴリズムを使用して、署名の検証を実行できます。

 つまり、2020年現在のキーの取得は、以下から取得せよとのことです。

https://[テナントID].b2clogin.com/[ディレクトリID]/[ポリシー]/discovery/v2.0/keys

ところで、以前の仕様だと、ポリシーはパスではなく、クエリで?p=で指定していました。

まず、ここからキーを取得しておき、次に、アクセスしてきたauthorizationHeaderから、Bearer を見つけ、値を取り出してjwtとして処理していくという流れですね。

nbf exp aud などを検証したあと、先ほどエンドポイントから取得したkeysの中から使用するキーを選択し、それに該当するパブリックキーで、送られてきたトークンをopenssl_verifyで、検証するという形でした。

 

実際に、これで検証できるかどうか、これから試してみようと思います。

 

 

Azure AD B2CをPHPと使う (1)

公式サンプルにはない

かつては、公式ドキュメントからもAzure AD B2CとPHPを使うサンプルへのリンクが張られていました。

現在のドキュメントのサンプルでは、PHP版は消えています。

docs.microsoft.com

 

.NET Node.js Python などでサンプルが保守されているのでしょう。

 

何が必要か

多くの場合、Webアプリケーション側のタスクは、ブラウザー上で認証、承認を得たクライアントから送られてくるトークンの検証であるはずなので、そういったシナリオであれば、あえてサンプルがなくても実現は難しくはないのではないかと思います。

そのSPAを介さないでPHPだけで頑張るというのは筋が悪いというか意味がないので、ここでは検討しないことにします。

 

古い情報

念のため。実は、古い情報としては、一応PHP版のサンプルもありました。

github.com

 

Laravelベースであることについて疑問が呈されたこともありますが、更新が止まったというよりも、サンプルが一つだけ上がった、という理解の方が正しいのではないかと思います。こちらは、あまり期待はしない方がよさそうです。

 

 

近いうちに作るよ?

Azure AD B2CをPHPと使う (4) JWT検証について - noopableの日記 (hatenablog.jp)

ここで触れましたが、Firebaseが用意しているJWTクラスを元にAzure AD B2Cのphp用のシンプルなラッパーを書こうと思っています。

といってもプライベートリポジトリでの作業になりますので、興味のある方はご連絡くださいませ。

 

有限責任事業組合(LLP)と持続化給付金について

LLPでも持続化給付金を受給できましたので、ご報告いたします。

有限責任事業組合(LLP)というのは、民法組合の特例で法律で定められた組織形態です。ここが最重要で、任意団体や民法組合(民法に基づく組合)と異なり、「有限責任事業組合契約に関する法律」によって定められ、法人と同様に登記も行う組織形態です。ただし、法人格はなく、LLPに参加する法人や個人はその事業の損益について構成員が税務申告を行います。

事業ごと、イベントごとに協力しあう組織や個人が一定の規律をもって行動するのに適した組織形態の一つといえると思います。

たとえば、オープンソースソフトウエアなどでも、LLCであったり株式会社であったりと法人格のある運用をされている場合があると思いますが、LLPであれば、法人、個人を問わず、そのプロジェクトに対する利害関係を持つ人の関係を柔軟に設計できるのでソフトウエアプロジェクトにもLLPは向いていると思います。

私も一つ参加しています。

 

さて、そのLLPですが、持続化給付金の対象といえるのかどうかが、一部で話題になっていました。

Yahoo!知恵袋などにも、正誤入り混じった情報が出ていますが、正しくは、

「構成員単位で給付の可否が判定される」

ということになろうかと思います。

 

税理士さん経由で聞いた話としては、少なくとも法人で給付されたケースはあり、その給付と同じような要件で個人参加の場合も申請できると考えられたので、私も申請してみました。

結果、給付されました!

 

そもそも、何が問題か。

その1 制度趣旨・給付対象

持続化給付金の法人としての給付対象は、

中小法人等を対象とし医療法人、農業法人NPO法人など、会社以外の法人についても幅広く対象となります。

とのことです。

つまり、「会社以外の法人」も対象です。

そして、中小法人等の給付規定には以下のように書いてあります。

「2020 年4月1日時点において、次のいずれかを満たす法人であること。ただし、組合若しくはその連合会又は一般社団法人については、その直接又は間接の構成員たる事業者の 3 分の 2 以上が個人または次のいずれかを満たす法人であること。(従って、任意団体は給付対象とはならない。)」

つまり、任意団体は給付対象とはならないが、組合は法人等に含むと解す余地がありそうに読めないでしょうか?!

それはさておき、LLPは法律に基づいて登記も行う組織形態です。少なくとも、任意団体、権利能力なき社団民法組合とは法律に基づく安定性としては別格のものといえます。

ところが、持続化給付金の給付規定等では、有限責任事業組合(LLP)について、一言も触れられていないのです。

そのため、さまざまな憶測と誤認が流布され、LLPでは、LLPとしても法人としても個人としても給付が受けられないといった誤情報が広まってしまうことになるのではないかと思います。

(LLPは制度趣旨として優れていると思われ、経産省主導で導入されていると考えられるのに、いまいち普及しないというのは、省内で、担当部署があまり重視されていないのでしょうかね?)

その2 税務申告の特殊性と売上時期

LLPの税務申告はやや特殊で、パススルー課税といって各構成毎に申告を行うため分配割合に基づいて、損益も貸借も計上されます。そして、税務申告においては、LLPが提出する法定調書のほか、各構成員が確定申告を行います。その際、その各会計科目についてすべて分配することもできますし、年間の収支をまとめて分配を集約した申告も可能です。

ここで、分配を集約した確定申告を行っていると、たとえば、LLPの売上が2000万円でも経費が2050万円であれば、構成員の確定申告書上には売上が現れないことがあります。(売上を分配形状して申告することも選択可能)。

そうすると、LLPでの売り上げが半減して、法人でも個人でも受給できるケースにおいても、LLP(その構成員)に限っては確定申告書に基づく計算というシステム上、受給できないということになります。

ちょっと、わかりにくいと思いますが、正直、制度がわかりにくいので、素人説明にも限界があります。申し訳ない。m(__)m

 

難題は多いが・・

実際に、個別のLLPや構成員がどのような申告を行っているのかによって、受給できる方法や手続きは違いがあろうかと思います。

しかし、私がLLPを構成する個人として受給できた例や、法人で受給できた例があるので、LLPだから受給できないと決め付けた話ではないということはいえます。

 

※ 余談ですが、

消費税のインボイス制度でも同じような問題が生じる気がしてなりません。

 

 

Auth0、AWS東京リージョンで提供開始

認証ソリューションとしてのスタンダードになりつつあるAuth0が、AWSで使えるようになったようですね。

prtimes.jp

しかし、どうなんでしょう。

元々使えていたのでは?と思うのですが・・・

Microsoft Azure Tech Advent Calendar 2020

Adventねた2つめ。

Microsoft Azure Tech Advent Calendar 2020 なるものがあります。

qiita.com

ざっとタイトル一覧を見ると、Azure AD絡みが2つあるようですね。

今、調査テスト中のAzure AD B2Cとは少し違うのですが、MS Graphを使うあたり、ノウハウとしてはかなり近いものがあります。要チェック!

jpazureid.github.io

 

図示してもらえるとわかりやすいですね。