やわらかテック

興味のあること。業務を通して得られた発見。個人的に試してみたことをアウトプットしています🍵

Oauthを簡単なプロセス通信でそれっぽく再現して覚える

ワイ認証が全然分かっていない

認証部分は自分が実装する前にパイセンエンジニアが既におおむね、下地を作った状態で、「これ使ってね〜」状態になっている事が多く、初期の開発に参加出来なかったりする。過去に趣味開発でOauthなりを使用したことはあるが、コピペで作ったので正直、よく覚えていないし理解もしていなかった。
最近はバックエンドでの開発が多いので、自分の苦手分野でもある認証について改めて理解を深めたいと思った。

ざっくりと調べてみた

認証と言っても幅広く、様々なものあった。簡単に今回、目にしたものをリスト形式で書き出した。
(調査時のメモはgitのREADME.mdに記載しました)

  • SSO(SingleSignOn) -> eg: 免許書1枚で様々な契約が可能
    • 知ってるやつ: SAML(プロトコル) -> Idp(IdentityProvider: ユーザー認証)とSP(ServiceProvider)でお互いに利用できるように設定(SAML対応していることが大前提)
    • Oauth(Oauth -> 認可(認証じゃない), OpenIDConnect -> 認証)
  • Basic認証
    • IDとPASSをheader paramaterに含めて送信して認証

普段よく聞く単語と出会うことが出来た。Web開発をメインでやっているので、自分と最も関わりが深いのはOauthだと思うし、最も気になる所。
Oauthの流れについては以下の記事が驚く程、分かりやすかった。

qiita.com

確かに一番分かりやすい。

動くものを作って学ぶ

やはり、動くものを作って理解を深めたいのでTwitterなりのAPIを申請しようかと思ったが、申請期間を待ったり、合わせてデータベースを用意したりするのが面倒だったので、今自分が持っているレシピの中でサクッと作れるであろう、プロセス間通信を利用してOauthの流れを再現してみようと思う。

概要図

処理の流れについて図にまとめた。以下のようにプロセス間通信を行い、一連の認可(Oauth故)の処理を行えば、再現出来ていると言えるのではないだろうか。

f:id:takamizawa46:20200816113039p:plain
process_oauth

実装

github.com

上記の図に登場した3つのプロセスをそれぞれモジュールで表現する。

順にそれぞれを簡単に解説しておく。

メインプロセス

github.com

他2つのプロセスを立ち上げて、一連の処理の流れを実行するためのプロセスとなる。command lineから受け取った引数によって、実行する処理を流れを変更する。

  • PASS -> 認証に成功してリソースの取得が可能
  • UNAUTHORIZED -> 認証に失敗してアクセストークンの発行がされない
  • UNVALID_TOKEN -> 認証にし成功してアクセストークンが発行されるが、有効ではないトークンが送られるためリソースの取得に失敗

認証を実行するプロセス

github.com

このプロセスは2種類のメッセージを受け取り、認証処理を実行する。ユーザー情報の保持には、サーバーにkey valueのobject(Elixirではmap)を保持させて、管理している。なお、パスワードのハッシュ化や暗号化は簡単のために今回は行っていない。合わせて、ユーザー情報はプロセスを立ち上げる際に、Fakerという外部ライブラリを使用して、適当な名前(id)とパスワード(password)を作成している。

www.okb-shelf.work

eg: ユーザー情報

[
  %{"id" => "yu-gi", "password" => "atemu"},
  %{"id" => "kaiba", "password" => "mokuba"},
  %{"id" => "zyo-no-chi", "password" => "sizuka"},
]
  • AUTH
    • 送られてきたidpassword情報を元にサーバーで保持しているユーザーのidpasswordに一致する存在するかを確認
    • 存在しているユーザーであれば、アクセストークンを作成してメッセージを通して返す
    • 作成したアクセストークン(value)をユーザー情報に紐づけてaccess_tokenというkeyで保持させる

eg: 認証に成功した後のuser情報

[
  %{"id" => "yu-gi", "password" => "atemu", "access_token": "xxxxxxxxx"},
  %{"id" => "kaiba", "password" => "mokuba"},
  %{"id" => "zyo-no-chi", "password" => "sizuka"},
]
  • CONFIRM
    • アクセストークンを受け取り、サーバーで保持しているユーザーで該当のアクセストークンが発行されたユーザーが存在するかを確認
    • 確認結果(boolean)をメッセージを通して返す

リソースを返却するプロセス

github.com

ここでは1種のメッセージ(as requset)を受け取り、処理を実行する。

  • REQUEST
    • 送られてきたアクセストークンを認証を実行するプロセスにメッセージ経由で送信
    • 認証結果を受け取り、true(通過)した場合はリソース(今回は簡単のため、ただの文字列)をメッセージを通して返す。falseの場合は401errorをraiseする

実行結果

処理の流れが確認できるようにloggerを仕込んであるので、順に結果を確認してみよう。
先にiex -S mixを使って、iexを立ち上げておく。

AUTH

iex(1)> OauthDemo.main("PASS")

# id => Ollie, password => 4HDiMF8jを受け取り、認証を実行
10:47:16.365 [info]  Received request 'Oauth': id => Ollie, password => 4HDiMF8j 
# 存在するユーザーだったため、アクセストークンが発行される
10:47:16.377 [info]  Created access token: access_token => husjlbdpho 
# リソースサーバーにリクエスト。合わせて認証を実行するプロセスでアクセストークンの確認を行う
10:47:16.377 [info]  Received request 'Confirm': access_token => husjlbdpho
# 問題ないアクセストークンであったため、リソースを返す
10:47:16.378 [info]  Received request: passed authorization
# 返ってきたリソースを出力
[Success] Response: Nasubi
:ok

UNAUTHORIZED

iex(2)> OauthDemo.main("UNAUTHORIZED")

# id => okabe, password => 1234を受け取り、認証を実行
10:52:29.226 [info]  Received request 'Oauth': id => okabe, password => 1234
 # 存在しないユーザーだったため、アクセストークンが発行されず401 errorをraise
10:52:29.227 [info]  Unauthorized. Not registed user => okabe
# 認証失敗の結果が返ってきたことを確認し出力 
[Success] Response: Unauthorized
:ok

UNVALID_TOKEN

iex(3)> OauthDemo.main("UNVALID_TOKEN")

# id => Derrick, password => ebOyk+eoを受け取り、認証を実行
10:54:08.658 [info]  Received request 'Oauth': id => Derrick, password => ebOyk+eo
# 存在するユーザーだったため、アクセストークンが発行される
10:54:08.658 [info]  Created access token: access_token => bsnmpgfrhb
# リソースサーバーにリクエスト。合わせて認証を実行するプロセスでアクセストークンの確認を行う
10:54:08.658 [info]  Received request 'Confirm': access_token => xxxxxxxx
# 不正なアクセストークンだったため、401errorをraise
10:54:08.659 [info]  Received request:  unauthorization
# 不正なアクセストークンによる失敗の結果が返ってきたことを確認し出力
[Success] Response: Unvalid token
:ok

最後に

一連のOauthの流れを作成して覚えることが出来た。今回は簡単のため、多くの機能やアーキテクチャを省略している。パスワードが筒抜けなのはありえないし、ユーザーの新たな追加やユーザー情報の確認など、追加しようと思えばいくらで機能は追加が可能だが、今回の本流となるところではないので、触れなかった。少しは認証に強くなれたと思いたい。

参考文献