Red Hat SSO(Keycloak)でステップアップ認証してみる(アプリはQuarkusで)

Red Hat SSO 7.6(Keycloakですと17.0)から、ステップアップ認証が利用可能になっています。
ステップアップ認証は、WebアプリやAPIで、参照の場合はログイン認証のみで、更新の場合はログイン認証+OTPやWebAuthを使った生体認証などができるようになります。
インターネットバンキングで、振り込みする際に追加で認証情報を求められることがあると思いますが、それがまさしくステップアップ認証になります。

関連する情報は以下になります。
・Red Hat SSO 7.6のリリースノート：ステップアップ認証サポートの記載
https://access.redhat.com/documentation/ja-jp/red_hat_single_sign-on/7.6/html/release_notes/_new_or_improved_features

・Red Hat SSO 7.6のサーバ管理ガイド：設定方法などの記載
https://access.redhat.com/documentation/ja-jp/red_hat_single_sign-on/7.6/html-single/server_administration_guide/index#_step-up-flow


## はじめに
ステップアップ認証は、OIDCのACR(Authentication Context Class Reference)を利用しています。
なので、アプリ側で該当するクレームで必要とする値がない場合は、認証リダイレクトにそのクレーム頂戴というクエリを追加する必要があります。
なので、微妙に試すのが面倒になるんですが、JavaのフレームワークのquarkusにはOIDCの認証リダイレクトにクエリパラメータとして追加できるプロパティがあるので、それを利用して、ソースコードなどはいじらずにやってみます。

## RH-SSOの設定

### Authenticationの設定
Realm名は、quarkusとします。
Authenticationの設定は、設定の手順をすべてスクショにするのと、結構な画面数になりますので、
以下のサイトの「8.3.4. ステップアップメカニズムを使用したブラウザーログインフローの作成」通りに、Authenticationを設定します。

・Red Hat SSO 7.6のサーバ管理ガイド： 8.3.4. ステップアップメカニズムを使用したブラウザーログインフローの作成
https://access.redhat.com/documentation/ja-jp/red_hat_single_sign-on/7.6/html-single/server_administration_guide/index#_step-up-flow

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353997/786311ea-047e-dae5-e14e-d3090eb8b428.png)

ここまでの設定で、Authenticationでは、ACRでなくLoA(Level of Authentication)を設定しています。
LoAが1なら、ユーザとパスワード認証
LoAが2なら、OTP認証
LoAは、数値で、ACRの文字列にマッピングすることで、claim または acr_values パラメーターでRH-SSOに要求できます。
結果は、アクセストークンやID トークンに含まれます。

### LoAとACRのマッピング
マッピングは、Realmのログインの設定タブで設定します。(Clientにもあります)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353997/12127fac-27fa-1efb-b159-c8cbb19cd471.png)

ここで、LoA 1 = first、 LoA 2 = secondと設定しました。

### ユーザの作成
test/testで作成して、OTP(FreeOTP,Google Authenticator)の設定をしておきます。

### アプリ(quarkus)の設定
clientの項目で、以下のclientを設定をします。
・Client ID: quarkus
・Client Protocol： openid-connect
・Access Type: confidential
・Valid Redirect URIs: http://localhost:8081/tokens    (あとで作成するアプリのアクセス先です)

設定が完了したら、client secretをメモっておきます。

## アプリ(quarkus)を動かす

quarkusのサイトにOIDCのサンプルアプリがありますので、これを利用します。
https://ja.quarkus.io/guides/security-openid-connect-web-authentication

quarkusのサイトは、理解を深めるために段階的に手順が説明してありますが、今回は最初から出来てるものをダウンロードします。
```sh
$ git clone https://github.com/quarkusio/quarkus-quickstarts.git
$ cd quarkus-quickstarts/security-openid-connect-web-authentication-quickstart
```

RH-SSOをOIDCのOPにするので、src/main/resources/application.propertiesを設定します。
```properties
quarkus.http.port=8081  (quarkusのポートがRH-SSOと被るので変えています)
quarkus.oidc.auth-server-url=http://localhost:8080/auth/realms/quarkus  (RH-SSOのデフォルトにしています)
#%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.keycloak.devservices.realm-path=quarkus-realm.json
quarkus.oidc.client-id=quarkus
quarkus.oidc.credentials.secret=wLpIgUOpu6x5lmywXy7PGFubT6lkW0Hv　　（client secretは環境によって異なります）
quarkus.oidc.application-type=web-app
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
quarkus.http.auth.permission.public.paths=/q/dev/*
quarkus.http.auth.permission.public.policy=permit
quarkus.log.category."com.gargoylesoftware.htmlunit.DefaultCssErrorHandler".level=ERROR
```

ここまで完了したら、アプリを起動します。
```sh
$ quarkus dev
```

ブラウザで、http://localhost:8081/tokensにアクセスします。

・ユーザ名とパスワードが聞かれます。(test/test)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353997/928cd350-2d6a-61c9-3d8e-d1e1d227d636.png)

・ユーザ名とパスワード入力後、アプリの画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353997/b78cd78b-c473-0164-ed89-bede1110f7e4.png)

次は、アプリをLoA=2(second)が必要にします。

## アプリ(quarkus)で、認証リダイレクトにクエリパラメータにacr_valuesを入れる

アプリを停止後、src/main/resources/application.propertiesに一行追加します。

```properties
quarkus.http.port=8081
quarkus.oidc.auth-server-url=http://localhost:8080/auth/realms/quarkus
quarkus.keycloak.devservices.realm-path=quarkus-realm.json
quarkus.oidc.client-id=quarkus
quarkus.oidc.credentials.secret=wLpIgUOpu6x5lmywXy7PGFubT6lkW0Hv
quarkus.oidc.application-type=web-app
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
quarkus.http.auth.permission.public.paths=/q/dev/*
quarkus.http.auth.permission.public.policy=permit
quarkus.log.category."com.gargoylesoftware.htmlunit.DefaultCssErrorHandler".level=ERROR

quarkus.oidc.authentication.extra-params.acr_values=second
```

quarkus.oidc.authentication.extra-paramsは、認証リダイレクトにクエリパラメータとして追加できるプロパティです。
上記の設定で、、認証リダイレクトのクエリに　〜省略〜&acr_values=secondが追加されます。

また、アプリを起動します。
```sh
$ quarkus dev
```

ブラウザで、http://localhost:8081/tokensにアクセスします。

・ユーザ名とパスワードが聞かれます。(test/test)(ここは最初のアプリ画面と同じです)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353997/928cd350-2d6a-61c9-3d8e-d1e1d227d636.png)

・ユーザ名とパスワード入力後、ちゃんとOTPのワンタイムの入力画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353997/8d4f6e27-31c9-a560-e08c-4d4877301099.png)

・OTPのワンタイムパスを入力後、アプリの画面が表示されます。(ここも最初のアプリ画面と同じです)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353997/b78cd78b-c473-0164-ed89-bede1110f7e4.png)

### まとめ
Red Hat SSO(Keycloak)のステップアップ認証をQuarkusで試してみました。
こういったステップアップ認証は手作りでやっていたところがあると思うのですが、これを利用することで実装コストが下げれるのではないかと思います。