長年、組織領域とインターネット領域の境界で高価なセキュリティ製品を配備し、脅威から資産を守る手法が、世の中のデファクトスタンダードとして、多くの企業で採用されてきました。しかし、「モバイルデバイスの活用」、「クラウドサービス利用の浸透」、「ワークスタイルの変革」などのリクエストによって、その有効性は失われつつあります。また、これらのリクエストに対し、資産ごとにセキュリティ対策を実施すると、コストが非常に高くなる傾向があります。
第一回の本記事では、資産を守るための新たな境界である「アイデンティティ」に注目し、その境界を体現する認証連携方式について解説を行います。そして、数ある認証連携方式の中から2014年2月に標準化された「OpenID Connect」に注目して、仕様説明と有用性を解説したいと思います。
認証基盤のこれまで
認証基盤における認証対象アプリケーションとの連携実装方法を振り返ります。 まず、ウェブアプリケーションを例に一般的な認証の流れを見て行きましょう。
ユーザー固有のページをアプリケーション利用者に提供する場合、どのようなウェブアプリケーションでも認証機能を有しています。また、ページの提供を受けることができるユーザーの情報はデータベース(RDBMSやLDAP、Active Directory)に格納されています。 このようにユーザーの情報と認証機構を保持しているシステムが増えてきました。そこで、組織は以下の恩恵を享受するために、新たに「認証基盤」を配置しました。
- アプリケーションの利便性向上
- シングルサインオンできる
- IDとパスワードを複数覚えなくてよくなる
- セキュリティレベルのばらつきを失くす
- アプリケーションの入り口を1つにできる
- 均一な認証セキュリティを保証できる
- システムの開発が楽になる
- 認証の機能を個々のシステムで実装しなくてよくなる
- 認証セッションを個々のシステムで持たなくてもよくなる
- 認証の変更がしやすい
- 要求やポリシーにあった認証を全てのシステムに即時提供できる
認証基盤の導入により、認証の流れは以下のように変わっていきました。
上記のようなフローは、「OSS(OpenAMなど)」や「商用製品」を使って実装することが出来、現在も多くの企業で採用されています。ただし、導入に至るには次のような課題がありました。
- リバースプロキシに負荷が集中する
- 独自プロトコルでの通信が常態化
- 認証基盤アプリケーションから受け取ったID情報を、ウェブアプリケーションに「どう連携するか?」、「どう受け取るか?」は個別に実装する必要がある
- 識別情報をドメインCookieを使って、エージェントやリバースプロキシに伝搬しているため、同一ドメイン内にしか伝達できない。
- 予め、ユーザーストアを共通化、もしくは同期、IDプロビジョニングしておく必要がある
用語注:リバースプロキシ
クライアントからリクエストを中継し、代理で特定のサーバーにリクエストを送信するプロキシサーバー。
特に3番目のID情報の受け渡しの方法は、下記に挙げる例のように、アプリケーションによって千差万別であり、それぞれに合わせた実装をエージェント or リバースプロキシ側とアプリケーション側で行う必要があります。
- HTTP HEADER・HTTP Cookie連携
- ウェブアプリケーションがHTTPリクエストにセットされた任意のヘッダーやCookieをアイデンティティ情報として、識別する機能を有している場合、採用できる。
- エージェントやリバースプロキシは、認証基盤アプリケーションから受け取ったアイデンティティ情報をHTTPヘッダーやCookieに追加する機能を有している。
- 代理認証連携
- 多くのウェブアプリケーションに採用されているログインフォームに対し、クレデンシャル情報をクライアント(ブラウザ)に替わってPOSTする。
- ログインフォームの仕様はアプリケーションによって様々なため、仕様調査や連携検証を十分に行う必要がある。
このような連携方式の対応には、アプリケーション担当者との多大な調整と連携検証・テストを十分に行う必要があり、コストが自然とかかってしまいます。よって、従来型の認証基盤は比較的大規模な企業や、持続的にセキュリティに対する投資ができる企業でしか採用されないという状況が少なからず見られます。 しかし、アイデンティティ情報の連携方法のばらつきは、アイデンティティ情報の交換プロトコルであるSAML(Security Assertion Markup Language)が解決してくれました。
SAMLの仕様では認証連携を実現する要素を下記の4つに分けて定義しており、アイデンティティ情報を安全に流通させるためのXMLの形式、および、通信仕様が定めてあります。
SAMLは「事前に信頼関係(設定)を構築し、信頼関係に基いてアイデンティティ情報を連携する」という仕組みを用いています。そのために、ユーザーが活用するアプリケーションが決まっているエンタープライズ向けの利用では重宝されているプロトコルとなっており、エンタープライズ向けアプリケーションの商用製品やOffice 365やGoogle Appsなどに代表されるクラウドサービスで、サポートされておりケースが増えています。 また、SAMLは認証情報の連携にCookieを用いない為に、先に紹介したエージェントやリバースプロキシを用いた認証連携方式と比べて組織・ドメインに縛られないアイデンティティ連携を実現できるプロトコルだと言えます。
新たなアイデンティティ連携プロトコルの台頭
SAMLはバージョン2.0となって10年経った現在でも、アイデンティティ連携プロトコルのスタンダードとなっています。市場にはSAML連携の機能を持つクラウドサービスや商用のウェブアプリケーションが存在します。しかしながら、エンタープライズにおけるアプリケーションに実装されている認証機能の多くは、未だSAML連携に対応しているわけではありません。これまで、筆者の所属する部隊では、多くのお客様に対し、OpenAMをベースに開発された統合認証基盤ソリューション「ThemiStruct-WAM」を使ったSIを実施してきました。その活動の中で、顧客に対しSAML対応に向けた開発支援や、ガイドラインについての解説を行っていますが、下記のような理由で認証対象のアプリケーションのSAML対応に至りにくいのが現状です。
- 顧客の理解が進まない
- SAMLの専門用語が多いし、難しい
- 連携検証・デバッグが難しい
- メリットを感じてもらいにくい
- なにが嬉しい・良くなるのか分からない
- セキュリティ的に問題ないのか分からない
- ウェブアプリケーション側(SAML SP)の実装にコストを掛けれない
- ウェブアプリケーションの担当ベンダーが実施する必要がある
- SAML SP実装の知識・スキルが定着していない
よって、エンタープライズ向け認証基盤は「SAML」と「独自プロトコル」の双方を扱える「ハイブリッドな認証基盤」が選ばれる時代が、今もなお続いています。また、新たに「ネイティブアプリケーションからの利用」、「シャドウITのコンプライアンスの確保」、「モバイルデバイスからの利用」等の対応も、認証基盤に求められてきております。 このように、時代の変遷とともに、認証基盤には多様なリクエストが集中しており、IT活用の心臓部であるのにもかかわらず、常に変革を求められるシステムとなりつつあります。
そんな中、SAMLが持つ課題を解決しうるプロトコルとして、OAuth 2.0をベースとしたシンプルなアイデンティティ連携を実現できる「OpenID Connect」が注目を集めており、エンタープライズ向けの活用事例も増えつつあります。
OpenID Connectとは
以下、OpenID Connect Core 1.0の日本語訳 (https://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html) からの引用です。
OpenID Connect 1.0 は, OAuth 2.0 プロトコルの上にシンプルなアイデンティティレイヤーを付与したものである. このプロトコルは Client が Authorization Server の認証結果に基づいて End-User のアイデンティティを検証可能にする. また同時に End-User の必要最低限のプロフィール情報を, 相互運用可能かつ RESTful な形で取得することも可能にする.
要するに、OAuth 2.0で実装した認可のフローをそのままに、追加で、「認証結果」と「属性情報(アイデンティティ情報を提供するエンドポイントへのアクセス認可情報)」を流通させるプロトコルとなります。このプロトコルの活用により、様々なウェブアプリケーションやネイティブアプリケーションの間でアイデンティティ情報を流通させる仕組みを、「簡単に」・「安全に」実現することができます。 また、OpenID Connect 1.0の仕様は2014年2月に米OpenID Foundationを通じて最終承認されています。
用語解説
OpenID Connect 1.0 (以下、OpenID Connect)の用語を以下に記します。
用語 | 説明 |
---|---|
OpenID Provider (OP) | ユーザーの認証を行う機能を有するサーバー。また、ユーザーの認証時にRelying Partyから要求されたアイデンティティ情報を供給することができるRESTエンドポイントを有するサーバー。 |
Relying Party (RP) | OpenID ProviderにID Tokenとアイデンティティ情報を要求するサーバー。SSO対象のアプリケーション(ウェブアプリケーション、ネイティブアプリケーション問わず)を指す。 |
ID Token | 認証と認可の情報を含むJWT(JSON Web Token)形式のトークン。 |
Access Token | UserInfoエンドポイントにアクセスするためのトークン |
UserInfo | Access Tokenを提示するクライアントに対して、アイデンティティ情報を提供する。 |
OpenID Connect で実現できること
具体的に、OpenID Connectを使って、以下のことを実現できます。
- 複数のRelying Partyの間でシングルサインオン
- OpenID Providerでユーザー認証を一元化し、一度のOpenID Providerへのサイン・インで複数のRelying Partyにアクセスすることができる。
- Relying Partyにおける、IDと認証の実装負荷の軽減
- OpenID Providerへクレデンシャルを集約することができ、また、OpenID Providerからクレデンシャルに紐づくユーザー属性情報の取得をできる。後者を活用することで、Relying Party上のユーザーの新規作成を容易に実装できる。
- ユーザーの利便性向上
- ユーザーの認証とアイデンティティ情報にアクセスするための認可処理を一体化しているため、ユーザーはアプリケーションのユーザー認証処理と同時に、アプリケーションへのアイデンティティ情報の連携の可否の制御をすることができる。
プロトコルの概要
OpenID Connectは以下の様な通信フローを以って、実現されています。
- Relying PartyはOpenID Providerに認可リクエストを送る
- ユーザーはOpenID Providerにサイン・インし、認可をされる
- OpenID ProviderはID Tokenとアクセストークンで応答する
- Relying Partyは必要に応じて、アクセストークンを用いて、UserInfoエンドポイントにリクエストをおくる
- UserInfoエンドポイントはユーザーに紐づくアイデンティティ情報を返却する
OpenID ConnectはOAuth 2.0のフローにアイデンティティ情報のやり取りを行うレイヤーを追加したものです。そして、そのアイデンティティ情報のやり取りが、OpenID ProviderとRelying Partyの間のID Tokenのやり取りに当たります。Relying PartyはこのID Tokenを用いて、ユーザーを識別し、アクセスコントロールを実装することができます。 このID Tokenは以下の様な仕様で定義された情報(一部抜粋)となります。
項目 | 値の例 | 説明 |
---|---|---|
iss | “https://op.example.domain/URI” | レスポンスの発行者の識別子(URL) |
sub | “sampleuser” | ログインユーザー名 |
aud | “client123456” | ID Tokenの要求元(Relying Party)であるウェブアプリケーションやネイティブアプリケーションの識別子 |
exp | 1436784324 | トークンが無効になる時刻(UTC で計測される 1970-01-01T0:0:0Z から秒数) |
iat | 1436784264 | トークン作成時刻(UTC で計測される 1970-01-01T0:0:0Z から秒数) |
nonce | “18b88a6ab3…d58a0” | 認可エンドポイントの1回だけ使われるパラメータ |
このような情報でID Tokenは構成されており、JWT(JSON Web Token)形式と呼ばれています。JWTは、URL Safe(URLに含めることの出来ない文字列を含まない)であり、また、デジタル署名で保護されたコンテンツを表現することが可能なJSON型のトークンです。 まとめると、OpenID ConnectはOAuthのフローをそのままに、クライアント(Relying Party)が信頼できるように、認証サーバー(OpenID Provider)が安全な方式(JWT)で認証結果(ID Token)を提供するプロトコルとなります。
2種類の通信フロー
OpenID Connectの基本的なフローでは、下記の2種類が定義されており、これらをRelying Partyが指定できるような作りになっています。
- Authorization Code Flow
- Implicit Flow
このフローによって、ID TokenとAccess TokenがどのようにRelying Partyに返却されるかが決定します。フローの指定は下記のように、Relying PartyからOpenID Providerに送られる「認可リクエスト」に含まれるresponse_typeで指定することが出来ます。
HTTP/1.1 302 Found Location: https://op.example.domain/authorize? response_type=code # フローのタイプの指定箇所 &scope=openid%20profile%20email &client_id=XXXXXX &state=abcdefg123 &redirect_uri=https%3A%2F%2Frp.example.domain%2Fcallback
Authorization Code Flow
Authorization Code Flowでは、OpenID Providerがエンドユーザー経由でRelying Partyに発行した認可コードをキーにID TokenやAccess Tokenを取得する方式となります。具体的には下記のようなフローとなります。
ID Tokenのやり取りをOpenID ProviderとRelying Partyが直接通信で行うため、互いに疎通できる環境下でのみ使うことができます。
Implicit Flow
Implicit Flowでは、前述のAuthorization Code Flowで使用していたToken Endpointを使用せず、ID TokenとAccess TokenはAuthorizationエンドポイントから返却されます。具体的には下記のようなフローとなります。
ID Tokenの受け渡しはWebブラウザを介して行うため、OpenID ProviderとRelying Partyの間に直接通信できない環境でも採用することができます。また、図中に示す通り、ID Tokenの受け渡しはURLフラグメントによる受け渡しとなるため、Relying Partyはフラグメント部分をパースした後、情報の検証を行うエンドポイントに対して、POSTでのデータ送信を行うようなスクリプトを配備する必要があります。
アイデンティティ情報の提供
OpenID Connectの仕様では2通りのアイデンティティ情報の提供方法があります。
- ID TokenからID情報を取得
- ID Tokenが含まれるレスポンスから取得する
- UserInfoエンドポイントで提供する方法
- Authorization Code Flowでは「7.」で要求し、「8.」で受け取る
- Implicit Flowでは「5.」で要求し、「6.」で受け取る
ID TokenからID情報を取得
1つ目の提供方法はOpenID ProviderからRelying PartyにID Tokenを返却する際、このID Tokenに含める方法となります。どういった属性を含めるかの権限要求は認可リクエスト時に行うことができ、下記のように指定します。
HTTP/1.1 302 Found Location: https://op.example.domain/authorize? response_type=code &scope=openid%20profile%20email # 属性の要求箇所 &client_id=XXXXXX &state=abcdefg123 &redirect_uri=https%3A%2F%2Frp.example.domain%2Fcallback
上記のようにURLクエリストリングのscopeパラメータを用いて、アイデンティティ情報の部分集合(クレーム)を指定します。OpenID Connectの仕様では、クレームを要求する際に、下記のscopeパラメータが定義されています。
- profile
- 姓、名、ニックネーム、生年月日、ロケールなどの情報を含む
- address
- phone
上記以外にも、OpenID Providerが独自でscopeを定義することも可能となっています。
UserInfoエンドポイントで提供する方法
2つ目の提供方法はRelying PartyがAccess Tokenを用いて、UserInfoエンドポイントに対して、アイデンティティ情報を要求する方法となります。UserInfoエンドポイントはOAuth 2.0でいうところの「Resource Server」に当たります。 (参考)https://tools.ietf.org/html/rfc6749#section-7
Relying Partyは下記のようなリクエストをUserInfoエンドポイントに送り、応答としてJSON形式のアイデンティティ情報を取得することができます。
GET /userinfo HTTP/1.1 Host: server.example.domain Authorization: Bearer SlAV32hkKG HTTP/1.1 200 OK Content-Type: application/json { "sub": "1234567", "name": "OGIS TARO", "given_name": "TARO", "family_name": "OGIS", "preferred_username": "t.ogis", "email": "t.ogis@example.domain" }
その他のOpenID Connectの仕様
ここまで、OpenID Connectの最もシンプルな仕様の解説を行いました。また、OpenID Connectの仕様は下記に構造化されており、用途に応じて選択することができます。
(出典:https://openid.net/connect/ )
本記事にて、ご紹介したのは上記図の「Core」の部分に当たり、ミニマムの限定された実装となっています。
おわりに
第一回では、これまでの認証基盤で採用されていた認証プロトコルについて、フロー図を用いながら解説を致しました。認証プロトコルを扱う上で、これまでは、技術的敷居があったり、都度開発が必要であったりと、ユースフルなプロトコルとは言えませんでした。OpenID Connectは今回ご紹介したとおり、多くの開発者にとって慣れ親しんだOAuth 2.0をベースとしており、これまでのプロトコルと比較して格段に理解が進むプロトコルとして注目されています。
第二回は第一回の後半でご紹介したOpenID Connectの認証連携実装例のうち、認証・認可・フェデレーションの機能を備えたOSSである「OpenAM」を使った、OpenID Providerの実装例をご紹介致します。
参考文献
- OpenID Connect Core (https://openid.net/specs/openid-connect-core-1_0.html)