本連載は、主にエンタープライズ向けアプリケーション開発者を対象に、新たな境界として台頭しつつある「アイデンティティ型の境界」がサポートするプロトコルの解説と実装例をご紹介していきます。
本記事の内容
第二回は、オープンソースソフトウェア(以下、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)