0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kong GatewayのOAuth2.0 Authentication Pluginを認可コードグラントで試してみる

Posted at

Kong GatewayではOAuth2の機能をGatewayに追加するのにOAuth2.0 Authentication Pluginというプラグインを提供している。
今回はこれの動作確認を行う。
なおここではOAuth2.0 Authentication Pluginを以降OAuth2 Pluginと省略する。OAuthという名前を含むプラグインは他にOAuth2.0 Introspection PluginやUpstream OAuth Pluginなどがあるが、そことは混同しないようご注意を。

OAuth2 Pluginとは

OAuth2 PluginはKong Gatewayを介して行うリクエスト・レスポンスの流れの中にOAuth2のレイヤーを追加し、認可機能を付与するものになる。

OAuth2 Pluginでは以下のグラントタイプを許可している。

  • 認可コードグラント
  • クライアントクレデンシャル
  • インプリシットグラント
  • リソースオーナーパスワードクレデンシャルグラント

注意点としては以下がある。

  • DB-lessおよびHybridモード(Konnectも含む)では利用不可
  • Kong GatewayのプロキシはHTTPSで動作する必要あり

検証

ここでは一番使われるであろう認可コードグラントで試してみる。

事前準備

Consumer、Service、Routeの作成とPluginの適用

検証用のConsumer、Service、Routeを作成する。

curl -X POST http://localhost:8001/consumers/ \
  -d "username=myuser" 
curl -X POST http://localhost:8001/services/ \
  -d "name=myservice" \
  -d "url=https://httpbin.konghq.com"
curl -X POST http://localhost:8001/services/myservice/routes \
  -d "name=myroute" \
  -d "paths=/httpbin"

ServiceにOAuth2 Pluginを設定する。

curl -X POST http://localhost:8001/services/myservice/plugins \
    -H "Content-Type: application/json" \
    -d '{
        "name": "oauth2",
        "config": {
            "scopes": ["email", "phone", "address"],
            "mandatory_scope": true,
            "enable_authorization_code": true
        }
    }'

Pluginを適用するとトークンなしではアクセスに失敗するようになる。

$ curl localhost:8000/httpbin
{"error_description":"The access token is missing","error":"invalid_request"}

ちなみにこの時点で公式ドキュメントにあるEndpointが利用可能になるが、このエンドポイントの実装先はAdmin APIではなくプロキシを使ったRouteの先にあるという点に注意。
例えば今回で言うとhttps://localhost:8443/httpbin/oauth2/authorizeが認可コードの発行依頼をするエンドポイントとなる。

Consumer側の認証設定

Consumerの認証設定をAPIで行うために、ConsumerのIDを取得する。

CONSUMER_ID=$(curl -s localhost:8001/consumers/myuser | jq -r .id)

取得したIDを用いてConsumerにOAuth2 Pluginの認証情報を有効化する。

curl -X POST http://localhost:8001/consumers/${CONSUMER_ID}/oauth2 \
  -d "name=myapp" \
  -d "redirect_uris=http://localhost:8000/httpbin"

Client IDやClient Secretは指定することも出来るが、指定しない場合は自動生成される。
自動生成されたClient IDとClient Secretを環境変数に設定する。

CLIENT_ID=$(curl -sX GET http://localhost:8001/consumers/${CONSUMER_ID}/oauth2 | jq -r ".data[].client_id")
CLIENT_SECRET=$(curl -sX GET http://localhost:8001/consumers/${CONSUMER_ID}/oauth2 | jq -r ".data[].client_secret")

OAuth2 Plugin設定からProvision Keyを取得する。

PROVISION_KEY=$(curl -sX GET http://localhost:8001/services/myservice/plugins | jq -r '.data[] | select(.name == "oauth2").config.provision_key')

OAuth2 Pluginを利用して認可コードグラントを進める場合、Provision Keyは後に認可コードを貰うために必要となる。

認可フローの確認

ここで改めて認可コードグラントのフローを確認しておく。

ここではユーザとクライアントを人力で行い、認可サーバをOAuth2 Pluginに担ってもらい、リソースサーバーを先程設定したServiceという形で検証していく。

認可コードの取得まで

最初に認可コードのリクエストを行う。

まず、せっかくまっさらなので今発行されているトークンが存在しないことを確認する。

$ curl -sX GET http://localhost:8001/oauth2_tokens/
{"data":[],"next":null}

認可コードの発行を認可サーバーに依頼する。

curl -k -X POST https://localhost:8443/httpbin/oauth2/authorize \
   -d "client_id=$CLIENT_ID" \
   -d "response_type=code" \
   -d "scope=email"  \
   -d "provision_key=$PROVISION_KEY" \
   -d "authenticated_userid=myuser"

Plugin作成時にも記載したが、アクセス先はAdmin APIではなくRouteのパスの下になる点に注意。
response_modeは認可コードリクエスト時は基本的にcodeになり、scopeはPlugin有効化時に指定したものである。
provision_keyauthenticated_useridはOAuth2 Plugin独自のもので、それぞれ必須のパラメータとなる。
provision_keyはプラグインが割り当てられた時に生成されたキーであり、authenticated_useridはアプリケーション側で認証したユーザIDを指定する。

実行すると以下のような値が返ってくる。

{"redirect_uri":"http://localhost:8000/httpbin?code=MUUxbON7R4K4ZSgTgVlFwCfNKifNVWbI"}

クエリのcode=部分が認可コードになるので、これを使ってアクセストークンを取得する。

$ curl -k -X POST https://localhost:8443/httpbin/oauth2/token \
   -d "grant_type=authorization_code" \
   -d "client_id=$CLIENT_ID" \
   -d "client_secret=$CLIENT_SECRET" \
   -d "code=MUUxbON7R4K4ZSgTgVlFwCfNKifNVWbI"

トークンの取得はアクセスパスがRouteのパスの下の/oauth2/tokenになる。
grant_typeで認可コードグラントであるauthorization_codeを指定し、codeに先程取得した認可コードを指定した。
結果は以下のようになる。

{"expires_in":7200,"token_type":"bearer","access_token":"PXMLx2XC1DZVUpfUL3eHERdffYT9uI77","refresh_token":"Z5kUVu7ecICVd5ZCVnvEOtl33MFmu25N"}

このaccess_tokenの方のトークンを使ってアクセスする。

$ curl -k -X GET https://localhost:8443/httpbin/user-agent \
  -H "Authorization: Bearer PXMLx2XC1DZVUpfUL3eHERdffYT9uI77" 
{
  "user-agent": "curl/8.7.1"
}

無事にアクセス出来た。
また先程Admin APIでトークンの一覧を確認した際は空だったが、今は見ると発行したトークンが確認できる。

$ curl -sX GET http://localhost:8001/oauth2_tokens/ | jq
{
  "data": [
    {
      "credential": {
        "id": "d12972b3-0be2-47b9-b9f6-a27c9d64e6a6"
      },
      "expires_in": 7200,
      "token_type": "bearer",
      "access_token": "PXMLx2XC1DZVUpfUL3eHERdffYT9uI77",
      "refresh_token": "Z5kUVu7ecICVd5ZCVnvEOtl33MFmu25N",
      "ttl": 1209285,
      "service": {
        "id": "e888cca8-a812-4897-b3e9-3b8c1f74779f"
      },
      "created_at": 1739518711,
      "scope": "email",
      "id": "4bf240b9-6bd2-4e8d-a38c-1dd284561bca",
      "authenticated_userid": "myuser"
    }
  ],
  "next": null
}

以上より、OAuth2 Pluginを使って認可サーバを立てることなくトークンを発行してアクセス出来ることが確認できた。

なお、今回は認可フローを確認するためにクライアントアプリケーションを用意せずにcurlで確認したが、クライアントアプリケーションを使ったサンプルはOAuth 2.0 Hello World for Kongというものがあるので、これを参考にすると良いと思う。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?