Edited at

Authleteを使った認可サーバの構築と、OAuthクライアント(Webアプリケーション)からの疎通

OAuthのサーバを素早く構築するために、クラウドサービスのAuthleteを利用した際のメモ。

Authleteとは、OAuth2.0 serverとOpenID provider を構築するためのクラウドサービスです。

OAuth2.0やOpenID Connectに対応したサーバをホンキで構築するにはそれなりにメンドクサイわけですが、そのメンドクサイ処理をAuthleteに委譲することで、簡単に認可サーバを構築することが出来るというモノです。


前提事項

記事の簡略化のため、OAuth/OpenID Connect の知識をある程度持ってる前提で話を進めます。Authorization Code Grant Flow の処理シーケンスをだいたい知ってるとか。


環境

Mac OS X 10.12.6 (macOS Sierra)

Apache Maven 3.2.3

Java version: 1.8.0_25

git version 2.11.0 (Apple Git-81)

でやってますが、mavenとgitが動けば、OS含めなんでもOKだと思います

また、各種サーバなど登場人物は以下の通り:

サーバ名
用途
URL

java-oauth-server
ユーザIDごとの認可情報を管理するサーバ。認可サーバと呼ぶ
http://oauth.example.com:8080/

java-resource-server
ユーザIDごとのデータや機能をもったサーバ。リソースサーバと呼ぶ
http://resource.example.com:8081/

java-oauth-client
リソースサーバのリソースを使用する、Webアプリケーション
http://client.example.com:8082/

今回の環境では各サーバはローカルに立ち上げようとしているので、適宜 /etc/hosts などで 127.0.0.1 に名前解決しておいてください。もちろんAWSのEC2など、任意の場所にあげていただいても結構です。


おおまかな流れ

おおまかな流れは以下の通りです。


  1. Authleteへのサインアップ

  2. 認可サーバの登録・クライアントの登録

  3. 認可サーバ、リソースサーバの構築

  4. Webアプリケーションからの疎通


Authlete管理画面での操作


サインアップと 認可サーバ情報の登録・作成

Authleteを用いるためにまずはサインアップします。

https://www.authlete.com/ の右肩よりSign Upします。

01.png

つぎの画面で、下記のように ID/password/アドレス などをいれればOKです。

02.png

サインアップが完了するとトップページが表示されます。

03.png

アカウントが作成され、一つの認可サーバ(Service 385xxxxxxxx)がすでに作成済みになっているようです。

APIキーとAPIシークレットが表示されていますが、あとで認可サーバやリソースサーバを構築する時に使用しますので、

API キー
API シークレット

385xxxxxxxx
NeE89hxxxxxxxxxxxxxxxxxxx

はメモしておきましょう。

ちなみに次回以降のログインは

https://so.authlete.com/

ココからID/passwordでログインします。


クライアントの登録・作成

うえのキャプチャにある「クライアントアプリ開発者コンソール」のURLにアクセスすると、上のとは別の、クライアント開発者向けログイン画面が表示されます。こちらはOAuthクライアントの管理画面で、上記のAPIキー(385xxxxxxxx)、API シークレット(NeE89hxxxxxxxxxxxxxxxxxxx)でログインすることが出来ます。

04.png

ログインすると、上記の通りクライアント名(Client 4455xxxx)というのが表示され、そのクライアントのクライアントIDとクライアントシークレットが表示されています。これらもあとで OAuthクライアントつまりWebアプリケーションを構築するときに使いますので、メモしておきましょう。

クライアント ID
クライアントシークレット

4455xxxx
FZlETE9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


整理

さて、ここまでで一旦整理すると、


  • Authleteへのログインアカウント

  • Authleteで認可サーバ・リソースサーバを立ち上げるための「API キー」「APIシークレット」

  • 上記認可サーバに登録されたOAuthクライアント(Webアプリケーション)を構築するための「クライアントID」「クライアントシークレット」

が払い出されたことになります。Authleteはアカウントを作ると認可サーバ(Service 385xxxxxxxx)が一つ作られ、それに紐付くクライアント(Client 4455xxxx)も一つ、自動で作成されるようです。


認可サーバとリソースサーバの構築

つづいて、OAuthクライアントがユーザ情報にアクセスする際の認可を行う認可サーバと、OAuthクライアントからのリクエストを受けて権限に応じた処理を実行するリソースサーバを構築します。

今回の構築では、Authleteさん提供の下記のコードを使ってみます。

構築といっても、上記のコードをGitHubから落としてきて、サインアップしたときに払い出された API キー、API シークレット を設定ファイルに書き込むだけです。


認可サーバの構築

認可サーバを構築します。先ほどのリポジトリをcloneしてきて、設定ファイル(authlete.properties)にAPI キー、API シークレットを設定すればOKです。

$ git clone https://github.com/authlete/java-oauth-server.git

$ cd java-oauth-server
$ cat authlete.properties
service.api_key = 385xxxxxxxx ← 正しい API キー に変更してください
service.api_secret = NeE89hxxxxxxxxxxxxxxxxxxx ← 正しい API シークレット に変更してください
$ mvn clean jetty:run


リソースサーバの構築

つづいてリソースサーバを構築します。先ほどのリポジトリをcloneしてきて、設定ファイル(authlete.properties)にAPI キー、API シークレットを設定すればOKです。認可サーバとおなじ作業ですね。

$ git clone https://github.com/authlete/java-resource-server.git

$ cd java-resource-server/
$ cat authlete.properties
service.api_key = 385xxxxxxxx ← 正しい API キー に変更してください
service.api_secret = NeE89hxxxxxxxxxxxxxxxxxxx ← 正しい API シークレット に変更してください
$ mvn clean jetty:run

ちなみにリソースサーバは、

curl http://resource.example.com:8081/api/country/JP -H "Authorization: Bearer xxxxxxxxxxx" -G

のように Authorization にアクセストークンをつけてリクエストすると、アクセストークンが正しければ

{

"name": "Japan",
"alpha2": "JP",
"alpha3": "JPN",
"numeric": 392,
"currency": "JPY"
}

のようなレスポンスが返るように作られています。

以上で、認可サーバとリソースサーバの構築は完了です。


Webアプリケーションからの疎通

つぎにWebアプリケーションからの疎通を行います。WebアプリケーションはURLが

http://client.example.com:8082/RedirectServlet

であるとします。認可コード取得後のリダイレクト先も、おなじサーブレット http://client.example.com:8082/RedirectServlet にしてみます。

ちなみに Authorization Code Grant Flow の処理シーケンスはだいたい以下の通りとなります。Authleteは認可サーバからお願いされて認可コードを発行したり、その認可コードをもとにアクセストークンを発行したり、リソースサーバがWebアプリケーションからアクセストークンを受け取った際に、そのアクセストークンが正しいものかを教えてくれたり、誰に紐付いているトークンかなどを教えてくれたりします。

sequence.png


リダイレクト先の登録

AuthleteにこのWebアプリケーションのリダイレクト先URIを登録します。「クライアントアプリ開発者コンソール」を開いて、一番下の編集ボタンをクリックします。

05.png

そのあと、認可タブに リダイレクトURI という設定があるので「 http://client.example.com:8082/RedirectServlet 」と記載して、更新ボタンをクリックすれば完了です。

06.png

登録されました。


Webアプリケーションの構築

Webアプリケーションは上記のシーケンス図で示したとおり、


  1. Web画面で○○でログイン、などのリンクをクリック(そのリンク先がRidirectServletになります)。

  2. 認可サーバの画面表示(サーブレットから302でリダイレクト)

  3. ユーザが認可サーバ上で認証・認可オペを実行

  4. 認証認可オペのあと認可コードが生成され、認可サーバは指定されたURIへリダイレクト(もとのサーブレットに302でリダイレクトされて戻ってくる)

  5. 戻ってきたら、認可コードともに認可サーバにアクセスして、アクセストークンを取得する

  6. アクセストークンをつかって、リソースサーバへAPI呼び出し(データ取得の問い合わせとか)

  7. 結果を取得

なんていう処理フローになるのですが、そんなサーブレットを作成しましたので、そのままそのプロジェクトを利用します。

を落としてきたあと、設定ファイル(settings1.properties)のclient_id, client_secret を値を下記の通り クライアント ID、クライアントシークレットに変更してください。

$ git clone https://github.com/masatomix/java-oauth-client.git

$ cd java-oauth-client/
$ git checkout -t origin/feature/forQiita
$ cat src/main/resources/settings1.properties
client_id = 4455xxxx ← 正しい クライアント ID に変更してください
client_secret = FZlETE9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ←正しい クライアントシークレット に変更してください
$ mvn clean jetty:run


疎通してみる。

http://client.example.com:8082/ にアクセスすると、「AuthleteをもちいたOAuthサーバで認可処理。」というリンクが表示されますのでクリックします。

07.png

そうすると認可サーバは下記のような「このWebアプリがあなたの情報に対して、アクセスしたいと言ってるけど認可する?」をだしてくるので、ユーザは考えたのち「私はだれ」を表すLogin IDとPasswordを入力し、Authorizeを押してアクセスを認可します。

08.png

Authleteさん提供の認可サーバ・リソースサーバはダミーのユーザ認証がコーディングされているので

Login ID
Password

john
john

というアカウントで認証・認可を行ってください。

Webアプリケーションが認可をされると、Webアプリケーションに対して認可コードが発行され、もとのサーブレットに302でリダイレクトされて戻ってきます。

さらにサーブレットは認可サーバにアクセストークンの取得をお願いし、認可サーバからアクセストークンを取得します。

認可サーバからアクセストークンを取得したら、サーブレットはHTTPヘッダに

Authorization: Bearer uU3Xml7rdxxxxxxxxx ←アクセストークン

をつけて、リソースサーバにデータ取得を依頼します。

リソースサーバはAuthleteにそのトークンの正当性を確認してもらったあと、ロジックを動かしてサーブレットにデータを返します。

これらの一連の処理が行われ、最終的に画面にデータが返ってくればOKです。

09.png

お疲れ様でした。

サーブレット内の処理では


  • トークンを取得する token_endpoint のAPIから、アクセストークンとともに返却されるid_token (いわゆるOpenID Connectのid_token)の表示

  • その id_token をJWTの仕様で Header、Payload(本体)、Signature(署名)に分割して、Base64デコードして表示

  • JWTのヘッダで署名方式を確認して、署名を検証することで改ざんが行われていないことをチェック。(デフォルトではAuthleteは クライアントシークレットで HS256で署名してるぽいので、それで検証している)

  • RS256で署名してる場合など必要に応じて、JWK(JSON Web Key)が公開されてるエンドポイント(jwks_uri)へアクセスし公開鍵を取得して、公開鍵で署名検証する

  • OpenID Connectの仕様に基づくuserinfo_endpoint へのデータ取得

などなどいろいろ書いてますが、興味があればコードをご参照ください。

ちなみに、実際の本番構築時には、CSRF対策やらなんやらセキュリティ関連の検討事項がいろいろとありますので、ご注意ください。


関連リンク