Java ApplicationsとOracle Identity Cloud Service間の認証について

Java WebアプリケーションとOracle Identity Cloud Service間の認証について理解する準備ができました。内容は次のとおりです。

  • Oracle Identity Cloud Service がJava SDKに対してサポートする3つのレグ認証フロー

  • Oracle Identity Cloud Serviceで認証するためにJavaアプリケーションでSDKを使用する場合

  • Java SDKのメソッドと関数

3方向認証フローについて

Oracle Identity Cloud Serviceでは、Java SDKの3つのlegged認証フローがサポートされます。このフローでは、ユーザーはOracle Identity Cloud Serviceと直接対話します。ユーザーのサイン・イン後、Oracle Identity Cloud Serviceは、SDKがユーザー・アクセス・トークンと交換する認可コードを発行します。Java Webアプリケーションでは、このアクセス・トークンを使用して、ユーザーにアプリケーション内の保護されたリソースへのアクセス権を付与します。3つのレグ化フローでは、認可コード付与タイプを使用します。

セキュリティを強化するために、Oracleは、Java Webアプリケーションを認証のためにOracle Identity Cloud Serviceと統合する3 leggedフローを使用することをお薦めします。認可コード権限タイプを使用することで、再認証を行わずにOracle Identity Cloud Serviceによって保護されている他のアプリケーションにアクセスすることもできます。

Java ApplicationでのSDKの使用について

Java Webアプリケーションでは、2つのユースケースが実装されます。1つは認証ユーザー用、もう1つはログイン・ユーザーに関する詳細情報へのアクセス用です。

次のデータ・フロー・ダイアグラムは、各ユースケースのWebブラウザ、WebアプリケーションおよびOracle Identity Cloud Service間のイベント、コールおよびレスポンスのフローを示しています。

ユースケース#1:ユーザーの認証

データ・フローの動作は次のとおりです。

  1. ユーザーが保護されたリソースをリクエストします。

  2. 認証モジュールでは、SDKを使用して、Oracle Identity Cloud Serviceのリクエスト認証コードURLを生成し、このURLをWebブラウザへのリダイレクト・レスポンスとして送信します。

  3. WebブラウザはURLを呼び出します。

  4. Oracle Identity Cloud Service Sign Inページが表示されます。

  5. ユーザーは、Oracle Identity Cloud Serviceサインイン資格証明を送信します。

  6. ユーザーのサイン・イン後、Oracle Identity Cloud Serviceはユーザーのセッションを作成し、認可コードを発行します。

  7. Webアプリケーションは、バックエンド(またはサーバー間)コールを行い、アクセス・トークンの認可コードを交換します。

  8. Oracle Identity Cloud Serviceでは、アクセス・トークンとidトークンが発行されます。

  9. セッションが確立され、ユーザーがホーム・ページにリダイレクトされます。

  10. Webアプリケーションのホーム・ページが表示されます。

ユースケース#2:ユーザーに関する詳細の取得

データ・フローの動作は次のとおりです。

  1. ユーザーが/myProfileリソースをリクエストします。

  2. Webアプリケーションでは、Oracle Identity Cloud ServiceのSDKを使用してIDトークンを検証します。

  3. Idトークン検証から返されるデータには、JSONオブジェクトの形式でユーザーの詳細が含まれます。

  4. 「プロファイル」ページでは、JSONオブジェクトがHTMLコンテンツとしてレンダリングされます。

メソッドと関数について

Java SDKは、Webアプリケーション・ライブラリとしてロードするJARファイルです。このJARファイルには、ライブラリにもロードする必要があるサード・パーティのライブラリが必要です。

Java SDK zipファイルには、SDKに必要な次のサード・パーティ・ライブラリが含まれています。アプリケーションにロードできます。

  • ASMヘルパー・ミニ開発1.0.2

  • Apache Commons Collections 4.1

  • Apache Commons Lang 3.7

  • JSON小および高速パーサー2.3

  • Nimbus LangTag 1.4.3

  • Nimbus JOSE + JWT 5.14

  • OAuth 2.0 SDK with OpenID Connect Extensions 5.30

Oracleでは、Java Webアプリケーションのサンプルを提供して、Java SDKの使用方法を説明します。このアプリケーションは、サーブレット・テクノロジを使用して作成され、Java SDKの仕組みを理解するために学習エクスペリエンスを簡素化したものです。アプリケーションでは、Mavenを使用してすべてのライブラリを取得し、Webアプリケーション・リソース(WAR)ファイルを生成します。

Java SDKでは、Oracle Identity Cloud Service接続情報にロードされるHashMapオブジェクトインスタンスが必要です。Java Webアプリケーションは、このHashMapインスタンスをConnectionOptions.javaクラス内のクラス属性として実装します。

//Instance of a HashMap.
    private Map<String,Object> options = new HashMap<>();
  
public ConnectionOptions(){
        this.options = new HashMap<>();
}
  
public Map<String,Object> getOptions(){
        //Adding Oracle Identity Cloud Service connection parameters to the HashMap instance.
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_HOST, "identity.oraclecloud.com");
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_PORT, "443");
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_CLIENT_ID, "123456789abcdefghij");
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_CLIENT_SECRET, "abcde-12345-zyxvu-98765-qwerty");
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_CLIENT_TENANT, "idcs-abcd1234");
        this.options.put(Constants.AUDIENCE_SERVICE_URL, "https://idcs-abcd1234.identity.oraclecloud.com");
        this.options.put(Constants.TOKEN_ISSUER, "https://identity.oraclecloud.com/");
        this.options.put(Constants.TOKEN_CLAIM_SCOPE, "urn:opc:idm:t.user.me openid");
        this.options.put("SSLEnabled", "true");
        this.options.put("redirectURL", "http://localhost:8080/callback");
        this.options.put("logoutSufix", "/oauth2/v1/userlogout");
        this.options.put(Constants.CONSOLE_LOG, "True");
        this.options.put(Constants.LOG_LEVEL, "DEBUG");
        return this.options;
    }

このSDKに必要な各属性の簡単な説明を次に示します。

名前 説明
IDCSTokenAssertionConfiguration.IDCS_HOST Oracle Identity Cloud Serviceインスタンスのドメイン接尾辞。
IDCSTokenAssertionConfiguration.IDCS_PORT Oracle Identity Cloud Serviceインスタンスに予約されているHTTPSポート番号(通常は443)。
IDCSTokenAssertionConfiguration.IDCS_CLIENT_ID Identity Cloud ServiceコンソールにJava Webアプリケーションを登録した後に生成されるクライアントIDの値。
IDCSTokenAssertionConfiguration.IDCS_CLIENT_SECRET Identity Cloud ServiceコンソールにJava Webアプリケーションを登録した後に生成されるクライアント・シークレットの値。
IDCSTokenAssertionConfiguration.IDCS_CLIENT_TENANT Oracle Identity Cloud Serviceインスタンスのドメイン接頭辞。通常、この接頭辞はidcs-abcd1234のような値です。
Constants.AUDIENCE_SERVICE_URL Oracle Identity Cloud Serviceインスタンスの完全修飾ドメイン名URL。
Constants.TOKEN_ISSUER この属性では、Oracleによって値https://identity.oraclecloud.comを保持することが推奨されます。
Constants.TOKEN_CLAIM_SCOPE

スコープにより、Oracle Identity Cloud Serviceユーザーにかわってアプリケーションがアクセスまたは処理できるデータが制御されます。

アプリケーションでSDKを使用してユーザーを認証する場合、有効範囲はopenidです。アプリケーションでSDKも使用してユーザーの詳細を取得する場合、有効範囲はurn:opc:idm:t.user.me openidです。

SSLEnabled Oracle Identity Cloud ServiceがHTTPSリクエストに応答するか、HTTPリクエストに応答するかを示します。この属性では、Oracleによって値trueを保持することが推奨されます。
Constants.CONSOLE_LOG SDKログを有効にします。
Constants.LOG_LEVEL SDKのログ・レベルを指定します。

これらの値のハードコードは、logoutSufix属性とredirectURL属性の両方を使用して回避されます。SDKでは必要ありません。

Java Webアプリケーションは、/auth URLをマップするAuthServletクラスを実装します。ユーザーがOracle Identity Cloud Serviceでの認証を決定すると、WebブラウザはこのURLへのリクエストを行います。AuthServletクラスによってAuthentication Managerオブジェクトが初期化され、Java SDKを使用してOracle Identity Cloud Serviceの認可コードURLが生成され、WebブラウザがこのURLにリダイレクトされます。

public class AuthServlet extends HttpServlet {
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Loading the configurations
        Map<String, Object> options = new ConnectionOptions().getOptions();
        //Configuration object instance with the parameters loaded.
        IDCSTokenAssertionConfiguration config = new IDCSTokenAssertionConfiguration(options);
	String redirectUrl = (String)options.get("redirectURL");
        String scope = (String)options.get(Constants.TOKEN_CLAIM_SCOPE);
        //Authentication Manager loaded with the configurations.
        AuthenticationManager am = AuthenticationManagerFactory.getInstance(config);
        //Using Authentication Manager to generate the Authorization Code URL, passing the
        //application's callback URL as parameter, along with code value and code parameter.
        String authzURL = am.getAuthorizationCodeUrl(redirectUrl, scope, "1234", "code");
        //Redirecting the browser to the Oracle Identity Cloud Service Authorization URL.
        response.sendRedirect(authzURL);
    }
}

次のパラメータを使用して、認可コードURLを生成します。

名前 説明
redirectUrl ユーザーがサインインすると、Oracle Identity Cloud ServiceによってユーザーのWebブラウザがこのURLにリダイレクトされます。このURLは、Identity Cloud Serviceコンソールで信頼できるアプリケーション用に構成するURLと一致している必要があります。Java WebアプリケーションのリダイレクトURLの指定の詳細は、「Java Applicationの登録」を参照してください。
scope 認証のOAuthまたはOpenID Connectスコープ。このアプリケーションに必要なのはopenid認証のみです。
state OAuthプロトコルは、このパラメータを定義します。サンプルのJava Webアプリケーションでは、このコードを使用して、Oracle Identity Cloud Serviceに通信を確立できるかどうかをチェックします。この例では、このパラメータの値は1234です。
response_type 承認コード権限タイプで必要なパラメータ。この例では、このパラメータの値はcodeです。

ユーザーのサインイン後、Oracle Identity Cloud ServiceはユーザーのWebブラウザをコールバックURLにリダイレクトします。このURLは開発者が実装する必要があります。JavaのWebアプリケーションでは、CallbackServletを使用してこのリクエストを処理します。

public class CallbackServlet extends HttpServlet {
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Loading the configurations
        Map<String, Object> options = new ConnectionOptions().getOptions();
        //After Oracle Identity Cloud Service authenticates the user, the browser is redirected to the
        //callback URL, implemented as a Servlet.
        IDCSTokenAssertionConfiguration config = new IDCSTokenAssertionConfiguration(options);
        //Authentication Manager loaded with the configurations.
        AuthenticationManager am = AuthenticationManagerFactory.getInstance(config);
        //Getting the authorization code from the "code" parameter
        String authzCode = request.getParameter("code");
        //Using the Authentication Manager to exchange the Authorization Code to an Access Token.
        AuthenticationResult ar = am.authorizationCode(authzCode);
        //Getting the Access Token object and its String value.
        AccessToken access_token = ar.getToken(OAuthToken.TokenType.ACCESS_TOKEN);
        String access_token_string = access_token.getToken();
        //Getting the ID Token object and its String value.
        IdToken id_token = ar.getToken(OAuthToken.TokenType.ID_TOKEN);
        String id_token_string = id_token.getToken();
        //Validating both Tokens to acquire information for User such as UserID, 
        //DisplayName, list of groups and AppRoles assigned to the user.
        IdToken id_token_validated = am.validateIdToken(id_token_string);
        //Storing information into the HTTP Session.
        HttpSession session=request.getSession();
        session.setAttribute("access_token", access_token_string);
        session.setAttribute("id_token", id_token_string);
        session.setAttribute("userId", id_token_validated.getUserId());
        session.setAttribute("displayName", id_token_validated.getDisplayName());
	//Forwarding the request to the Home page.
        request.getRequestDispatcher("private/home.jsp").forward(request, response);
    }
}	

アプリケーションが認可コード・パラメータをリクエストし、それを使用してJava SDKのAuthenticationManager.authorizationCode()メソッドをコールし、アクセス・トークンとidトークンの両方をリクエストします。サーブレットは次に、AuthenticationManagerインスタンスを使用してidトークンを検証します。AuthenticationManager.validateIdToken()メソッドは、表示名、ユーザーid、ユーザーに割り当てられたグループとアプリケーション・ロールのリストなどのユーザー情報を含むIdTokenオブジェクトのインスタンスを返します。アクセス・トークンとIdトークンの両方の値、および一部のユーザー情報がHTTPセッション・オブジェクトに格納されて、/private/home.jspというアプリケーション内の保護されたURLにリクエストを転送できます。/private/home.jspに加えて、Java Webアプリケーションには、別の保護されたURLsがあります: /private/myProfile.jsp

myProfile.jsp」ページでは、次のサンプル・コードを使用して、Oracle Identity Cloud Serviceにサインインしたユーザーに関する詳細情報を取得します。


<%if(session.getAttribute("access_token")==null) response.sendRedirect("/login.html");%>
<!DOCTYPE html>
<%
/**
 * The /private/myProfile.jsp page accesses the user's access token previously set in the session, 
 * calls the getAuthenticatedUser method to retrieve the user's information, and then formats it as HTML.
 * @author felippe.oliveira@oracle.com
 * @Copyright Oracle
*/
  java.util.Map<String, Object> options = new sampleapp.util.ConnectionOptions().getOptions();
  //Configuration object instance with the parameters loaded.
  oracle.security.jps.idcsbinding.shared.IDCSTokenAssertionConfiguration configuration = new oracle.security.jps.idcsbinding.shared.IDCSTokenAssertionConfiguration(options);
  oracle.security.jps.idcsbinding.shared.AuthenticationManager am = oracle.security.jps.idcsbinding.shared.AuthenticationManagerFactory.getInstance(configuration);
  
  //Getting the Access Token and the Id Token from the session object
  String access_token_string = (String)session.getAttribute("access_token");
  String id_token_string = (String)session.getAttribute("id_token");

  //Validating the ID Token to get user information, groups and app roles associated with the user.
  oracle.security.jps.idcsbinding.api.AccessToken access_token_validated = am.validateAccessToken(access_token_string);
  oracle.security.jps.idcsbinding.api.IdToken id_token_validated = am.validateIdToken(id_token_string);
%>

/private/myProfile.jsp」ページでは、セッションに設定されたidトークン値にアクセスし、AuthenticationManager.validateIdToken()メソッドをコールしてユーザーの情報を取得し、HTMLコンテンツとして表示します。


<p><b>Information from the Identity Token:</b></p><p><%
out.println("DisplayName = "+ id_token_validated.getDisplayName() +"<br>");
out.println("IdentityDomain = "+ id_token_validated.getIdentityDomain() +"<br>");
out.println("UserName = "+ id_token_validated.getUserName()+"<br>");
out.println("UserId = "+ id_token_validated.getUserId()+"<br>");
out.println("Issuer = "+ id_token_validated.getIssuer()+"<br>");

java.util.List<oracle.security.jps.idcsbinding.api.IDCSAppRole> appRoles = id_token_validated.getAppRoles();
if(!appRoles.isEmpty()){
   out.println("App Roles:<br>");
   for(oracle.security.jps.idcsbinding.api.IDCSAppRole appRole: appRoles){
      out.println("&nbsp;appRole = "+ appRole.getName() +"<br>");
   }//for
}//if

java.util.List<oracle.security.jps.idcsbinding.api.IDCSGroup> groups = id_token_validated.getGroupMembership();
if(!groups.isEmpty()){
   out.println("Groups:<br>");
   for(oracle.security.jps.idcsbinding.api.IDCSGroup group: groups){
      out.println("&nbsp;group = "+ group.getName() +"<br>");
   }//for
}//if
%>
</p>
<p><b>Access Token:</b></p><p><%=access_token_string%></p>

アプリケーションとOracle Identity Cloud Serviceの間のシングル・サインオンからユーザーにサイン・アウトするには、Java WebアプリケーションによってLogoutServletが実装され、これにより/logout URLがマップされます。

public class LogoutServlet extends HttpServlet {
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session=request.getSession();
        String id_token = (String)session.getAttribute("id_token");
        session.invalidate();
        Map options = new ConnectionOptions().getOptions();
        String logoutURL = (String)options.get(Constants.AUDIENCE_SERVICE_URL) + (String)options.get("logoutSufix") +"?post_logout_redirect_uri=http%3A//localhost%3A8080&id_token_hint="+ id_token;
        response.sendRedirect(logoutURL);
    }
}

このサーブレットは、アプリケーションのセッションを無効化し、ユーザーのWebブラウザをOracle Identity Cloud ServiceのOAuthログアウトURLにリダイレクトします。