Keycloakで認可サービスを試してみよう[後編]:Keycloak超入門(最終回)(3/3 ページ)
本連載では、近年注目されている認証プロトコル「OpenID Connect」をサポートするオープンソースのシングルサインオン(SSO)ソフトウェア「Keycloak」の活用方法を解説していきます。Keycloakの認可サービスを利用することで、アプリケーションに対して、より細やかで柔軟なアクセス制御を実現することが可能です。今回は、後編をお届けします。
APIサービス(リソースサーバ)の設定とソースコードの解説
●Tomcatアダプター(keycloak.json)の設定
このkeycloak.jsonで、Tomcatアダプターについての設定を行います。主な設定としては、第8回と同様、認可サーバのURLやレルム名、クライアント名、クライアントシークレットの設定などが含まれます(表9)。
上記に加え、今回のUMA方式の検証では、操作(スコープ)によるアクセス制御も利用するため、policy-enforcerに特徴的な設定をする必要があります。表10の「paths」の設定において、HTTPメソッドとスコープとの関連付けの設定が必要です。例えば、当該パスに該当するGETメソッドのリクエストを行った場合、「item:view」というスコープが要求されるという意味になります。「paths」で定義した以外のパスに対してのアクセスが拒否されないように、「enforcement-mode」は「PERMISSIVE」に設定しておく必要があります。
また、RPTなしでリソースにアクセスした際にUMAの仕様に準じた、パーミッションチケットを受け取るために、「user-managed-access」という設定が重要になります。
{ "realm": "demo-authz", "auth-server-url": "http://sso.example.com/auth", "ssl-required" : "none", "resource": "authz-uma-api", "bearer-only" : true, "credentials": { "secret": "secret" }, "policy-enforcer": { "enforcement-mode": "PERMISSIVE", "user-managed-access": {}, "paths": [ { "path" : "/api/items/{id}", "methods" : [ { "method": "GET", "scopes" : ["item:view"] }, { "method": "DELETE", "scopes" : ["item:delete"] }, { "method": "PUT", "scopes" : ["item:update"] } ] } ] } }
パラメーター名 | 必須 | 説明 |
---|---|---|
realm | ○ | クライアントが定義されているレルム名を指定 |
auth-server-url | ○ | 認可サーバURLを指定 |
ssl-required | SSLが必須かどうかを指定 今回はHTTPでアクセスを許可しているため、noneを指定 本番環境では決してこのパラメーターをnoneにしてはいけません |
|
resource | ○ | クライアント名を指定 |
bearer-only | APIサービスのようにユーザー認証を受け付けないアプリの場合は、trueを指定 | |
credentials | ○ | クライアントシークレットを指定 |
policy-enforcer | 認可サービスを利用する場合には指定 | |
表9 Tomcatアダプターの設定 |
パラメーター名 | 必須 | 説明 | |
---|---|---|---|
enforcement-mode | ポリシーエンフォーサーの動作モードの指定 | ||
ENFORCING | pathsに該当しないアクセスがあった場合は、そのアクセスは拒否される。認可サーバにパーミッションの確認も行わない | ||
PERMISSIVE | pathsに該当しないアクセスがあった場合は、そのアクセスは許可される。アクセスが許可されたURLも、認可サーバ側のアクセス可否問い合わせで許可される必要がない | ||
DISABLED | ポリシー評価を実施せず、全てのアクセスを許可 | ||
user-managed-access | アダプターがUMAプロトコルを使用することの指定。指定されている場合、アダプターはサーバにパーミッションチケットを問い合わせ、UMA仕様に従ってクライアントに戻す | ||
paths | ポリシーエンフォーサーで処理させるパスの配列 | ||
path | スコープによりアクセス制御するパスを指定 ※コンテキストパスは含みません |
||
methods | スコープとHTTPメソッドを対応させるために必要なマッピング設定 | ||
method | スコープに対応するHTTPメソッド名を指定 | ||
scopes | HTTPメソッドに対応するスコープ名の配列を指定 | ||
表10 Tomcatアダプターのpolicy-enforcerの設定 |
※ policy-enforcerにはここで指定したもの以外にもさまざまなオプションがあります。詳しくは、こちらのページをご参照ください。
●リソースの作成処理(POST /authz-uma-api/api/items)の解説
UMA方式を利用する場合、「認可クライアントJava API」を利用して、リソースサーバから認可サーバ(Keycloak)に対して、リソース情報の登録/削除を行う必要があります。リソース情報とは、Keycloakで認可制御が必要なリソースのURIや利用可能スコープ、リソースオーナーIDなどを含んだ管理オブジェクトです。
このAPIの呼び出しでは、リソースの実体を作成するとともに、Keycloakにログインユーザー用のリソース情報を登録しています。認可クライアントJava APIから、KeycloakのProtection APIを経由して、Keycloak上にリソース情報が登録されます。Keycloakにリソース情報が登録されると、他者との共有やパーミッションの申請の許可/拒否などが実施できるようになります。実装のポイントは、以下のリスト内(1)〜(4)の部分です。
@POST @Produces(MediaType.APPLICATION_JSON) public Response createResource(@QueryParam("name") String name, @QueryParam("memo") String memo) { String uuid = UUID.randomUUID().toString(); String subject = servletRequest.getUserPrincipal().getName(); String createUserId = getKeycloakSecurityContext().getToken().getPreferredUsername(); (・・・省略・・・) // (1)リソースで利用できる全てのスコープをHashSetに追加 HashSet<ScopeRepresentation> scopes = new HashSet<>(); scopes.add(new ScopeRepresentation(SCOPE_ITEM_VIEW)); scopes.add(new ScopeRepresentation(SCOPE_ITEM_UPDATE)); scopes.add(new ScopeRepresentation(SCOPE_ITEM_DELETE)); // (2)ResourceRepresentationインスタンスの生成 String uri = URI_PREFIX + uuid; ResourceRepresentation newResource = new ResourceRepresentation(name, scopes, uri, "urn:authz-uma-api:resources:item"); newResource.setOwner(subject); newResource.setOwnerManagedAccess(true); // (3)既に同一のリソース情報が登録されていないかどうかをチェック ResourceRepresentation resource = getResourceRepresentationByName(name, subject); if ( resource != null) { item.resultMessage = "'" + name + "' は既に作成済みです!"; return Response.status(Response.Status.CONFLICT).entity(item).build(); } // (4)リソース情報の登録(Protection API経由) getAuthzClient().protection().resource().create(newResource); return Response.status(Response.Status.CREATED).entity(item).build(); }
(1)リソースに対して行える全ての操作(スコープ)をHashSetに追加します。ここでは、「item:view」「item:update」「item:delete」の3種類を追加しています。
(2)Keycloakに登録するResourceRepresentationインスタンスを生成します。コンストラクタには、リソース名、スコープのマップ、uri、リソースタイプを指定します。ここで指定しているリソースタイプ("urn:authz-uma-api:resources:item")で、「認可」設定の「Item Permission」と関連付けが行われます。UMA方式の場合は、setOwnerメソッドでオーナーのIDを設定してsetOwnerManagedAccessメソッドでtrueを設定し、このリソースでUMAを有効にする必要があります。
(3)既に、同一のリソース情報が登録されていないかどうかをProtection APIを使ってチェックします。
(4)Protection APIから、リソース情報登録用のAPIを呼び出します。
●リソースの削除処理(DELETE /authz-uma-api/api/items/{ID})の解説
このAPIの呼び出しでは、リソースの実体を削除するとともに、Keycloak上の該当リソース情報の登録を削除しています。Keycloakからリソース情報が削除されると、それまでの共有設定や申請も全て削除されます。実装のポイントは、以下のリスト内(1)〜(3)の部分です。
@DELETE @Path("/{id}") @Produces(MediaType.APPLICATION_JSON) public Response deleteResource(@PathParam("id") String id) { ItemDetail item = getItemDetail(id); item.resultMessage = "'" + item.name + "' が削除されました!"; database.remove(id); // (1)リソース情報の検索(Protection API経由) List<ResourceRepresentation> search = getResourceRepresentations(id); // (2)既にリソース情報が削除されていないかどうかをチェック if (search.isEmpty()) { item.resultMessage = "このリソースは既に削除されています!"; return Response.status(Response.Status.NOT_FOUND).entity(item).build(); } // (3)リソース情報の削除(Protection API経由) ResourceRepresentation resource = search.get(0); getAuthzClient().protection().resource().delete(resource.getId()); return Response.ok(item).build(); }
(1)Protection API経由で、削除対象のリソース情報を検索します。
(2)既に削除されている場合は、処理を終了します。
(3)Protection API経由で、リソース情報削除用のAPIを呼び出します。削除の場合は、リソース情報のIDを引数に渡すだけです。
※ Protection APIや認可クライアントJava APIの利用方法については、こちらのページも併せてご参照ください。
まとめ
以上、第8回と第9回を通して、Keycloakで認可サービスを利用する方法が一通り理解できたでしょうか。
UMA方式に関しては、Keycloakやクライアントアダプターの設定に加え、アプリケーション側への実装が必要となるため、既成のアプリケーションに組み込むのは、ハードルが高いかもしれません。しかし、これから新規作成するアプリケーションでUMA仕様に適する要件があれば、ぜひ、UMA方式の採用を検討してみてください。
また、今回のUMA方式の検証では、個人から個人への共有(Person to person sharing)の動作は確認できましたが、組織やロール単位での共有(Person to organization sharing)の動作は確認しませんでした。Keycloakの「マイリソース」の画面では、共有対象として組織やロールを選択する画面がないので、現状は画面からの実施は不可能ですが、UMAのパーミッション変更APIなどを駆使することで実現できるはずです。興味のある方はぜひ取り組んでみてください(UMAの理解が深まると思います)。
全9回にわたり、『Keycloak超入門』にお付き合いいただきありがとうございました。所々、「これが超入門?」と思われる部分もあったかもしれませんが、Keycloakがシンプルかつ強力に認証/認可機能を実現できるオープンソースであることをご紹介できたのではないかと思います。また、「専門性が高い」「ハードルが高い」といった従来のシングルサインオンに対する印象をお持ちの方が、本連載を読んで少しでも身近に感じていただければ幸いです。
本連載は、前半を日立製作所、後半を野村総合研究所で担当させていただきました。これからも、Keycloakの活用を推進すべく、執筆活動やコミュニティー活動を進めていく予定です。今後ともよろしくお願いいたします。
筆者紹介
和田 広之(わだ ひろゆき)
野村総合研究所のオープンソースサポートサービス「OpenStandia」で、オープンソースのサポートや製品開発を担当。
- [連載]OSSによるアイデンティティ管理
Twitter: @wadahiro
筆者紹介
相田 洋志(あいだ ひろし)
野村総合研究所のオープンソースサポートサービス「OpenStandia」で、オープンソースの導入支援やプロジェクト推進を担当。
Twitter: @daian183
筆者紹介
田村 広平(たむら こうへい)
野村総合研究所のオープンソースサポートサービス「OpenStandia」で、OpenAMやKeycloakを中心としたOSSの研究開発・テクニカルサポートを担当。
- [連載]OSSによるアイデンティティ管理
- [「第6回OpenAMコンソーシアムセミナー」リポート]認証の最新動向と、OpenAMの適用事例を探る
Twitter: @tamura__246
筆者紹介
上田 直樹(うえだ なおき)
野村総合研究所のオープンソースサポートサービス「OpenStandia」で、OpenAMやKeycloakを中心としたOSSの研究開発・導入支援を担当。
Twitter: @naoki_dx_xb
筆者紹介
青柳 隆(あおやぎ たかし)
野村総合研究所のオープンソースサポートサービス「OpenStandia」で、OpenAMやKeycloakを中心としたOSSの障害調査・テクニカルサポートを担当。
Twitter: @yagiaoskywalker
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- なぜ「シングルサインオン」が必要なのか?
企業でのWebサービスの実現が具体的になるにつれ、パスワード/IDマネジメントが重視されるようになり、「シングル・サインオン」がますます注目を集めている。この連載では、シングル・サインオンの実践ステップなど具体的な考え方を紹介する。また、メタディレクトリやLDAPなど「ディレクトリ統合」をキーワードとしてシングル・サインオンを実現するための技術を分かりやすく解説する。(編集部) - 第1回 もはや企業のID管理で避けては通れない「IDaaS」とは?
これまで社内設置が当たり前だったアイデンティティ(ID)管理/認証システム。でも「クラウド」「モバイル」に代表される激烈な変化に対応できる、と本当に思っていますか? ID管理/シングルサインオンの新たな選択肢「IDaaS」について解説する連載開始! - 強力なSSOを実現するXML認証・認可サービス(SAML)
- OpenIG、OpenDJと連携したOpenAMの新機能
今回は、OpenAMの姉妹製品で既存アプリケーションを改修せずにシングルサインオンを可能にする「OpenIG」と、OpenAMのデフォルトデータストアである「OpenDJ」について解説します。