本連載は、主にエンタープライズ向けアプリケーション開発者を対象に、新たな境界として台頭しつつある「アイデンティティ型の境界」がサポートするプロトコルの解説と実装例をご紹介していきます。
本記事の内容
第二回は、オープンソースソフトウェア(以下、OSS)である「OpenAM」を用いた、OpenID Provider(以下、OP)の実装手順について解説致します。
実装手順は、OpenAMのインストールから、OPの構成手順、Relying Party(以下、RP)の登録、および、OPの動作確認手順を掲載しております。
OpenAMのご紹介
OpenAMとは?
OpenAMは、認証、認可、フェデレーション等の機能を備えた、WebアプリケーションやクラウドサービスへのSSOを実現するOSSです。
旧Sun Microsystems社が開発したSun Java System Access Managerという商用製品がベースとなっており、OpenSSOとしてOSS化された後、現在のOpenAMへ派生して開発が継続されています。
もともと商用製品であったことを背景に、高機能で、日本を含む全世界で多くの導入実績があり、大規模な環境での稼動も実証されています。
当社の統合認証ソリューションである「ThemiStruct-WAM」はOpenAMをコアのソフトウェアとし、独自でソフトウェアコンポーネントを開発して機能強化を図っています。
OpenAMやThemiStruct-WAMの紹介・詳説は当社のホームページにも記載しております。
OpenAMがサポートする認証プロトコル
下図はOpenAMの開発元であるForgerock社が公開しているホワイトペーパーに記載されているアーキテクチャ図になります。
こちらに記載の通り、現在のOpenAMはSAMLをはじめとした認証プロトコルに多数対応しています。今回は、OpenAMのバージョン11.0.0で実装されたOpenID Connectの機能を使い、OPを実装致します。

参考 : FR_WhitePaper-OpenAM-Short-Letter.pdf
実装手順の解説の前に
本記事での実施内容
以降の手順では、下記を順番に実施しています。
- Amazon EC2上にOpenAMをインストール
- OpenAMをOPとして設定
- OPにRPの設定を登録
- OPの簡易動作確認
用語解説
本手順に登場する用語について、下記に説明を記載致します。
| 用語 | 説明 |
|---|---|
| Realm/レルム | OpenAM上で論理的に認証ユーザーリポジトリや認証・認可設定を分離して管理するための仕組み |
| Agent/エージェント | 保護リソースに導入するOpenAMの独自エージェントやRPなどのクライアントを指す |
| Amazon EC2 | クラウド内でサイズ変更が可能なコンピューティング処理能力を提供するウェブサービス |
| セキュリティグループ | EC2に対して適用する仮想ファイアウォール |
| AWS IAM | AWSの各種サービス、リソースへアクセスするユーザーをコントロール |
インストール環境
OpenAMをインストールするサーバーの推奨環境は以下のとおりです。
| 項目 | 推奨値 |
|---|---|
| OS | Linux, Windows Server, UNIX |
| メモリ | 2GB以上 |
| JDK | JDK1.6以上 |
なお、本記事では下記の環境(Amazon EC2)を使用し、OpenAMを構築するものと致します。
| 項目 | 推奨値 |
|---|---|
| 仮想化基盤 | Amazon EC2 |
| OS | Amazon Linux |
| インスタンスタイプ | t2.small |
| メモリ | 2GB |
| JDK | OpenJDK 1.8 |
事前準備
本記事のインストール手順を実行する際、下記の事前準備が整っていることを前提と致します。
- AWSマネジメントコンソールにログインすることができるAWSアカウント、若しくは、IAMユーザーアカウントを所有していること
- EC2インスタンスをローンチする権限をIAMユーザーが有していること(AWSアカウントの場合は不要)
- OPに割り当てるFQDNを決定する。なお、ドメインは手順の実施者が所有していること
- EC2インスタンスが持つパブリックなホスト名に、別名レコード(CNAME)として任意のFQDNを設定できる権限を有していること
注意事項
本記事のインストール手順を実行する際、下記の注意事項を読んで、ご理解頂ますようお願いします。
- 本手順でデプロイを実施したOpenAMは2015年8月6日時点の最新のソースコードを用いたビルドバージョン(以下、Nightly Build版)です
- Nightly Build版のOpenAMは日々更新が行われているため、本記事に記載のスクリーンショットとは異なる画面が表示される場合があります
- 本手順の成果物は試用のための設定で構成されており、本番利用をするためのセキュリティ設定、チューニング設定は一切行っていません。本手順の実施によって生じた損害・障害・不利益等に対する責任は負いかねます
EC2のローンチとOpenAMのインストール
EC2のローンチ手順はAWSが公開しているAmazon EC2 インスタンスの起動手順を参考にします。
下記は本手順での設定を行ったEC2インスタンス作成の確認画面です。

① AMIの詳細
EC2インスタンスにプリインストールされるOSの設定です。
2015年9月1日版のAmazon Linuxを選択しています。
② インスタンスタイプ
EC2インスタンスタイプの設定です。
t2.smallを選択しています。
③ セキュリティグループ
EC2インスタンスに適用するセキュリティグループの設定です。
| 項目 | 設定値 |
|---|---|
| セキュリティグループ名 | Security Group for OpenID Provider |
| 説明 | HTTPS Request : Allow from All |
| タイプ | HTTPS |
| プロトコル | TCP |
| ポート範囲 | 443 |
| 送信元 | 任意の場所(0.0.0.0/0) |
④ インスタンスの詳細
EC2インスタンスのローンチ先ネットワーク設定やOSの初回起動時に実行されるコマンドの設定です。
| 項目 | 設定値 |
|---|---|
| インスタンス数 | 1 |
| ネットワーク | vpc-XXXXXXXX |
| サブネット | 優先順位なし |
| EBS最適化 | いいえ |
| モニタリング | いいえ |
| 削除保護 | いいえ |
| シャットダウン動作 | 停止 |
| IAMロール | なし |
| テナンシー | default |
| ホストID | |
| アフィニティ | オフ |
| カーネルID | デフォルトを使用 |
| RAMディスクID | デフォルトを使用 |
| ユーザーデータ | (※後述) |
| パブリックIPの割り当て | サブネット設定を使用(有効) |
| ネットワークインターフェイス |
なお、本設定のユーザーデータに入力された値は、EC2インスタンスがローンチされた際、初回のみ自動で実行されるスクリプトをbase64エンコードしたものになります。
今回はこのユーザーデータに記載するスクリプトでOpenAMのインストールを実施しています。実行するスクリプトは下記のとおりです。
#!/bin/bash openamHostname="openidprovider"; openamDomain="sample.domain"; openamDate="20150806" yum install -y httpd mod_ssl java-1.8.0-openjdk java-1.8.0-openjdk-devel tomcat8 echo 127.0.0.1 localhost localhost.localdomain $openamHostname.$openamDomain > /etc/hosts echo "Proxypass / ajp://localhost:8009/" > /etc/httpd/conf.d/proxy.conf sed -i 's/^\(Listen 80\)$/#\1/' /etc/httpd/conf/httpd.conf wget https://download.forgerock.org/downloads/openam/OpenAM-13.0.0-SNAPSHOT_$openamDate.war -P /tmp/ mv /tmp/OpenAM-13.0.0-SNAPSHOT_$openamDate.war /var/lib/tomcat8/webapps/openam.war chkconfig httpd on chkconfig tomcat8 on service httpd start service tomcat8 start
- スクリプト内で用いられている変数について
- openamHostnameは事前準備で決めたOPのホスト名(本手順では、
openidprovider) - openamDomainは事前準備で決めたOPのドメイン名(本手順では、
sample.domain) - openamDate最新のNightly Build版OpenAMのバージョン番号(本手順では、
20150806)
- openamHostnameは事前準備で決めたOPのホスト名(本手順では、
⑤ ストレージ
EC2インスタンスにアタッチメントされるEBS(ストレージ)の設定です。
| 項目 | 設定値 |
|---|---|
| タイプ | ルート |
| デバイス | /dev/xvda |
| スナップショット | snap-xxxxxxxx |
| サイズ(GiB) | 8 |
| ボリュームタイプ | gp2 |
| IOPS | 24/3000 |
| 合わせて削除 | はい |
| 暗号化済み | 暗号化なし |
⑥ タグ
ローンチしたEC2に付加するタグ情報の設定です。
ローンチ後にインスタンスの識別がし易いよう、値にOpenID Provider (OpenAM)を設定しています。
確認と作成
設定した内容の確認が完了し次第、画面右下の作成をクリックします。

EC2インスタンスにSSHログインするためのキーペアを選択、または作成する画面が表示されます。
今回は、SSHでログインして実施する作業が無いため、キーペアなしで続行を選択し、画面下部のチェックボックスにチェックを入れます。
最後に、インスタンスの作成をクリックします。

EC2インスタンスの作成ステータス画面が表示されます。画面上部に表示されているインスタンスID(本手順では、i-00000000と表記)をクリックします。

先ほどローンチしたEC2インスタンスが既に選択された状態で、EC2インスタンス管理画面が表示されます。
画面中段に表示されているパブリックDNSに表記された値がローンチしたEC2インスタンスに対し、AWSが自動で割り当てたFQDNとなっています。
以後の手順解説では、FQDNにopenidprovider.sample.domainという別名レコード(CNAME)を割り当てて、解説をします。

OpenAMの初期設定
ブラウザを新規で起動し、アドレス欄にhttps://openidprovider.sample.domain/openamと入力し、アクセスを行います。もし、アクセスに失敗する場合、EC2の起動、および、初回のみ自動で実行されるスクリプト(ユーザーデータ)の実行に時間が掛かっている場合があります。
設定オプション画面が表示されます。
デフォルト設定をクリックします。

OpenAMに適用されているライセンス(Common Development and Distribution License 1.0)が表示されます。内容の確認を実施した後、画面下部のI accept the license agreementにチェックを入れ、Continueをクリックします。
デフォルト設定オプション画面が表示されます。
OpenAMの管理アカウント(amadmin)のパスワードとポリシーエージェントユーザーのパスワードを設定します。なお、ポリシーエージェントユーザーのパスワードは本手順では使用致しません。

初期設定が完了すると、下記の画面が表示されます。ログインに進むをクリックします。

OpenAMのログイン画面が表示されます。
OpenAMの管理アカウント(IDがamadmin、パスワードが初期設定時に入力したパスワード)を使ってログインします。

OpenAMの管理画面が表示されていれば、OpenAMの初期設定は完了となります。

OpenAMをOPとして設定
続けて、初期設定が完了したOpenAMをOPとして動作するように設定を実施します。
Top Level Realmをクリックします。

Realm Overview画面が表示されます。
Configure OAuth2/OpenID Connectをクリックした後に表示されるConfigure OAuth2/OpenID Connectをクリックします。

Configure OpenID Connect画面が表示されます。
OPが発行する各種トークンに関する設定をすることができます。
本画面で設定可能なトークンの種別は以下のとおりです。
| 項目 | 説明 |
|---|---|
| 認可コード | 認可コードフローにおいて、RPがアクセストークンやリフレッシュトークンを取得するために使用する一時的なトークン |
| アクセストークン | OP上の保護されたリソース(ID情報)への、RPからのリクエスト方法を指定する |
| リフレッシュトークン | アクセストークンの有効期限が切れた場合、再取得を行う際に使用するトークン。本トークンの発行は任意である。 |
これらのトークンの発行有無や、有効期限を設定することができます。
本手順ではデフォルトの設定のままとし、画面右上の作成をクリックします。

作成が完了すると、下記の完了画面が表示されます。了解をクリックします。
本設定を以って、OpenAMはOPとして動作するように設定されました。

OPの設定情報取得用エンドポイントの確認
OPは特定のパス(/openam/oauth2/.well-known/openid-configuration)へのHTTP GETリクエストに対し、設定情報を記載したドキュメント(JSON)をレスポンスする必要があります。
これまでの手順で、OpenAMをOPとして設定を行ったため、当該URIが有効になっています。ブラウザを新規で起動し、アドレス欄にhttps://openidprovider.sample.domain/openam/oauth2/.well-known/openid-configurationと入力し、アクセスを行い、確認してみましょう。
{
"response_types_supported":["token id_token", "code token", "code token id_token", "token", "code id_token", "code", "id_token"],
"registration_endpoint":"https://openidprovider.sample.domain:443/openam/oauth2/connect/register",
"token_endpoint":"https://openidprovider.sample.domain:443/openam/oauth2/access_token",
"end_session_endpoint":"https://openidprovider.sample.domain:443/openam/oauth2/connect/endSession",
"scopes_supported":["phone", "address", "email", "openid", "profile"],
"acr_values_supported":[],
"version":"3.0",
"userinfo_endpoint":"https://openidprovider.sample.domain:443/openam/oauth2/userinfo",
"token_endpoint_auth_methods_supported":["client_secret_post", "private_key_jwt", "client_secret_basic"],
"subject_types_supported":["public"],
"issuer":"https://openidprovider.sample.domain:443/openam/oauth2",
"claims_parameter_supported":false,
"jwks_uri":"https://openidprovider.sample.domain:443/openam/oauth2/connect/jwk_uri",
"id_token_signing_alg_values_supported":["HS256", "HS512", "RS256", "HS384"],
"check_session_iframe":"https://openidprovider.sample.domain:443/openam/oauth2/connect/checkSession",
"claims_supported":["zoneinfo", "phone_number", "email", "address", "locale", "name", "family_name", "given_name"],
"authorization_endpoint":"https://openidprovider.sample.domain:443/openam/oauth2/authorize"
}
上記のような、JSON形式のドキュメントの取得が出来れば、OPの設定は完了です。
RPの登録
第一回で解説した下記のOpenID Connectの認証フロー(図は認可コードフロー)における、1. 認可リクエストにて、OPはRPからの認可リクエストのクエリーストリングに含まれるscope、response_type、client_id、redirect_uriなどの検証を行います。OPの動作確認を行うにあたり、予め、RPにこれらの情報を登録しておく必要があります。

RPからの認可リクエストに含まれる情報の詳細は下記のとおりです。
| 属性名 | 内容 |
|---|---|
| scope | scopeには必要なクレームに対応した値(profileやmail)などを指定する。また、openidを含むことで、OpenID Connectの認可リクエストであることを明示できる。OPが対応している値の確認はOPの設定情報取得用エンドポイントから確認が可能である。 |
| response_type | 以後のフローで使用される認証処理フローを指定する。認可コードフローの場合はcode、インプリシットフローの場合は、id_token、または、id_token token。 |
| client_id | OPが持つ、RPのクライアント識別子。OAuth 2.0 Client Identifierにあたる。 |
| redirect_uri | OPからの認可レスポンスが返されるURIをURLエンコードしたもの。URIは事前にOPに登録した値と一致する必要がある。 |
| nonce | リプレイ攻撃防止用のパラメータ。クライアントのセッションとOPが払い出すID Tokenとを関連付けるためのパラメータ。 |
| state | リクエストとそれに対するコールバックとの間の状態を保守するために使用されるパラメータ |
実際にRPを実装し、RPへのID連携の実施は次回の掲載となりますが、簡単にOPとしての動作確認を行うために、RPの情報をOPに登録しましょう。
まず、OpenAMに管理アカウント(amadmin)でログインを行います。

Realms画面が表示されます。
Top Level Realmをクリックします。

Top Level Realm画面が表示されます。
画面右のAgentsをクリックします。

エージェント設定の画面が表示されます。
画面上部のOAuth 2.0 クライアントをクリックします。

OAuth 2.0 クライアント設定の画面が表示されます。
エージェントの設定枠内の新規をクリックします。

新規でOAuth 2.0 クライアントを登録する画面が表示されます。
名前(clientidに該当)とパスワードを入力し、画面右上の作成_をクリックします。
本手順では名前をsampleRPとしています。

続いて、残りのscope、redirect_uri、response_typeの設定を行います。
エージェント設定枠内に新規で作成されたsampleRPをクリックします。

sampleRPの設定画面が表示されます。
画面上部にあるリダイレクトURIとスコープを入力します。
本手順ではリダイレクトURIをhttps://localhost/cb、スコープをopenidとしています。

なお、response_typeについては、下記のようにデフォルトで登録済みである。

リダイレクトURIとスコープの設定、response_typeの登録確認が完了次第、画面右上の保存をクリックします。

以上で、RPの登録は完了となります。
認可リクエストを送信し、動作を確認する
ここまでの手順で、OpenAMをOPとして動作するように設定を行い、RPを識別できるよう、各種情報をOPに登録しました。
よって、下記図のインプリシットフローにおける、「1. 認可リクエスト」をブラウザがRPに替わって送信し、「2. サイン・イン」、「3. 連携の同意」を経ると、「4. 認可レスポンス」のリダイレクトコンテンツをブラウザが受信できます。

それでは、確認してみましょう。
ブラウザを起動し、下記URLにアクセスします。
https://openidprovider.sample.domain:443/openam/oauth2/authorize?response_type=id_token%20token&client_id=sampleRP&redirect_uri=https%3A%2F%2Flocalhost%2Fcb&scope=openid&nonce=ZZZZZZ&state=ZZZZZZ
OpenAMのログイン画面が表示されます。
OpenAMには予め、試用ユーザーが登録されています。ユーザーIDにdemo、パスワードにchangeitを入力し、LOG INをクリックします。

同意画面が表示されます。
ここでは、RPに対し、scopeパラメータで指定したクレーム情報をRPに対して、連携をしても良いかを尋ねられます。
Allowをクリックします。

今回はresponse_typeにid_token tokenを指定(インプリシットフローの開始)したため、ID TokenがRP(OPに登録したredirect_uri)にリダイレクトで連携されます。今回は、redirect_uriにhttps://localhost/cbと設定したため、ブラウザはリダイレクトに失敗するような挙動となりますが、ブラウザがリダイレクトしようとしたURLからID Tokenの情報を取得することができます。
https://localhost/cb# scope=openid& token_type=Bearer& expires_in=59& id_token=eyAidHlwIjogIkpXVCIsICJhbGciOiAiUlMNTYiLCAia2lkIjogIjk5OTk5OTk5LWFhYWEtNzc3Ny1mZmZmLTMzMzMzMzMzMzMzMyIgfQ.eyAidG9rZW5OYW1lIjogImlkX3Rva2VuIiwgImF6cCI6ICJzYW1wbGVSUCIsICJzdWIiOiAiZGVtbyIsICJhdF9oYXNoIjogIlpaWlpaWlpaWlpaWlpaWlpaWlpaWloiLCAiaXNzIjogImh0dHBzOi8vb3BlbmlkcHJvdmlkZXIuZXhhbXBsZS5kb21haW46NDQzL29wZW5hbS9vYXV0aDIiLCAib3JnLmZvcmdlcm9jay5vcGVuaWRjb25uZWN0Lm9wcyI6ICI0NDQ0NDQ0LWJiYmItODg4OC1jY2NjLTAwMDAwMDAwMDAwMCIsICJpYXQiOiAxNDQ3ODMxNTg2LCAiYXV0aF90aW1lIjogMTQ0NzgzMTE5NSwgImV4cCI6IDE0NDc4MzIxODYsICJ0b2tlblR5cGUiOiAiSldUVG9rZW4iLCAibm9uY2UiOiAiWlpaWlpaIiwgInJlYWxtIjogIi8iLCAiYXVkIjogWyAic2FtcGxlUlAiIF0gfQ.abcd **** 省略 ****& access_token=69bbd4d9-e4a0-4ec0-aed1-e9ff3e7e0448
上述のクエリーストリングは以下の情報で構成されています。
| 属性名 | 内容 |
|---|---|
| scope | 認可リクエスト時に指定した(RPが要求した)クレームに対応した値 |
| token_type | RPがOPのリソース(ID情報)を取得する際に、ここで指定した形式でアクセストークンを送信すること想定としている |
| expires_in | アクセストークンの有効期限 |
| id_token | ID Tokenの値(※後述) |
| access_token | アクセストークンの値 |
上述のクエリーストリングid_tokenに記載の値は、第一回で解説したとおり、JWT(JSON Web Token)フォーマットでエンコードされています。値をデコードするにあたり、まず、値を「.(ドット)」で3分割します。3分割した値の各部は下記のように定義されています。
| 場所 | 名称 | 説明 |
|---|---|---|
| 前部分 | ヘッダー部 | 署名用のアルゴリズムを含むJSONをBase64 URLエンコードした値 |
| 真ん中 | ペイロード部 | 署名対象のJSONデータをBase64 URLエンコードした値 |
| 後ろ部分 | シグネチャー部 | ヘッダー部とペイロード部をもとに作成した署名をBase64 URLエンコードした値 |
実際にペイロード部をBase64 URLデコードすると、ID Tokenの中に含まれる情報を取得することができます。本来、ID Tokenの送信先であるRPは、これら情報を受け取ることで、認証を完了させることができます。
{
"tokenName": "id_token",
"azp": "sampleRP",
"sub": "demo",
"at_hash": "ZZZZZZZZZZZZZZZZZZZZZZ",
"iss": "https://openidprovider.example.domain:443/openam/oauth2",
"org.forgerock.openidconnect.ops": "4444444-bbbb-8888-cccc-000000000000",
"iat": 1447831586,
"auth_time": 1447831195,
"exp": 1447832186,
"tokenType": "JWTToken",
"nonce": "ZZZZZZ",
"realm": "/",
"aud": [ "sampleRP" ]
}
なお、OpenAMが発行するID Tokenの中には、OpenAMが独自で追加している情報が含まれています。(上記では、tokenName、org.forgerock.openidconnect.ops、tokenType、realmがOpenAM独自の情報となります。)
以上で、OPの簡易な動作確認は完了となります。
おわりに
第二回では、OSSで提供されているOpenAMを用いて、Amazon EC2上にOPを実装し、テストとして、インプリシットフローでID Tokenの取得をする手順について、解説いたしました。本手順からお分かり頂けるように、OpenAMはインストール手順も簡素化されており、直ぐに構成が完了し、試用ができるようになっています。
第三回では、RPに該当するサンプルアプリケーションの実装例をご紹介し、実際にOPがRPに対して、ID連携を行っていることの確認を実施致します。
参考文献
- OpenID Connect Core(https://openid.net/specs/openid-connect-core-1_0.html)
- OpenAM Administration Guide(https://backstage.forgerock.com/#!/docs/openam/12.0.0/admin-guide/chap-oauth2#configure-oauth2-authz)
