MicroProfile OpenAPIを使用したセキュアAPIのドキュメント化
富士通技術者ブログ~Javaミドルウェア~

2023年1月6日 初版
数村 憲治

Beyond the Twelve-Factor Appでも言及されているように、APIの設計はモダンなアプリケーション開発において重要な位置づけになっています。また、APIのふるまいだけではなく、そのAPIが前提とするセキュリティ要件も設計段階で明確にしておくことが、セキュアなAPI構築につながると考えられています。
本稿では、MicroProfile Interoperable JWT RBAC(以降、MP JWTと記載)を使用したセキュアAPIを例に、MicroProfile OpenAPI(以降、MP OpenAPIと記載)でドキュメント化する方法について解説します。ただし、本稿では、MP OpenAPIに関する基本事項については説明しませんので、必要に応じて、過去の記事を参照ください。


ここで紹介するプログラムの完全なソースコードは、以下で参照可能です。

MP JWTを使用したMicroProfileアプリケーション

本章では、MP JWTを使用したMicroProfileアプリケーションを例に、MP OpenAPIのドキュメント化方法を簡単に紹介します。

MP JWTは、マイクロサービスのエンドポイントに対して、JSON Web Tokens(JWT)を使用した、ロールベースアクセス制御(Role Based Access Control)を提供します。MP JWTについては、過去の記事もご参照ください。

以下のプログラムは、Jakarta RESTful Web Servicesのアプリケーションで、ユーザIDを指定したURL(例:"http://example.com/user/100")をリクエストすると、該当するユーザ名を返却するAPIを定義しています。このプログラムでは、(1)の@RolesAllowedに記載しているロールを持つユーザがアクセスでき、ロールはJSON Web Token内で指定しアプリケーションに渡します。APIの概要については(2)で、APIに指定するパラメタについては(3)で、APIのレスポンスについては(4)/(5)で、 MP OpenAPIを使用しドキュメント化されています。

@Path("/user")
public class User {
  @GET
  @Path("/{id}")
  @Produces("text/plain")
  @RolesAllowed("管理者")・・・(1)
  @Operation(summary = "JWTを使用したセキュアな呼出し")・・・(2)
  @Parameter(name = "id", description = "ユーザID")・・・(3)  
  @APIResponse(responseCode = "200",
	       description = "指定したIDに該当するユーザの名前を表示します。",
	       content = @Content(mediaType = "text/plain"))・・・(4) 
  @APIResponse(responseCode = "404", description = "指定したIDに該当するユーザが存在しません。")・・・(5)
  public Response user(@PathParam("id") int id) {
    String name = getName(id);
    if (name == null)
      return Response.status(Response.Status.NOT_FOUND).entity("該当ユーザは存在しません\n").build();
    else
      return Response.ok(name).build();
  }

上記プログラムを実行するために、MicroProfile 5.0互換実装の一つである、Launcher を用意します。 Launcherは以下よりダウンロードし利用します。

Launcherの使い方は、ダウンロードした launcher-4.0.jar を任意の場所に置いて、javaコマンドの -jar オプションに指定するだけです。(インストール作業は不要です。)詳細なLauncherの使用方法は、以下のドキュメントを参照してください。

$ java -Dmp.jwt.verify.publickey.algorithm=ES256 -Dmp.jwt.verify.publickey={Base64エンコードしたJWK} -jar launcher-4.0.jar --deploy secureapi-1.0.war

このプログラムのビルド・実行の詳細については、GitHub を参照ください。

上記プログラムのようなMP OpenAPIでドキュメント化された内容を可読化するためにはいくつか方法があります。一つは、yaml形式で表示する方法で、該当MicroProfileアプリケーションに対して、MP OpenAPIのエンドポイント(この場合であれば、"http://localhost:8080/openapi")を指定します。もう一つは、Swagger UIを使用する方法で、該当MicroProfileアプリケーションに対して、Swagger UIのエンドポイント(この場合であれば、"http://localhost:8080/openapi-ui")を指定します。いずれも、図1や図2に示すように、APIの呼出し方法やレスポンスに関して、 必要な情報が出力されているようにみえます。

図1:MP OpenAPIエンドポイント
図1:MP OpenAPIエンドポイント



図2:Swagger UI
図2:Swagger UI

しかし、実際に、このAPIにアクセスするためには、適切なJSON Web TokenをAuthorizationヘッダに付与して呼び出す必要がありますが、そのことについての記述がありません。先ほどの、Swagger UIの「Try it out」ボタンから、APIのテスト呼出しが行えますが、単純に、ユーザIDを指定するだけでは、レスポンスコード401が返却されます。図3の例では、ユーザIDに、「10」を指定し実行した結果ですが、ドキュメントに記述のない、「401 Error: Unauthorized」というレスポンスが返却されています。

図3:ユーザIDに「10」を指定して、APIを実行した結果
図3:ユーザIDに「10」を指定して、APIを実行した結果

次章では、このような、APIが前提とするセキュリティ要件を、MP OpenAPIでドキュメント化する方法を紹介します。

セキュリティスキーマの使用

OpenAPIでは、セキュリティ関連情報を記述する、 セキュリティスキーマ が定義されています。MP OpenAPIでは、このスキーマを @SecurityScheme アノテーションで記述できます。前章のプログラムを、@SecuritySchemeを使って書き直したものが以下になります。

@Path("/secureuser")
@SecurityScheme(securitySchemeName = "JWT-Auth", ・・・(1)  
		type = SecuritySchemeType.HTTP,・・・(2)     
		scheme = "bearer",・・・(3)                 
		bearerFormat = "JWT",・・・(4)               
		description = "JWTを使用したスキーマ。\n適切なJson Web TokenをAuthorizationヘッダに指定してください。")
public class SecureUser {
  @GET
  @Path("/{id}")
  @Produces("text/plain")
  @RolesAllowed("管理者")
  @Operation(summary = "JWTを使用したセキュアな呼出し")
  @Parameter(name = "id", description = "ユーザID")
  @APIResponse(responseCode = "200",
	       description = "指定したIDに該当するユーザの名前を表示します。",
	       content = @Content(mediaType = "text/plain"))
  @APIResponse(responseCode = "404", description = "指定したIDに該当するユーザが存在しません。")
  @APIResponse(responseCode = "401", description = "不適切なトークンによる呼出し。")・・・(5) 
  @SecurityRequirement(name = "JWT-Auth")・・・(6)  
  public Response user(@PathParam("id") int id) {

@SecuritySchemeには、どのようなセキュリティ手段を使うのかを記述します。 (1)で、このスキーマの名前を指定します。この名前は、後の、@SecurityRequirementのパラメタに指定します。 今回は、JWTを使うため、上記(2)、(3)、(4)記載のように、 typeに SecuritySchemeType.HTTP、schemeに"bearer"、bearerFormatに"JWT"を指定します。 SecuritySchemeType.HTTPを指定すると、Authorizationヘッダが使われるようになります。 したがって、この、(2)、(3)、(4)の記述により、

  Authorization: Bearer 

というHTTPヘッダが使われることになります。

@SecuritySchemeはスキーマを定義するものですが、 定義したスキーマを使うには、 (6)に記載のように、エンドポイントに対して、@SecurityRequirementを使用します。 nameパラメタには、対応する@SecuritySchemeのsecuritySchemeNameで指定した値を指定します。 また、(5)のように、適切なJWTをAPIに指定しなかった場合のレスポンスに関する説明も記述しておきます。

@SecuritySchemeと@SecurityRequirementを使用するように変更した上記アプリケーションを Swagger UIで見ると図4のようになります。

図4:セキュリティスキーマを使用
図4:セキュリティスキーマを使用


画面右側に、「Authorize」というボタンが新たに出現するようになりました。 このボタンを押すと、図5のオーソライズ情報入力画面が出現します。


図5:MP OpenAPIエンドポイント
図5:MP OpenAPIエンドポイント



このダイアログ画面には、@SecuritySchemeに記載したセキュリティ要件が表示され、 API利用者がセキュリティに必要な情報を入力することができます。 今回の例では、図6のように適切なJWTを入力します。

図6:JWTを入力
図6:JWTを入力


オーソライズ情報入力画面を閉じると、図4「セキュリティスキーマを使用」画面の右側に出ていた鍵のアイコンの絵が、 図7のように、開いていた状態から閉じた状態に変わります。

図7:鍵マーク
図7:鍵マーク

鍵が閉じた状態で、ユーザIDを指定し、リクエストを送信します(Executeボタンを押下)。 「Curl」の欄には、Authorizationヘッダが、指定したJWTとともに付与されていて、 HTTPステータスコードが200で、正常なレスポンスが返りました。

図8:正常な結果
図8:正常な結果


まとめ

本稿では、MicroProfile OpenAPIを使った、Jakarta RESTful Web Serivicesのアプリケーションのドキュメント化方法、 特にセキュリティスキーマ、また、Swagger UIでの検証方法について紹介しました。 セキュアなAPIの設計・ドキュメント化の際には、本稿で紹介した方法を参考にしてください。

本コンテンツに関するお問い合わせ

お電話でのお問い合わせ

富士通コンタクトライン(総合窓口)

0120-933-200

受付時間:9時~12時および13時~17時30分
(土曜日・日曜日・祝日・当社指定の休業日を除く)

Webでのお問い合わせ

当社はセキュリティ保護の観点からSSL技術を使用しております。

ページの先頭へ