Real Application Securityは、アプリケーション・セッションを透過的かつ安全に設定するためのアプリケーション・セッション・サービスをOracle Fusion Middlewareで提供し、既存のアプリケーション・ユーザー、ロール、セキュリティ・コンテキストをサポートします。このアプリケーション・セッション・サービスは、アプリケーション・セッションのセットアップおよびアプリケーションがアプリケーション・セッションで使用できる一連のAPIに使用されるサーブレット・フィルタです。このアプリケーション・セッション・サービスは、Oracle Fusion Middlewareによって外部で管理されるユーザーとロールをサポートします。
Oracle Database 12cリリース1 (12.1.0.2)以降、このアプリケーション・セッション・サービスはOracle Platform Security Service (OPSS)をアプリケーション・セキュリティ・プロバイダとして使用して、Java EE Webアプリケーションをサポートします。このアプリケーション・セッション・サービスは、OPSSでアプリケーションとともにサポートできるJava EEコンテナにデプロイできます。
Real Application SecurityはOracle Database認可システムとして、誰(アプリケーション・ユーザー)がどのデータベース・リソース(マイ・レポート、マイSSNの従業員の購買注文レコード)でどのアプリケーション・レベルの操作(ApprovePurchaseOrder、ViewSSN)を実行できるかを守らせることで、アプリケーションのセキュリティをサポートします。アプリケーション・セッションは、アプリケーション・セキュリティを徹底するために使用されます。一般に、ユーザーとロールは外部でプロビジョニングされます。つまり、エンタープライズ・ユーザーはアイデンティティ・ストアでプロビジョニングされ、アプリケーション・ロールはOracle Identity ManagementやOracle Entitlement Server (OES)などのポリシー・ストアで管理されます。
アプリケーション・ユーザーおよびロールを外部で管理
Real Application Securityは、アプリケーション・ユーザーおよびロールのプロビジョニングを管理するために、Oracle Entitlement Serverなどの外部パーティによってプロビジョニングされたユーザーとロールをサポートします。他方、OPSSはアプリケーション・ロールのセキュリティを徹底するための実行時セキュリティ・フレームワークを提供します。これらは外部アプリケーション・ユーザーおよび外部アプリケーション・ロールと呼ばれます(詳細は、Oracle Fusion MiddlewareとReal Application Securityの統合を参照)。
Real Application Securityには、データベースでネイティブに管理されるアプリケーションのユーザーおよびロールもあり、これらはReal Application Securityアプリケーション・ユーザーおよびアプリケーション・ロールと呼ばれます(詳細は、アプリケーション・ユーザーおよびアプリケーション・ロールの構成を参照)。
外部アプリケーション・ユーザーおよび外部アプリケーション・ロールについては、Real Application Securityはユーザーのロール割当てを含め、ユーザー・プロビジョニングを管理しません。ただし、データベース内のネイティブなアプリケーション・ユーザーおよびアプリケーション・ロールについては、アプリケーション・ユーザーへのアプリケーション・ロールの付与、アプリケーション・ロールへのデータベース・ロールの付与、アプリケーション・ロールへのアプリケーション・ロールの付与がデータベースで管理されます。Real Application Securityアプリケーション・ユーザーとアプリケーション・ロールおよび外部アプリケーション・ユーザーと外部アプリケーション・ロールの両方がアプリケーション・セッションでサポートされ、データ・セキュリティ・ポリシーで使用できます。アイデンティティ・ストアで外部から管理されるユーザーとデータベースでネイティブに管理されるユーザーの両方に、アプリケーション権限を付与できます。
Oracle Fusion Middlewareのアプリケーション・セッション
アプリケーション・セッションはアプリケーション・ユーザーの実行時セキュリティ・コンテキストを表します。これには、ユーザーID、データベースおよびアプリケーション・ロール、ネームスペース属性値が含まれます。Oracle Fusion Middlewareのアプリケーション・セッションは、外部で管理されるユーザーおよびロールを使用しています。アプリケーション・セッションの構成の詳細は、アプリケーション・ユーザー・セッションの構成を参照してください。
Oracle Fusion Middlewareのセッション・マネージャ
Real Application Securityでは、セッション・マネージャがアプリケーション・セッション操作を認可し、アプリケーション・セッションの作成および変更に必要な権限を持っています。アプリケーション・コードまたはアプリケーション・データベース接続は、これらの権限を持つことができません。データベースに対しては、セッション・マネージャはReal Application Security直接ログイン・ユーザーです(直接ログイン・アプリケーション・ユーザー・アカウントの作成を参照)。アプリケーション・セッション・サービスの初期化開始時にデータベースと通信し、認可資格証明に基づいてデータベース・サーバーと信頼関係を構築します。その後、このメカニズムを使用して、アプリケーションの代理でアプリケーション・セッションの操作を引き続き認可します。
Oracle Fusion Middlewareの動的ロール
アプリケーション・ロール以外に、アプリケーション・セッションでは動的ロールをサポートしています。これは、データベースでネイティブに定義する必要があるReal Application Securityロールです(動的アプリケーション・ロールを参照)。このロールは、ユーザーまたは他のロールには付与されません。実行時にアプリケーション・セッションでプログラムによって有効にする必要があります。これはReal Application Securityフィルタで自動的に行うか、信頼できるアプリケーション・コードによって明示的に行います。
動的ロールはリクエスト範囲またはセッション範囲として定義できます。セッション範囲では、次回の連結で無効化するように明示的に指定した場合を除き、有効化された動的ロールは次回の連結でも引き続き有効です。リクエスト範囲では、アプリケーション・セッションが接続から連結解除された後、ロールは無効化されます。
動的ロールには2つの一般的な用途があります。
オブジェクト権限
アプリケーション・ユーザーはデータベース・ユーザーではありません。アプリケーション・ユーザーとアプリケーション・ロールが外部アイデンティティ・ストアでプロビジョニングされるときに、これらのオブジェクト権限をReal Application Security動的ロールに付与できます。Real Application Securityフィルタがアプリケーション・ユーザーにアプリケーション・セッションを設定する際、現在のアプリケーションにアクセスしている各アプリケーション・セッションで動的ロールを有効化します。動的ロールは、現在のアプリケーション専用です。
アプリケーション・セッション権限の昇格
一部のデータベース操作を実行するために、特定の信頼できるアプリケーション・コードに、一時的に高い権限を付与する必要があります。これをサポートするには、Javaコード・ベース・ポリシーを使用して宣言された信頼できるコードから連結されるアプリケーション・セッション中に、Real Application Security動的ロールを有効にします。連結解除時には、ロールを無効にする必要があります。
ユースケースの1つとして、セッション・ネームスペース属性がReal Application Securityで詳細にセキュリティ保護されている場合のアプリケーション・ネームスペースの設定があげられます。ネームスペースは、データベースでネームスペース・テンプレートとして事前定義しておく必要があります。定義時には、ネームスペースの関連ACLで認可ポリシー、つまり、誰(ユーザー/ロール)がネームスペースで何(modify_namespace、modify_attribute)を実行できるかを指定できます。信頼できるアプリケーション・コードのみがネームスペース属性を変更できるように、動的ロールに権限が付与されます。また、動的ロールは、Javaコード権限で識別される特定の信頼できるアプリケーション・コードによってプログラムを使用してのみ有効化できます。これにより、信頼できるコードのみが特定のネームスペースを設定できるユースケースがサポートされます。
図8-1は、Oracle Fusion Middlewareに実装されたアプリケーション・セッション・サービスを示しています。
図8-1 Oracle Fusion Middlewareのアプリケーション・セッション・サービス
アプリケーション・セッション・サービスはOracle Fusion Middlewareと統合されたソリューションで、Oracle Fusion Middlewareを活用してデータベースでアプリケーション・セッションを提供します。Oracle Fusion Middlewareでは:
アプリケーション・ユーザーは、コンテナによって認証されます。WLSでは一般に、オーセンティケータはSSOサーバーを使用してユーザーを認証します。
アプリケーション・ユーザーおよびグループは、アイデンティティ・ストアで管理されます。
OPSSは、コンテナのセキュリティ・コンテキストに基づいてアプリケーション・セキュリティ・コンテキストを設定するアプリケーション・セキュリティ・フレームワークです。OPSSを使用したアプリケーション・セキュリティの詳細は、Oracle Application Server Containers for J2EEセキュリティ・ガイドを参照してください。
Real Application Securityサーブレット・フィルタはアプリケーション・セッションを透過的に設定し、アプリケーション・セッションをOPSSサブジェクトと同期します。サーバー・フィルタ・コードは、アプリケーション・セッションで次の働きをする一連のAPIで構成されています。
セッションの連結、連結解除、破棄(アプリケーション・セッションAPIについてを参照)
権限の昇格の提供(権限昇格APIについてを参照)
ネームスペース操作の提供(ネームスペースAPIについてを参照)
認可の提供(権限確認APIについてを参照)
Real Application Securityは:
アプリケーション・セッションで外部ユーザーと外部ロールをサポートするAPIを提供します
セッション・マネージャを使用してセッションを認可します
ネームスペースでファイングレイン・アクセス・コントロールをサポートします
Real Application Securityアプリケーション・セッション・フィルタは、javax.servlet.Filter
インタフェースを実装する標準Java EEサーブレット・フィルタです。このフィルタの基本機能は、認証されたユーザーのセキュリティ・コンテキスト(OPSSサブジェクト)に応じてアプリケーション・セッションを透過的に設定することです。
このアプリケーション・セッション・フィルタを使用することで、アプリケーション・セッションをアプリケーション間で継続的に共有できます。リクエストごとに作成することはできませんが、ステートフル・コンテキストに関連付けて、ログアウトするまで同じユーザーに対して再使用する必要があります。Webアプリケーションの場合、httpセッションがこのようなコンテキストです。ログオンからログアウトまで同じユーザーの継続的なアクセスについて、複数のシングル・サインオン・アプリケーションまたはコンテナ間で、コンテナによって管理されます。
httpセッション・オブジェクトは、ServletFilter
からは常にアクセスできますが、汎用アプリケーション・コードからはアクセスできないことがあります。
この項の内容は次のとおりです: アプリケーション・セッション・フィルタ操作について。
アプリケーション・セッション・フィルタは、次の方法でアプリケーション・セッションを設定します。
ユーザーの初回アクセスで、アプリケーション・セッションを作成します。
ユーザーがログインしている場合は、認証コンテキストのユーザーとしてアプリケーション・セッションを作成します(OPSSサブジェクト)。
ユーザーがログインしていない場合は、匿名ユーザーとしてアプリケーション・セッションを作成します。
同じアプリケーションへのユーザーの後続アクセスでは、既存のアプリケーション・セッション・インスタンスを再使用します。
複数のアプリケーションが同じReal Application Securityデータベースにアクセスする際、複数のアプリケーション間で同じアプリケーション・セッションを共有します。
各httpリクエストの開始時にアプリケーション・セッションを同期して、現在のアプリケーション・セッションのユーザーとロールが常に認証コンテキスト(OPSSサブジェクト)と同期され、各アプリケーション・セッションで構成済の動的ロールのみが有効化されるようにします。
同期は、OPSSサブジェクトの値をサーバーにプッシュし、現在のアプリケーション・セッションについてサーバーで計算された値を取得することによって行われます。
アプリケーション・コードを実行する前にフィルタを起動すると、アプリケーション・セッションのユーザーとロールは固定されます。ユーザーとロールの同期を行うのは、アプリケーション・コードではなくフィルタです。
アプリケーション・コードは、ネームスペースの設定を行います。フィルタは、以前のネームスペースを戻すのに役立つだけです。ネームスペースの設定の詳細は、ネームスペースAPIについてを参照してください。
アプリケーション・セッションは、httpセッションIDに基づいてローカルでキャッシュされます。httpセッションは、コンテナによって管理されます。Real Application Securityには、コンテナのアプリケーション・セッション・イベントをリッスンするためのアプリケーション・セッション・リスナーがあります。コンテナでhttpセッションが無効化されると、アプリケーション・セッションはReal Application Securityリスナーによってローカル・キャッシュから削除されます。
Real Application Securityアプリケーション・セッション・サービスは1つのjarファイル、xsee.jar
で配布されます。xsee.jar
jarファイルは共通ディレクトリにデプロイすることをお薦めします。Webアプリケーション(web-inf/lib
内のWARファイル)と一緒にはデプロイしないでください。この方法により、jarファイルをアプリケーション・コードと分離し、いくつかの特別なコード・ベース権限をアプリケーション・コードには付与せずにxsee.jar
jarファイルにのみ付与できます。
xsee.jar
jarファイルがCSFストアからセッション・マネージャの資格証明を取得するには、コード・ベース権限CredentialAccessPermission
をxsee.jar
jarファイルに付与する必要があります。フィルタは内部的にReal Application Securityセッション・マネージャを使用して、セッション操作を認可します。
例8-1では、xsee.jar
jarファイルをWLSのドメイン/lib
ディレクトリにデプロイしています。javaポリシー・ファイル(system-jazn-data.xml
)にはCredentialAccessPermission
特権があり、セッション・マネージャのキー/マップはデフォルト値を使用していると想定しています。
デプロイ手順については、Oracle WebLogic Serverの理解の標準Java EEデプロイメントに関する項を参照してください。
テストまたは評価を行うためのアプリケーションを簡単にすばやくデプロイするには、自動デプロイメントを使用します。これは、すべて(クラス、web.xml
)を1つのWARファイルにパッケージし、Weblogic autodeploy
ディレクトリにコピーすることで、アプリケーション・セッション・サービスを簡単にデプロイする方法です。Oracle WebLogic Serverへのアプリケーションのデプロイの開発ドメインへのアプリケーションの自動デプロイに関する項を参照してください。
セッション・マネージャの資格証明を作成するには、手動構成の手順2を参照してください。
例8-1 xsee.jarファイルへのコード・ベース権限CredentialAccessPermissionの付与
<grant> <grantee> <codesource> <url>file:${domain.home}/lib/xsee.jar</url> </codesource> </grantee> <permissions> <permission> <class>oracle.security.jps.service.credstore.CredentialAccessPermission</class> <name>context=SYSTEM,mapName=oracle.rdbms.ras, keyName=default</name> <actions>read</actions> </permission> </permissions> </grant>
フィルタは、アプリケーションのweb.xml
構成ファイルで、標準的な方法で構成されます。特定のURLにのみ適用するように構成できます。これにより、データベース・アクセスを必要としない特定ページに、不必要なアプリケーション・セッションが設定されるのを防ぎます。フィルタは、ユーザー認証が実行され、認証コンテキストが確立されているとみなします。OPSSでは、ユーザーのアプリケーション・コンテキストはOPSSフィルタで計算されるため、フィルタ・チェーンのアプリケーション・セッション・フィルタの前にOPSSフィルタをデプロイする必要があります。アプリケーション・セッション・フィルタは、次のweb.xml
パラメータを使用します。
application.datasource
アプリケーションはこのapplication.datasource
パラメータを使用します。アプリケーション・セッション・フィルタは、初期化操作、アプリケーション・セッション設定操作およびネームスペース操作にこのパラメータを必要とします。
dynamic.roles
使用されるReal Application Security動的ロールのリストは、カンマ(,)で区切られます。データベースでセッション範囲として動的ロールが作成されている必要があります。作成されていない場合、次の例外がスローされます: ORA-46055: 無効なロールが指定されました
。
このロールは、現在のアプリケーションの各アプリケーション・セッションに対して有効化され、他のアプリケーションでは自動的に無効化されます。これらの動的ロールは、匿名セッションに対して有効化される点に注意してください。各アプリケーション・セッションに不要な場合、動的ロールに過大に権限を付与しないでください。通常、動的ロールに付与する必要があるのはオブジェクト権限のみです。
Real Application Securityによって保護されない表については、アプリケーションはアクセスのために必要に応じてアプリケーション・ユーザーではなくデータベース接続プール・ユーザーを使用できます。その場合、連結アプリケーション・セッションAPIコールは不要であり、動的ロールにオブジェクト権限は付与されません。
session.manager.pwd.key
およびsession.manager.pwd.map
session.manager.pwd.key
パラメータとsession.manager.pwd.map
パラメータ(oracle.rdbms.ras
として固定)は資格証明ストア内の資格証明(ユーザーIDとパスワード)を指します。session.manager.pwd.key
パラメータは、セッション・マネージャの資格証明を取得するために使用されます。現在、OPSS CSF資格証明ストアは資格証明の格納に使用され、CSF APIは実行時に資格証明を取得するために使用されます。また、セッション・マネージャのユーザーIDとパスワードは両方ともストアから取得できます。
session.manager.pwd.key
パラメータのデフォルト値はdefault
です。アプリケーションでデフォルトの資格証明が使用されている場合、このパラメータは省略できます。
アプリケーションでデフォルトの資格証明ではなく特定のセッション・マネージャを使用する場合、アプリケーションの管理者は別のキー名で資格証明を作成し、このパラメータを使用して構成する必要があります。詳細は、Oracle Application Server Containers for J2EEセキュリティ・ガイドの「OPSSセキュリティ・ストアの構成」を参照してください。
session.manager.pool.min
およびsession.manager.pool.max
セッション・マネージャの接続は、中間層でのデータ・セキュリティ・ポリシー(ACL)の問合せにも使用されます。この接続はプールとして管理されます。session.manager.pool.min
パラメータはプールの最小サイズを決定します。このパラメータはオプションです。デフォルト値は1です。
session.manager.pool.max
パラメータはプールの最大サイズを決定します。このパラメータはオプションです。デフォルト値は3です。
権限チェックが不要な場合は、session.manager.pool.min
値とsession.manager.pool.max
値の両方に対して、プール・サイズを1に設定する必要があります。
例8-2は、サーブレット・フィルタ、そのパラメータ、リスナーを含むアプリケーション・セッション・フィルタのサンプル構成を示しています。デフォルト値のあるパラメータはすべて、この例では省略されています。
例8-2 アプリケーション・セッション・フィルタのサンプル構成
<filter> <filter-name>ApplicationSessionFilter</filter-name> <filter-class>oracle.security.xs.ee.session.ApplicationSessionFilter</filter-class> <init-param> <param-name>application.datasource</param-name> <param-value>jdbc/myDBDS</param-value> </init-param> <init-param> <param-name>dynamic.roles</param-name> <param-value>my_drole</param-value> </init-param> </filter> <listener> <description>RAS Session Listener</description> <listener-class>oracle.security.xs.ee.session.ApplicationSessionListener</listener-class> </listener>
Real Application Securityを使用するには、アプリケーション・セッション・サービスとOPSSの両方をOracle Fusion MiddlewareのJava EEコンテナにデプロイして構成する必要があります。
WebLogic Serverの場合、前提条件は次のとおりです。
Oracle database 12c JDBCドライバに対して動作保証されたJRFベースのWLSドメイン(OPSSは組み込まれています)。必要とする機能に応じて、1つのドライバjarだけでなく多数のJDBC jarが必要になることがあります(UCP、I18N、SQLXMLなど)。
Oracle Database 12cリリース1 (12.1)以降
WebLogic Server 10.3.6および12.1.2 JRFリリース(Oracle Fusion Middlewareの一部)の場合、付属するJDBCドライバはOracle Database 12c互換ではありません。Oracle Database 12c JDBC jar (ojdbc6.jar
またはojdbc7.jar
および必要な機能に応じたその他のjar)を取得し、これらのjarをWebLogic Serverのクラスパスの前に追加する必要があります。詳細な手順は、Oracle WebLogic Server JDBCデータ・ソースの管理のセクションBを参照してください。
JDBCドライバとデータベースのバージョンが一致しない場合、Real Application Securityフィルタの初期化はエラー・メッセージが表示されて失敗します。次に例を示します。
Oracle Database 11g JDBCドライバがOracle Database 12cで使用されている場合、サーバー・ログに次のエラー・メッセージが表示されます: メソッドが欠落しているためRASセッション・マネージャを初期化できません
。
Oracle Database 12c JDBCドライバがOracle Database 11gで使用されている場合、サーバー・ログに次のエラー・メッセージが表示されます: ORA-00439: 機能は使用できません: Fusionセキュリティ
。
アプリケーションでアプリケーション・セッション・サービスを使用するには、次の手動構成手順に従います。手順は、WebLogic 10.3.6および12.1.2、JRFリリースの両方に使用できます。
Oracle Fusion Middlewareでは、構成ユーティリティを使用してアプリケーション・グループに共通設定を構成できます。WebLogicの場合、これはドメイン構成ウィザードです。今後のWLSリリース(リリース12.1.3)では、この構成ウィザードによって手順1から3 (手動構成)を自動化できます。この自動アプローチには、オフライン構成をサポートできるという利点もあります(管理サーバーが実行されていない場合)。
構成ウィザードを起動すると(<ORACLE_HOME>/oracle_common/common/bin/config.sh
)、次のユーザー・インタフェース(UI)が示され、Real Application Security構成情報の入力を求めるメッセージが表示されます。
最初のUIでは、アプリケーション・セッション・サービスは、選択するOracle Fusion Middleware機能の1つとして表示されます。選択すると、その依存関係(OPSS、JRFの一部)も自動的に選択されます。
2つめのUIでは、デフォルト・セッション・マネージャの資格証明を入力するよう求められます。
コード権限を付与するUIはありません。これは、事前定義されたxmlファイルをドメインのsystem-jazn-data.xml
ファイルに結合することで、自動的に行われます。事前定義されたxmlファイルには、必要なすべてのReal Application Securityコード権限付与が含まれます。
管理者がアプリケーションに別のセッション・マネージャを使用することを決定した場合、管理者は手動による手順2を実行するか、UIから特別なキー名を追加する必要があります。同じキー名をアプリケーションのweb.xml
に渡す必要があります。この場合、マップ名(ストア名)は引き続きoracle.rdbms.ras
に固定されているため、コード権限を付与する必要はありません。すべてのキーはすでに内部的に付与されているためです。
アプリケーション・セッションAPIは、クラスApplicationSessionService
を介して静的メソッドとして公開されます。APIは、現在のサブジェクトに基づいて設定された現在のアプリケーション・セッションで動作します。各APIの内部では、IDアサーションが内部的に実行され、現在のアプリケーション・セッションがサブジェクトと一致することが確認されます。不一致が見つかった場合、ApplicationSesseionException
例外がスローされます。サブジェクトとして呼び指すために、アプリケーション・セッションAPIのコール元コードは、常にSubject.doAs
の内部で実行する必要があります。詳細は、JDKのSubject.doAs
を参照してください。
現在のユーザーのアプリケーション・セッションを、特定のデータベース接続に連結します。
現在のユーザーのアプリケーション・セッションに連結するアプリケーション・コードには、コード・ベース権限は必要ありません。アプリケーション・セッションはそのままで動作し、連結によって追加の権限が昇格されることはありません。
構文
public static void attachSession(java.sql.Connection conn) throws ApplicationSessionException
パラメータ
パラメータ | 説明 |
---|---|
|
データベース・サーバー・ラウンドトリップのJDBC接続 |
例
現在のユーザーのアプリケーション・セッションを、特定のデータベース接続から連結解除します。
アプリケーション・セッションを常にアプリケーション・コードの最終ブロックから連結解除することをお薦めします。そうしないと、連結された接続が正しいユーザーの下で実行されていないコードに付与されることがあります。使用後にアプリケーション・セッションを適切に連結解除することは、コール元の責任です。
連結解除がコールされずに、同じ接続で連結が再度コールされると、サーバーは前に連結されたアプリケーション・セッションからの連結解除を施行して、現在のアプリケーション・セッションに連結します。
構文
public static void detachSession(java.sql.Connection conn) throws ApplicationSessionException
パラメータ
パラメータ | 説明 |
---|---|
|
データベース・サーバー・ラウンドトリップのJDBC接続 |
例
例8-3に、連結および連結解除APIをデータベース問合せとともに使用するサンプル・コードを示します。コール元は、問合せニーズに基づいて、連結コールと連結解除コールの境界を決定する必要があります。
例8-3 アプリケーション・セッションAPI: AttachSessionとDetachSession
/** * Typical application code calling attach/detach for database query */ public void queryHR(Connection conn) { String query = " select emp.employee_id, emp.salary from hr.employees emp"; Statement stmt = null; ResultSet rs = null; String id, salary; try { // attach connection to the current application session ApplicationSessionService.attachSession(conn); stmt = conn.createStatement(); rs = stmt.executeQuery(query); while (rs.next()) { id = rs.getString("employee_id"); salary = rs.getString("salary"); } } catch (ApplicationSessionException e) { } catch (SQLException e) { } finally { // detach the current application session from the connection try { ApplicationSessionService.detachSession(conn); } catch (Exception e) {} if (stmt != null) try {stmt.close();} catch (SQLException e) {}; if (rs != null) try { rs.close();} catch (SQLException e{}; } }
データベースで現在のアプリケーション・セッションを破棄して、現在のスレッドの実行コンテキストから削除します。これは、ログアウト時にアプリケーションによって呼び出す必要があります。最初にフィルタによって設定された現在のアプリケーション・セッションを破棄します。
構文
public static void destroySession(java.sql.Connection conn) throws ApplicationSessionException
パラメータ
パラメータ | 説明 |
---|---|
|
データベース・サーバー・ラウンドトリップのJDBC接続 |
例
例8-4に、アプリケーション・セッション・サービスを破棄するサンプル・コードを示します。
例8-4 アプリケーション・セッションAPI: DestroySession
void doLogout(HttpServletRequest request) {
DataSource dataSource = null;
Connection conn = null;
try {
InitialContext ic;
try {
ic = new InitialContext();
dataSource = (DataSource)ic.lookup("jdbc/myDBDS");
if (dataSource != null)
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
} catch (NamingException e) {
e.printStackTrace();
}
// invalidate Http session
request.getSession().invalidate();
// destroy XS session at DB
ApplicationSessionService.destroySession(conn);
} catch (ApplicationSessionException e) {
e.printStackTrace();
} finally {
if (conn != null)
try {
conn.close();
} catch (SQLException e) {
}
}
}
この項では、次のトピックについて説明します: アプリケーション・セッションでの動的ロールの有効化。
現在のアプリケーション・セッションを特定のデータベース接続に連結し、連結したアプリケーション・セッションでReal Application Security動的ロールを有効化します。これにより、アプリケーション・ネームスペースの設定など一部のデータベース操作を実行するために、信頼できるアプリケーション・コードに一時的に高い権限を付与できます。
これは、特定の信頼できるアプリケーション・コードのアプリケーション・セッション権限を昇格するためです。Real Application Security動的ロールは、連結時に有効化されます。信頼できるコードは、javaコード権限によって識別されます。
構文
public static void attachSessionPrivileged(java.sql.Connection conn, java.lang.String role) throws ApplicationSessionException
パラメータ
パラメータ | 説明 |
---|---|
|
データベース・サーバー・ラウンドトリップのJDBC接続 |
|
特定の動的ロール、リクエスト範囲である必要があります |
例
使用上の注意
javaセキュリティ・マネージャがオンであるかオフであるか、常にAPIで内部的に権限がチェックされます。コール元に権限がある場合(これは、特定のロールがポリシー・ファイルで定義されたロールとも一致することを意味します)、特定の動的ロールが連結時に有効化されます。権限がない場合、APIはAccessControlException
で失敗します。
コール元コード(caller.jar
ファイル)とアプリケーション・セッション・サービス・コード(xsee.jar
)は両方とも、SessioncodePermission
権限を持っている必要があります。caller.jar
がコンテナによって直接呼び出される場合は、これで十分です。caller.jar
が別のアプリケーション・コードによって呼び出される場合、アプリケーション・コードにこの権限が必要かどうかは、コール元が判断します。コール元でアプリケーションにこの権限が必要ない場合、コール元はAccessController.doPrivileged
でnull AccessControllerContext
を指定したattachSessionPrivileged
を呼び出すことができます。詳細は、Java APIを参照してください。これを実行することで、caller.jar
はアプリケーション・コードを全面的に信頼します。
動的ロールは、現在のアプリケーション・セッションではなく連結されたアプリケーション・セッションでのみ有効化されます。連結および連結解除の期間内で有効化されます。データベースでリクエスト範囲として動的ロールが定義されている必要があります。定義されていない場合、次の例外がスローされます: ORA-46055: 無効なロールが指定されました
。
例8-5 権限昇格API
<grant> <grantee> <codesource> <url>file:${domain.home}/servers/DefaultServer/tmp/_WL_user/MyWar/pi47ig/war/WEB-INF/lib/trusted.jar' </url> </codesource> </grantee> <permissions> <permission> <class>oracle.security.xs.ee.session.SessionCodePermission</class> <name> MY_NS_DROLE</name> <actions>attach </actions> </permission> </permissions> </grant> <grant> <grantee> <codesource> <url>file:${domain.home}/lib/xsee.jar</url> </codesource> </grantee> <permissions> <permission> <class>oracle.security.xs.ee.session.SessionCodePermission</class> <name>MY_NS_DROLE</name> <actions>attac </actions> </permission> </permissions> </grant>
現在のアプリケーション・セッションでネームスペースを作成します。指定されたネームスペースがデータベースで事前定義されていて、アプリケーション・セッションでADMIN_ANY_NAMESPACE
権限が有効化されている場合を除き、連結されたアプリケーション・セッションがMODIFY_NAMESPACE
操作を実行することをネームスペースACLで許可する必要があります。
構文
public static void createNamespace(java.sql.Connection conn, java.lang.String name) throws ApplicationSessionException
パラメータ
パラメータ | 説明 |
---|---|
|
データベース・サーバー・ラウンドトリップのJDBC接続 |
|
特定のネームスペース名 |
例
例8-6を参照してください。
現在のアプリケーション・セッションからネームスペースを削除します。指定されたネームスペースがデータベースで事前定義されていて、アプリケーション・セッションでADMIN_ANY_NAMESPACE
権限が有効化されている場合を除き、連結されたアプリケーション・セッションがMODIFY_NAMESPACE
操作を実行することをネームスペースACLで許可する必要があります。
構文
public static void deleteNamespace(java.sql.Connection conn, java.lang.String name) throws NamespaceNotFoundException, ApplicationSessionException
パラメータ
パラメータ | 説明 |
---|---|
|
データベース・サーバー・ラウンドトリップのJDBC接続 |
|
特定のネームスペース名。 |
例
例8-6を参照してください。
属性値を現在のアプリケーション・セッションのネームスペースに設定します。指定されたネームスペースがデータベースで事前定義されていて、アプリケーション・セッションでADMIN_ANY_NAMESPACE
権限が有効化されている場合を除き、連結されたアプリケーション・セッションがMODIFY_ATTRIBUTE
操作を実行することをネームスペースACLで許可する必要があります。
ネームスペースに属性が存在しない場合、APIは特定の値で属性を作成します。存在する場合は、既存の値を特定の値に設定します。
構文
public static void setNamespaceAttribute(java.sql.Connection conn, java.lang.String name, java.lang.String attribute, java.lang.String value) throws NamespaceNotFoundException, ApplicationSessionException
パラメータ
パラメータ | 説明 |
---|---|
|
データベース・サーバー・ラウンドトリップのJDBC接続 |
|
特定のネームスペース名 |
|
特定のネームスペース属性名 |
|
特定のネームスペース属性値 |
例
例8-6を参照してください。
現在のアプリケーション・セッションでネームスペースから属性を削除します。指定されたネームスペースがデータベースで事前定義されていて、アプリケーション・セッションでADMIN_ANY_NAMESPACE
権限が有効化されている場合を除き、連結されたアプリケーション・セッションがMODIFY_ATTRIBUTE
操作を実行することをネームスペースACLで許可する必要があります。
構文
public static void deleteNamespaceAttribute(java.sql.Connection conn, java.lang.String name, java.lang.String attribute) throws NamespaceNotFoundException, ApplicationSessionException
パラメータ
パラメータ | 説明 |
---|---|
|
データベース・サーバー・ラウンドトリップのJDBC接続 |
|
特定のネームスペース名 |
|
特定のネームスペース属性名 |
例
例8-6を参照してください。
現在のアプリケーション・セッションでネームスペースから属性を取得します。特定のネームスペースを作成する必要があります。データベース接続は不要で、この操作に対する権限はチェックされません。
ネームスペースを変更するAPI(getNamespaceAttribute
以外)は、入力パラメータとしてデータベース接続を持ちます。これらのAPIは、JVMの現在のアプリケーション・セッションでネームスペースを更新し、変更内容をデータベース表にシリアライズします。接続は連結する必要があります。連結されたアプリケーション・セッションを使用して、サーバーがネームスペースの変更を認可できるかどうかを特定します。
特定の信頼できるアプリケーション・コードにのみ、ネームスペースの設定を許可します。接続は、ネームスペースで昇格権限(MODIFY_NAMESPACE
、MODIFY_ATTRIBUTE
)を持つ動的ロールで連結できます。これは、attachSessionPrivileged
APIを使用し、ネームスペース権限のみを動的ロールに付与することで実現できます。
構文
public static java.lang.String getNamespaceAttribute(java.lang.String name, java.lang.String attribute) throws NamespaceNotFoundException, ApplicationSessionException
パラメータ
パラメータ | 説明 |
---|---|
|
特定のネームスペース名 |
|
特定のネームスペース属性名 |
例
例8-6に、ネームスペースAPIを使用してネームスペースを設定し、アプリケーション・セッションの権限昇格APIを使用するサンプル・サーブレット・フィルタを示します。
アプリケーション・ネームスペースの使用方法について知っておくべき重要な点
次の使用情報で、アプリケーション・ネームスペースの使用方法について重要な点をまとめます。
Real Application Securityフィルタは、すべてのアプリケーション・ネームスペースを現在のアプリケーション・セッションにキャッシュします。
初回アクセスの場合、データベースに新規アプリケーション・セッションを作成する必要があります。この時点で、まだアプリケーション・ネームスペースは設定されていません。
ユーザーの以後のアクセスでは、フィルタが常に、アプリケーション・セッションに作成されたすべてのネームスペースをJVMの現在のアプリケーション・セッションにキャッシュします。
アプリケーション・コードは常に、現在のアプリケーション・セッションからネームスペースをアクセスします。各更新操作は、表および現在のアプリケーション・セッション(JVM)の値を変更する、サーバーへのラウンド・トリップです。そのために、各更新APIにはデータベース接続パラメータがあります。ただし、読取り属性は、データベースにアクセスせずにJVMの現在のアプリケーション・セッションから読み取るローカル操作です。
ネームスペースの変更が正常に完了すると、変更内容は新たに連結されたアプリケーション・セッションだけでなく、すでに連結されたアプリケーション・セッションにも伝播されます。連結されたアプリケーション・セッションはすべて、単一ソース(現在のアプリケーション・セッション)を参照するためです。
現在のアプリケーション・セッションのネームスペースは、Webアプリケーションのhttpリクエスト範囲内で同じです。他のアプリケーションはいつでもネームスペースを変更できます。変更は、Real Application Securityフィルタによって現在のhttpリクエストの開始時に1回だけ取得されます。同じhttpリクエスト内で行われた連結はすべて、現在のアプリケーション・セッションの同じネームスペースを参照します。
アプリケーション・コードは、ネームスペース値の変更を完全に制御します。現在のアプリケーション・セッションのネームスペースをいつでも読み取り、ネームスペースAPIをコールしてネームスペースを更新するかどうかを決定します。
例8-6 ネームスペースAPI
/** * Trusted application code (servlet filter) sets up namespace * Using privilege elevation and namespace APIs */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { Connection conn = null; try { conn = myDatasource.getConnection(); // Attach an application session with a dynamic role. ApplicationSessionService.attachSessionPrivileged(conn, "myNSRole"); try { // Get the current value. String currentValue = ApplicationSessionService.getNamespaceAttribute("mySecuredNS", "myAttribute"); // If the current value is not desired, set it. if ("myValue".compareToIgnoreCase(currentValue) != 0) ApplicationSessionService.setNamespaceAttribute(conn, "mySecuredNS", "myAttribute", "myValue"); } catch (NamespaceNotFoundException e) { // Namespace is not found, create it. ApplicationSessionService.createNamespace(conn, "mySecuredNS"); // Set the attribute. ApplicationSessionService.setNamespaceAttribute(conn, "mySecuredNS", "myAttribute", "myValue"); } } catch (SQLException e) { } catch (ApplicationSessionException e) { } finally { // Detach an application session. try { ApplicationSessionService.detachSession(conn); } catch (Exception e) {} if (conn != null) try { conn.close();} catch (Exception e) {} } // Execution of application code. chain.doFilter(request, response);
この項では、次のトピックについて説明します: ACLの権限のチェック。
指定された接続の連結されているアプリケーション・セッションを使用して、ACLの権限をチェックします。次の使用上の注意が伴います。
連結された接続が指定されている必要があります。権限チェックは、連結されているアプリケーション・セッションに基づきます。attachSessionPrivileged
コールを介して、連結されているアプリケーション・セッションに、現在のアプリケーション・セッションより多くの権限を付与できます。
APIはACL IDの入力パラメータを取得します。これは、ORA_GET_ACLID
演算子を使用して表から問い合せることができます。この演算子は、現在の行に関連付けられている一連のACL IDを返します。
このAPIは、権限名の入力パラメータを取得します。この入力パラメータは、SELECT
またはUPDATE
などのDML権限か、他のユーザー定義権限です。
構文
public static boolean checkPrivilege(java.sql.Connection conn, byte[] acls, java.lang.String privilege) throws ApplicationSessionException
パラメータ
パラメータ | 説明 |
---|---|
|
データベース・サーバー・ラウンドトリップのJDBC接続 |
|
行形式での特定のACL ID |
|
特定の権限名 |
例
例8-7では、行に関連付けられているACLを取得して、ACLのUPDATE
権限をチェックします。
例8-7 権限チェックAPI
public Collection<Employee> queryHR(Connection conn ) {
Statement stmt = null;
ResultSet rs = null;
Collection<Employee> result = new ArrayList<Employee>();
try {
// attach session
ApplicationSessionService.attachSession(conn);
stmt = conn.createStatement();
rs = stmt.executeQuery(query);
while (rs.next()) {
Employee emp = new Employee();
emp.setId(rs.getString("EMPLOYEE_ID"));
AuthorizationIndicator ai =
((OracleResultSet)rs).getAuthorizationIndicator("salary");
if (ai == AuthorizationIndicator.NONE) {
emp.setSalary(rs.getString("salary"));
} else {
emp.setSalary("******") ;
}
// get ACL associated with the row
emp.setAcl(rs.getBytes("acl_id"));
// check "update" privilege
boolean canUpdate = ApplicationSessionService.checkPrivilege(conn, emp.getAcl(), "UPDATE");
emp.setUpdate(canUpdate);
result.add(emp);
emp.setFname(rs.getString("first_name"));
emp.setLname(rs.getString("last_name"));
emp.setEmail(rs.getString("email"));
emp.setPhone(rs.getString("phone_number"));
emp.setManagerId(rs.getString("manager_id"));
emp.setDepId(rs.getString("department_id"));
}
} catch (ApplicationSessionException e) {
e.printStackTrace();
// process me
} catch (SQLException e) {
// process me
e.printStackTrace();
} finally {
if (stmt != null) try {stmt.close();} catch (SQLException e) {};
if (rs != null) try { rs.close();} catch (SQLException e) {};
try {ApplicationSessionService.detachSession(conn);} catch (ApplicationSessionException e) {};
}
return result;
}
この項では、アプリケーション・セッション・サービスで、Oracle Fusion Middlewareによって外部で管理されるユーザーとロールをサポートする方法を示します。このJava例は、セキュリティ人事管理(HR)シナリオに基づいています。サンプルHR
スキーマのEMPLOYEES
表を使用します。
関連項目:
ユーザーおよびグループからアプリケーション・ロールへのマッピングの詳細は、HRデモのユースケース - ユーザー・ロールについてを参照してください。
例8-8に、外部プリンシパル用にHRデモ・アプリケーションを設定するセットアップ・スクリプト(setup.sql
)を示します。
このセットアップ・スクリプトは、次の操作を実行します。
外部ユーザーのオブジェクト権限のための動的ロールHROBJ
を作成します。
データ権限、更新、削除、挿入を示す、権限view_sensitive_info
と集約権限update_info
を含むセキュリティ・クラスHRPRIVS
を作成します。これは事前定義クラスDML
から生じたクラスです。
EMP
ACL、EMP_ACL
を作成し、制限された部門の従業員レコードにアクセスするためのEMP
、HRMGR
およびHRREP
権限を付与します。各外部プリンシパル(アプリケーション・ロール: HRREP
、HRMGR
およびEMP
)は、OPSSポリシー・ストアGUID値と一致する必要があります。
セルフACL、SELF_ACL
を作成して、従業員に自分のレコードを表示および更新するためのEMP
権限を付与します。
マネージャACL、MGR_ACL
を作成して、マネージャが自分の従業員の給与情報を確認できるようにします。
EMPLOYEES
表に、データ・セキュリティ・ポリシーEMPLOYEE_DS
を作成します。このポリシーは、部門60および100の従業員へのアクセスを制御するインスタンス・セットをEMP_ACL
に定義します。機密性の高いSALARY列へのアクセスを制御する属性制約も定義します。
2つの追加インスタンス・セットをSELF_ACL
およびMGR_ACL
に定義し、データ・セキュリティ・ポリシーEMPLOYEE_DS
に追加します。
ディスパッチャに、追加の権限をいくつか付与します。
例8-8 外部プリンシパル用のHRデモ・アプリケーションの設定
Rem Copyright (c) 2009, 2014, Oracle and/or its affiliates.
Rem All rights reserved.
SET ECHO ON
SET FEEDBACK 1
SET NUMWIDTH 10
SET LINESIZE 80
SET TRIMSPOOL ON
SET TAB OFF
SET PAGESIZE 100
-- A PL/SQL function to determine manager-report relationship
conn hr/hr;
create or replace package hrutil as
function ismyreport(id IN PLS_INTEGER)
return PLS_INTEGER ;
end hrutil;
/
create or replace package body hrutil as
function ismyreport(id IN PLS_INTEGER)
return PLS_INTEGER is
mycount PLS_INTEGER ;
myid PLS_INTEGER ;
begin
select employee_id into myid from hr.employees
where UPPER(email) = XS_SYS_CONTEXT('PROFILE_NS','EMAIL');
select count(employee_id) into mycount from hr.employees
where employee_id = id start with manager_id = myid
connect by prior employee_id = manager_id ;
return mycount ;
end ismyreport ;
end hrutil ;
/
-- Create a dynamic role for object privileges for external users.
connect sys/password as sysdba
show con_name;
-- Create a dynamic role for HR object privileges.
exec xs_principal.delete_principal('HROBJ',XS_ADMIN_UTIL.CASCADE_OPTION);
exec xs_principal.create_dynamic_role('HROBJ');
-- Create a db role to have HR object privileges.
drop role hr_db_obj;
create role hr_db_obj;
-- Grant object privilege to the db role.
grant select, insert, update, delete on hr.employees to hr_db_obj;
-- Grant db role to dynamic role.
grant hr_db_obj to HROBJ;
-- Create a security class with privilege view_sensitive_info, and
-- aggregate privilege update_info that implies data privileges,
-- update, delete, insert, which come from pre-defined security class
-- DML.
DECLARE
priv_list XS$PRIVILEGE_LIST;
BEGIN
priv_list :=XS$PRIVILEGE_LIST(
XS$PRIVILEGE(name=>'VIEW_SENSITIVE_INFO'),
XS$PRIVILEGE(name=>'UPDATE_INFO',
implied_priv_list=>XS$NAME_LIST
('"UPDATE"', '"DELETE"', '"INSERT"')));
xs_security_class.create_security_class(
name=>'HRPRIVS',
parent_list=>XS$NAME_LIST('DML'),
priv_list=>priv_list);
END;
/
-- External Principal (app role) Used for data security:
-- Such a principal must match the OPSS policy store.
-- roleName="HRREP" guid="37ED0D108C2F11E2BF802D569259982"
-- roleName="HRMGR" guid="4077A2B08C2F11E2BF802D569259982"
-- roleName="EMP" guid="F917C3608CF011E2BF802D569259982"
-- Create an EMP Acl to grant EMP, HRMGR and HRREP privileges to access an employee record in the restricted departments.
DECLARE
ace_list XS$ACE_LIST;
BEGIN
ace_list := XS$ACE_LIST(
XS$ACE_TYPE(privilege_list=>XS$NAME_LIST('"SELECT"','VIEW_SENSITIVE_INFO'),
granted=>true,
principal_name=>'"37ED0D108C2F11E2BF802D569259982"', principal_type=>XS_ACL.PTYPE_EXTERNAL),
XS$ACE_TYPE(privilege_list=>XS$NAME_LIST('UPDATE_INFO'),
granted=>true,
principal_name=>'"4077A2B08C2F11E2BF802D569259982"', principal_type=>XS_ACL.PTYPE_EXTERNAL),
XS$ACE_TYPE(privilege_list=>XS$NAME_LIST('"SELECT"'),
granted=>true,
principal_name=>'"F917C3608CF011E2BF802D569259982"', principal_type=>XS_ACL.PTYPE_EXTERNAL));
xs_acl.create_acl(name=> 'EMP_ACL',
ace_list=> ace_list,
sec_class=>'HRPRIVS',
description=> 'Employee access to his/her data');
END;
/
-- Create a self Acl to grant EMP privileges to for an employee to see and update his own record.
-- Grant UPDATE, VIEW_SENSITIVE_INFO privileges to the EMP role.
DECLARE
ace_list XS$ACE_LIST;
BEGIN
ace_list := XS$ACE_LIST(
XS$ACE_TYPE(privilege_list=> XS$NAME_LIST('"UPDATE"', 'VIEW_SENSITIVE_INFO'),
principal_name=>'"F917C3608CF011E2BF802D569259982"', principal_type=>XS_ACL.PTYPE_EXTERNAL));
xs_acl.create_acl(name=> 'SELF_ACL',
ace_list=> ace_list,
sec_class=>'HRPRIVS',
description=> 'Employee access to his/her data');
END;
/
-- Create Manager ACL, to allow a manager to see his employee's salary.
-- Grant VIEW_SENSITIVE_INFO privileges to EMP role on the Manager's employees.
--
DECLARE
ace_list XS$ACE_LIST;
BEGIN
ace_list := XS$ACE_LIST(
XS$ACE_TYPE(privilege_list=> XS$NAME_LIST('VIEW_SENSITIVE_INFO'),
principal_name=>'"F917C3608CF011E2BF802D569259982"', principal_type=>XS_ACL.PTYPE_EXTERNAL));
xs_acl.create_acl(name=> 'MGR_ACL',
ace_list=> ace_list,
sec_class=>'HRPRIVS',
description=> 'Manager can see his reports salaray');
END;
/
-- Create data security policy for the EMPLOYEE table. The policy defines
-- an instant set to control the access to the employees in department
-- 60 and 100. It also defines an attribute constraint to control
-- the access to sensitive column SALARY.
DECLARE
inst_sets XS$REALM_CONSTRAINT_LIST;
attr_secs XS$COLUMN_CONSTRAINT_LIST;
BEGIN
inst_sets :=
XS$REALM_CONSTRAINT_LIST(
XS$REALM_CONSTRAINT_TYPE(realm=> 'DEPARTMENT_ID in (60, 100)',
acl_list=> XS$NAME_LIST('EMP_ACL')));
attr_secs :=
XS$COLUMN_CONSTRAINT_LIST(
XS$COLUMN_CONSTRAINT_TYPE(column_list=> XS$LIST('SALARY'),
privilege=> 'VIEW_SENSITIVE_INFO'));
xs_data_security.create_policy(
name=>'EMPLOYEES_DS',
realm_constraint_list=>inst_sets,
column_constraint_list=>attr_secs);
END;
/
-- Add more instance sets to the above data security.
declare
inst1 xs$REALM_CONSTRAINT_TYPE;
inst2 xs$REALM_CONSTRAINT_TYPE;
begin
inst1 := xs$REALM_CONSTRAINT_TYPE(realm=> 'UPPER(email) = XS_SYS_CONTEXT(''PROFILE_NS'',''EMAIL'')',
acl_list=> XS$NAME_LIST('SELF_ACL'));
xs_data_security.append_realm_constraints('EMPLOYEES_DS', inst1);
inst2 := xs$REALM_CONSTRAINT_TYPE(realm=> 'hr.hrutil.ismyreport(employee_id) = 1',
acl_list=> XS$NAME_LIST('MGR_ACL'));
xs_data_security.append_realm_constraints('EMPLOYEES_DS', inst2);
end;
/
-- Apply the data security policy on the table.
begin
XS_DATA_SECURITY.apply_object_policy(schema=>'HR', object=>'EMPLOYEES',
policy=>'EMPLOYEES_DS');
end;
/
-- Grant more privileges for the dispatcher.
exec XS_ADMIN_UTIL.GRANT_SYSTEM_PRIVILEGE('ADMIN_ANY_NAMESPACE','ts',XS_ADMIN_UTIL.PTYPE_XS);
grant select on sys.dba_xs_session_roles to ts_role;
EXIT;
例8-9に、フィルタ、そのパラメータ、リスナーを含む完全なアプリケーション・セッション・フィルタのサンプル構成ファイル(web.xml
)を示します。例8-11に示すネームスペース(MyFilter.java
)を設定するためのフィルタ、例8-10に示すMyHR.java
という名前のサンプル・サーブレット・アプリケーション、およびMySession.java
、MyUpdate.java
およびLogoutServlet.java
(これは示されていません)を参照します。
MySession
はV$XS_SESSION_ROLES
ビューを問い合せてアプリケーション・セッションのロールを表示し、XS$SESSION
ネームスペースのユーザーを問い合せてアプリケーション・セッションのユーザーを表示し、V$XS_SESSION_NS_ATTRIBUTES
ビューを問い合せてアプリケーション・セッションのネームスペースを表示して、アプリケーション・セッションに連結します。
MyUpdate
はHR.EMPLOYEES
表で更新を実行して、従業員の電話番号を更新します。
LogoutServlet
はログアウト操作を実行してから、データベースでアプリケーション・セッションを破棄します。
ApplicationSessionFilter
フィルタ構成では、フィルタ・セクションはクラスApllicationSessionFilter
を参照し、パラメータapplication.datasource
とパラメータ値jdbc/myDBDS
を記述し、パラメータdynamic roles
と例8-8のセットアップ・スクリプトで作成された値HROBJ
を記述します。
例8-9 完全なアプリケーション・セッション・フィルタのサンプル構成
<?xml version = '1.0' encoding = 'UTF-8'?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"> <filter> <filter-name>JpsFilter</filter-name> <filter-class>oracle.security.jps.ee.http.JpsFilter</filter-class> <init-param> <param-name>enable.anonymous</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>remove.anonymous.role</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>application.name</param-name> <param-value>MyHRApp</param-value> </init-param> <!-- Following needed for Menu Security --> <!--init-param> <param-name>oracle.security.jps.jaas.mode</param-name> <param-value>subjectOnly</param-value> </init-param--> </filter> <filter> <filter-name>ApplicationSessionFilter</filter-name> <filter-class>oracle.security.xs.ee.session.ApplicationSessionFilter</filter-class> <init-param> <param-name>application.datasource</param-name> <param-value>jdbc/myDBDS</param-value> </init-param> <init-param> <param-name>dynamic.roles</param-name> <param-value>HROBJ</param-value> </init-param> <!-- <init-param> <param-name>dispatcher.pool.max</param-name> <param-value>90</param-value> </init-param> --> <!-- init-param> <param-name>application.id</param-name> <param-value>MyHRApp</param-value> </init-param> <init-param> <param-name>session.provider</param-name> <param-value>XS</param-value> </init-param> <init-param> <param-name>db.url</param-name> <param-value>jdbc:oracle:thin:@myhost:1521:orcl</param-value> </init-param> <init-param> <param-name>dispatcher.id</param-name> <param-value>ts</param-value> </init-param> <init-param> <param-name>dispatcher.pwd.map</param-name> <param-value>XS_MAP</param-value> </init-param> <init-param> <param-name>dispatcher.pwd.key</param-name> <param-value>XS_KEY</param-value> </init-param> <init-param> <param-name>dispatcher.pool.min</param-name> <param-value>3</param-value> </init-param> <init-param> <param-name>dispatcher.pool.max</param-name> <param-value>10</param-value> </init-param --> <!--init-param> <param-name>namespaces</param-name> <param-value>sec_ns</param-value> </init-param--> </filter> <filter> <filter-name>MyFilter</filter-name> <filter-class>trusted.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>JpsFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping> <filter-mapping> <filter-name>ApplicationSessionFilter</filter-name> <url-pattern>/myhr</url-pattern> <url-pattern>/mysession</url-pattern> <url-pattern>/myupdate</url-pattern> <url-pattern>/logout</url-pattern> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping> <filter-mapping> <filter-name>MyFilter</filter-name> <url-pattern>/myhr</url-pattern> <url-pattern>/mysession</url-pattern> <url-pattern>/myupdate</url-pattern> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping> <listener> <listener-class>oracle.security.xs.ee.session.ApplicationSessionListener</listener-class> </listener> <servlet> <servlet-name>MySession</servlet-name> <servlet-class>app.MySession</servlet-class> </servlet> <servlet> <servlet-name>LogoutServlet</servlet-name> <servlet-class>app.MyLogout</servlet-class> </servlet> <servlet> <servlet-name>MyHR</servlet-name> <servlet-class>app.MyHR</servlet-class> </servlet> <servlet> <servlet-name>MyUpdate</servlet-name> <servlet-class>app.MyUpdate</servlet-class> </servlet> <servlet-mapping> <servlet-name>MySession</servlet-name> <url-pattern>/mysession</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>LogoutServlet</servlet-name> <url-pattern>/logout</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>MyHR</servlet-name> <url-pattern>/myhr</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>MyUpdate</servlet-name> <url-pattern>/myupdate</url-pattern> </servlet-mapping> <security-constraint> <web-resource-collection> <web-resource-name>my servlet</web-resource-name> <url-pattern>/myhr</url-pattern> <url-pattern>/mysession</url-pattern> <url-pattern>/myupdate</url-pattern> </web-resource-collection> <auth-constraint> <role-name>valid-users</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>CLIENT-CERT,FORM</auth-method> <form-login-config> <form-login-page>/login.jsp</form-login-page> <form-error-page>/error.jsp</form-error-page> </form-login-config> </login-config> <security-role> <role-name>valid-users</role-name> </security-role> </web-app>
例8-10に、例8-9に示すアプリケーション・セッション・フィルタのサンプル構成(web.xml
ファイル)で参照されている、MyHR.java
というサンプル・サーブレット・アプリケーションを示します。
MyHRアプリケーションはEMPLOYEES
表で問合せを実行して、結果を返します。権限がある場合は、ログイン資格証明に応じて、次に説明されている特定タスクを実行できます。
従業員として、自分の給与情報は表示できますが、他人の給与情報は表示できず、自分の連絡先情報のみ更新できます。
HRマネージャとしてログインしている場合、すべての従業員の給与レコードを表示でき、彼らの連絡先情報を更新できます。
HRデモ(3) - チーム・マネージャとしてログインについて
チーム・マネージャとしてログインしている場合、自分のチームの従業員の給与情報のみ表示できますが、彼らの連絡先情報は更新できず、自分の連絡先情報のみ更新できます。
ACLの権限チェック(checkPrivilege
)から、UPDATE
権限がある場合はその従業員のレコードの更新を実行する権限があり、EMPLOYEE_ID
にその従業員のレコードにアクセスできるリンクが表示されます。
例8-10 サンプル・サーブレット・アプリケーション(MyHR.java)
/* Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.*/ package app; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource; import oracle.jdbc.OracleResultSet; import oracle.jdbc.OracleResultSet.AuthorizationIndicator; import oracle.security.xs.ee.session.ApplicationSessionException; import oracle.security.xs.ee.session.ApplicationSessionService; public class MyHR extends HttpServlet { private static final String CONTENT_TYPE = "text/html; charset=UTF-8"; String query = " select emp.EMPLOYEE_ID, emp.first_name, emp.last_name, " + " emp.email, emp.phone_number, salary, emp.manager_id, " + " emp.department_id,ora_get_aclids(emp) as acl_id" + " from hr.employees emp"; public void init(ServletConfig config) throws ServletException { super.init(config); } public void queryHR(PrintWriter out) throws ApplicationSessionException { DataSource dataSource = null; Connection conn = null; try { InitialContext ic; try { ic = new InitialContext(); dataSource = (DataSource)ic.lookup("jdbc/myDBDS"); if (dataSource != null) try { conn = dataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } } catch (NamingException e) { e.printStackTrace(); } try { queryHR(conn, out); } catch (Exception e) { e.printStackTrace(); } } finally { if (conn != null) try { conn.close(); } catch (SQLException e) { } } } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); PrintWriter pw = response.getWriter(); pw.println(HEADER); pw.println("<h1><font size=\"+2\">RAS Session Service Demo</font></h1>"); pw.println("<font size=\"+1\">"); pw.println("You are logged in as <b>" + request.getRemoteUser() + "</b>"); try { queryHR(pw); } catch (ApplicationSessionException e) { e.printStackTrace(); } pw.println(FOOTER); pw.close(); } public Collection<Employee> queryHR(Connection conn ) { Statement stmt = null; ResultSet rs = null; Collection<Employee> result = new ArrayList<Employee>(); try { // attach session ApplicationSessionService.attachSession(conn); stmt = conn.createStatement(); rs = stmt.executeQuery(query); while (rs.next()) { Employee emp = new Employee(); emp.setId(rs.getString("EMPLOYEE_ID")); AuthorizationIndicator ai = ((OracleResultSet)rs).getAuthorizationIndicator("salary"); if (ai == AuthorizationIndicator.NONE) { emp.setSalary(rs.getString("salary")); } else { emp.setSalary("******") ; } // get ACL associated with the row emp.setAcl(rs.getBytes("acl_id")); // check "update" privilege boolean canUpdate = ApplicationSessionService.checkPrivilege(conn, emp.getAcl(), "UPDATE"); emp.setUpdate(canUpdate); result.add(emp); emp.setFname(rs.getString("first_name")); emp.setLname(rs.getString("last_name")); emp.setEmail(rs.getString("email")); emp.setPhone(rs.getString("phone_number")); emp.setManagerId(rs.getString("manager_id")); emp.setDepId(rs.getString("department_id")); } } catch (ApplicationSessionException e) { e.printStackTrace(); // process me } catch (SQLException e) { // process me e.printStackTrace(); } finally { if (stmt != null) try {stmt.close();} catch (SQLException e) {}; if (rs != null) try { rs.close();} catch (SQLException e) {}; try {ApplicationSessionService.detachSession(conn);} catch (ApplicationSessionException e) {}; } return result; } public void queryHR(Connection conn, PrintWriter out ) { Collection<Employee> list = queryHR(conn); PrintWriter pw = out; pw.println("<br>Displaying employee record(s) that you can access.<br>"); pw.println("</font>"); pw.println("<i>NOTE: Salary is only shown if you are authorized to view, and ID is shown as a link if you are authorized to perform an update.</i><br>"); out.println("<table border=\"1\">"); String tmp; if (list.size() > 0) { out.println("<tr>"); out.println("<th>ID</th>"); out.println("<th>First Name</th>"); out.println("<th>Last Name</th>"); out.println("<th>Email</th>"); out.println("<th>Phone</th>"); out.println("<th>Salary</th>"); out.println("<th>Department ID</th>"); out.println("<th>Manager ID</th>"); out.println("</tr>"); } for (Employee e: list) { if (e.canUpdate()) { tmp = "<a href=\"update.jsp?id=" + e.getId() + "\">" + e.getId() + "</a>"; } else { tmp = e.getId(); } out.println("<tr><td>" + tmp + "</td>"); out.println("<td>" + e.getFname() + "</td>"); out.println("<td>" + e.getLname() + "</td>"); out.println("<td>" + e.getEmail() + "</td>"); out.println("<td>" + e.getPhone() + "</td>"); out.println("<td>" + e.getSalary() + "</td>"); out.println("<td>" + e.getDepId() + "</td>"); out.println("<td>" + e.getManagerId() + "</td></tr>"); } out.println("</TABLE>"); }; class Employee { String id; String salary; boolean update; String fname; String lname; String email; String phone; String managerId; String depId; byte[] acl; public void setId(String id) { this.id = id; } public String getId() { return id; } public void setSalary(String salary) { this.salary = salary; } public String getSalary() { return salary; } public void setUpdate(boolean canUpdate) { this.update = canUpdate; } public boolean canUpdate() { return update; } public void setFname(String fname) { this.fname = fname; } public String getFname() { return fname; } public void setLname(String lname) { this.lname = lname; } public String getLname() { return lname; } public void setEmail(String email) { this.email = email; } public String getEmail() { return email; } public void setPhone(String phone) { this.phone = phone; } public String getPhone() { return phone; } public void setManagerId(String managerId) { this.managerId = managerId; } public String getManagerId() { return managerId; } public void setDepId(String depId) { this.depId = depId; } public String getDepId() { return depId; } public void setAcl(byte[] acl) { this.acl = acl; } public byte[] getAcl() { return acl; } } private static String HEADER = "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head>" + "<meta content=\"text/html; charset=UTF-8\" http-equiv=\"content-type\"/>" + "<title>Oracle</title>" + "<link href=\"css/general.css\" type=\"text/css\" rel=\"stylesheet\"/>" + "<link href=\"css/window.css\" type=\"text/css\" rel=\"stylesheet\"/>" + "<link href=\"css/login.css\" type=\"text/css\" rel=\"stylesheet\"/>" + "<script type=\"text/javascript\">" + " if (top != self) top.location.href = location.href;" + "</script>" + "<style type=\"text/css\">" + "html { background-color: #001C34;}" + "</style>" + "</head>" + "<body onload=\"document.loginData.j_username.focus();\">" + " <div id=\"top\">" + " <div id=\"login-header\">" + " <div id=\"login-logo\">" + " <img src=\"images/logo.png\"/>" + "</div>" + " </div>" + " <div id=\"content\">" + "<div id=\"app_data\"><div id=\"title\"></div>"; private static String FOOTER = "<a href=\"/myapp/logout\">Logout</a>" + "</div></div><div id=\"info\"></div></div></body></html>"; }
例8-11に、アプリケーション・ネームスペースを設定するためのフィルタを示します。このフィルタはMyHR.java
という名前で、例8-9に示すアプリケーション・セッション・フィルタのサンプル構成(web.xml
ファイル)で参照されています。
このフィルタは別個のjarとしてデプロイする必要があり、jarファイルにSessionCodePermission
を付与する必要があります。
このフィルタはまずV$XS_SESSION_ROLES
ビューを問い合せて、Real Security Applicationセッションのロールを表示します。次に、このフィルタは信頼できるアプリケーション・コード(フィルタ)がネームスペース(getNamespaceAttribute)が存在するかどうかを最初にチェックする方法をデモし、存在しない場合は、セッション権限昇格(attachSessionPrivileged
)を使用してセキュリティ・クリティカルなネームスペースおよびネームスペースAPI (createNamespace
、setNamespaceAttribute
)を設定してネームスペースを作成し、ネームスペース属性を設定します。
例8-11 アプリケーション・ネームスペースを設定するためのフィルタ
/* Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.*/ package trusted; import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.sql.DataSource; import oracle.security.xs.ee.session.ApplicationSessionException; import oracle.security.xs.ee.session.ApplicationSessionService; import oracle.security.xs.ee.session.NamespaceNotFoundException; /** * Demonstrate how trusted application code (a filter) can set up * security critical namespace using session privilege elevation and * namespace APIs. * * The filter should be deployed as a separate jar, and SessionCodePermission * should be granted to the jar. */ public class MyFilter implements Filter { private FilterConfig _filterConfig = null; DataSource myDatasource = null; public void init(FilterConfig filterConfig) throws ServletException { _filterConfig = filterConfig; } public void destroy() { _filterConfig = null; } public void querySessionRoles(Connection conn) throws SQLException { String query = "select role_name from v$xs_session_roles order by role_name"; String roles = null; try { Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(query); System.out.println("<p> roles in RAS session (from myfilter):</p>"); System.out.println("<TABLE>"); while (rs.next()) { roles = rs.getString(1); System.out.println("<tr><td>" + roles + "</td></tr>"); } System.out.println("</TABLE>"); } finally { } return; } private boolean namespaceExists(String ns, String attribute, String value) throws ApplicationSessionException { try { return value.equalsIgnoreCase(ApplicationSessionService.getNamespaceAttribute(ns, attribute)); } catch (NamespaceNotFoundException e) { return false; } } private Connection getConnection() { DataSource dataSource = null; InitialContext ic; try { ic = new InitialContext(); //TODO cache context dataSource = (DataSource)ic.lookup("jdbc/myDBDS"); if (dataSource != null) try { return dataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } } catch (NamingException e) { e.printStackTrace(); } return null; } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { Connection conn = null; try { String email = ((HttpServletRequest)request).getRemoteUser(); if ( email != null && !namespaceExists("PROFILE_NS", "EMAIL", email )) { conn = getConnection(); //AccessController.doPrivileged(new AttachAction(conn), null); ApplicationSessionService.attachSessionPrivileged(conn, "SESSION_NS_DROLE"); ApplicationSessionService.createNamespace(conn, "PROFILE_NS"); ApplicationSessionService.setNamespaceAttribute(conn, "PROFILE_NS", "EMAIL", email); ApplicationSessionService.detachSession(conn); } } catch (ApplicationSessionException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { if (conn != null) try { conn.close(); } catch (SQLException e) { } } try { chain.doFilter(request, response); } catch (IOException e) { e.printStackTrace(); } catch (ServletException e) { e.printStackTrace(); } } }
HRデモのユースケースでは、アイデンティティ管理ストアにユーザー名、ユーザー名のパスワード、グループ名が含まれます。他方、OPSSセキュリティ・ストアにはアプリケーション・ロールとユーザーおよびグループからアプリケーション・ロールへのマッピングが含まれます。例8-12に、あるユーザーLPOPP
について、ユーザーおよびグループからアプリケーション・ロールへのマッピングを行うためのコード・スニペットを示します。
例8-12 ユーザーおよびグループからアプリケーション・ロールへのマッピング
<app-role>
<name>EMP</name>
<display-name>Employee for dept #60 and dept #100</display-name>
<description>HR manager for dept #60 and representative for dept #100</description>
<guid>F917C3608CF011E2BF802D569259982</guid>
<class>oracle.security.jps.service.policystore.ApplicationRole</class>
<members>
<member>
<class>weblogic.security.principal.WLSUserImpl</class>
<name>LPOPP</name>
</member>
</members>
</app-role>
表8-1に、従業員LPOPP
としてログインした場合にアクセスできる従業員レコードを示します。全員の給与情報以外のレコードおよび自分の給与情報を表示でき、自分の連絡先情報を更新できます。
このアクセス権は、次によって設定されます。
レルムおよび権限付与(1): DEPARTMENT_ID in (60, 100)
およびSELECT to EMP
レルムおよび権限付与(2): UPPER(email) = XS_SYS_CONTEXT("PROFILE_NS","EMAIL")
およびUPDATE, VIEW_SENSITIVE_INFO to EMP
列制約: SALARY
にはVIEW_SENSITIVE_INFO
権限が必要です
給与は、ユーザーに表示権限がある場合にのみ表示され、更新権限がある場合はリンクとしてIDが示されます(表にイタリック形式で)。
例8-1 セッション・サービスHRデモ(1) - 従業員LPOPPとしてログイン
ID | 名 | 姓 | 電子メール | 電話番号 | 給与 | 部門ID | マネージャID |
---|---|---|---|---|---|---|---|
103 |
Alexander |
Hunold |
AHUNOLD |
510.222.3388 |
****** |
60 |
102 |
104 |
Bruce |
Ernst |
BERNST |
590.423.4568 |
****** |
60 |
103 |
105 |
David |
Austin |
DAUSTIN |
590.423.4569 |
****** |
60 |
103 |
106 |
Valli |
Pataballa |
VPATABAL |
590.423.4560 |
****** |
60 |
103 |
107 |
Diana |
Lorentz |
DLORENTZ |
590.423.4567 |
****** |
60 |
103 |
108 |
Nancy |
Greenberg |
NGREENBE |
515.124.4569 |
****** |
100 |
101 |
109 |
Daniel |
Faviet |
DFAVIET |
515.124.4169 |
****** |
100 |
108 |
110 |
John |
Chen |
JCHEN |
515.124.4269 |
****** |
100 |
108 |
111 |
Ismael |
Sciarra |
ISCIARRA |
515.124.4369 |
****** |
100 |
108 |
112 |
Jose Manuel |
Urman |
JMURMAN |
515.124.4469 |
****** |
100 |
108 |
113 |
Luis |
Popp |
LPOOP |
133.444.5555 |
6900 |
100 |
108 |
表8-2に、HRマネージャHRMGR
としてログインした場合にアクセスできる従業員レコードを示します。すべての従業員の給与情報を表示でき、すべての従業員の連絡先情報を更新できます。
このアクセス権は、次のレルムおよび権限付与によって設定されます: DEPARTMENT_ID in (60, 100)
、SELECT
、UPDATE
およびVIEW_SENSITIVE_INFO to HRMGR
。
給与は、ユーザーに表示権限がある場合にのみ表示され、更新権限がある場合はリンクとしてIDが示されます(表にイタリック形式で)。
例8-2 セッション・サービスHRデモ(2) - HRマネージャHRMGRとしてログイン
ID | 名 | 姓 | 電子メール | 電話番号 | 給与 | 部門ID | マネージャID |
---|---|---|---|---|---|---|---|
103 |
Alexander |
Hunold |
AHUNOLD |
510.222.3388 |
9000 |
60 |
102 |
104 |
Bruce |
Ernst |
BERNST |
590.423.4568 |
6000 |
60 |
103 |
105 |
David |
Austin |
DAUSTIN |
590.423.4569 |
4800 |
60 |
103 |
106 |
Valli |
Pataballa |
VPATABAL |
590.423.4560 |
4800 |
60 |
103 |
107 |
Diana |
Lorentz |
DLORENTZ |
590.423.4567 |
4200 |
60 |
103 |
108 |
Nancy |
Greenberg |
NGREENBE |
515.124.4569 |
12008 |
100 |
101 |
109 |
Daniel |
Faviet |
DFAVIET |
515.124.4169 |
9000 |
100 |
108 |
110 |
John |
Chen |
JCHEN |
515.124.4269 |
8200 |
100 |
108 |
111 |
Ismael |
Sciarra |
ISCIARRA |
515.124.4369 |
7700 |
100 |
108 |
112 |
Jose Manuel |
Urman |
JMURMAN |
515.124.4469 |
7800 |
100 |
108 |
113 |
Luis |
Popp |
LPOOP |
133.444.5555 |
6900 |
100 |
108 |
表8-3に、チーム・マネージャAHUNOLD
としてログインした場合にアクセスできる従業員レコードを示します。チーム・マネージャの給与情報は表示できますが、彼らの連絡先情報は更新できず、自分の連絡先情報のみ更新できます。
このアクセス権は、次のレルムおよび権限付与によって設定されます: is my member(employee_id) =1
とVIEW_SENSITIVE_INFO to EMP
。
給与は、ユーザーに表示権限がある場合にのみ表示され、更新権限がある場合はリンクとしてIDが示されます(表にイタリック形式で)。
例8-3 セッション・サービスHRデモ(3) - チーム・マネージャAHUNOLDとしてログイン
ID | 名 | 姓 | 電子メール | 電話番号 | 給与 | 部門ID | マネージャID |
---|---|---|---|---|---|---|---|
103 |
Alexander |
Hunold |
AHUNOLD |
510.222.3388 |
9000 |
60 |
102 |
104 |
Bruce |
Ernst |
BERNST |
590.423.4568 |
6000 |
60 |
103 |
105 |
David |
Austin |
DAUSTIN |
590.423.4569 |
4800 |
60 |
103 |
106 |
Valli |
Pataballa |
VPATABAL |
590.423.4560 |
4800 |
60 |
103 |
107 |
Diana |
Lorentz |
DLORENTZ |
590.423.4567 |
4200 |
60 |
103 |
108 |
Nancy |
Greenberg |
NGREENBE |
515.124.4569 |
****** |
100 |
101 |
109 |
Daniel |
Faviet |
DFAVIET |
515.124.4169 |
****** |
100 |
108 |
110 |
John |
Chen |
JCHEN |
515.124.4269 |
****** |
100 |
108 |
111 |
Ismael |
Sciarra |
ISCIARRA |
515.124.4369 |
****** |
100 |
108 |
112 |
Jose Manuel |
Urman |
JMURMAN |
515.124.4469 |
****** |
100 |
108 |
113 |
Luis |
Popp |
LPOOP |
133.444.5555 |
****** |
100 |
108 |