Exchange Online の先進認証に対応しました(3)

f:id:kizashi1122:20201110142108j:plain

id:kizashi1122 です。 前回の記事から2ヶ月が経ってしまいました。 続きを書きましょう。

blog.ingage.jp

時間がだいぶ経ったので、ここで目的と前回までのまとめを整理しておきます。

目的

目的は、「Exchange Online の POP3/SMTP を利用する際に、パスワードではなく先進認証で得られたトークンを使う」です。 Rest API は使いません。

前回までのまとめ

  • Azure AD 側に POP3/SMTP 利用のための設定をおこなう
  • Rails で OAuth ができるところまでもっていく

というところまでです。アクセストークンがゲットできて、手元にあるという状態になります。

SMTP / POP3 にトークンを使ってアクセスする

そんなことができるのかと思いますができます。 Gmail では以下のページに書かれています。大変わかりやすいです。IMAP/POP3/SMTP それぞれの認証の仕方が書かれています。

developers.google.com

SASL XOAUTH2 という方式があるのですね。

次に、Exchange Online のドキュメントを確認します。

docs.microsoft.com

なんだみんなこの SASL XOAUTH2に則って作ってるのか、じゃあGmailもExchange Onlineも同じだなと思うとハマります

SASL XOAUTH2 format と言われる、ユーザ名とアクセストークンを使って一つの文字列を作る、これは同じなんです。これはいいのです。

base64("user=" {User} "^Aauth=Bearer " {Access Token} "^A^A")

実際の認証部分が大事なのです。

SMTP の認証

Gmail のドキュメントでは以下のようなサンプルが書かれています。

[connection begins]
S: 220 mx.google.com ESMTP 12sm2095603fks.9
C: EHLO sender.example.com
S: 250-mx.google.com at your service, [172.31.135.47]
S: 250-SIZE 35651584
S: 250-8BITMIME
S: 250-AUTH LOGIN PLAIN XOAUTH XOAUTH2
S: 250-ENHANCEDSTATUSCODES
S: 250 PIPELINING
C: AUTH XOAUTH2 dXNlcj1zb21ldXNlckBleGFtcGxlLmNvbQFhdXRoPUJlYXJlciB5YTI5LnZGOWRmdDRxbVRjMk52YjNSbGNrQmhkSFJoZG1semRHRXVZMjl0Q2cBAQ==
S: 235 2.7.0 Accepted
[connection continues...]

本家ページ上では改行されていますが、注釈に改行は実際はないよと書いているのでここでは改行は削除してます。

なるほど、つまり認証コマンドを投げるときは

AUTH XOAUTH2 <SASL XOAUTH2 フォーマットで生成した文字列>

を発行するんだなと。当然、Exchange Online も同じだろって思うんです。ですが、違います。 Exchange Online のドキュメントにはこう書かれています。

[connection begins]
C: auth xoauth2
S: 334
C: dXNlcj1zb21ldXNlckBleGFtcGxlLmNvbQFhdXRoPUJlYXJlciB5YTI5LnZGOWRmdDRxbVRjMk52YjNSbGNrQmhkSFJoZG1semRHRXVZMjl0Q2cBAQ==
S: 235 2.7.0 Authentication successful
[connection continues...]

本家では読みやすさのための改行だったので、ここでは改行は削除しています。

Exchange Online では Gmail と違って認証のために2回コマンドを投げる必要があることがわかります。

AUTH XOAUTH2

dXNlcj1zb21ldXNlckBleGFtcGxlLmNvbQFhdXRoPUJlYXJlciB5YTI5LnZGOWRmdDRxbVRjMk52YjNSbGNrQmhkSFJoZG1semRHRXVZMjl0Q2cBAQ==

の2回に分ける必要があるんです。

なんやねん!

せっかく処理を共通化できると思ったのに分岐させる必要がでてくるわけです。

POP3 の認証

想像に難くないですが、POP3 についても、Gmail と Exchange Online には同じような差があります。

Gmail。

[connection begins]
C: AUTH XOAUTH2 dXNlcj1zb21ldXNlckBleGFtcGxlLmNvbQFhdXRoPUJlYX
JlciB5YTI5LnZGOWRmdDRxbVRjMk52YjNSbGNrQmhkSFJoZG1semRHRXVZMjl0
Q2cBAQ==
S: +OK Welcome.
[connection continues...]

1行。

Exchange Online。

[connection begins] 
C: AUTH XOAUTH2     
S: +    
C: dXNlcj1zb21ldXNlckBleGFtcGxlLmNvbQFhdXRoPUJlYX   
JlciB5YTI5LnZGOWRmdDRxbVRjMk52YjNSbGNrQmhkSFJoZG1semRHRXVZMjl0  
Q2cBAQ==    
S: +OK User successfully authenticated. 
[connection continues...]

2行(2回)

この個性はハマりました。
その個性いるかね?と思います。

インゲージではこんなことにもめげないエンジニアを募集しています。 ご応募お待ちしてます。