2 アクセス・クライアントの開発
この章では、カスタム・アクセス・クライアントの開発方法と次の項目について説明します。
2.1 アクセス・クライアントの開発について
Access Managerでは、用意されているJava Access SDKやAccess Manager APIを使用して、独自のアクセス・クライアント、カスタム認証プラグイン、カスタム・ログイン・ページおよびカスタム・エラー・ページを作成したり、Access Managerポリシーをプログラムによって管理できるほか、偽装機能を有効化したり、管理用カスタム・ユーザー・インタフェースを開発できます。
WebGateは、リソースに対するHTTPリクエストを捕捉して、認証と認可のためにOAMサーバーに転送するWebサーバー・プラグインです。WebGateは、アクセス・リクエストに対する実際の強制ポイントとして機能するWebサーバー・エージェントです。複数のWebGateがそのまま使用できる状態で用意されており、アクセス・リクエストを捕捉するOracle HTTP Serverにインストールできます。
アクセス・クライアントとは、12c Access SDKおよびAPIを使用して開発されたカスタムWebGateのことです。標準のWebGateが適切でない場合は、カスタム・アクセス・クライアントを記述してデプロイすることにより、WebリソースまたはWeb以外のリソース(HTTP以外)に対するユーザーまたはアプリケーションからのリクエストを処理できます。
この項では次のトピックを記載しています:
2.1.1 Access SDKおよびAPIについて
Access SDKは、オラクル社が様々なエンタープライズ・プラットフォーム(32ビットおよび64ビットの両方のモードを使用)およびハードウェアの組合せで認証した、プラットフォーム非依存パッケージです。
12c Access SDKは、密結合されている高パフォーマンスの統合の開発においてJavaアプリケーション開発者が使用するためのものです。これは、Oracle Fusion Middlewareアプリケーション間でサポートされているJDKバージョンで提供されています。詳細は、このガイドの他にOracle Fusion Middleware Oracle Access Management Access Manager Access SDK Java APIリファレンスを参照してください。
ノート:
開発者はあらゆる新規開発において12c Access SDKを使用することを強くお薦めします。
次のAccess APIが含まれています。
-
oracle.security.am.asdk: 12c OAMサーバー機能を利用するための拡張機能を提供する認証および認可API。12c Access SDK APIは、Oracle Access Manager 12cバージョンのサーバーと併用できます。
ノート:
oracle.security.am.asdk
パッケージでは、12c Java APIを提供しています。12cバージョンは以前のリリースのAPIと非常によく似ており、12c OAMサーバーと併用するための拡張機能が備わっています。機能的な観点からすると、12c Access SDKは、以前のリリースである11g Access SDKのパリティを維持しており、12c APIレイヤーを使用して既存のカスタム・コードを記述しなおすことができます。
12c Access SDKには、認証および認可機能が組み込まれています。ただし、管理APIは組み込まれていません(たとえば、12cポリシー・マネージャAPIはありません)。
Access SDKの最も一般的な用途は、Access Managerとその他のアプリケーション(Oracleまたはサード・パーティ)とのカスタム統合の開発を可能にすることです。使用例を次に示します。
-
Oracleがデフォルトで統合を提供していないWebサーバーまたはアプリケーション・サーバー用のカスタム・アクセス・クライアントの開発。
-
Access Manager認証プロセスの一部として格納される可能性があるセッション情報へのアクセス。
-
ユーザー・プリンシパルのHTTPヘッダーを信頼せず、Access ManagerセッションCookieの有効性を確認。
表2-1では、12c Access SDKの主な機能について説明します。
表2-1 12c Access SDKの機能
機能 | 説明 |
---|---|
インストール |
クライアント・パッケージ: oamasdk-api.jarおよび12cエージェントの動作に必要なその他のJPS jarファイルを格納した1個のzipファイルで構成されています。サポート・ファイル(署名およびTLSネゴシエーション用)は含まれておらず、個別に生成する必要があります。 サーバー関連コード: コアAccess Managerサーバー・インストールの一部として組み込まれています。 ノート: Oracle Access Manager 11gで開発されたアクセス・クライアントおよびプラグインは12cリリースで使用できます。Oracle Access Manager 11gバンドル・パッチは、12c環境で使用するためのJava SDKコード拡張機能を配布する目的で使用します。 |
組込みバージョニング |
次のことが可能です。
|
ロギング |
Access SDKロギング・メカニズムにより、ローカル・ファイルに表示する詳細のレベル(情報、警告およびエラーの各レベル)を指定できます。メッセージは、問題を解決するための十分な詳細を提供します。たとえば、互換性のないAccess SDKパッケージが使用されている場合、ログ・メッセージには、バージョン不一致に関する詳細と、遵守する必要があるバージョン基準が含まれます。 SDKが指定期間内に大量のログを生成した場合、ファイル制限または期間に基づいてログのロールオーバーを構成できます。たとえば、ファイル制限に達した場合(または一定時間が経過した場合)、ログ・ファイルはアーカイブ・ディレクトリにコピーされ、新規ログ・ファイルが開始されます。 |
2.1.2 カスタム・アクセス・クライアントについて
アクセス・クライアントAPIのすべてまたはサブセットを使用することで、目的の機能に応じて、様々なタイプのカスタム・アクセス・クライアントを開発できます。APIは通常、ユーザーとの通信に使用される保護されたリソースおよびネットワーク・プロトコルのタイプは認識しません。たとえば、HTTPプロトコルの詳細およびHTTP Cookieの用途はAccess SDKの範囲外です。非HTTPリソースを保護するアクセス・クライアントは、HTTPリソースを保護するエージェントと同じくらい容易に開発できます。
Access SDKを使用すると、認証、認可、監査など保護されたリソースへのアクセスを制御する目的で、Access Managerとのカスタム統合を開発できます。通常このアクセス制御を実現するには、Access SDKランタイムとインタフェースするためのAccess Client APIを起動するアプリケーションまたはプラグインであるカスタム・アクセス・クライアントを開発およびデプロイします。
アクセス・クライアント側のキャッシュがAccess SDKランタイム内で内部的に使用され、処理オーバーヘッドがさらに抑えられます。Access SDKランタイムとOAMサーバーの連携により、動的構成管理が透過的に実行され、それによって、管理コンソールで行ったアクセス・クライアント構成の変更が、対象となるAccess SDKランタイムに自動的に反映されます。
カスタム・アクセス・クライアント単独で、または他のアクセス・クライアントと組み合せて実行できる一般的な機能は、次のとおりです。
-
資格証明をAccess Managerおよびその構成済ユーザー・リポジトリに対して検証してユーザーを認証します。
-
ユーザーを認証し、リソースへのアクセスについて認可の有無をチェックします。
-
ユーザーを認証し、セッション・トークンで表された一意のAccess Managerセッションを作成します。
-
ユーザーにより提供されたセッション・トークンを検証し、保護されたリソースへのユーザーのアクセス権を認可します。
-
セッション・トークンまたは名前付きセッション識別子がある場合は、Access Managerセッションを終了します。
-
名前付きユーザー識別子を指定し、指定ユーザーのAccess Managerセッションを列挙します。
-
Access Managerのカスタム・セッション属性を保存または取得します。
アクセス・クライアントの一部の操作は、指定されたアクセス・クライアント・インスタンスによる使用に制限されています。例については、Oracle Fusion Middleware Oracle Access Management Access Manager Access SDK Java APIリファレンスのOperationNotPermittedに関する項
を参照してください。
アクセス・クライアントは、OAMサーバーで保護されたLDAPドメイン内のリソースへのユーザーのアクセス・リクエストを処理します。一般的には、リソース・リクエストを受け取るサーブレット(プラグイン)またはスタンドアロン・アプリケーションにカスタム・アクセス・クライアント・コードを埋め込みます。このコードは、Access Manager APIライブラリを使用して、OAMサーバー上での認証および認可サービスを実行します。
リソースが保護されていない場合、アクセス・クライアントはリクエストされたリソースに対する自由なアクセスをユーザーに許可します。リソースが保護されていて、ユーザーがアクセスを得るために特定の資格証明を提示できるように認可されている場合は、アクセス・クライアントがそのユーザー資格証明の取得を試み、OAMサーバーが資格証明を確認できるようにします。ユーザーの認証とリソースへの認可が成功すると、アクセス・クライアントは、ユーザーがリソースを利用できるようにします。アクセス・クライアントには、表2-2に示すように各種要素に応じてバリエーションがあります。
表2-2 アクセス・クライアントのバリエーション
バリエーション | 説明 |
---|---|
アプリケーションのタイプ |
スタンドアロン・アプリケーション対サーバー・プラグインです。 |
開発言語 |
各開発言語により、APIの基礎となる機能へのインタフェースを選択できます。 12cでは、Javaがカスタム・アクセス・クライアントの唯一の開発言語です。 |
リソース・タイプ |
HTTPおよびHTTP以外の両方のリソースを保護します。 |
資格証明の取得 |
他のメソッド間における、HTTPフォーム・ベース入力、セッション・トークンの使用およびコマンド行入力を有効にします。 |
記述およびデプロイされたカスタム・アクセス・クライアントは、標準のWebGateと同じようにOracle Access Management管理者が管理します。管理コンソールを使用したカスタム・アクセス・クライアントの管理の詳細は、リソース・タイプおよびその使用に関する項を参照してください。
関連項目:
2.1.2.1 カスタム・アクセス・クライアントを作成するケース
一般に、Oracle Access Managerによってまだデフォルト・ソリューションが用意されていないリソースへのアクセスを制御する必要がある場合に、標準のWebゲートのかわりに、カスタム・アクセス・クライアントをデプロイします。これには次のような場合が含まれます。
-
HTTP以外のリソースの保護。
-
特殊機能を実装するために開発したカスタムWebサーバーの保護(リバース・プロキシなど)。
-
HTTPとHTTP以外のリソースの組合せを保護するためのシングル・サインオン(SSO)の実装。
たとえば、Oracle WebLogic ServerクラスタおよびOracle WebLogic Server以外のリソースが含まれる企業環境内でのSSOを容易にするアクセス・クライアントを作成できます。
2.1.2.2 アクセス・クライアントのアーキテクチャのリソースのタイプ
各アクセス・クライアントは、次の3種類のリソースから構築されます。
-
カスタム・アクセス・クライアント・コード
サーブレットまたはスタンドアロン・アプリケーションに組み込まれます。12cリリースでは、Java言語プラットフォームを使用してアクセス・クライアント・コードを記述します。
-
構成情報。
-
ObAccessClient.xmlファイル: プライマリ構成ファイル。アクセス・クライアント・プロファイルを構成する構成情報が格納されています。
-
cwallet.ssoおよびjps-config.xmlファイル: 12cエージェントの場合のみ。
-
トランスポート・セキュリティ・モードが簡易または証明書の場合、次のファイルが必要です。
-
oamclient-truststore.jks – 証明書発行局のCA証明書が含まれるJKS形式の信頼ストア・ファイル。
-
oamclient-keystore.jks – アクセス・クライアントに対して発行された証明書および秘密キーが含まれるJKS形式のキー・ストア・ファイル。
-
password.xml – グローバル・パス・フレーズの値を保持するXMLファイル。秘密キー・ファイルを保護する際にも同じパスワードが使用されます。
-
-
-
Access Manager APIライブラリ
アクセス・クライアントとOAMサーバー間の連携を可能にします。
図2-1は、ホスト・サーバーにインストールされたアクセス・クライアント・コンポーネント間の関係を示しています。
2.1.3 アクセス・クライアントのリクエスト処理について
「アクセス・クライアントのアーキテクチャのリソースのタイプ」で説明しているリソースのタイプにより生じる多様性にかかわらず、アクセス・クライアントの多くは同じ基本ステップに従ってユーザー・リクエストを処理します。ユーザーまたはアプリケーションが、アクセス・クライアントがインストールされているサーバー上で動作するサーブレットまたはアプリケーションに対してリソース・リクエストを発行すると、そのサーブレットまたはアプリケーションに埋め込まれたアクセス・クライアント・コードが図2-2に示す基本プロセスを開始します。図の下に、プロセス概要の詳細の説明を示します。
-
アクセス・クライアント・コードが埋め込まれているアプリケーションまたはサーブレットが、ユーザーのリソース・リクエストを受け取ります。
-
アクセス・クライアントにより、
ResourceRequest
構造体が構成されます。この構造体は、リクエストされたリソースが保護されているかどうかをアクセス・クライアント・コードがOAMサーバーに問い合せるために使用されます。 -
OAMサーバーが応答します。
-
状況に応じて、次のいずれかが発生します。
-
リソースが保護されていない場合、アクセス・クライアントは
DenyOnNotProtected
フラグの値に基づいて、リソースに対するアクセス権を付与または拒否します。デフォルト値はtrueです。Access Manager 12cエージェントの場合、
DenyOnNotProtected
フラグは常にtrueであり、変更できません。 -
リソースが保護されている場合、アクセス・クライアントが
AuthenticationScheme
構造体を構成、使用して、ユーザーがどの資格証明を提示する必要があるかをOAMサーバーに問い合せます。このステップは、アクセス・クライアントでリソース別の認証スキームを使用できる場合にのみ必要です。
-
-
OAMサーバーが応答します。
-
アプリケーションは、フォームまたはその他の手段を使用してユーザー資格証明を要求します。場合によっては、ユーザー資格証明が次の一部としてすでに発行されていることがあります。
-
有効なセッション・トークン
-
Webブラウザからの入力
-
アクセス・クライアント・アプリケーションを起動したコマンド行スクリプトの引数またはキーボード入力
-
-
ユーザーがアプリケーションに応答します。
-
アクセス・クライアントにより
UserSession
構造体が構成され、この構造体を通して、OAMサーバーはユーザー資格証明を取得し、資格証明をOracle Access Managerユーザー・ディレクトリ内のユーザー・プロファイルにマップします。 -
資格証明が有効と判定されると、アクセス・クライアントがユーザーのセッション・トークンを作成し、認可リクエストをOAMサーバーに送信します。このリクエストには、ユーザーID、ターゲット・リソースの名前およびリクエストされた操作が含まれています。
Access SDKを使用して開発されたアクセス・クライアントの場合、SSOトークンが名前なしの文字列型として発行されます。既存の
UserSession
オブジェクトに対してgetSessionToken()
を使用すると、そのセッションのトークンが返されます。既存のトークンがある場合は、そのトークンを使用してユーザー・セッション・オブジェクトを構成できます。トークンは暗号化されおり、ユーザーには理解できませんが、内部的には11g形式または12c形式になっています。 -
アクセス・クライアントはリソースへのアクセス権をユーザーに付与しますが、これはユーザーがリクエストした特定のリソースに対する操作を行う権限がある場合に限られます。
図2-2に示したフローは、認可プロセスのメイン・パスのみを表しています。その後に分岐する次の場合については、通常、サーブレットまたはアプリケーション内の追加コード部分によって処理されます。
-
リクエストされたリソースが保護されていない場合。
-
保護されたリソースに関連付けられている認証チャレンジ・メソッドがアプリケーションでサポートされていない場合。
-
ユーザーが、指定された条件で有効な資格証明を提示できなかった場合。
-
その他のエラー状態が発生した場合。
-
特殊な状況や機能を処理するために、開発者がアクセス・クライアントに追加のカスタム・コードを組み込んである場合。
カスタム・アクセス・クライアントを記述する場合、ユーザーをバックチャネル経由で認証できます。
2.2 Access SDKのインストール
Java Access SDK Client for Access Manager 12cをインストールするには、次のステップを実行します。
Access SDKのインストール後は、サブディレクトリおよびファイルの相対的な場所を変更しないでください。変更すると、APIが正しくビルドおよび操作できなくなります。
2.3 アクセス・クライアントの開発
Access Managerでは、用意されているJava Access SDKやAccess Manager APIを使用して、独自のアクセス・クライアント、カスタム認証プラグイン、カスタム・ログイン・ページおよびカスタム・エラー・ページを作成したり、Access Managerポリシーをプログラムによって管理できるほか、偽装機能を有効化したり、管理用カスタム・ユーザー・インタフェースを開発できます。
この項の内容は、次のとおりです。
2.3.1 アクセス・クライアントの構造の理解
一般的なアクセス・クライアント・アプリケーションの構造は、アクセス・クライアント・セッションの設定に必要な一連のイベントを大まかにミラー化しています。
-
必要なライブラリをインクルードまたはインポートします。
-
リソースを取得します。
-
認証スキームを取得します。
-
認証スキームに必要となるユーザー資格証明を収集します。
-
ユーザー・セッションを作成します。
-
リソースに対するユーザー認可をチェックします。
-
クリーン・アップします(Javaは自動ガベージ・コレクションを使用)。
-
停止します。
2.3.2 アクセス・クライアントの一般的な実行フローの理解
HTTPフォーム・ベースのアクセス・クライアントのアプリケーションとプラグインは、すべて同じ基本パターンを実行します。図2-3は、フォーム・ベースのアプリケーションのプロセス・フローを示しています。次の図に詳細の説明を示します。
-
ライブラリをインポートします。
-
SDKを初期化します。
-
ResourceRequest
オブジェクトを作成します。 -
リクエストされたリソースが保護されているかどうかを判別します。
リソースが保護されていない場合: リソースが保護されていない場合、アクセス・クライアントは
DenyOnNotProtected
フラグの値に基づいて、リソースに対するアクセス権を付与または拒否します。デフォルト値はtrue
です。Access Managerエージェントの場合、DenyOnNotProtected
フラグは常にtrue
であり、変更できません。 -
リクエストされたリソースが保護されている場合:
AuthenticationScheme
オブジェクトを作成します。 -
HTTPフォーム・ベースの認証スキームの場合: ユーザーIDとパスワードを含む構造体を作成し、
UserSession
オブジェクトを作成して、ユーザーが認証されるかどうかを判定します。 -
HTTPフォーム・ベースでない認証スキームの場合: アクセスを拒否して理由を報告し、APIを停止し、プログラムを終了します。
-
ユーザーが認証された場合: ユーザーが認可されるかどうかを判定します(ステップ10)。
-
ユーザーが認証されていない場合: アクセスを拒否して理由を報告し、APIを停止し、プログラムを終了します。
-
ユーザーが認可された場合: アクセスを許可し、APIを停止し、プログラムを終了します。
-
ユーザーが認可されなかった場合: アクセスを拒否して理由を報告し、APIを停止し、プログラムを終了します。
ノート:
このテスト・アプリケーション、あるいはその他のいずれかの例を実行する場合、アクセス・システムが正しくインストールおよび設定されていることを確認してください。特に、サンプル・プログラムで必要とされるURLと認証スキームに完全に一致するリソースが保護されるように構成されているかどうかを確認してください。アプリケーション・ドメインの作成およびアプリケーション・ドメインによるリソースの保護の詳細は、新しいアプリケーション・ドメインの作成に関する項を参照してください。
2.3.3 サンプル・コード: 簡単なアクセス・クライアント
この例は、簡易アクセス・クライアント・プログラムです。これは、動作中のアクセス・クライアントに必要な最小限のタスクの実装方法を示しています。
-
OAMサーバーに接続します。
-
HTTPフォーム・チャレンジ・メソッドを採用した認証スキームを使用してログインします。
-
HTTP GETリクエストを使用してリソースの認証を確認します。
-
Access SDK APIの例外を捕捉およびレポートします。
通常、このコール順序は、フォーム・チャレンジ・メソッドを使用するアクセス・クライアントに共通です。フォーム・メソッドのアクセス・クライアント間の主な違いは、認証に必要な資格証明と保護するリソース・タイプです。
JAccessClient.java
の完全なリストは例2-1に示しています。このコードをテキスト・ファイルJAccessClient.java
に一字一句すべてコピーし、Access Manager SDKがインストールされているコンピュータ上でこれを実行できます。
この例の注釈付きバージョンは、「注釈付きサンプル・コード: 簡単なアクセス・クライアント」を参照してください。これにより、12c Java Access Manager APIコールに慣れることができます。
例2-1 JAccessClient.java
import java.util.Hashtable; import oracle.security.am.asdk.*; public class JAccessClient { public static final String _resource = "//Example.com:80/secrets/ index.html"; public static final String _protocol = "http"; public static final String _method = "GET"; public static final String _login = "jsmith"; public static final String _passwd = "j5m1th"; public static final String m_configLocation = "/myfolder"; public static void main(String argv[]) { AccessClient ac = null; try { ac = AccessClient.createDefaultInstance(m_configLocation, AccessClient.CompatibilityMode.OAM_11G); ResourceRequest rrq = new ResourceRequest( _protocol, _resource, _method); if (rrq.isProtected()) { System.out.println("Resource is protected."); AuthenticationScheme authnScheme = new AuthenticationScheme(rrq); if (authnScheme.isForm()) { System.out.println("Form Authentication Scheme."); Hashtable creds = new Hashtable(); creds.put("userid", _login); creds.put("password", _passwd); UserSession session = new UserSession(rrq, creds); if (session.getStatus() == UserSession.LOGGEDIN) { if (session.isAuthorized(rrq)) { System.out.println("User is logged in and authorized for the" +"request at level " + session.getLevel()); } else { System.out.println("User is logged in but NOT authorized"); } //user can be loggedout by calling logoff method on the session object } else { System.out.println("User is NOT logged in"); } } else { System.out.println("non-Form Authentication Scheme."); } } else { System.out.println("Resource is NOT protected."); } } catch (AccessException ae) { System.out.println("Access Exception: " + ae.getMessage()); } ac.shutdown(); } }
2.3.4 注釈付きサンプル・コード: 簡単なアクセス・クライアント
資格証明を保持する標準Javaライブラリ・クラス・ハッシュテーブルをインポートします。
import java.io.Hashtable;
Access SDK APIクラスのJava実装が含まれるライブラリをインポートします。
import oracle.security.am.asdk.*;
このアプリケーションにJAccessClient
と命名します。
public class JAccessClient {
このアプリケーションは最も単純な例のため、リソースへのユーザー・アクセス・リクエストに関連したパラメータを表すためにグローバル定数を宣言することとします。
このパラメータ・セットは、実際のアプリケーションでは通常、リクエスト元アプリケーション、HTTPフォーム入力またはコマンド行入力から渡される文字列の配列として受信されます。たとえば:
public static final String _resource = "//Example.com:80/secrets/index.html"; public static final String _protocol = "http"; public static final String _method = "GET"; public static final String _login = "jsmith"; public static final String _passwd = "j5m1th";
Javaインタプリタ上でメイン・メソッドを起動します。argv
という名前の文字列配列がメイン・メソッドに渡されます。この例では、jsmith
というユーザーが、j5m1th
というパスワードを使用して、HTTPリソースの//Example.com:80/secrets/index.html
をリクエストします。GETは、リクエスト先リソースに対して実行するHTTP操作です。サポートされているHTTP操作およびアプリケーション・ドメインによるリソースの保護の詳細は、アプリケーション・ドメインのリソースに関する項を参照してください。
public static void main(String argv[]) {
メイン・メソッド内のすべての関連するプログラム文をtryという大きなブロック内に配置し、プログラム終了までにすべての例外をこの捕捉用ブロックで捕捉できるようにします。
AccessClient ac = null; try {
Access SDKを初期化するために、ObAccessClient.xml
構成ファイルのディレクトリの場所を指定して、AccessClient
インスタンスを作成します。Access SDKを初期化するための構成場所を指定するには複数の方法があります。詳細は、Oracle Fusion Middleware Oracle Access Management Access Manager Access SDK Java APIリファレンスを参照してください。
AccessClient
のインスタンスによってAccess SDK APIが初期化されます。AccessClientインスタンスがOAM_11gモードで作成される場合は、11gエージェント・プロファイルを使用する必要があります。同様に、AccessClientインスタンスがOAM_12cモードで作成される場合は、12cエージェント・プロファイルを使用する必要があります。AccessClient.CompatibilityMode.OAM_11G
は、11gと12c両方のサーバーと互換性のある古い11gエージェント・モードで動作するようにAccess SDKを初期化することを示しています。デフォルトでは、この互換性モードを指定しないと、デフォルトのOAM_12c
が使用されます。この場合、エージェントは12cエージェント・モードで動作し、12c OAMサーバーとしか対話できません。
ac = AccessClient.createDefaultInstance(m_configLocation , AccessClient.CompatibilityMode.OAM_11G);
ResourceRequest
コンストラクタを次の3つのパラメータとともに使用して、rrq
という名前の新規のリソース・リクエスト・オブジェクトを作成します。
-
_protocol: リクエストするリソースのタイプを示します。未指定の場合、デフォルト値はHTTPです。使用可能な値としてEJBもありますが、ここでの例にはこれは使用しません。カスタム・リソース・タイプの作成に関する項で説明されているように、カスタム・タイプを作成することもできます。
-
_resource: リソース名です。この特定の例でリクエストされたリソース・タイプはHTTPであるため、次のようにリソース名の先頭にホスト名およびポート番号を追加することは有効です。
//Example.com:80/secrets/index.html
-
_method: リソースに対して実行する操作のタイプです。リソース・タイプがHTTPの場合、指定可能な操作はGETとPOSTです。EJBタイプのリソースでは、操作はEXECUTEにかぎります。カスタム・リソース・タイプの場合、リソース・タイプを設定する際に、許可する操作を定義します。リソース・タイプの定義およびアプリケーション・ドメインによるリソースの保護の詳細は、リソース・タイプの管理に関する項を参照してください。
ResourceRequest rrq = new ResourceRequest(_protocol, _resource, _method);
リクエスト先リソースrrq
が認証スキームによって保護されているかどうかを確認します。
if (rrq.isProtected()) {
リソースが保護されている場合は、そのことをレポートします。
System.out.println("Resource is protected.");
AuthenticationScheme
コンストラクタを使用して、authnScheme
という名前の認可スキーム・オブジェクトを作成します。リソース・リクエストrrq
を指定し、この特定のリソースに特定の認可スキームが関連付けられているかどうかを、AuthenticationScheme
に確認させます。
AuthenticationScheme authnScheme =new AuthenticationScheme(rrq);
フォーム・ベースの認可スキームが使用されているかどうかを判別します。
if (authnScheme.isForm()) {
認可スキームがチャレンジ・メソッドとしてHTTPフォームを使用している場合、そのことを報告してから、ユーザー名(userid
)およびユーザー・パスワード(password
)を表すname:value
ペアを保持するための、creds
という名前のハッシュテーブルを作成します。_login
および_passwd
の値をハッシュテーブルに読み込みます。
System.out.println("Form Authentication Scheme."); Hashtable creds = new Hashtable(); creds.put("userid", _login); creds.put("password", _passwd);
UserSession
コンストラクタを使用して、sessionという名前のユーザー・セッション・オブジェクトを作成します。リソース・リクエストをrrq
に、認証スキームをcreds
に指定して、認証試行が成功したかどうかを示す状態情報が含まれる新規の構造体をUserSession
が戻すようにします。
UserSession session = new UserSession(rrq, creds);
UserSession
状態情報に対してgetStatus
メソッドを起動し、ユーザーが正常にログインできたか(認証されたか)どうかを確認します。
if (session.getStatus() == UserSession.LOGGEDIN) {
ユーザーが認証されている場合は、リソース・リクエスト構造体rrq
に指定したリソースへのアクセスをユーザーが認可されるかどうかを確認します。
if (session.isAuthorized(rrq)) { System.out.println( "User is logged in " + "and authorized for the request " +
session
という名前のユーザー・セッションに対してgetLevel
メソッドによって戻される認可レベルを確認します。
"at level " + session.getLevel());
rrq
に指定されたリソースに対してユーザーが認可されていない場合は、ユーザーは認証されているが、リクエストしたリソースへのアクセスは認可されていないことを報告します。
} else { System.out.println("User is logged in but NOT authorized");
ユーザーが認証されていない場合は、そのことを報告します。(実際のアプリケーションでは、ユーザーに認証のための機会をさらに与える場合があります)。
} else { System.out.println("User is NOT logged in");
認証スキームでHTTPフォーム・ベースのチャレンジ・メソッドが使用されていない場合は、そのことを報告します。実際のアプリケーションでは、このようなとき、basic
(userid
とpassword
のみを要求する)、certificate
(SSL over HTTPSまたはTLS over HTTPS)、またはsecure
(リダイレクトURLによるHTTPS)など、認可スキームに指定されている他のチャレンジ・メソッドを提供するように分岐する場合があります。チャレンジ・メソッドとユーザー認証の構成の詳細は、資格証明チャレンジ・メソッドに関する項を参照してください。
} else { System.out.println("non-Form Authentication Scheme."); }
リソースが保護されていない場合は、そのことを報告します。(アクセス・クライアントはリソースを保護しようとしなくなるので、ユーザーはリクエストしたリソースへのアクセスを自動的に取得します)
} else { System.out.println("Resource is NOT protected."); } }
前述のtryブロック内でエラーが発生した場合は、オブジェクトae
から関連テキスト・メッセージを取得して、これを報告します。
catch (AccessException ae) { System.out.println( "Access Exception: " + ae.getMessage()); }
アプリケーションにおいてユーザーのログアウトが必要な場合は、UserSession
クラスのオブジェクト上でログオフ・メソッドを起動できます。
これで、OAMサーバーへのコールが終了になるため、APIを停止して、このコールでAPIが保持してきたメモリーを解放します。
ac.shutdown(); } }
プログラムを終了します。このアプリケーションで作成した構造体が使用するメモリーは、不要になった時点でJava Garbage Collectionにより自動的にクリーンアップされるので、割当て解除する必要はありません。
2.3.5 サンプル・コード: Javaログイン・サーブレット
この例では、「サンプル・コード: 簡単なアクセス・クライアント」で説明した、アクセス・クライアントを定義するAPIコールの基本パターンを実行しています。ただしこの例は、Webサーバーまたはアプリケーション・サーバー内で実行されるJavaサーブレットとして実装されています。アクセス・クライアント・サーブレットは、この環境では、Webアプリケーションのユーザーに対してさらに重要な役割を果すことができます。サーブレットは、セッション・トークンをユーザーのHTTPセッション内に格納することで、ユーザーがシングル・サインオンできるようにします。つまり、最初のリクエストで確立された認証済OAMサーバー・セッション情報は、1回認可確認した後でも破棄されません。格納されたセッション・トークンは、破棄されずに、Beanやその他のサーブレットなどのサーバー側アプリケーション・コンポーネントで利用できるようになり、これらのコンポーネントが同じ資格証明をリクエストするためにユーザーに繰り返し割り込む必要がなくなります。セッション・トークン、ObSSOCookies
およびシングル・サインオンの構成の詳細は、SSO Cookieの理解に関する項を参照してください。
ノート:
このJavaサーブレットの例では、Access Manager WebGateによって保護されたリソースに対してSSOを提供していません。
このサンプル・ログイン・サーブレットは、カスタム・ログイン・ページ上のフォームでuserid/passwordパラメータを受け付け、ユーザーにAccess Managerへのログインの機会を提供します。ログインが成功した場合、サーブレットは、セッション・トークンをUserSession
オブジェクト内に格納します。これにより、同じHTTPセッション内の後続のリクエストは認証ステップをバイパスし(後続のリクエストが最初のリクエストと同じ認証スキームを使用する場合)、シングル・サインオンを実現します。
Javaログイン・サーブレットの完全なリストは、例2-2に示しています。このコードは、Webサーバーまたはアプリケーション・サーバーに組み込むプラグインのベースとして使用できます。「注釈付きサンプル・コード: Javaログイン・サーブレット」は、このコードの注釈付きバージョンです。
例2-2 Javaログイン・サーブレットの例
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import java.util.*; import oracle.security.am.asdk.*; public class LoginServlet extends HttpServlet { public void init(ServletConfig config) throws ServletException { try { AccessClient ac = AccessClient.createDefaultInstance("/myfolder" , AccessClient.CompatibilityMode.OAM_11G); } catch (AccessException ae) { ae.printStackTrace(); } } public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { AuthenticationScheme authnScheme = null; UserSession user = null; ResourceRequest resource = null; response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD><TITLE>LoginServlet: Error Page</TITLE></HEAD>"); out.println("<BODY>"); HttpSession session = request.getSession( false); String requestedPage = request.getParameter("request"); String reqMethod = request.getMethod(); Hashtable cred = new Hashtable(); try { if (requestedPage == null || requestedPage.length()==0) { out.println("<p>REQUESTED PAGE NOT SPECIFIED\n"); out.println("</BODY></HTML>"); return; } resource = new ResourceRequest("http", requestedPage, "GET"); if (resource.isProtected()) { authnScheme = new AuthenticationScheme(resource); if (authnScheme.isBasic()) { if (session == null) { String sUserName = request.getParameter("userid"); String sPassword = request.getParameter("password"); if (sUserName != null) { cred.put("userid", sUserName); cred.put("password", sPassword); user = new UserSession(resource, cred); if (user.getStatus() == UserSession.LOGGEDIN) { if (user.isAuthorized(resource)) { session = request.getSession( true); session.putValue( "user", user); response.sendRedirect( requestedPage ); } else { out.println("<p>User " + sUserName + " not" + " authorized for " + requestedPage + "\n"); } } else { out.println("<p>User" + sUserName + "NOT LOGGED IN\n"); } } else { out.println("<p>USERNAME PARAM REQUIRED\n"); } } else { user = (UserSession)session.getValue("user"); if (user.getStatus() == UserSession.LOGGEDIN) { out.println("<p>User " + user.getUserIdentity() + " already"+ "LOGGEDIN\n"); } } } else { out.println("<p>Resource Page" + requestedPage + " is not"+ " protected with BASIC\n"); } } else { out.println("<p>Page " + requestedPage + " is not protected\n"); } } catch (AccessException ex) { out.println(ex); } out.println("</BODY></HTML>"); } }
2.3.6 注釈付きサンプル・コード: Javaログイン・サーブレット
システム入出力および基本機能を実装する標準Javaパッケージをインポートします。
import java.io.*; import java.util.*;
サーブレット関連機能を実装する2つのJava拡張機能パッケージをインポートします。
import javax.servlet.*; import javax.servlet.http.*;
Access SDK APIのJava実装であるoracle.security.am.asdk.jar
パッケージをインポートします。
import oracle.security.am.asdk.*;
このサーブレットは、Java Enterprise Editionでサポートされている汎用HttpServlet
の機能をベースにビルドされており、LoginServlet
という名前です。
public class LoginServlet extends HttpServlet {
サーブレット・エンジンはinit
メソッドを1回コールして、アクセス・クライアントを初期化します。initメソッドでは、構成ファイルObAccessClient.xmlの場所を渡し、AccessClient
をインスタンス化してAccess SDKを初期化できます。アクセス・クライアントの作成の詳細は、Oracle Fusion Middleware Oracle Access Management Access Manager Access SDK Java APIリファレンスを参照してください。OAM_11G
互換性フラグを指定すると、Access SDKは11gおよび12cの両方のサーバーと互換性のあるモードで初期化されます。OAM_11G
互換性フラグを指定すると、Access SDKは古い11gエージェント・モードで初期化されます。このモードは、11gおよび12cの両方のサーバーと互換性があります。デフォルトでは、この互換性モードを指定しないと、デフォルトのOAM_12C
が使用されます。この場合、エージェントは12cエージェント・モードで動作し、12c OAMサーバーとしか対話できません。
ノート:
AccessClientインスタンスがOAM_11Gモードで作成される場合は、11gエージェント・プロファイルを使用する必要があります。同様に、AccessClientインスタンスがOAM_12cモードで作成される場合は、12cエージェント・プロファイルを使用する必要があります。
初期化に失敗した場合は、そのことを該当のエラー・メッセージとともに報告します。
public void init() { AccessClient ac = AccessClient.createDefaultInstance("/myfolder" , AccessClient.CompatibilityMode.OAM_11G); } catch (AccessException ae) { ae.printStackTrace(); } }
javax.servlet.service
メソッドを起動し、ユーザーのリソース・リクエストを処理します。
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
メンバーをnull
として初期化します。これらはリソース・リクエストの処理に使用するアクセス構造を格納し、このアプリケーションが使用するレスポンス・タイプをtext/html
に設定します。
AuthenticationScheme authnScheme = null; UserSession user = null; ResourceRequest resource = null; response.setContentType("text/html");
LoginServlet: Error Page
という名前の出力ストリームを開き、ユーザーのブラウザにリダイレクトします。
PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD><TITLE>LoginServlet: Error Page</TITLE></HEAD>"); out.println("<BODY>");
このユーザーのセッションがすでに存在するかどうかを確認します。パラメータとしてfalse
を指定してgetSession
メソッドを起動すると、既存のサーブレット・セッション(UserSession
ではない)の値が戻され(セッションが存在する場合)、存在しない場合はNULLが戻されます。
HttpSession session = request.getSession(false);
ターゲット・リソースの名前を取得して、これをrequestedPage
変数に代入し、リクエストに使用されたHTTPメソッド(GET、POST、PUTなど)の名前を取得して、これをreqMethod
変数に代入します。
String requestedPage = request.getParameter(Constants.REQUEST); String reqMethod = request.getMethod();
cred
という名前のハッシュテーブルを作成し、ユーザーの資格証明を格納します。
Hashtable cred = new Hashtable();
requestedPage
変数が空のまま戻された場合は、ターゲット・リソースの名前が正しく指定されていないことを報告し、サーブレットを終了します。
try { if (requestedPage == null) { out.println("<p>REQUESTED PAGE NOT SPECIFIED\n"); out.println("</BODY></HTML>"); return; }
リクエストしたページの名前が戻された場合は、ResourceRequest
構造体を作成して、次を設定します。
-
リソース・タイプ: HTTP
-
HTTPメソッド: GET
-
resource
:requestedPage
変数に設定されている値
resource = new ResourceRequest("http", requestedPage, "GET");
ターゲット・リソースが保護されている場合は、リソース・リクエスト用にAuthenticationScheme
構造体を作成し、名前をauthnScheme
とします。
if (resource.isProtected()) { authnScheme = new AuthenticationScheme(resource);
ターゲット・リソースに関連付けられている認証スキームがHTTP basic
で、現在ユーザー・セッションが存在しない場合は、javax.servlet.servletrequest.getParameter
を起動してユーザーの資格証明であるユーザー名とパスワードを戻し、それぞれsUserName
とsPassword
の変数に代入します。
次の文でauthnScheme.isBasic
コールを正しく動作させるには、次のように、ユーザー名とパスワードをユーザーのHTTPリクエストの問合せ文字列内に含める必要があります。
http://host.example.com/resource?username=bob&userpassword=bobspassword
ここで、resource
は、リクエスト先のリソース、bob
はリクエスト元のユーザー、bobspassword
はユーザーのパスワードです。
if (authnScheme.isBasic()) { if (session == null) { String sUserName = request.getParameter(Constants.USERNAME); String sPassword = request.getParameter(Constants.PASSWORD);
ユーザー名が存在する場合は、cred
という名前のハッシュテーブルに、関連パスワードとあわせて読み取ります。
if (sUserName != null) { cred.put("userid", sUserName); cred.put("password", sPassword);
ノート:
authnScheme.isBasic
のかわりにauthnScheme.isForm
を使用する場合は、追加コードを記述して、次のステップを実装する必要があります。
-
元のリクエストを処理して、フォーム・ベースのログインが必要なことを判断します。
-
ログイン・フォームに関する302リダイレクト・レスポンスを送信し、HTTPセッションに元のリソース情報を保存します。
-
ユーザー名とパスワードとともにポストされたフォーム・データを処理して、ユーザーを認証します。
-
HTTPリソースから元のリソースを取得し、そのリソースに関する302リダイレクト・レスポンスを送信します。
-
元のリクエストをもう1回処理しますが、今回はHTTPセッション内に格納されている
UserSession
を使用して処理します。
resource
という名前のResourceRequest
構造体とcred
ハッシュテーブルの情報に基づいて、ユーザー・セッションを作成します。
user = new UserSession(resource, cred);
戻されたユーザーのステータス・コードがLOGGEDIN
の場合、そのユーザーの認証は成功しています。
if (user.getStatus() == UserSession.LOGGEDIN) {
ターゲット・リソースへのアクセスをユーザーが認可されるかどうかを確認します。
if (user.isAuthorized(resource)) {
サーブレット・ユーザー・セッション(UserSession
と混同しないでください)を作成し、そこにユーザーの名前を追加します。
session = request.getSession( true); session.putValue( "user", user);
ユーザーのブラウザをターゲット・ページにリダイレクトします。
response.sendRedirect(requestedPage);
ターゲット・リソースへのアクセスをユーザーが認可されなかった場合は、そのことを報告します。
} else { out.println("<p>User " + sUserName + " not authorized for " + requestedPage + "\n"); }
ユーザーが正しく認可されていない場合は、そのことを報告します。
} else { out.println("<p>User" + sUserName + "NOT LOGGED IN\n"); }
ユーザー名が入力されていない場合は、そのことを報告します。
} else { out.println("<p>USERNAME PARAM REQUIRED\n"); }
セッションがすでに存在する場合は、USERを取得し、これをuser
セッション変数に代入します。
} else { user = (UserSession)session.getValue("user");
ユーザーがログインできた場合、つまりユーザーの認証が成功した場合は、そのことをユーザー名とともに報告します。
if (user.getStatus() == UserSession.LOGGEDIN) { out.println("<p>User " + user.getUserIdentity() + " already LOGGEDIN\n"); } }
ターゲット・リソースがbasic
認証スキームで保護されていない場合は、そのことを報告します。
} else { out.println("<p>Resource Page" + requestedPage + " is not protected with BASIC\n"); }
ターゲット・リソースがどの認証スキームによっても保護されていない場合は、そのことを報告します。
} else { out.println("<p>Page " + requestedPage + " is not protected\n"); }
エラーが発生した場合は、トレースバックを報告します。
} catch (AccessException ex) { oe.println(ex); }
出力をユーザーのブラウザにストリームとして送信します。
out.println("</BODY></HTML>"); } }
2.3.7 サンプル・コード: その他のメソッド
次のサンプルは、「サンプル・コード: 簡単なアクセス・クライアント」で説明した、サンプル・アプリケーションJAccessClient.java
で確立されている基本パターンをベースとして構築されており、追加でいくつかのOAMサーバー・メソッドを呼び出しています。たとえば、セッション・オブジェクトを点検して、現在の認証スキームに関連付けられているポリシー・ルール内にどのアクションおよび名前付きレスポンスが現在構成されているかを確認します。
このデモを実行するには、アプリケーションを実行する前にOAMサーバーによりいくつかのアクションを構成する必要があります。認証アクションおよびユーザー認証の構成の詳細は、アクセス・テスター・コンソールからのユーザー認証のテストに関する項を参照してください。
例2-3には、このサンプル・アプリケーションの完全なリストが記載されています。このコードの注釈付きバージョンは、「注釈付きサンプル・コード: その他のメソッド」を参照してください。
例2-3 access_test_java.java
import java.util.*; import oracle.security.am.asdk.*; public class access_test_java { public static void main(String[] arg) { String userid, password, method, url, configDir, type, location; ResourceRequest res; Hashtable parameters = null; Hashtable cred = new Hashtable(); AccessClient ac = null; if (arg.length < 5) { System.out.println("Usage: EXPECTED: userid password Type HTTP-method" +" URL [Installdir [authz-parameters] [location]]]"); return; } else { userid = arg[0]; password = arg[1]; type = arg[2]; method = arg[3]; url = arg[4]; } if (arg.length >= 6) { configDir = arg[5]; } else { configDir = null; } if (arg.length >= 7 && arg[6] != null) { parameters = new Hashtable(); StringTokenizer tok1 = new StringTokenizer(arg[6], "&"); while (tok1.hasMoreTokens()) { String nameValue = tok1.nextToken(); StringTokenizer tok2 = new StringTokenizer(nameValue, "="); String name = tok2.nextToken(); String value = tok2.hasMoreTokens() ? tok2.nextToken() : ""; parameters.put(name, value); } } location = arg.length >= 8 ? arg[7] : null; try { ac = AccessClient.createDefaultInstance(configDir , AccessClient.CompatibilityMode.OAM_11G); } catch (AccessException ae) { System.out.println("OAM Server SDK Initialization failed"); ae.printStackTrace(); return; } cred.put("userid", userid); cred.put("password", password); try { res = new ResourceRequest(type, url, method); if (res.isProtected()) { System.out.println("Resource " + type + ":" + url + " protected"); } else { System.out.println("Resource " + type + ":" + url + " unprotected"); } } catch (Throwable t) { t.printStackTrace(); System.out.println("Failed to created new resource request"); return; } UserSession user = null; try { user = new UserSession(res, cred); } catch (Throwable t) { t.printStackTrace(); System.out.println("Failed to create new user session"); return; } try { if (user.getStatus() == UserSession.LOGGEDIN) { if (location != null) user.setLocation(location); System.out.println("user status is " + user.getStatus()); if (parameters != null ? user.isAuthorized(res, parameters) : user.isAuthorized(res)) { System.out.println("Permission GRANTED"); System.out.println("User Session Token =" + user.getSessionToken()); if (location != null) { System.out.println("Location = " + user.getLocation()); } } else { System.out.println("Permission DENIED"); if (user.getError() == UserSession.ERR_NEED_MORE_DATA) { int nParams = res.getNumberOfAuthorizationParameters(); System.out.print("Required Authorization Parameters (" + nParams + ") :"); Enumeration e = res.getAuthorizationParameters().keys(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); System.out.print(" " + name); } System.out.println(); } } } else { System.out.println("user status is " + user.getStatus()); } } catch (AccessException ae) { System.out.println("Failed to get user authorization"); } String[] actionTypes = user.getActionTypes(); for(int i =0; i < actionTypes.length; i++) { Hashtable actions = user.getActions(actionTypes[i]); Enumeration e = actions.keys(); int item = 0; System.out.println("Printing Actions for type " + actionTypes[i]); while(e.hasMoreElements()) { String name = (String)e.nextElement(); System.out.println("Actions[" + item +"]: Name " + name + " value " + actions.get(name)); item++; } } AuthenticationScheme auths; try { auths = new AuthenticationScheme(res); if (auths.isBasic()) { System.out.println("Auth scheme is Basic"); } else { System.out.println("Auth scheme is NOT Basic"); } } catch (AccessException ase) { ase.printStackTrace(); return; } try { ResourceRequest resNew = (ResourceRequest) res.clone(); System.out.println("Clone resource Name: " + resNew.getResource()); } catch (Exception e) { e.printStackTrace(); } res = null; auths = null; ac.shutdown(); } }
2.3.8 注釈付きサンプル・コード: その他のメソッド
基本ユーティリティ、列挙およびトークン処理機能を実装する標準のJavaライブラリをインポートします。
import java.util.*;
Access SDK APIライブラリをインポートします。
import oracle.security.am.asdk.*;
このクラスにaccess_test_java
という名前を付けます。
public class access_test_java {
arg
という名前の配列で渡される値を格納する、7つの変数文字列を宣言します。
public static void main(String[] arg) { String userid, password, method, url, configDir, type, location;
現在のResourceRequestをres
に設定します。
ResourceRequest res;
まだ空になっていない可能性を考慮して、ハッシュテーブル・パラメータをnull
に初期化します。
Hashtable parameters = null;
cred
という名前の新規のハッシュテーブルを作成します。
Hashtable cred = new Hashtable();
AccessClient
参照をnullに初期化します。
AccessClient ac = null;
arg
という名前の配列に含まれている文字列が5個未満の場合、コマンド行入力で予期している構文と内容を報告します。これは順序が指定された5個の必須引数、およびオプションの変数であるconfigDir
、authz-parameters
およびlocation
です。
if (arg.length < 5) { System.out.println("Usage: EXPECTED: userid password type HTTP-method URL [configDir [authz-parameters] [location]]]");
最初に指定された引数が5個未満の場合、メイン・メソッドを終了することで事実上プログラムの実行を終了します。
return; } else {
arg
という名前の配列に5個以上の文字列がある場合は、最初の5個の引数(arg[0]からarg[4])をuserid
、password
、type
、method
、url
の変数に代入します。
userid = arg[0]; password = arg[1]; type = arg[2]; method = arg[3]; url = arg[4]; }
arg
に6個以上の引数がある場合は、配列内の6番目の文字列をconfigDir
変数に代入します。
if (arg.length >= 6) configDir = arg[5];
arg
に6個以上の引数がない場合、つまり、5個未満ではないことをすでに確認し、ちょうど5個の引数があることがわかっている場合は、configDir
をNULLに設定します。
else configDir = null;
arg
に7個以上の文字列があり、arg[6] (authz-parameters変数に暗黙のうちに割り当てられる)が空ではない場合、parameters
という名前の新規のハッシュテーブルを作成します。authz-parameters文字列の構文の形式: p1=v1&p2=v2&...
if (arg.length >= 7 && arg[6] != null) { parameters = new Hashtable();
デリミタとしてアンパサンド記号(&)を使用して、tok1
という名前の文字列トークン関数を作成し、arg[6]を解析します。これにより、arg[6]がpn=vnの形式でトークンの配列に分解されます(nはトークンの連番)。
StringTokenizer tok1 = new StringTokenizer(arg[6], "&");
tok1
のすべてのアイテムについて、直後のトークンをnameValue
変数として戻します。このようにして、nameValue
に文字列pn=vnが代入されます(nはトークンの連番)。
while (tok1.hasMoreTokens()) { String nameValue = tok1.nextToken();
デリミタとして等記号(=)を使用して、tok2
という名前の文字列トークン関数を作成し、nameValue
を解析します。このようにして、pn=vnをpnとvnのトークンに分解します。
StringTokenizer tok2 = new StringTokenizer(nameValue, "=");
最初のトークンをname
変数に代入します。
String name = tok2.nextToken();
2番目のトークンをvalue
に代入します。tok2
に他のトークンが残っている場合は、直後のトークンを戻し、これをvalue
に代入します。残っていない場合は、空文字列をvalue
に代入します。
String value = tok2.hasMoreTokens() ? tok2.nextToken() : "";
parameters
ハッシュテーブルにname
とvalue
を挿入します。
parameters.put(name, value); } }
arg
内に8個以上の引数がある場合は、arg[7]をlocation
変数に代入します。ない場合は、location
を空にします。
location = arg.length >= 8 ? arg[7] : null;
他のオプションを使用して提供する構成ファイルの場所がnullである場合、configDir
を使用してAccessClient
インスタンスを作成します。アクセス・クライアントの作成の詳細は、Oracle Fusion Middleware Oracle Access Management Access Manager Access SDK Java APIリファレンスを参照してください。
try { ac = AccessClient.createDefaultInstance(configDir , AccessClient.CompatibilityMode.OAM_11G); }
初期化の試行によりエラーが発生した場合は、トレースバックとともに標準エラー・ストリームに当該のエラー・メッセージ(ae
)を報告します。
catch (AccessException ae) { System.out.println(" OAM Server SDK Initialize failed"); ae.printStackTrace();
メイン・メソッドを終了することで、事実上プログラムを終了します。
return; }
各変数、ユーザーIDおよびパスワードをcred
という名前のハッシュテーブルに読み取ります。
cred.put("userid", userid); cred.put("password", password);
res
という名前のResourceRequest
オブジェクトを作成すると、変数タイプ、URLおよびメソッドの値がOAMサーバーから戻されます。
try { res = new ResourceRequest(type, url, method);
リクエストしたリソースres
が保護されているかどうかを確認して、該当するメッセージを表示します。
if (res.isProtected()) System.out.println("Resource " + type ":" + url + " protected"); else System.out.println("Resource " + type + ":" + url + " unprotected"); }
ResourceRequest
構造体を作成できなかった場合は、エラー・メッセージt
とともに障害を報告します。
catch (Throwable t) { t.printStackTrace(); System.out.println("Failed to create new resource request");
メイン・メソッドを終了することで、事実上プログラムを終了します。
return; }
UserSession
パラメータのuser
を空に設定します。
UserSession user = null;
ResourceRequest
構造体のres
とAuthenticationScheme
構造体のcred
の値を戻す、user
という名前のUserSession
構造体を作成します。
try user = new UserSession(res, cred);
UserSession
構造体を作成できなかった場合は、エラー・メッセージt
とともに障害を報告します。
catch (Throwable t) { t.printStackTrace(); System.out.println("Failed to create new user session");
メイン・メソッドを終了することで、事実上プログラムを終了します。
return; }
ユーザーが現在ログインしているかどうか、つまりこのユーザーの認証が成功しているかどうかを確認します。
try { if (user.getStatus() == UserSession.LOGGEDIN) {
ユーザーがログインしている場合は、location
変数が空でないかどうかを確認します。location
が空でない場合は、AccessClient
のlocation
パラメータにこのlocation
変数の値を設定し、OAMサーバーが戻すステータス・コードとともに、ユーザーがログインしていることを報告します。
if (location != null) user.setLocation(location); System.out.println("user status is " + user.getStatus());
認可をチェックします。これを行うには、parameters
が存在するかどうかを確認します。存在する場合は、parameters
に格納されているパラメータをアタッチしたときにターゲット・リソースへのアクセスがユーザーに認可されるかどうかを確認します。parameters
が存在しない場合は、ターゲット・リソースへのアクセスがユーザーに認可されているかどうかを確認します。
try { if (parameters != null ? user.isAuthorized(res, parameters) : user.isAuthorized(res)) {
存在するすべてのパラメータを指定したときにユーザーがリソースへのアクセスを認可される場合は、権限が付与されたことを報告します。
System.out.println("Permission GRANTED");
さらに、ユーザー・セッション・トークンをシリアル番号付きで表示します。
System.out.println("User Session Token =" + user.getSessionToken());
location変数が空でない場合は、その値を報告します。
if (location != null) { System.out.println("Location = " + user.getLocation()); }
リソースへのアクセスをユーザーが認可されなかった場合は、権限が拒否されたことを報告します。
} else { System.out.println("Permission DENIED");
UserSession
がERR_NEED_MORE_DATAを戻す場合は、nParams
変数を認可に必要なパラメータの数に設定し、その数値をユーザーに報告します。
if (user.getError() == UserSession.ERR_NEED_MORE_DATA) { int nParams = res.getNumberOfAuthorizationParameters(); System.out.print("Required Authorization Parameters (" + nParams + ") :");
resという名前のResourceRequest
オブジェクトのgetAuthorizationParameters
メソッドによって戻されるハッシュテーブルのkeys
パラメータの値として、e
を設定します。
Enumeration e = res.getAuthorizationParameters().keys();
e
に含まれているすべての要素の名前を報告します。
while (e.hasMoreElements()) { String name = (String) e.nextElement(); System.out.print(" " + name); } System.out.println(); }
そうでない場合は、次の文に進みます。
else } }
ユーザーがログインできなかった場合は、現在のユーザー・ステータスを報告します。
else System.out.println("user status is " + user.getStatus());
エラーが発生した場合は、認可の試行が失敗したことを報告します。
catch (AccessException ae) System.out.println("Failed to get user authorization"); }
ここで、現行のユーザー・セッションに現在設定されているすべてのアクションを報告します。これを行うには、getActionTypes
メソッドによって戻される文字列からactionTypes
という名前の配列を作成します。次に、actionTypes
内の各文字列をactions
という名前のハッシュテーブルに読み取ります。actions
に含まれている各キーの名前および値を報告します。
String[] actionTypes = user.getActionTypes(); for(int i =0; actionTypes[i] != null; i++){ Hashtable actions = user.getActions(actionTypes[i]); Enumeration e = actions.keys(); int item = 0; System.out.println("Printing Actions for type " + actionTypes[i]); while(e.hasMoreElements()) { String name = (String)e.nextElement(); System.out.println("Actions[" + item +"]: Name " + name + " value " + actions.get(name)); item++; } }
ResourceRequest
オブジェクトのres
に対するauths
という名前のAuthenticationScheme
オブジェクトの作成を試みます。
AuthenticationScheme auths; try auths = new AuthenticationScheme(res);
AuthenticationScheme
を作成できなかった場合は、エラー・メッセージase
とともに障害を報告します。
catch (AccessException ase) { ase.printStackTrace();
メイン・メソッドを終了することで、事実上プログラムを終了します。
return; }
認可スキームがBasicかどうかを確認します。
try { if (auths.isBasic())
その場合は、そのことを報告します。
System.out.println("Auth scheme is Basic");
Basicでない場合は、その事実を報告します。
else System.out.println("Auth scheme is NOT Basic");
コピー・コンストラクタを使用して、元オブジェクトres
からresNEW
という名前の新規のResourceRequest
オブジェクトを作成します。
ResourceRequest resNew = (ResourceRequest) res.clone();
新しくクローニングしたオブジェクトの名前を報告します。
System.out.println("Clone resource Name: " + resNew.getResource());
なんらかの理由によりResourceRequest
オブジェクトがクローニングできなかった場合は、対応するトレースバックによって障害を報告します。
} catch (Exception e) { e.printStackTrace(); }
ResourceRequest
オブジェクトres
とAuthenticationScheme
オブジェクトauths
をNULLに設定し、Access SDK APIを切断します。
res = null; auths = null; ac.shutdown(); } }
2.3.9 サンプル・コード: Javaでの証明書ベース認証
次のコードの抜粋では、X.509証明書を処理するアクセス・クライアントのJavaでの実装例を示しています。この抜粋は、管理者がアクセス・システムに証明書ベースの認証を構成する場合に適しています。
証明書はBase64でエンコードされている必要があります。OAMサーバーでは、ユーザーの識別にのみこの証明書を使用します。有効期間、ルート認証が信頼されているかどうかなどの検証は実行されません。
File oCertFile = new File("sample_cert.pem"); FileInputStream inStream = new FileInputStream(oCertFile); CertificateFactory cf = CertificateFactory.getInstance("X.509"); // cert must point to a valid java.security.cert.X509Certificate instance. X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream); // Convert the certificate into a byte array byte[] encodedCert = cert.getEncoded(); // Encode the byte array using Base 64-encoding and convert it into a string String base64EncodedCert = new String(Base64.encodeBase64 (encodedCert)); // Create hashtable to hold credentials Hashtable<String, String> creds = new Hashtable<String, String>(); // Store the Base 64-encoded under the key "certificate" creds.put("certificate", base64EncodedCert); // Create ResourceResource request object including all information about the // // resource being accessed including Resource type (for example http, ejb etc. // If null, defaults to http), and operation for the resource object // (for example GET, POST, PUT, HEAD, DELETE, TRACE, OPTIONS, CONNECT, OTHER) ResourceRequest resourceRequest = new ResourceRequest(resourceType, resourceUrl, operation); // Create a UserSession with the requestRequest and the cred hashtable UserSession userSession = new UserSession(resourceRequest, creds); // The above statement will throw an exception if the certificate cannot be mapped // to a valid user by the OAM Server.
この抜粋に関連するインポート文を次に示します。
import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.io.FileInputStream; import oracle.security.am.common.nap.util.Base64;
2.4 Access SDKログの理解
Access SDKでは、ログの生成にJavaロギングAPIが使用されます。oracle.security.am.asdk
パッケージには、AccessLogger
クラスが含まれ、このクラスがAccess SDKログを生成します。Access SDKによって生成されるログには、実行された操作に関する情報が含まれます。たとえば、操作ステータス、発生したエラーまたは例外、およびトラブルシューティングに役立つ一般情報を記録できます。
この項では、実行ログ中で、ステータスまたはエラーを示すためにAccess SDKが使用するメッセージおよび例外について説明します。
ノート:
Access SDKは、ステータスまたはエラーの状態を示すローカライズ済メッセージをサポートします。例外としてアプリケーションに提供されるエラー・メッセージもローカライズされます。これらのローカライズ済エラー・メッセージは、Access SDKログ・ファイルに記録されます。
次のタイプの例外が、Access SDKログにおけるエラー条件を示すために使用されます。
-
OperationNotPermittedException
Access SDKには、一連のセッション管理APIが用意されています。権限を持つアクセス・クライアントのみが、これらのセッション管理操作を実行できます。Access SDKを初期化するには、指定のエージェント・プロファイルに
AllowManagementOperations
フラグが設定されている必要があります。アクセス・クライアントがこれらの操作の実行を許可されていない場合、OAMサーバーがエラーを返します。サーバーがエラーを返すと、Access SDKがこの例外をスローします。
-
AccessException
操作の実行中に予期しないリカバリ不能なエラーが発生すると、Access SDK APIは
AccessException
をスローします。
Access SDKログを生成するには、アプリケーションの起動時にログ構成ファイルを指定する必要があります。このログ構成ファイルはアプリケーション実行中のJavaプロパティとして指定しますが、この場合、Javaプロパティ-Djava.util.logging.config.file
はlogging.properties
へのパスです。たとえば:
java -Djava.util.logging.config.file=JRE_DIRECTORY/lib/logging.properties
logging.properties
ファイルは、VMがロードされた直後に構成され準備が整うロガー、ハンドラ、フォーマッタおよびフィルタの数を定義します。状況に応じて、必要なロギング・レベルを構成することもできます。
logging.properties
ファイルのjava.util.logging.FileHandler.pattern
プロパティに対して、ログ・ファイル・パスを指定する必要があります。ファイル名のみを指定した場合、ファイルはカレント・ディレクトリの下に作成されます。logging.properties
ファイルの例は次のとおりです。
# "handlers" specifies a comma separated list of log Handler # classes. These handlers will be installed during VM startup. # Note that these classes must be on the system classpath. # By default we only configure a ConsoleHandler, which will only # show messages at the INFO and above levels. # Add handlers to the root logger. # These are inherited by all other loggers. handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler # Set the logging level of the root logger. # Levels from lowest to highest are # FINEST, FINER, FINE, CONFIG, INFO, WARNING and SEVERE. # The default level for all loggers and handlers is INFO. .level= ALL # Configure the ConsoleHandler. # ConsoleHandler uses java.util.logging.SimpleFormatter by default. # Even though the root logger has the same level as this, # the next line is still needed because we're configuring a handler, # not a logger, and handlers don't inherit properties from the root logger. java.util.logging.ConsoleHandler.level =INFO java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter # The following special tokens can be used in the pattern property # which specifies the location and name of the log file. # / - standard path separator # %t - system temporary directory # %h - value of the user.home system property # %g - generation number for rotating logs # %u - unique number to avoid conflicts # FileHandler writes to %h/demo0.log by default. java.util.logging.FileHandler.pattern=%h/asdk%u.log # Configure the FileHandler. # FileHandler uses java.util.logging.XMLFormatter by default. #java.util.logging.FileHandler.limit = 50000 #java.util.logging.FileHandler.count = 1 java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter java.util.logging.FileHandler.level=ALL
2.5 アクセス・クライアント・プログラムの構築
この項の内容は、次のとおりです。
2.5.2 新規アクセス・クライアント・プログラムのコンパイル
「開発環境の設定」に示された開発環境を構成した後で、次のようなコマンドを使用して、Access Clientプログラムをコンパイルできます。
Javac –cp <location of Access SDK jar> SampleProgram.java
必要に応じて、CLASSPATH、アクセス・クライアント・プログラム名などの詳細を変更します。CLASSPATHに追加するjarファイルの詳細は、「Access SDKのインストール」を参照してください。
2.6 アクセス・クライアントのデプロイ
アクセス・クライアントの開発後に、テストして使用するには、実際のAccess Manager環境でデプロイする必要があります。アクセス・クライアント・プログラムはすでに開発され、コンパイル済であることが前提です
次の概要では、Oracle Access Managementの管理者資格証明を使用してユーザーが実行する必要があるタスクを説明します。
2.7 アクセス・クライアントの構成
この項では、Access SDKを使用して開発されたアクセス・クライアントをデプロイする前に必要な構成ステップについて説明します。アクセス・クライアントのデプロイメント・プロセスは、その他のAccess Managerエージェントのデプロイメント・プロセスに類似しています。この項の内容は次のとおりです。
2.7.1 Access SDKの構成要件の理解
Access SDK構成は、次のファイルで構成されます。
-
ObAccessClient.xml
この構成ファイル(ObAccessClient.xml)は、Access Managerサーバーのホスト、ポート、アクセス・クライアントの動作を決定する他の構成アイテムなど、各種詳細が含まれます。たとえば、アイドル・セッション時間などがあります。
ObAccessClient.xmlを使用するかわりに、ブートストラップ構成を提供してAccess SDKを初期化する方法もあります。アクセス・クライアントまたはアプリケーションは、独自の構成ストアまたは他のメソッドのブートストラップ構成を使用できます。OAMサーバーのホストやポート番号などの構成の詳細は、
AccessClient.createDefaultInstance
を使用して呼び出すことができます。プログラムによる初期化の詳細は、Oracle Fusion Middleware Oracle Access Management Access Manager Access SDK Java APIリファレンスを参照してください。 -
cwallet.sso
このOracleウォレット・ファイルは、11gエージェントをAccess Managerに登録する際に作成されるアーティファクトです。cwallet.ssoファイルには、エージェントに対して発行されたトークンをOAMサーバーが暗号化するときに使用する秘密キーが格納されています。
cwallet.ssoファイルは、他のファイルと同じ場所に保存することも、他の場所に保存することもできます。そのパスをjps-config.xmlで、jps-config.xmlの位置に対する相対パスとして宣言する必要があります。cwallet.ssoは11gエージェントのみに適用されます。
JRF環境では、<DOMAIN_HOME>/config/fmwconfigディレクトリの下にシステムのjps-config.xmlがあります。このファイルによって、同じディレクトリ内にあるシステムのcwallet.ssoを使用するように指定されます。システム・ウォレットには、システム内のすべてのコンポーネント用のキーと資格証明が含まれます。このため、次の手順を使用してエージェント登録用のcwallet.ssoとシステムのcwallet.ssoをマージする必要があります。
-
merge-cred.xmlを準備します。このファイルには、ソースのcwallet.sso(エージェント登録アーティファクト)のディレクトリおよび宛先のcwallet.sso(システム・アーティファクト)を指定します。このファイルの内容は、例2-4で定義されている内容と似たものになります。
-
次のWLSTコマンドを実行してウォレットをマージします。
<MW_HOME>/common/bin/wlst.sh wls:/offline> connect("<username>", "<password>", "<host>:<admin_port>") wls:/base_domain/serverConfig> migrateSecurityStore(type="credStore",configFile="merge-creds.xml", src="FileSourceContext",dst="FileDestinationContext")
-
次のコマンドを実行して、エージェントのcwallet.ssoがシステムのcwallet.ssoに正常にマージされたかどうかを確認します。
<MW_HOME>/oracle_common/bin/orapki wallet display -wallet <destination cwallet.sso dir>
-
-
jps-config.xml
このファイルは、cwallet.ssoファイルを読み込むためのライブラリで必要とされます。次のいずれかの場所に格納できます。
-
デフォルトでは、<current working dir>/config/jps-config.xml (クライアント・インストールzipファイルを解凍すると、テンプレートが抽出されます)です。ここで、<current working dir>は、クライアント・インストールzipファイルを解凍したディレクトリです。または
-
-Doracle.security.jps.config=
jps-config.xml file location
で指定できます。ファイルの場所をJavaコマンドでプロパティとして渡す必要があります。
サンプルのjps-config.xmlファイルがクライアント・インストール・パッケージzipファイルに含まれています。これは11gエージェントのみに適用されます。
ノート:
前述のとおり、JRF環境では<DOMAIN_HOME>/config/fmwconfigディレクトリの下にあるシステムのjps-config.xmlファイルがデフォルトで使用されます。別のjps-config.xmlを準備する必要はありません。
-
-
Javaのセキュリティ権限付与
Javaセキュリティ・マネージャが有効な場合は、ウォレット内の資格証明にアクセスできるように、system-jazn-data.xmlファイルにアプリケーション用の権限付与を追加する必要があります。環境に応じて次のいずれかを選択します。
-
JRF環境でアプリケーションをデプロイしている場合は、system-jazn-data.xmlファイルに次の権限付与を追加します。
<grant> <grantee> <codesource> <url>... ...</url> </codesource> </grantee> <permissions> <permission> <class>oracle.security.jps.service.credstore. CredentialAccessPermission</class> <name>context=SYSTEM,mapName=OAMAgent,keyName=*</name> <actions>read</actions> </permission> <permissions> <grant>
-
JRF以外の環境でスタンドアロン・アプリケーションを使用しており、Javaセキュリティ・マネージャが有効になっていない場合は(スタンドアロン・アプリケーションでは一般的)、ポリシー・ファイルは不要です。
-
JRF以外の環境でアプリケーションをデプロイしており、Javaセキュリティ・マネージャが有効な場合は、使用される該当のJavaセキュリティ・ポリシー・ファイルを見つけ(たとえばWeblogic Serverの場合はweblogic.policy)、このファイルに次のセキュリティ権限付与を追加します。
grant codeBase "<url>" { permission oracle.security.jps.service.credstore.CredentialAccessPermission "context=SYSTEM,mapName=OAMAgent,keyName=*", "read"; };
<url>には、デプロイされるアプリケーションのコード・ソースの場所を指定します。たとえば、
file:/scratch/install/WLS_HOME/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_user/ASDKServlet/-
-
-
SSL用のJKSキーストア
このファイルは、トランスポート・セキュリティ・モードが簡易または証明書である場合のみ必要です。11g OAMサーバーおよび12c OAMサーバーのどちらも、エージェントとの通信においてオープン、簡易および証明書のトランスポート・セキュリティ・モードをサポートしています。資格証明は、Oracle Access Protocol (OAP)を使用して渡されます。OAPをオープン・モードで使用すると、通信が傍受に対して脆弱になるため、本番環境ではオープン・モードで使用しないでください。オープン・モードは、テスト環境でのみ使用してください。
Access SDKを使用して開発されたアクセス・クライアントは、エージェントと呼ばれます。OAMサーバーが構成されているモードによっては、アクセス・クライアントを同じモードで通信するよう構成する必要があります。
12cエージェントはそれぞれ固有のエージェント・キーを持ちます。12cエージェント・キーはcwallet.ssoに格納されています。このキーを使用して、SSOトークン、
accessClientPasswd
、および簡易または証明書トランスポート・セキュリティ・モードで使用されるグローバル・パスフレーズ(password.xmlに格納)が暗号化されます。マスター・トークンから有効範囲付きセッション・トークンを取得した場合を除き、1つのエージェントに対して発行されたSSOトークンを別のエージェントに直接使用できません。『Fusion Middleware Oracle Access Management管理者ガイド』のOAMプロキシの簡易および証明書モード・セキュリティのアクセス・プロトコルの管理に関する項を参照してください。トランスポート・セキュリティ・モードが簡易または証明書の場合、次のものが必要です。
-
oamclient-truststore.jks
-
oamclient-keystore.jks
-
password.xml
関連項目:
-
-
password.xml
このファイルは、トランスポート・セキュリティ・モードが簡易または証明書である場合のみ必要です。このファイルには、パスワードが暗号化された形式で含まれます。このパスワードは、SSLキー・ファイルの保護に使用されます。
「必要な構成ファイルの生成」を参照してください。
-
ログ構成
ログ・ファイルを生成するために必要です。詳細は、「Access SDKログの理解」を参照してください。
例2-4 merge-cred.xmlのサンプル
<?xml version="1.0" encoding="UTF-8" standalone='yes'?> <jpsConfig xmlns="http://xmlns.oracle.com/oracleas/schema/11/jps-config-11_1.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/oracleas/schema/11/ jps-config-11_1.xsd" schema-major-version="11" schema-minor-version="1"> <serviceProviders> <serviceProvider class="oracle.security.jps.internal.credstore.ssp.SspCredentialStoreProvider" name="credstoressp" type="CREDENTIAL_STORE"> <description>File-based credential provider</description> </serviceProvider> </serviceProviders> <serviceInstances> <!-- Source file-based credential store instance --> <serviceInstance location="<source cwallet.sso dir>" provider="credstoressp" name="credential.file.source"> </serviceInstance> <!-- Destination file-based credential store instance --> <serviceInstance location="<destination cwallet.sso dir>" provider="credstoressp" name="credential.file.destination"> </serviceInstance> </serviceInstances> <jpsContexts> <jpsContext name="FileSourceContext"> <serviceInstanceRef ref="credential.file.source"/> </jpsContext> <jpsContext name="FileDestinationContext"> <serviceInstanceRef ref="credential.file.destination"/> </jpsContext> </jpsContexts> </jpsConfig>
2.7.2 必要な構成ファイルの生成
ObAccessClient.xml構成ファイルを取得するには、管理コンソールまたはリモート登録ツールを使用して、アクセス・クライアントを11gエージェントとしてOAM 12cサーバーに登録します。11gエージェントの登録時には、cwallet.ssoファイルも作成されます。詳細は、『Fusion Middleware Oracle Access Management管理者ガイド』のエージェント登録の概要に関する項を参照してください。
Oracle Access Management管理コンソールでは、password.xmlファイルも作成されます。
oracle.security.am.asdk
APIで開発されたアクセス・クライアント・アプリケーションは、構成ファイルおよびその他の必要なファイルを取得するための場所を指定できます。このためには、Access SDKを初期化し、構成ファイルが存在するディレクトリの場所を指定します。
構成ファイルの場所をAccess SDKに指定するオプションの詳細は、Oracle Fusion Middleware Oracle Access Management Access Manager Access SDK Java APIリファレンスを参照してください。
2.7.3 SSL証明書とキー・ファイルの要件
Access SDKでは、一般に信頼ストアまたはキー・ストアとして知られるデータベースのSSL証明書およびキー・ファイルを使用します。これらのストアはJKS (Java Key Standard)形式である必要があります。詳細は、次の各項を参照してください。
2.7.3.1 簡易トランスポート・セキュリティ・モードについて
簡易トランスポート・モードでは、OAMサーバーによってJKSキーストアが自動生成されます。生成されたキーストアは、WLS_OAM_DOMAIN_HOME/output/webgate-ssl/に保存されます。
2.7.3.2 証明書トランスポート・セキュリティ・モードでの作業
証明書トランスポート・セキュリティ・モードでは、サーバーおよびエージェントの証明書を認証局にリクエストする必要があります。オプションにより、証明書モード証明書を発行する目的で、簡易モードの自己署名証明書を認証局として使用することもできます。証明書モードを準備するには、次のステップを実行します。
2.7.3.2.1 CA証明書のインポート
12c Java Access SDKを使用する場合、このステップは必要ありません。
以前のバージョンのJNI SDKを使用する場合は、CA証明書を信頼ストアにインポートする必要があります。11g Access SDKは、簡易モードで使用できる自己署名付きCA証明書を提供し、アクセス・クライアントに証明書を発行するために使用されます。12c OAMサーバーは自己署名付きCA証明書を提供します。
-
OAM 12cサーバー: CA証明書(cacert.der)は、$MIDDLEWARE_HOME/user_projects/domains/base_domain/config/fmwconfigに配置されます。
次のコマンドを実行して、PEMまたはDER形式のCA証明書を信頼ストアにインポートします。
2.7.3.2.2 キーストアの設定
アクセス・クライアントのSSL証明書および秘密キーファイルをキーストアに追加する必要があります。アクセス・クライアントがOAMサーバーと通信できるように、SSL証明書および秘密キー・ファイルは簡易モードで生成する必要があります。
-
11g OAMサーバー: リモート登録ツールおよび管理コンソールを使用して、アクセス・クライアントの証明書(aaa_cert.pem)およびキー・ファイル(aaa_key.pem)をPEM形式で生成します。
キーストアoamclient-keystore.jksに証明書およびキー・ファイルをインポートするには、次のコマンドを実行します。
2.8 ベスト・プラクティス
この項では、様々な問題を回避する方法や、開発中に頻繁に発生する問題を解決するための方法をいくつか説明します。この項の内容は、次のとおりです。
2.8.1 カスタム・アクセス・クライアントでの問題の回避
カスタム・アクセス・クライアントでの問題発生を回避するための提案を次に示します。
-
アクセス・クライアントが適切なOAMサーバーに接続しようとしているかを確認します。
-
OAMサーバーについての構成情報とアクセス・クライアントについての構成情報が一致するようにします。Oracle Access Management管理コンソールを使用して、OAMサーバー上のアクセス・クライアントの構成情報を確認できます。詳細は、『Fusion Middleware Oracle Access Management管理者ガイド』のOAMエージェントの登録および管理に関する項を参照してください。
-
OAMサーバーとの接続や切断をきれいに行うには、
AccessClient
クラスのinitialize
メソッドおよびshutdown
メソッドを使用します。 -
環境変数OBACCESS_INSTALL_DIRをWindowsまたはUNIXタイプのホスト・コンピュータ上で設定し、アクセス・クライアントをコンパイルおよびリンクできるようにする必要があります。一般的に、この変数は、アクセス・クライアントを実行する場合にも必ず設定しておく必要があります。
-
開発中に問題を捕捉したり報告するには、カスタム・アクセス・クライアント・コードの作成に使用した言語の例外処理機能(try、throwおよびcatch)を使用します。
-
アクセス・クライアントは、マルチスレッド・アプリケーション全体でただ1つのスレッドとなります。そのような環境内で確実に安全な操作ができるように、開発者は、スレッド・セーフなコードを開発するための次のプラクティスを遵守するようお薦めします。
-
シングル・スレッド関数ではなく、スレッド・セーフ関数を使用します。たとえば、localtimeでなくlocaltime_rを使用します。
-
マルチスレッド機能がサポートされるよう、適切なビルド環境とコンパイラ・フラグを指定します。たとえば、-D_REENTRANTを使用します。また、UNIX型プラットフォームでは-mt、Windowsプラットフォームでは/MDを使用します。
-
FILEポインタなどのスレッド・セーフ方式の共有ローカル変数は注意して使用してください。
-
2.8.2 アクセス・クライアントに関する問題の特定と解決
アクセス・クライアントが実行に失敗したかどうかの確認点を次に示します。
-
OAMサーバーが実行中であることを確認します。Windowsシステムでこれを確認するには、「コンピュータの管理」、「サービス」、「AccessServer」の順にナビゲートします。AccessServerは、アクセス・クライアントを接続するOAMサーバーの名前です。
-
アクセス・クライアントがユーザー・ログアウトを実行することを確認し、OAMサーバー側のセッションが必ず削除されるようにします。ユーザー・セッションが蓄積すると、ユーザー認証に失敗する可能性があります。
-
コードが想定しているドメイン・ポリシーが正しく存在し、有効化されていることを確認します。
-
リリース・ノートの確認
-
アクセス・システムの低位レベルのポリシーが、検査中のポリシーをオーバーライドして、アクセス・クライアントに応答しないようにします。
-
アクセス・テスターを使用すると、特定のリソースにどのポリシーが適用されるかを確認できます。アクセス・テスターの使用方法およびアプリケーション・ドメインによるリソースの保護の詳細は、「アクセス・テスターを使用した接続性およびポリシーの検証」を参照してください。
2.8.3 Java Access SDKとコンテナを使用する環境に関する問題
この項では、Java Access SDKの使用時に発生する可能性のある環境の競合を解消するための情報を提供します。次のコンテナに関する情報が含まれます。
2.8.3.1 Java EEコンテナを使用する環境に関する問題の解決
Access SDKを使用するWebアプリケーションで、Javaクラス・バージョンの競合を解消するには、次の手順に従ってください。
Access SDKによって使用されるライブラリと異なるバージョンのライブラリが、同じJava EEコンテナにホストされている別のアプリケーションによってロードされると、競合が発生します。表示される可能性のあるエラー・メッセージのサンプルを次に示します。
oracle/security/am/common/aaaclient/ObAAAServiceClient.<init>(Ljava/lang /String;[CILjava/lang/String;Ljava/lang/String;[C[CZIJJLjava/lang/Integer;Ljava/u til/List;Ljava/util/List;)V at oracle.security.am.asdk.AccessClient.createClient(AccessClient.java:798) at oracle.security.am.asdk.AccessClient.initialize(AccessClient.java:610) at oracle.security.am.asdk.AccessClient.<init>(AccessClient.java:527) at oracle.security.am.asdk.AccessClient.createDefaultInstance(AccessClient.java:234) at com.newco.authenticateIdentity.AuthenticateIdentityAccessClient.authenticateUser( AuthenticateIdentityAccessClient.java:52)
この問題は、Java EEコンテナへのクラスのロード方法に関係しています。詳細は、使用しているコンテナの、クラスのロードについて記載されたドキュメントを参照してください。
この問題を解消するには、特定のライブラリ・バージョンを必要とするWebアプリケーションに対してクラス・ローダー・フィルタリングを構成します。詳細とステップは、使用しているアプリケーション・サーバーのドキュメントを参照してください。
2.8.3.2 Oracle WebLogicサーバーを使用する環境に関する問題の解決
システム・クラス・ローダーを使用してロードするかわりに、WebLogic Server FilteringClassLoader
を使用すると、アプリケーションから常にロードされるパッケージを指定できます。
この問題を解決するには、次のステップを実行します。
2.8.3.3 その他のアプリケーション・サーバーを使用する環境に関する問題の解決
どのアプリケーション・サーバーにも構成ファイルがあり、そのファイルでクラスのロードに関連するオプションが構成されます。一般に、特定のクラス・ローダーで一連のクラスをロードできるようにするために必要な構成ファイルとタグを特定することがキーとなります。
- アプリケーション・サーバーの構成ファイルを特定します。
- アプリケーション・クラス・ローダーを使用して、クラスがCLASSPATHで指定されていても親クラス・ローダーによってロードされないようにします。
- デフォルトのクラスのロード動作を変更して、現在のクラス・ローダーがクラスのロードに失敗した場合にのみ親クラス・ローダーがコールされるようにします。
- または、WebLogic Serverのように、指定のクラス・ローダーを使用してクラスをロードできる方法が存在する場合もあります。
- アプリケーション・サーバーによっては、アプリケーション用に親ドメインとは別のドメインを定義し、親を最後にロードするようクラスのロード動作を設定する必要がある場合もあります。