JavaアプリケーションとOracle Identity Cloud Service間の認証について学習
Java WebアプリケーションとOracle Identity Cloud Service間の認証について学習する準備ができました。これには、次の内容の理解が含まれます。
-
Oracle Identity Cloud ServiceがJava SDKに対してサポートする3-legged認証フロー
-
JavaアプリケーションでSDKを使用してOracle Identity Cloud Serviceで認証する場合のユース・ケース
-
Java SDKのメソッドおよび関数
3-Legged認証フローについて学習
Oracle Identity Cloud Serviceでは、Java SDKの3-legged認証フローがサポートされています。このフローでは、ユーザーはOracle Identity Cloud Serviceと直接対話します。ユーザーがサインインすると、Oracle Identity Cloud Serviceは、SDKがユーザー・アクセス・トークンと交換する認可コードを発行します。Java Webアプリケーションでは、このアクセス・トークンを使用して、アプリケーション内の保護されたリソースへのアクセス権をユーザーに付与します。3-leggedフローでは、認可コード付与タイプが使用されます。
セキュリティを強化するために、Oracleでは、3-leggedフローを使用して、認証のためにJava WebアプリケーションをOracle Identity Cloud Serviceと統合することをお薦めします。認可コード付与タイプを使用すると、再認証しなくても、Oracle Identity Cloud Serviceによって保護されている他のアプリケーションにアクセスすることもできます。
JavaアプリケーションでSDKを使用するための主なユースケースについて学習
Java Webアプリケーションは、2つのユースケースを実装します。1つはユーザーの認証用、もう1つはログイン・ユーザーに関する詳細情報へのアクセス用です。
次のデータ・フロー図は、各ユース・ケースのWebブラウザ、WebアプリケーションおよびOracle Identity Cloud Service間のイベント、コールおよびレスポンスのフローを示しています。
ユースケース1: ユーザーの認証
データ・フローは次のようになります。
-
ユーザーが保護されたリソースをリクエストします。
-
認証モジュールは、SDKを使用してOracle Identity Cloud Serviceのrequest-authorization-code URLを生成し、このURLをWebブラウザへのリダイレクト・レスポンスとして送信します。
-
WebブラウザがURLをコールします。
-
Oracle Identity Cloud Serviceの「サインイン」ページが表示されます。
-
ユーザーがOracle Identity Cloud Serviceのサインイン資格証明を送信します。
-
ユーザーがサインインすると、Oracle Identity Cloud Serviceによってユーザーのセッションが作成され、認可コードが発行されます。
-
Webアプリケーションは、認可コードをアクセス・トークンと交換するためのバックエンド(またはサーバー間)呼出しを行います。
-
Oracle Identity Cloud Serviceは、アクセス・トークンとIDトークンを発行します。
-
セッションが確立され、ユーザーはホーム・ページにリダイレクトされます。
-
Webアプリケーションの「ホーム」ページが表示されます。
ユースケース2: ユーザーの詳細の取得
データ・フローは次のようになります。
-
ユーザーは
/myProfile
リソースをリクエストします。 -
Webアプリケーションは、Oracle Identity Cloud ServiceのSDKを使用してIDトークンを検証します。
-
IDトークン検証から返されるデータには、JSONオブジェクトの形式でユーザーの詳細が含まれます。
-
「マイ・プロファイル」ページでは、JSONオブジェクトがHTMLコンテンツとしてレンダリングされます。
メソッドおよび関数について学習
Java SDKは、Webアプリケーション・ライブラリとしてロードするJARファイルです。このJARファイルには、次のサード・パーティ・ライブラリが必要です。このライブラリもライブラリにロードする必要があります。
Java SDK zipファイルには、SDKに必要な次のサードパーティ・ライブラリが含まれています。アプリケーションにロードできます。
-
ASMヘルパーMinidev 1.0.2
-
Apache Commons Collections 4.1
-
Apache Commons Lang 3.7
-
JSON小規模および高速パーサー2.3
-
ニンバス LangTag 1.4.3
-
ニンバスJOSE+JWT 5.14
-
OAuth 2.0 SDK with OpenID Connect Extensions 5.30
Oracleには、Java SDKの使用方法を示すサンプルJava Webアプリケーションが用意されています。このアプリケーションは、Servletテクノロジを使用して構築され、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を使用してユーザーを認証する場合、スコープは |
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アプリケーションの登録を参照してください。 |
scope |
認証のOAuthまたはOpenID Connectスコープ。このアプリケーションでは、openid 認証のみが必要です。
|
state |
OAuthプロトコルは、このパラメータを定義します。サンプルJava Webアプリケーションでは、このコードを使用して、Oracle Identity Cloud Serviceへの通信を確立できるかどうかを確認します。この例では、このパラメータの値は1234 です。
|
response_type |
認可コード付与タイプに必要なパラメータ。この例では、このパラメータの値はcode です。
|
ユーザーがサインインすると、Oracle Identity Cloud Serviceは、開発者が実装する必要があるコールバックURLにユーザーのWebブラウザをリダイレクトします。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アプリケーションには/private/myProfile.jsp
という別の保護されたURLがあります。
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(" 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(" group = "+ group.getName() +"<br>");
}//for
}//if
%>
</p>
<p><b>Access Token:</b></p><p><%=access_token_string%></p>
アプリケーションとOracle Identity Cloud Service間のシングル・サインオンからユーザーをサインアウトするために、Java Webアプリケーションは、/logout
URLをマップするLogoutServlet
を実装します。
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にリダイレクトされます。