RailsアプリにAzure Active Directoryを使って認証機能をつける

はじめに

先日、Java(Spring Boot)でAzure Active Directoryを使って認証機能をつける記事を書きました。

miyohide.hatenablog.com

Railsアプリに認証機能を追加する際、devisesorceryなどのgemを使うのがよく使われますが、最近ではIDaaSというサービスがたくさん出ています。これらを使うことでユーザー管理に伴う様々な問題から解放されるということなので、Azure Active Directoryを使ってRailsアプリに認証機能を実装してみることにしました。

最初に試したこと

sorceryWiki Pageをみていたら、External Microsoft Graph authenticationという記事を見つけたのでこれをやってみることにしました。

ただ、Wiki中に

Finally under Redirect URI add a URI for your app. This is the address Azure will respond to with Authentication info.

と記載があるのですが、私がAzure Portal上で試すと「クエリ文字列を含める事はできない」というエラーメッセージが出て登録できませんでした。

結局、動かすことができずに終了しました。

マイクロソフトチュートリアルをやってみる

何かいい手はないものかと思っていたところに、たまたまマイクロソフトがチュートリアルを公開していることを発見。これに沿って実装してみることにしました。

いくつか変更

結果的にはこのチュートリアルはうまく動きましたが、いくつか変更が必要な点がありました。また、最近のRailsアプリではよりよい実装方法があるのでそこも対処してみました。

oauth_environment_variables.rbの作成

「Add Azure AD authentication」の部分にてoauth_environment_variables.rbを作成していろいろな値を環境変数経由で格納するところがあるのですが、これはRailsが持っているcredentialの管理方法に従った方が良いかなと思いました。

実際のやり方は「パーフェクトRuby on Rails【増補改訂版】」に載っているので参照すると良いでしょう。

なお、この変更で値の参照方法もENV['AZURE_APP_ID']のように環境変数を参照する形からRails.application.credentials.azure_app_idのように変更する必要があります。

scopeの範囲

チュートリアルではENV['AZURE_SCOPES']openid profile email offline_access user.read mailboxsettings.read calendars.readwriteを指定していましたが、私が試した時はうまく動きませんでした。おそらく試したユーザーの設定方法に依存するかと思います。私の場合、emailmailboxsettings.readcalendars.readwriteの内容を消すと動かすことができました。

合わせてmicrosoft_graph_auth.rbraw_infoメソッドにおいて/meエンドポイントへのクエリ文字列からもmailmailboxSettingsを削除しましたが、これがどう影響したかは調べきれていないです。

OmniAuth::AuthenticityError Forbidden Erros が発生する

一番ハマったのがOmniAuth::AuthenticityError Forbidden Errosが発生する問題です。色々と検索したところ、以下のstackoverflowの記事が該当しました。

Build Ruby on Rails apps with Microsoft Graph Tutorial OmniAuth::AuthenticityError Forbidden Erros

omniauth gemのバージョンを1系に固定化することで対応可能ということなので、Gemfilegem 'omniauth', '~> 1'を1行追加してbundle updateを実行しました。

これで、「Add Azure AD authentication」の最後まで動作しました。

localhost:3000にアクセスするとこんな画面ですが...

f:id:miyohide:20210310205359p:plain

右上のSign inをクリックすると以下のような画面が表示され...

f:id:miyohide:20210310205445p:plain

必要な情報を入れると以下の画面になります。

f:id:miyohide:20210310205544p:plain

ユーザーの取得を行う

チュートリアルではカレンダーデータの取得を行なっていましたが、自分はMicrosoft Graph APIのユーザーの取得を発行してみることにしました。

チュートリアルでは、app/helpers/graph_helper.rbを作成していますが、ヘルパーはViewのために書くものなので、ちょっと違和感があります。私は、lib以下に作成し、make_api_callメソッドの定義を以下のようにしました(self.を追加した)。

def self.make_api_call(method, endpoint, token, headers = nil, params = nil, payload = nil)

このメソッドをcontrollerで

::GraphHelper.make_api_call("GET", "/v1.0/me", access_token)

という形で呼び出してあげると、Graph APIの呼び出しが成功します。

画面整形して表示させたのが以下のものです。

f:id:miyohide:20210310205337p:plain

実装ソースコード

以下で公開しています。

github.com