id:kizashi1122 です。
さて。
Exchange Online の先進認証に対応しました(1) - インゲージ開発者ブログ
前回のエントリでSMTPとPOP3の先進認証対応のため Azure AD 側にアプリを作るところまでは終わりました。
今度はサービス側に設定をしていきましょう。Ruby on Rails を使っている前提で解説します。他の言語の場合は使うライブラリが違ってくるなどはあるでしょうが、OAuth 2.0 のフローは言語依存しませんし、設定しないといけない項目は同じなので参考になるかと思います。
omniauth-oauth2 gem の利用
Ruby で OAuth 2.0 といえば、だいたい相場が決まっていて omniauth-oauth2 gem を直接使うか、omniauth-oauth2 gem を継承した認可サーバーに特化した gem を使うかになります。 Office 365 の場合は、こんな gem が見つかりました。
設定はこんな感じと README に書いています。
Rails.application.config.middleware.use OmniAuth::Builder do provider :microsoft_office365, ENV['OFFICE365_KEY'], ENV['OFFICE365_SECRET'], { authorize_params: { prompt: 'consent'}, scope: 'offline_access https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send' } end
スコープをどう設定するか?
もうここで気づいた人がいるかもしれません。
通常、認可サーバ側に設定するスコープ(パーミッション)と、クライアント側から指定するスコープは同じです。
前回のエントリで設定したスコープはこちら。
しかしクライアントに設定するスコープは上述の設定どおり
になります。
ここは海外のサイトを見てもたくさんの人がハマっているので要注意です。
そんなのどこに書いてるんだッ!と思いますがちゃんと書いています。
よく見ると、Azure AD で設定するアクセス許可の適用範囲は POP.AccessAsUser.All
だけど、OAuth2のフローでのアクセス許可のスコープ文字列は https://outlook.office.com/POP.AccessAsUser.All
であるということが読み取れます。
また今回はスコープ以外のパラメータとして prompt: consent
も指定しています。
これは OAuth の同意画面を表示し、許可を求める画面を表示するような設定です。
他に設定できる値についてはこちらを確認してください。
まだハマる
このあと適切に Controller を設定し、Azure AD で設定したコールバックURLも動くようにすればいいだけですが、なんと動きません。 OAuth の同意画面のあとのフローでエラーになります。正確に言うとトークンの取得後でエラーになります。これはハマります。
これは omniauth-oauth2 gem の特性が原因です。
このトークン取得後、この raw_info メソッドが自動的に認可に使用したユーザの情報を取得しようと API を叩きます。が、これは失敗します。そりゃそうだろ User.Read とか email とかスコープを指定してないじゃないかと言うかもしれませんが、これを指定しても動きません。
これはいまだに謎で、オフィシャルな情報は当たれていないのですが、こんな情報がありました。
IMAP, SMTP scopes are targeted for Exchange resource and not Graph. Whereas User.Read, Mail.ReadWrite are meant for Graph resource.
We do not support generation of tokens that are meant for two resources
SMTP.Send
は Exchange のリソースへのアクセスをするスコープであり、User.Read
は Graph リソースへのアクセスをするスコープである、と。そして、2つのリソースにアクセスできるトークンの発行はできない、と。User.Read
と同様に email
スコープも同じなのでしょう。メールアドレスも取得できません。
結局は私たちは、 omniauth-microsoft-office365 gem を使うのを辞めて、自分たちで作ることにしました。といっても、ほとんど同じでトークンの取得後自身の情報取得のためにAPIを叩かないようにしただけです。
認可につかった「メールアドレス」が通常SMTPやPOP3の認証IDなのでこれが取得できないのはかなり残念な仕様です。
ここまでで
ハマりポイントは多いです。1つ目はOffice 365 の特性でしょうが、オフィシャルのドキュメントにはしっかりと記述はされています。2つ目については Ruby の gem の特性と自分の情報を取得できないという Office 365の特性のコンビネーションでした。
私は事前に Gmail での先進認証対応を先にしていたので、その仕様が頭に入っており、そっちに引っ張られてドハマりしてしまったという感じです。
さて、次は、トークンを使って SMTPプロトコルで認証する、POP3プロトコルで認証するというところに入ります。 ここでもハマります・・・。
続きはこちら。