連載
» 2019年12月11日 05時00分 公開

Keycloak超入門(最終回):Keycloakで認可サービスを試してみよう[後編] (3/3)

[和田広之, 相田洋志, 田村広平, 上田直樹, 青柳隆,野村総合研究所/野村総合研究所/フリーランス/株式会社リック/フリーランス]
前のページへ 1|2|3       

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"]
          }
        ]
      }
    ]
  }
}
▲/usr/local/tomcat/webapps/authz-uma-api/WEB-INF/keycloak.json
パラメーター名 必須 説明
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」で、オープンソースのサポートや製品開発を担当。

Twitter: @wadahiro


筆者紹介

相田 洋志(あいだ ひろし)

野村総合研究所のオープンソースサポートサービス「OpenStandia」で、オープンソースの導入支援やプロジェクト推進を担当。

Twitter: @daian183


筆者紹介

田村 広平(たむら こうへい)

野村総合研究所のオープンソースサポートサービス「OpenStandia」で、OpenAMやKeycloakを中心としたOSSの研究開発・テクニカルサポートを担当。

Twitter: @tamura__246


筆者紹介

上田 直樹(うえだ なおき)

野村総合研究所のオープンソースサポートサービス「OpenStandia」で、OpenAMやKeycloakを中心としたOSSの研究開発・導入支援を担当。

Twitter: @naoki_dx_xb


筆者紹介

青柳 隆(あおやぎ たかし)

野村総合研究所のオープンソースサポートサービス「OpenStandia」で、OpenAMやKeycloakを中心としたOSSの障害調査・テクニカルサポートを担当。

Twitter: @yagiaoskywalker


前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

編集部からのお知らせ

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。