オブジェクトの広場は株式会社オージス総研グループのエンジニアによる技術発表サイトです

クラウド/Webサービス

第二回 OpenID Providerの実装例 ~OpenAM~

OpenID Connectでつくる「アイデンティティ境界」
株式会社オージス総研
テミストラクトソリューション部
千野 修平
2015年12月17日

本連載は、主にエンタープライズ向けアプリケーション開発者を対象に、新たな境界として台頭しつつある「アイデンティティ型の境界」がサポートするプロトコルの解説と実装例をご紹介していきます。

本記事の内容

第二回は、オープンソースソフトウェア(以下、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を実装致します。

OpenAM アーキテクチャ図

参考 : 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インスタンス作成の確認画面です。

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 http://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

⑤ ストレージ

EC2インスタンスにアタッチメントされるEBS(ストレージ)の設定です。

項目 設定値
タイプ ルート
デバイス /dev/xvda
スナップショット snap-xxxxxxxx
サイズ(GiB) 8
ボリュームタイプ gp2
IOPS 24/3000
合わせて削除 はい
暗号化済み 暗号化なし

⑥ タグ

ローンチしたEC2に付加するタグ情報の設定です。 ローンチ後にインスタンスの識別がし易いよう、OpenID Provider (OpenAM)を設定しています。

確認と作成

設定した内容の確認が完了し次第、画面右下の作成をクリックします。

EC2インスタンス作成の確認

EC2インスタンスにSSHログインするためのキーペアを選択、または作成する画面が表示されます。

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

最後に、インスタンスの作成をクリックします。

インスタンスの作成

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

作成ステータス画面

先ほどローンチしたEC2インスタンスが既に選択された状態で、EC2インスタンス管理画面が表示されます。

画面中段に表示されているパブリックDNSに表記された値がローンチしたEC2インスタンスに対し、AWSが自動で割り当てたFQDNとなっています。

以後の手順解説では、FQDNにopenidprovider.sample.domainという別名レコード(CNAME)を割り当てて、解説をします。

EC2インスタンス管理画面

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の初期設定は完了となります。

OpenAMの管理画面

OpenAMをOPとして設定

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

Top Level Realmをクリックします。

Top Level Realmをクリック

Realm Overview画面が表示されます。

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

Realm Overview画面

Configure OpenID Connect画面が表示されます。

OPが発行する各種トークンに関する設定をすることができます。

本画面で設定可能なトークンの種別は以下のとおりです。

項目 説明
認可コード 認可コードフローにおいて、RPがアクセストークンやリフレッシュトークンを取得するために使用する一時的なトークン
アクセストークン OP上の保護されたリソース(ID情報)への、RPからのリクエスト方法を指定する
リフレッシュトークン アクセストークンの有効期限が切れた場合、再取得を行う際に使用するトークン。本トークンの発行は任意である。

これらのトークンの発行有無や、有効期限を設定することができます。

本手順ではデフォルトの設定のままとし、画面右上の作成をクリックします。

Configure OpenID Connect画面

作成が完了すると、下記の完了画面が表示されます。了解をクリックします。

本設定を以って、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には必要なクレームに対応した値(profilemail)などを指定する。また、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)でログインを行います。

OpenAMに管理アカウントでログイン

Realms画面が表示されます。

Top Level Realmをクリックします。

Realms画面

Top Level Realm画面が表示されます。

画面右のAgentsをクリックします。

Top Level Realm画面

エージェント設定の画面が表示されます。

画面上部のOAuth 2.0 クライアントをクリックします。

エージェント設定画面

OAuth 2.0 クライアント設定の画面が表示されます。

エージェントの設定枠内の新規をクリックします。

OAuth 2.0 クライアント設定画面

新規でOAuth 2.0 クライアントを登録する画面が表示されます。

名前(clientidに該当)とパスワードを入力し、画面右上の作成_をクリックします。

本手順では名前sampleRPとしています。

OAuth 2.0 クライアントを登録する画面

続いて、残りのscoperedirect_uriresponse_typeの設定を行います。

エージェント設定枠内に新規で作成されたsampleRPをクリックします。

OAuth 2.0 クライアント画面

sampleRPの設定画面が表示されます。

画面上部にあるリダイレクトURIスコープを入力します。

本手順ではリダイレクトURIhttps://localhost/cbスコープopenidとしています。

sampleRPの設定画面

なお、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には予め、試用ユーザーが登録されています。ユーザーIDdemoパスワードchangeitを入力し、LOG INをクリックします。

OpenAMのログイン画面

同意画面が表示されます。

ここでは、RPに対し、scopeパラメータで指定したクレーム情報をRPに対して、連携をしても良いかを尋ねられます。

Allowをクリックします。

同意画面

今回はresponse_typeid_token tokenを指定(インプリシットフローの開始)したため、ID TokenがRP(OPに登録したredirect_uri)にリダイレクトで連携されます。今回は、redirect_urihttps://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が独自で追加している情報が含まれています。(上記では、tokenNameorg.forgerock.openidconnect.opstokenTyperealmがOpenAM独自の情報となります。)

以上で、OPの簡易な動作確認は完了となります。

おわりに

第二回では、OSSで提供されているOpenAMを用いて、Amazon EC2上にOPを実装し、テストとして、インプリシットフローでID Tokenの取得をする手順について、解説いたしました。本手順からお分かり頂けるように、OpenAMはインストール手順も簡素化されており、直ぐに構成が完了し、試用ができるようになっています。

第三回では、RPに該当するサンプルアプリケーションの実装例をご紹介し、実際にOPがRPに対して、ID連携を行っていることの確認を実施致します。

参考文献