ヘッダーをスキップ
Oracle Application Development Framework開発者ガイド
10g(10.1.3.0)
B40012-02
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

18 アプリケーションへのセキュリティの追加

この章では、WebアプリケーションでOracle ADF Securityを使用して、Oracle Application Serverで認証と認可を処理する方法について説明します。コンテナ管理のセキュリティに厳格に従う場合にOracle ADF Securityを省略する方法についても説明します。

この章の内容は次のとおりです。

18.1 Oracle ADF Webアプリケーションでのセキュリティの導入

Oracle ADF Securityは、Webアプリケーションのセキュリティを提供します。Oracle ADF Securityは、認証と認可のためのOracle Application Server Java Authentication and Authorization(JAAS)Providerを実装する交換可能アーキテクチャに基づいて実装されます。

まず、リソース・プロバイダを使用するようにアプリケーションを構成する必要があります。ログインとパスワードの認証に使用されるユーザー・データは、データベースやLDAPディレクトリなどのリソース・プロバイダ内に格納されます。jazn.xmlファイルを編集して、OracleAS JAAS Providerのアイデンティティ管理プロバイダを選択します。jazn.xmlファイルの編集については、次の項をお読みください。

次に、Oracle ADF Securityを使用するようにアプリケーションのコンテナを構成します。これで、認証と認可にOracle ADF Securityを使用できるようになります。Oracle ADF Securityを使用せずに、コンテナ管理のセキュリティを使用することもできます。

次の各項では、認証を構成し、ログイン・ページとログアウト・ページを作成する方法について説明しています。

リソースを特定のユーザーに指定する場合は、Oracle ADF Modelレイヤーを使用して認可を有効にできます。ADFによる認可を使用しない場合も、ADFによる認証を使用できます。標準のJ2EEによる認可とOracle ADF Modelレイヤーを統合して、リソースを制限することもできます。SRDemoアプリケーションでは、後者のアプローチを採用しています。認可を実装するための2つのアプローチを理解するには、次の各項を参照してください。


注意:

OC4Jのセキュリティ機能の詳細は、Oracle Application Serverドキュメント・ライブラリの『Oracle Containers for J2EEセキュリティ・ガイド』を参照してください。たとえば、「標準セキュリティの概要」では、JAASセキュリティ・モデルの概要を説明しています。

18.2 JAZNリソース・プロバイダの指定

軽量のXMLリソース・プロバイダ(system-jazn-data.xml)またはOracle Internet DirectoryからJAZNレルムを使用する場合は、jazn.xmlファイルを編集して、これらのプロバイダの1つを選択する必要があります。

注意: 別のJAAS準拠セキュリティ・プロバイダを使用している場合は、セキュリティ・プロバイダのマニュアルを参照してください。

18.2.1 リソース・プロバイダの指定方法

軽量XMLリソース・プロバイダ(system-jazn-data.xml)またはOracle Internet Directory(LDAPプロバイダ)からJAZNレルムを使用するには、アプリケーションでどちらのプロバイダを使用するかを指定する必要があります。

リソース・プロバイダを指定するには、次のディレクトリにあるjazn.xmlのプロバイダ環境ディスクリプタを編集します。

  • JDeveloperの埋込みOC4Jの場合:

    <JDEV_HOME>/jdev/system/oracle.j2ee.10.1.3/embedded-oc4j/configディレクトリ

  • JDeveloperのスタンドアロンOC4Jの場合:

    <JDEV_HOME>/j2ee/home/configディレクトリ

  • Oracle Application Serverの場合:

    <OC4J_HOME>/j2ee/<instance_name>/configディレクトリ

XMLベースのプロバイダで使用する場合は、LDAPの環境ディスクリプタをコメント・アウトします。

<jazn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation=
         "http://xmlns.oracle.com/oracleas/schema/jazn-10_0.xsd"
   schema-major-version="10"
   schema-minor-version="0"
   provider="XML"
   location="./system-jazn-data.xml"
   default-realm="jazn.com"
/>

<!--
<jazn
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation=
         "http://xmlns.oracle.com/oracleas/schema/jazn-10_0.xsd"
   schema-major-version="10"
   schema-minor-version="0"
   provider="LDAP"
   location="ldap://myoid.us.oracle.com:389"
/>
-->

LDAPプロバイダを使用する場合は、XMLの環境ディスクリプタをコメント・アウトします。

<!--
<jazn
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation=
         "http://xmlns.oracle.com/oracleas/schema/jazn-10_0.xsd"
   schema-major-version="10"
   schema-minor-version="0"
   provider="XML"
   location="./system-jazn-data.xml"
   default-realm="jazn.com"
/>
-->

<jazn
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation=
         "http://xmlns.oracle.com/oracleas/schema/jazn-10_0.xsd"
   schema-major-version="10"
   schema-minor-version="0"
   provider="LDAP"
   location="ldap://myoid.us.oracle.com:389"
/>

18.2.2 Oracle ADF Securityとリソース・プロバイダについて必要な知識

Oracle ADF SecurityではOracleAS JAASを使用するため、LoginContextに基づいて基本的な認証を行います。LoginContextでは、実際の認証を処理する交換可能なコード・ビットであるログイン・モジュールを使用します。Oracle ADF Securityでは、標準的なユーザー名とパスワードによる認証に、OracleAS JAAS ProviderのRealmLoginModuleログイン・モジュールも使用します。

Oracle ADF Securityは、指定されたリソース・プロバイダに対してユーザーを認証できます。データベースやLDAPディレクトリなどのリソース・プロバイダには、ログインとパスワードを認証するためのデータが含まれています。

具体的には、Oracle ADF Securityは、Oracle Single Sign-OnとOracle Internet Directory(OID)を使用した認証をサポートしています。スケーラビリティと高い管理機能が必要な本番環境では、OID(LDAPベースのプロバイダ)を使用して、アイデンティティ管理を提供する必要があります。この場合、Oracle Containers for J2EEに付属のLDAP管理ツールを使用してユーザーを管理する必要があります。

OID使用の詳細は、Oracle Application Serverドキュメント・ライブラリの『Oracle Identity Management委任管理ガイド』を参照してください。

さらに、JDeveloperには、小規模アプリケーションや開発およびテストに使用できるXMLベースのリソース・プロバイダ(system-jazn-data.xml)も付属しています。このプロバイダには、ユーザー、ロール、権限およびログイン・モジュールの構成が含まれています。

18.3 web.xmlファイル内での認証の構成

多くのWebベース・アプリケーションには、リクエストの発信者に関する情報が必要な、サイトの「保護された」領域へのリンクがある場合があります。つまり、リンク先の領域へは、認証されたユーザーのみがアクセスできます。この機能は、adfAuthenticationサーブレットを使用して動的に実現されるか、ADFなしで、OC4Jにより提供されるJ2EEコンテナ管理の認証のみを使用して実現されます。どちらの方法でも、コンテナにセキュリティ制約を構成して、認証されていないセッションによるサーバーへのアクセスを防ぎます。


注意:

SRDemoアプリケーションでは、現在ADF ModelレイヤーでのOracle ADF Securityのデモを行えません。SRDemoアプリケーションでの認証の処理方法については、18.3.1項「J2EEコンテナ管理の認証を有効にする方法」を参照してください。

ユーザーが認証されると、アプリケーションはそのユーザーが認可制約で定義されたリソースにアクセスする権限を持っているかどうかを判断できます。この制約とアプリケーションで認識されるユーザーまたはロールは、web.xmlファイルで設定します。

たとえば、SRDemoアプリケーションでは、3つのロールを使用して、だれがどのような機能を実行するアクセス権を持つかを指定しています。各ユーザーを、user、technicianまたはmanagerの3つのロールのいずれかに分類する必要があります。3つの基準はすべて、Oracle Application Serverが提供するコンテナ管理のフォームベース認証を使用して実装されます。

18.3.1 J2EEコンテナ管理の認証を有効にする方法

アプリケーションに、データ・ストアにアクセスするユーザーの認証が必要なページが含まれている場合、web.xml構成ファイルで次の宣言をする必要があります。

  • <security-role>では、セキュリティ・コンテキストでの有効なロールを定義します。

  • <login-config>では、フォームベースまたはHTTPSなど、認証のプロトコルを定義します。

  • <security-constraint>では、認可されたユーザーまたはロールのみがアクセスできるリソースをURLパターンとHTTPメソッドで定義します。

  • <servlet>では、認証を提供するサーブレットを定義します。

  • <servlet-mapping>では、サーブレットをURLパターンにマップします。

  • <filter>では、認証リクエストの内容の変換に使用するフィルタを定義します。

  • <filter-mapping>では、フィルタをアプリケーションが使用するファイル拡張子にマップします。ADFバインディング・フィルタの詳細は、「ADFバインディング・フィルタの構成」を参照してください。


注意:

ADF FacesコンポーネントをJSFページに最初に挿入すると、JDeveloperによりweb.xmlファイルが更新され、ADF Facesサーブレット・フィルタとADF Facesリソース・サーブレットが定義されます。これらのサーブレット設定の詳細は、「ADF Facesコンポーネントの初回挿入時に発生する処理」を参照してください。

web.xmlファイルに定義されたセキュリティ・ロールにより、アプリケーションで認識できるユーザー・グループの論理名が識別されます。セキュリティ制約を作成して、認証されたユーザーが認可されたロールに属しているかどうかに基づいて特定のWebページに対するアクセスを制限します。

J2EEコンテナ管理のセキュリティ用にセキュリティ・ロールを指定する方法:

  1. ナビゲータでJSPプロジェクトを展開し、web.xmlファイルを右クリックして「プロパティ」を選択します。web.xmlファイルは、プロジェクトのWEB-INFフォルダにあります。

  2. セキュリティ・ロール定義を追加するには、「Webアプリケーション・デプロイメント・ディスクリプタ」エディタの左パネルの「セキュリティ・ロール」を選択し、「追加」をクリックします。

    ここに入力したロールは、データ・ストアからのロールと一致している必要があります。たとえば、XMLベースのプロバイダ(system-jazn-data.xmlを使用して定義)を使用している場合は、認証が必要な定義済の<roles><name>の値を入力します。さらに、セキュリティ・ロール・マッピングを使用するようにOC4Jを構成する場合は、ロール名はorion-web.xml構成ファイルの<security-role-mapping>要素で定義されたロールとも一致している必要があります。

  3. すべての変更を保存して、次に示すとおりログイン構成の作成に進みます。

図18-1に、セキュリティ・ロール定義の表示されたweb.xmlエディタを示します。SRDemoアプリケーションには、3つのセキュリティ・ロールが定義されています。

図18-1 「Webアプリケーション・デプロイメント・ディスクリプタ」ダイアログの「セキュリティ・ロール」パネル

デプロイメント・ディスクリプタ・エディタのセキュリティ・ロール

ログイン構成を構成する前に、ログインWebページとオプションのログイン・エラー・ページを作成しておく必要があります。詳細は、18.4項「ログイン・ページの作成」を参照してください。

J2EEコンテナ管理のセキュリティ用にログイン構成を作成する方法:

  1. ナビゲータでJSPプロジェクトを展開し、web.xmlファイルを右クリックして「プロパティ」を選択します。web.xmlファイルは、プロジェクトのWEB-INFフォルダにあります。

  2. ログイン構成を作成するには、エディタの左パネルで「ログイン構成」を選択します。たとえば、フォームベースの認証を使用するには、「フォームベース認証」を選択し、login.jspxloginerror.jspxなど、ログイン・ページとログイン・エラー・ページのレンダリングに使用するファイルの名前を入力します。詳細は、18.4.1項「ログイン・ページとエラー・ページの関連付け」を参照してください。

  3. すべての変更を保存し、「Webアプリケーション・デプロイメント・ディスクリプタ」エディタを閉じます。

図18-2に、ログイン構成定義の表示されたweb.xmlエディタを示します。

図18-2 「Webアプリケーション・デプロイメント・ディスクリプタ」ダイアログの「ログイン構成」パネル

デプロイメント・ディスクリプタ・エディタのログイン構成

J2EEコンテナ管理のセキュリティ用にセキュリティ制約を作成する方法:

  1. ナビゲータでJSPプロジェクトを展開し、web.xmlファイルを右クリックして「プロパティ」を選択します。web.xmlファイルは、プロジェクトのWEB-INFフォルダにあります。

  2. セキュリティ制約の定義を追加するには、エディタの左側で「セキュリティ制約」を選択し、パネルの下部で「新規」をクリックします。

  3. 新しいWebリソースを追加するには、「制約」ページで「追加」をクリックします。

    ヒント: セキュリティ制約はURLとして指定するため、Webリソース名は、アプリケーションのデータベース接続名に基づいて指定できます。たとえば、データベース接続がMyConnectionの場合、Webリソース名にjdbc/MyConnectionと入力できます。

  4. クライアント・リクエストのURLパターンを指定するには、指定したWebリソース名をクリックし、「URLパターン」を選択して「追加」をクリックします。Webアプリケーション・フォルダを基準にトップ・レベルにあるJSPログイン・ページを参照するには、スラッシュ(/)を入力します。

  5. 認可されたセキュリティ・ロールを指定するには、「認可」タブを選択します。認証を必要とするセキュリティ・ロールを選択します。手順2で設定したロールを選択できます。

  6. トランスポート保証を指定するには、「ユーザー・データ」タブを選択します。使用する保証のタイプを選択します。

  7. すべての変更を保存し、「Webアプリケーション・デプロイメント・ディスクリプタ」エディタを閉じます。

図18-3に、セキュリティ制約定義の表示されたweb.xmlエディタを示します。

図18-3 「Webアプリケーション・デプロイメント・ディスクリプタ」ダイアログの「セキュリティ制約」パネル

デプロイメント・ディスクリプタ・エディタのセキュリティ制約

18.3.2 Oracle ADF Security以外のセキュリティ制約を使用する場合の処理

例18-1に、J2EEコンテナ管理のセキュリティ構成の完了時にweb.xmlファイルに含める必要がある定義のサンプルを示します。

例18-1 SRDemoアプリケーションのweb.xmlファイルで有効に設定されたJ2EEセキュリティ

<security-constraint>
    <web-resource-collection>
      <web-resource-name>ALL Manager</web-resource-name>
      <url-pattern>faces/app/management/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>manager</role-name>
    </auth-constraint>
</security-constraint>
<security-constraint>
    <web-resource-collection>
      <web-resource-name>AllStaff</web-resource-name>
      <url-pattern>faces/app/staff/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>technician</role-name>
      <role-name>manager</role-name>
    </auth-constraint>
</security-constraint>
<security-constraint>
    <web-resource-collection>
      <web-resource-name>SRDemo Sample</web-resource-name>
      <url-pattern>faces/app/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
       <role-name>user</role-name>
          <role-name>technician</role-name>
          <role-name>manager</role-name>
       </auth-constraint>
  </security-constraint>
  <login-config>
     <auth-method>FORM</auth-method>
     <form-login-config>
        <form-login-page>infrastructure/SRLogin.jspx</form-login-page>
        <form-error-page>infrastructure/SRLogin.jspx</form-error-page>
     </form-login-config>
  </login-config>
  <security-role>
     <description>Customers of ACME corp</description>
     <role-name>user</role-name>
  </security-role>
  <security-role>
     <description>Employees of ACME corp</description>
     <role-name>technician</role-name>
  </security-role>
  <security-role>
     <description>The boss</description>
     <role-name>manager</role-name>
  </security-role>

ユーザーが保護されたページへのリンクをクリックし、そのユーザーが認証されていない(認証済のユーザー・プリンシパルが現在SecurityContextにない)場合、OC4Jのセキュリティ・サーブレットがコールされ、Webコンテナによってデプロイメント・ディスクリプタの<form-login-config>要素に定義されたログイン・ページが起動されます。

ユーザーがユーザー名とパスワードを送信すると、そのデータはユーザー情報が格納されているリソース・プロバイダのデータと比較され、一致した場合、リクエストの送信者(ユーザー)は認証されます。ユーザー名がSecurityContextに格納されます。ここには、認可権限を判断するために他のセキュリティ関連情報(ユーザーが属するグループなど)を取得するときにアクセスできます。

web.xmlデプロイメント・ディスクリプタでは、アプリケーションの認証済ユーザーが使用できるリソースを指定する<security-constraints>を通じて宣言的なセキュリティがサポートされます。ユーザーがWebページへのアクセスを許可されるかどうかは、<auth_constraint>要素で指定されているロール内の該当するメンバーシップによって異なります。アプリケーションでは、サーブレット・メソッドのisUserInRole()をコールして、特定のユーザーが指定されたセキュリティ・ロールに所属しているかどうかを判別します。<security-role>要素により、system-jazn-data.xmlファイルのJAZNレルムで定義されているのと同じ名前に基づいて、ロールの論理名が定義されます。

18.3.3 Oracle ADFによる認証を有効にする方法

Webベース・アプリケーションの場合、web.xmlファイル内のadfAuthenticationサーブレットに対してセキュリティ制約を構成できます。この制約は、認証されていないセッションによるサーブレットへのアクセスを禁止します。保護された領域へのリンクに制約で定義されたURLパターンが含まれているかぎり、Webコンテナはユーザーが認証されていない場合ログイン・ページを起動します。


注意:

adfAuthenticationサーブレットはオプションで、動的な認証を可能にします。つまり、まだログインしていないユーザーが認可を必要とするページにアクセスした場合、ユーザーはログインを求められます。サーブレットは、オプションのパラメータsuccess_urlをとります。success_urlを指定した場合、ログインに成功すると、ユーザーはリクエストしたページに移動します。success_urlを指定しない場合、ログインに成功すると、ユーザーはログイン処理が開始されたページに戻ります。

Oracle ADF Security用にweb.xmlを構成する方法:

  1. ナビゲータでJSPプロジェクトを展開し、web.xmlファイルを右クリックして「プロパティ」を選択します。web.xmlファイルは、プロジェクトのWEB-INFフォルダにあります。

  2. セキュリティ・ロール、ログイン構成およびセキュリティ制約を通常どおり定義します。(前述の手順を参照してください。)

  3. ADF認証サーブレットの<servlet>要素を作成するには、エディタの左パネルで「Servlet/JSP」を選択して「新規」をクリックします。次のように入力します。

    サーブレット名: adfAuthentication

    サーブレット・クラス: oracle.adf.share.security.authentication.AuthenticationServlet

    認証に成功した場合に表示されるページのURLを含む初期化パラメータを追加するには、「初期化パラメータ」を選択して「追加」をクリックします。URLを入力しない場合、ユーザーは現在のページに戻ります。

  4. サーブレット・マッピングを作成するには、エディタの左パネルで「サーブレット・マッピング」を選択して「追加」をクリックします。次のように入力します。

    URLパターン: /adfAuthentication/*

    サーブレット名: adfAuthentication

  5. すべての変更を保存し、「Webアプリケーション・デプロイメント・ディスクリプタ」エディタを閉じます。

図18-4に、adfAuthenticationサーブレットのサーブレット・マッピング定義の表示されたweb.xmlエディタを示します。

図18-4 「Webアプリケーション・デプロイメント・ディスクリプタ」ダイアログの「サーブレット・マッピング」パネル

デプロイメント・ディスクリプタ・エディタのADFサーブレット・マッピング

18.3.4 Oracle ADFによるセキュリティ制約を使用する場合の処理

例18-2に、web.xmlファイルに含める必要がある定義のサンプルを示します。

例18-2 サンプルweb.xmlファイルで有効に設定されたOracle ADF Security

<servlet>
  <servlet-name>adfAuthentication</servlet-name>
 <servlet-class>oracle.adf.share.security.authentication.
                              AuthenticationServlet</servlet-class>
  <init-param>
    <param-name>sucess_url</param-name>
    <param-value>inputForm.jsp</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>adfAuthentication</servlet-name>
  <url-pattern>/adfAuthentication/*</url-pattern>
</servlet-mapping>
<security-constraint>
  <web-resource-collection>
    <web-resource-name>adfAuthentication</web-resource-name>
    <url-pattern>/adfAuthentication</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>user</role-name>
  </auth-constraint>
</security-constraint>
<login-config>
  <auth-method>FORM</auth-method>
  <form-login-config>
    <form-login-page>login.jspx</form-login-page>
    <form-error-page>login.jspx</form-error-page>
  </form-login-config>
</login-config>
<security-role>
  <role-name>user</role-name>
</security-role>

ユーザーが保護されたリンクをクリックし、そのユーザーが認証されていない(認証済のユーザー・プリンシパルが現在SecurityContextにない)場合、Oracle ADF Securityのログイン・サーブレットがコールされ、Webコンテナによってログイン・ページが起動されます。

ユーザーがユーザー名とパスワードを送信すると、そのデータはユーザー情報が格納されているリソース・プロバイダのデータと比較され、一致した場合、リクエストの送信者(ユーザー)は認証されます。ユーザー名がSecurityContextに格納されます。ここには、認可権限を判断するために他のセキュリティ関連情報(ユーザーが属するグループなど)を取得するときにアクセスできます。

Oracle ADF SecurityはOracleAS JAASを実装しているため、認証によって、リクエストの送信者を表すJAASサブジェクトも作成されます。

18.4 ログイン・ページの作成

Webアプリケーションのログイン・ページでは、フォームのポスト方法として、J2EEセキュリティ・コンテナ・ログイン・メソッドj_security_checkを使用する必要があります。図18-5は、SRDemoアプリケーションのサンプル・ログイン・ページです。

図18-5 SRDemoアプリケーションのサンプル・ログイン・ページ

SRDemoアプリケーションのサンプル・ログイン・ページ

注意:

ログイン・ページを作成する場合、JSP要素とJSTLタグを使用できます。ページはJSFXドキュメントとしてフォーマットできますが、JSFとコンテナのセキュリティに関する制約により、JSFコンポーネントは使用できません。

ログイン・フォームのWebページの作成方法:

  1. ユーザー・インタフェース・プロジェクトを選択し、新規ギャラリを開いて、「Web Tier - JSP」カテゴリから「JSP」を選択します。「Web Tier - JSF」カテゴリを選択して、ログイン・フォームをJSPXドキュメントとして作成しないでください。

  2. JSPの作成ウィザードで、JSPファイル・タイプとしてJSPXドキュメント・タイプを選択します。ウィザードでは、マネージドBeanを使用せずにJSPXドキュメントを作成できます。

  3. ウィザードの「タグ・ライブラリ」ページで「すべてのライブラリ」を選択し、「選択済のライブラリ」リストにJSTLフォーマット1.1JSTLコア1.1を追加します。

  4. 「終了」をクリックしてウィザードを終了し、JSPXファイルをユーザー・インタフェース・プロジェクトに追加します。

  5. コンポーネント・パレットで「JSTL 1.1 FMT」ページを選択し、「SetBundle」をJSPXドキュメントの構造ウィンドウにドラッグし、title要素の上に表示されるようにします。

  6. 「SetBundleの挿入」ダイアログで、「basename」をページのリソース・バンドルを含むパッケージに設定します。たとえば、SRDemoアプリケーションでは、oracle.srdemo.view.resources.UIResourcesです。

  7. オプションで、「Message」を構造ウィンドウに表示されているtitle要素の上にドラッグします。Message要素をダブルクリックし、keyプロパティをリソース・バンドルのページ・タイトル・キーに設定します。たとえば、SRDemoアプリケーションでは、キーはsrlogin.pageTitleです。ページ作成から文字列タイトルの残りを削除します。

  8. コンポーネント・パレットから「HTML Forms」ページを選択し、「Form」をページ本体内にドラッグします。「フォームの挿入」ダイアログで、アクションをj_security_checkに、メソッドをpostに設定します。

  9. ユーザー名の「Text Field」をフォームにドラッグし、名前をj_usernameに設定します。

  10. フォームに「Password Field」をドラッグし、j_passwordという名前を付けます。

  11. フォームに「Submit Button」をドラッグし、ラベルをSign Onに設定します。

  12. コンポーネント・パレットでもう一度「JSTL 1.1 FMT」ページを選択し、2つの「Message」タグをフォームにドラッグして、入力フィールドの横に表示されるようにします。キー・プロパティを設定します。たとえば、SRDemoアプリケーションでは、リソース・キーはsrlogin.passwordsrlogin.usernameです。

例18-3は、SRDemoアプリケーションのログイン・ページのソース・コードです。このJSPXドキュメントでは、JSFコンポーネントの使用時にセキュリティ・コンテナとの競合が発生しないよう、HTML要素とJSTLタグのみを使用しています。セキュリティ・チェック方法は、<form>要素上に表示され、フォームにはユーザー名とパスワードを受け入れる入力フィールドがあります。これらのフィールドは、それぞれの値をコンテナのログインBean属性のj_usernamej_passwordに割り当てます。

例18-3 SRLogin.jspxからのサンプル・ソース

<html>
    <head>
      <meta http-equiv="Content-Type"
            content="text/html; charset=windows-1252"/>
      <fmt:setBundle basename="oracle.srdemo.view.resources.UIResources"/>
      <title>
        <fmt:message key="srdemo.login"/>
      </title>
    </head>
    <body>
        ... omitting the "number of attempts" checking logic ...
        <form action="j_security_check" method="post">
          <table cellspacing="3" cellpadding="2" border="0" width="100%">
            <tr>
              <td colspan="3">
                <img height="69" width="340"
                     src="/SRDemo/faces/images/SRBranding.gif"
                     alt="SRDemo Logo"/>
                <hr/>
              </td>
            </tr>
            <tr>
              <td colspan="3">
                <h1>
                  <fmt:message key="srlogin.pageTitle"/>
                </h1>
              </td>
            </tr>
            <tr>
              <td colspan="3">
                <c:if test="${sessionScope.loginAttempts >0}">
                  <h3><fmt:message key="srdemo.badLogin"/></h3>
                </c:if>
              </td>
            </tr>
            <tr>
              <td>&amp;nbsp;</td>
              <td> </td>
              <td rowspan="7">
                <table border="1" cellpadding="5">
                  <tr>
                    <td>
                      <fmt:message key="srlogin.info"/>
                    </td>
                  </tr>
                </table>
              </td>
            </tr>
            <tr>
              <td>&amp;nbsp;</td>
            </tr>
            <tr>
              <td width="120">
                <b><fmt:message key="srlogin.username"/></b>
              </td>
              <td>
                <input type="text" name="j_username"/>
              </td>
            </tr>
            <tr>
              <td width="120">
                <b><fmt:message key="srlogin.password"/></b>
              </td>
              <td>
                <input type="password" name="j_password"/
              </td>
            </tr>
            <tr>
              <td> </td>
              <td>
                <input type="submit" name="logon" value="Sign On"/>
              </td>
            </tr>
            <tr>
            </tr>
              <td>&amp;nbsp;</td>
            <tr>
              <td>&amp;nbsp;</td>
            </tr>
            <tr>
              <td>&amp;nbsp;</td>
            </tr>
            <tr>
              <td colspan="3">
                <hr/>
              </td>
            </tr>
          </table>
        </form>
      </c:if>
    </body>
</html>

18.4.1 ログイン・ページとエラー・ページの関連付け

Webコンテナが認証を実行できるように、web.xmlファイルには、ログイン構成情報を含める必要があります。ログイン用に表示するページとユーザーの認証ができなかったためにログインに失敗したときに表示するページを指定します。

ログインの処理方法の構成:

  1. アプリケーション・ナビゲータで、WEB-INFフォルダにあるweb.xmlを探します。

  2. web.xmlを右クリックして「プロパティ」を選択します。

  3. 「Webアプリケーション・デプロイメント・ディスクリプタ」ダイアログで、「ログイン構成」を選択します。

  4. 「フォームベース認証」を選択し、ログイン・ページとエラー・ページ用のパス名を入力します。ログイン・ページとエラー・ページのパスには、ユーザーの認証に使用されるドキュメント・ルートに対する相対パスを指定します。たとえば、SRDemoアプリケーションでは、ログインおよびエラー用の両方のページにパスinfrastructure/SRLogin.jspxが使用されています。

図18-6に、ログイン構成定義の表示されたweb.xmlエディタを示します。

図18-6 「Webアプリケーション・デプロイメント・ディスクリプタ」ダイアログの「ログイン構成」パネル

デプロイメント・ディスクリプタ・エディタのログイン構成

18.4.2 ログイン・ページとエラー・ページを関連付ける場合の処理

web.xmlのログイン構成情報を定義すると、JDeveloperによって次の定義が作成されます。

<login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
      <form-login-page>infrastructure/SRLogin.jspx</form-login-page>
      <form-error-page>infrastructure/SRLogin.jspx</form-error-page>
    </form-login-config>
  </login-config>

フォームベース認証を選択し、ユーザーが記述した認証用のHTMLフォームを指定したため、ページ・サーブレットでは、ユーザーを認証するために指定されたJSPページが検索されます。JSPページは、特定のネーミング規則に準拠するフォームを含むHTMLページを戻す必要があります。同様に、認証が失敗した場合も、サーブレットにより表示するページが検索されます。SRDemoアプリケーションでは、どちらの場合も同じページが表示されますが、異なるページを定義することも可能です。

例18-3は、HTMLフォームに認証サーブレットの起動を許可する規則を示しています。特に、フォームでは次の3つの情報を指定する必要があります。

  1. <form action="j_security_check" method="post">: コンテナのログインBeanのセキュリティ・チェック・メソッドj_security_checkを起動します。

  2. <input type="text" name="j_username"/>: ユーザー名の値をコンテナのログインBeanの属性j_usernameに割り当てます。

  3. <input type="password" name="j_password"/>: パスワードの値をコンテナのログインBeanの属性j_passwordに割り当てます。

HTMLフォームは、ログインBean属性の値を、正確な名前で返す必要があります。JSF JSPページでは、この動作はJSFフォームにより保証されません。そのため、HTMLフォームを使用してログインBeanの属性名を保持するために、JSPドキュメント・ページを使用することをお薦めします。

18.5 ログアウト・ページの作成

ログアウト・ページは、グローバル・メニュー・ページを含む任意のページに表示されるグローバル・ログアウト・ボタンからコールできます。ログアウト・ページの目的は、ユーザーに終了するかどうかを確認するためのプロンプトを表示することです。ユーザーがログアウトを選択すると、ユーザーのセッションは無効となり、アプリケーションの初期画面に戻ります。アプリケーションを続行するには、もう一度ログインする必要があります。図18-7は、SRDemoアプリケーションのサンプル・ログアウト・ページです。

図18-7 SRDemoアプリケーションのサンプル・ログアウト・ページ

基本的なモデル・プロジェクトを示すナビゲータ

ログアウト・ページの作成方法:

  1. ユーザー・インタフェース・プロジェクトを選択し、新規ギャラリを開いて、「Web Tier - JSF」カテゴリから「JSF JSP」を選択します。ここでは、JSFコンポーネントを使用できます。

  2. JSF JSPの作成ウィザードで、JSF JSPファイル・タイプとして「JSPドキュメント」タイプを選択します。ここでは、JSFコンポーネントを使用するJSPXドキュメントを作成します。

  3. 「コンポーネント・バインディング」ページで、マネージドBeanを作成しないでください。

  4. ウィザードの「タグ・ライブラリ」ページで、「選択済のライブラリ」リストに「ADF Faces Components」「ADF Faces HTML」を追加します。

  5. 「終了」をクリックしてウィザードを終了し、JSPXファイルをユーザー・インタフェース・プロジェクトに追加します。

  6. コンポーネント・パレットで「ADF Faces Core」ページを選択し、コンポーネントDocumentFormおよびPanelPageを、PanelPageがForm内に、FormがDocument内にネスト表示されるようにドラッグします。

  7. 次に、コンポーネントPanelBoxPanelHeaderおよびPanelButtonBarを、PanelButtonBarがPanelHeader内に、PanelHeaderがPanelBox内にネスト表示されるようにドラッグして、コマンド・ボタンのPanelPageコンテナを構成します。すべてがPanelPage内でネストされている必要があります。

  8. ユーザーがログアウトするかどうかを選択できるボタンを作成するには、2つのCommandButtonコンポーネントをPanelButtonBar内にドラッグします。

  9. 最初のボタンはログアウト機能を提供します。マネージドBeanを作成して個別に関連付けることができます。詳細は、18.5.1項「ログアウト・アクションの関連付け」を参照してください。

  10. 2番目のボタンは、アクションGlobalHomeを起動して、ユーザーを希望のページに移動します。このアクションは、ナビゲーション・ルールを使用してfaces-config.xmlファイルで定義します。

例18-4は、SRDemoアプリケーションのログアウト・ページのソース・コードです。このJSPXドキュメントはセキュリティ・コンテナと対話しないため、JSFコンポーネントの使用に関する制約がありません。ログアウト機能を起動するアクションは、ログアウトのラベルを持つ<af:commandButton>に表示されます。

例18-4 SRLogout.jspxからのサンプル・ソース

<af:form>
      <af:panelPage title="#{res['srlogout.pageTitle']}">
        <!--Page Content Start-->
        <af:panelBox>
          <af:panelHeader text="#{res['srlogout.subTitle']}"
                          messageType="warning">
            <af:outputText value="#{res['srlogout.text']}"/>
            <af:panelButtonBar>
              <af:commandButton text="#{res['srlogout.logout.label']}"
                                action="#{backing_SRLogout.logoutButton_action}"/>
              <af:commandButton text="#{res['srlogout.goBack.label']}"
                                action="GlobalHome"/>
            </af:panelButtonBar>
          </af:panelHeader>
        </af:panelBox>
        <!-- Page Content End -->
        ... omitting facets related to the visual design of the page ...
      </af:panelPage>
</af:form>

18.5.1 ログアウト・アクションの関連付け

JSPXドキュメントは、ログアウト・ページのログアウト・コマンド・ボタンに対応するプロパティを持つマネージドBeanを使用して、ログアウト・アクションを処理できます。

ログアウト・アクションの処理方法:

  1. ログアウト・ページを開いて、ログアウト・アクション用に予約したコマンド・ボタンをダブルクリックします。

  2. 「アクション」プロパティ・ダイアログで、「メソッド・バインディング」が選択された状態で「新規」をクリックし、マネージドBeanクラスを定義します。

  3. 「マネージドBeanの作成」ダイアログで、マネージドBeanの新規クラス・ファイル名を指定し、マネージドBeanの名前を入力してfaces-config.xmlファイルに登録します。

  4. 「アクション」プロパティ・ダイアログで「新規」をクリックし、コンポーネントの結果値を設定する文字列を返すためにマネージドBeanクラスに実装するメソッドに名前を付けます。

    図18-8に、マネージドBeanのbacking_SRLogoutとメソッドのlogoutButton_action()が入力された「アクション」プロパティ・ダイアログを示します。

  5. 図18-8 ログアウト・コマンド・ボタンのアクション・バインディング・ダイアログ

    「アクション」ダイアログのバッキングBeanメソッド定義
  6. 生成された.javaファイルで、ユーザーを適切なページに戻すコマンド・ボタンのメソッド・ハンドラを実装します。例18-5のサンプルを参照してください。


警告:

アプリケーションがHTTPセッションでinvalidate()メソッドをコールして、ログオフ時に現行セッションを終了する場合、「リダイレクト」を使用してホームページに戻り、ADF Modelバインディング・コンテナへのアクセスを求める必要があります。データ・バインドされたページにリダイレクトすることで、HTTPセッションの無効化後にADFバインディング・コンテキストが確実に再作成されます。

例18-5は、SRDemoアプリケーションのログアウト・ページのマネージドBeanからのメソッド・ハンドラです。logoutButton_action()メソッドによりセッションが無効化され、ホームページにリダイレクトされます。セキュリティ・コンテナからユーザーに自動的に再認証が求められます。

例18-5 SRLogout.javaからのサンプル・ソース

  public String logoutButton_action() throws IOException{
    ExternalContext ectx = FacesContext.getCurrentInstance().getExternalContext();
    HttpServletResponse response = (HttpServletResponse)ectx.getResponse();
    HttpSession session = (HttpSession)ectx.getSession(false);
    session.invalidate();

    response.sendRedirect("SRWelcome.jspx");
    return null;
  }

18.5.2 ログアウト・アクションを関連付ける場合の処理

コマンド・ボタンにactionプロパティを定義すると、JDeveloperにより、起動されるマネージドBeanとBeanメソッドの名前でLogout.jspxページのソース・コードが更新されます。

<af:commandButton text="#{res['srlogout.logout.label']}"
               action="#{backing_SRLogout.logoutButton_action}"/>

また、faces-config.xmlファイルが更新されてマネージドBeanが定義されます。

<managed-bean>
     <managed-bean-name>backing_SRLogout</managed-bean-name>
     <managed-bean-class>oracle.srdemo.view.backing.SRLogout</managed-bean-class>
     <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

ユーザーがログアウト・ボタンをクリックすると、JSFコントローラによってFaces構成ファイルの対応するクラス・ファイルが識別され、アクション・ハンドラ・メソッドの名前がマネージドBeanに渡されます。その後、アクション・ハンドラにより、例18-5に示されているとおり、セッションが無効化されてホームページにリダイレクトされます。

18.6 Oracle ADF Securityを使用した認可の実装

認可を使用すると、アクセスを試みるユーザーに基づいて、リソースへのアクセスを制限できます。Oracle ADF Securityは、セキュリティ対応リソースの認可用にOracleAS JAASを実装しています。

Oracle ADF Securityによってセキュリティのレベルを細かく設定し、JAASを使用したJava権限に基づいてオブジェクト・インスタンスへのアクセスを制御できます。具体的には、特定のOracle ADF Modelレイヤー・オブジェクトは「セキュリティ対応」です。つまり、開発者が特定のリソースに対して許可できるコンポーネント固有の権限が事前に定義されています。


注意:

SRDemoアプリケーションでは、現在ADF ModelレイヤーでのOracle ADF Securityのデモを行えません。SRDemoアプリケーションでの認可の処理方法の詳細は、18.7項「プログラムによる認可の実装」を参照してください。

次のOracle ADFオブジェクトはセキュリティ対応オブジェクトで、各データ・バインドWebページに関連付けられたページ定義ファイルによって定義されます。

これらのオブジェクトへの権限を設定するには、そのオブジェクト(リソース)で特定のアクションを実行する権限を持つ認証済ユーザーまたはロールを定義します。権限受領者はプリンシパルとして定義されたロール、ユーザーまたはグループで、権限にマップされます。権限とは、Oracle ADF Securityクラスによって定義される、リソースに対して特定のアクションを実行できる権限です(詳細はOracle ADFのJavadocを参照)。権限は集約されます。つまり、グループのロールに権限が付与されて、ユーザーがそのグループに属している場合、ユーザーにもこれらの権限が与えられます。権限が存在しない場合、ロール、ユーザーまたはグループによるアクセスは拒否されます。

表18-1に、バインディング・コンテナ、イテレータ・バインディング、属性レベル・バインディング(表、リスト、ブール、属性値バインディング)、メソッド・バインディングに付与できる権限を示します。実行時にページ定義ファイルから作成されるOracle ADFオブジェクトでユーザーに権限を付与するには、認可エディタを使用します。

表18-1 Oracle ADF Securityの認可権限

ADF Modelオブジェクト 定義済のアクション ユーザー・インタフェースのコンポーネントへの影響

Webページのバインディング・コンテナ

grant: ページでの権限を管理できる。

実行時のカスタマイズが可能なページで、アクセス制御を設定するように構成されたリンクまたはボタンは、この権限を付与されていないユーザーに対して無効になります。


edit: ページのコンテンツを編集できる。

ユーザーに表示アクション権限が付与され、編集アクション権限は付与されていない場合、入力テキスト・ボックスのデータは読取リ専用として表示されます。


personalize: ページのユーザー・カスタマイズが可能。

実行時のカスタマイズが可能なページで、ページをパーソナライズ・モードにするように構成されたリンクまたはボタンは、この権限を付与されていないユーザーに対して無効になります。


view: ページを表示できる。

この権限を付与されていないユーザーには認可エラーが表示されます。

イテレータ・バインディング

read: 返された行を読み取れる。

すべてのデータ行が返されます。ただし、個々の属性バインディングに権限を付与することで、表示または更新可能な行を制限できます。


update: 行のデータを更新できる。

コミット操作がデータ・コントロール・パレットからコマンド・ボタンとしてドロップされている場合、この権限を付与されていないユーザーに対してボタンは無効になります。行全体の更新を制限するかわりに、個々の属性の更新を制限できます。


create: 新しい行を作成できる。

作成操作がデータ・コントロール・パレットからコマンド・ボタンとしてドロップされている場合、この権限を付与されていないユーザーに対してボタンは無効になります。


delete: 行を削除できる。

削除操作がデータ・コントロール・パレットからコマンド・ボタンとしてドロップされている場合、この権限を付与されていないユーザーに対してボタンは無効になります。

メソッド・アクション・バインディング

invoke: メソッドを実行できる。

メソッドがコマンド・ボタンにバインドされている場合、この権限を付与されていないユーザーに対してボタンは無効になります。メソッドが暗黙的に起動される場合、メソッドはこの権限を付与されたユーザーの場合のみ実行されます。

属性レベル・バインディング

read: 属性の値を読み取れる。

属性の値が表示されます。


update: 属性の値を更新できる。

この権限を付与されていないユーザーには、入力テキスト・ボックスのデータは読取り専用として表示されます。


Oracle ADFによる認可を実装する前に、次のことを行う必要があります。

18.6.1 Oracle ADF Securityによる認可を使用するようにアプリケーションを構成

アプリケーションでADFによる認可を使用する前に、Oracle ADF Securityを使用するようにアプリケーションを構成する必要があります。

18.6.1.1 Oracle ADF Securityによる認可の構成方法

Oracle ADF Securityによる認可を有効にするには、Oracle ADF Securityを使用するようにアプリケーションのコンテナを設定する、adf-config.xmlという名前の構成ファイルを作成する必要があります。このファイルによって、ADFContextとSecurityContextが初期化されます。

Oracle ADF Securityを使用するようにアプリケーションを構成する方法:

  1. セキュリティを必要とするプロジェクトを右クリックし、「新規」を選択します。

  2. 新規ギャラリで「XML」カテゴリを選択します。

    XMLが表示されない場合は、上部の「フィルタ方法」リストを使用して「すべてのテクノロジ」を選択します。

  3. 「項目」リストで「XML文書」を選択し、「OK」をクリックします。

  4. ファイルにadf-config.xmlという名前を付け、<application_name>/.adf/META-INFディレクトリに保存して、「OK」.をクリックします。

    ソース・エディタにファイルが開きます。

  5. 生成されたコードを次のように置き換えます。

    <?xml version="1.0" encoding="windows-1252" ?>
    <adf-config xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance "
        xsi:schemaLocation=" http://xmlns.oracle.com/adf/config
        ../../../../../bc4jrt/src/oracle/adf/share/config/schema/config.xsd"
        xmlns=" http://xmlns.oracle.com/adf/config "
        xmlns:sec=" http://xmlns.oracle.com/adf/security/config ">
       <sec:adf-config-child xmlns=" http://xmlns.oracle.com/adf/security/config ">
         <JaasSecurityContext
            initialContextFactoryClass="oracle.adf.share.security.
                 JAASInitialContextFactory"
            authorizationEnforce="true"
            jaasProviderClass="oracle.adf.share.security.providers.jazn.
                 JAZNSecurity Context" >
        </JaasSecurityContext>
       </sec:adf-config-child>
    </adf-config>
    
  6. ファイルを保存して閉じます。

18.6.1.2 Oracle ADF Securityを使用するようにアプリケーションを構成した場合の処理

<JaasSecurityContext>要素のauthorizationEnforceパラメータがTrueに設定されている場合、認証されたユーザー・プリンシパルを、認証後ADF SecurityContextに入れることができます。


ヒント:

Oracle ADF Securityを使用せずにアプリケーションを実行する場合は、authorizationEnforceパラメータをFalseに設定します。

18.6.1.3 認可プロパティについて必要な知識

セキュリティのオンとオフは切り替えられるので、認可チェックを起動する前にアプリケーションでこのプロパティの設定を決定することをお薦めします。アプリケーションは、認可プロパティの設定をチェックして、Oracle ADF Securityが有効かどうかを判断できます。これは、ADFContextの下にあるSecurityContextのisAuthorizationEnabled()メソッドから公開されます。たとえば、次のように入力します。

if (ADFContext.getCurrent().getSecurityContext().isAuthorizationEnabled())
  {
    Permission p = new RegionPermission("view.pageDefs.page1PageDef", "Edit");
    AccessController.checkPermission(p);
    // do the protected action
  } catch (AccessControlException ace) {
    // do whatever's appropriate on an access denied
}

18.6.2 ADFバインディング・コンテナでの認可の設定

認可エディタを使用して、ページ定義全体で定義されているとおりに、バインディング・コンテナに対するユーザーの権限を付与します。Oracle ADFの権限の詳細は、表18-1を参照してください。

認可エディタを使用したバインディング・コンテナでの権限の付与方法:

  1. Webページを作成します。ビジュアル・エディタからページを右クリックし、「ページ定義に移動」を選択します。

  2. 構造ウィンドウでルート・ノードのPageDefを右クリックし、「認可の編集」を選択します。

  3. 認可エディタには、リソース・プロバイダで定義されたプリンシパル(ロールおよびユーザー)とともに、バインディング・コンテナの事前定義済の権限が表示されます。

    このダイアログの使用方法の詳細は、「ヘルプ」をクリックするか[F1]を押してください。

18.6.3 ADFイテレータ・バインディングでの認可の設定

認可エディタを使用して、ユーザーにイテレータ・バインディングでの権限を付与します。Oracle ADFの権限の詳細は、表18-1を参照してください。

認可エディタを使用したイテレータでの権限の付与方法:

  1. Webページを作成します。ビジュアル・エディタからページを右クリックし、「ページ定義に移動」を選択します。

  2. 構造ウィンドウで、executablesノードを展開します。

  3. 権限を付与するイテレータを右クリックし、「認可の編集」を選択します。

  4. 認可エディタには、リソース・プロバイダで定義されたプリンシパル(ロールおよびユーザー)とともに、イテレータの事前定義済の権限が表示されます。

    このダイアログの使用方法の詳細は、「ヘルプ」をクリックするか[F1]を押してください。

18.6.4 ADF属性およびMethodActionバインディングでの認可の設定

認可エディタを使用して、ユーザーに属性およびメソッド・アクション・バインディングでの権限を付与します。

属性について付与された権限は、作成、削除、コミットなどの操作を実行する権限を表します。したがって、操作に対してではなく、属性またはイテレータに対して認可を設定してください。Oracle ADFの権限の詳細は、表18-1を参照してください。

認可エディタを使用した属性およびメソッド・バインディングでの権限の付与方法:

  1. Webページを作成します。ビジュアル・エディタからページを右クリックし、「ページ定義に移動」を選択します。

  2. 構造ウィンドウで、bindingsノードを展開します。

  3. 権限を付与する属性またはメソッド・アクション・バインディングを右クリックし、「認可の編集」を選択します。

  4. 認可エディタには、リソース・プロバイダで定義されたプリンシパル(ロールおよびユーザー)とともに、属性またはメソッド・アクション・バインディングの事前定義済の権限が表示されます。

    このダイアログの使用方法の詳細は、「ヘルプ」をクリックするか[F1]を押してください。

18.6.5 Oracle ADF Securityによる認可の処理

ユーザーが定義済の権限を持つリソースに対してアクションを実行しようとすると、Oracle ADF Securityは、ユーザーが権限で定義されたプリンシパルかどうかを確認します。ユーザーがまだ認証されていない場合、ログイン・ページまたはフォームが表示されます。認証されたユーザーでも権限がない場合は、セキュリティ・エラーが表示されます。

例18-6に、Oracle JAZN軽量XMLプロバイダを使用する場合の属性バインディングおよびメソッド・バインディングに対する権限を示します。これらの権限は、system-jazn-data.xmlファイルに書き込まれます。これらの権限では、usersというロールにはdeleteDepartments()メソッドを起動するMethodPermissionDepartmentID属性値を読み取るAttributePermissionが付与されています。

例18-6 サンプルsystem-jazn-data.xmlファイルのOracle ADFの権限

<grant>
  <grantee>
    <principals>
      <principal>
        <realm-name>jazn.com</realm-name>
        <type>role</type>
        <class>oracle.security.jazn.spi.xml.XMLRealmRole</class>
        <name>jazn.com/users</name>
      </principal>
    </principals>
  </grantee>
  <permissions>
    <permission>
      <class>oracle.adf.share.security.authorization.MethodPermission</class>
      <name>SessionEJB.dataProvider.deleteDepartments</name>
      <actions>invoke</actions>
    </permission>
    <permission>
      <class>oracle.adf.share.security.authorization.AttributePermission</class>
      <name>EmployeesView1.DepartmentId</name>
      <actions>read</actions>
    </permission>
  </permissions>
</grant>

ユーザーまたはロールは、リソース・プロバイダで定義されています。

18.7 プログラムによる認可の実装

リソースとユーザーに対して認可ポリシーを設定できます。たとえば、特定のユーザー・グループのみに、特定データの表示、作成、変更や特定メソッドの起動を許可できます。ユーザーが属するグループに基づいて、コンポーネントのレンダリングを禁止することもできます。ユーザーは認証されているため、アプリケーションはそのユーザーに認可制約のあるオブジェクトへのアクセスを許可するかどうかを決定できます。

アプリケーションはプログラムでロールを参照し、特定のユーザーがそのロールに属しているかどうかを確認できます。SRDemoアプリケーションでは、この操作にFacesContextインタフェースで定義された(HttpServletRequestインタフェースからも使用できる)メソッドisUserInRole()を使用しています。

SRDemoアプリケーションは、3つのコア・ロールを使用して、特定機能を実行できるユーザーを決定します。各ユーザーは、user、technicianまたはmanagerのロールに分類されます。remoteUser値(FacesContextでuseridプロパティから取得)は、SRDemoアプリケーションのUSERS表の電子メール・アドレスと一致します。これらの基準は、18.3.1項「J2EEコンテナ管理の認証を有効にする方法」で説明したように、Oracle Application Serverが提供するコンテナ管理のフォームベース認証を使用して実装されています。

18.7.1 ユーザー情報をELアクセス可能にする

セキュリティ・コンテナの設定後、認証によって次のことが行われます。

  • アプリケーションが初めて参照したときに、コンテナのセキュリティ属性を読み取ります。

  • 式言語を通してアクセス可能なフォームで主要なセキュリティ情報を使用できるようにします。

これを実現するために、JSF Webアプリケーションでは、セッション・スコープに登録されたマネージドBeanを利用できます。マネージドBeanは、faces-config.xmlファイルを使用してアプリケーションに登録するJavaクラスです。アプリケーションを起動すると、アプリケーションはこの構成ファイルを解析し、Beanを利用可能にして、EL式で参照できるようにします。その結果、WebページからBeanのコンテンツへのアクセスが可能となります。

マネージドBeanの使用の詳細は、10.2項「マネージドBeanを使用した情報の格納」を参照してください。

次のSRList.jspxからのサンプルは、managerが編集ページの表示に使用するボタンをWebページに表示するかどうかを制御します。

<af:commandButton text="#{res['srlist.buttonbar.edit']}"
           action="#{backing_SRList.editButton_action}"
           rendered="#{userInfo.manager}"/>

次のSRCreateConfirm.jspxからのサンプルは、ユーザーの認証ステータスに基づいて、ユーザー名をWebページに表示するかどうかを制御します。

<f:facet name="infoUser">
     <!-- Show the Logged in user -->
     <h:outputFormat value="#{res['srdemo.connectedUser']}"
                     rendered="#{userInfo.authenticated}" escape="false">
            <f:param value="#{userInfo.userName}"/>
     </h:outputFormat>
</f:facet>

18.7.1.1 ロールを管理するクラスの作成

マネージドBeanのプロパティを使用して、ユーザーを検証し、使用可能なロールを判断するために必要なコードを含むクラスのメソッドを起動できます。このクラスは、マネージドBeanを作成する前に作成して、マネージドBeanを定義するときに使用するプロパティ名がわかっているようにする必要があります。

Javaクラスの作成方法:

  1. 新規ギャラリで、「General」カテゴリと「Javaクラス」項目を選択します。

  2. 「Javaクラスの作成」ダイアログで、クラス名を入力し、デフォルト値を受け入れて、デフォルト・コンストラクタとともにpublicクラスを作成します。

例18-7に、SRDemoアプリケーションが実装している主要メソッドを示します。

例18-7 SRDemoアプリケーションのUserInfo.javaサンプル

/**
 * Constructor
 */
public UserInfo() {

        FacesContext ctx = FacesContext.getCurrentInstance();
        ExternalContext ectx = ctx.getExternalContext();

        //Only allow Development mode functions if security is not active        _devMode = (ectx.getAuthType() == null);

        //Ask the container who the user logged in as
        _userName = ectx.getRemoteUser();

        //Default the value if not authenticated
        if (_userName == null || _userName.length()==0) {
            _userName = "Not Authenticated";
        }        //Set the user role flag...
        //Watch out for a tricky bug here:
        //We have to evaluate the roles Most > Least restrictive
        //because the manager role is assigned to the technician and user roles
        //thus checking if a manager is in "user" will succeed and we'll stop
        //there at the lower level of priviledge
        for (int i=(ROLE_NAMES.length-1);i>0;i--)  {
            if (ectx.isUserInRole(ROLE_NAMES[i])){
                _userRole = i;
                break;
            }
        }
    }    /*
     * Function to take the login name from the container and match that
     * against the email id in the USERs table.
     * Note this is NOT an authentication step, the user is already
     * authenticated at this stage by container security. The binding
     * container is injected from faces-config.xml and refers to a special
     * pageDef "headless_UserInfoPageDef.xml" which only contains the definition     * of this method call,
     */
    private Integer lookupUserId(String userName) {
        if (getBindings() != null) {
            OperationBinding oper =
           (OperationBinding)getBindings().getOperationBinding("findUserByEmail");
            //now set the argument to the function with the username we want
            Map params = oper.getParamsMap();
            params.put("emailParam",userName);
            // And execute
            User user = (User)oper.execute();
            setUserobject(user);
            //It is possible that the data in the database has changed and
             //there is no match in the table for this ID - return an appropriate
            //Error in that case
            if (user != null){
                return user.getUserId();
            }
            else{
                FacesContext ctx = FacesContext.getCurrentInstance();
                ctx.addMessage(null,JSFUtils.getMessageFromBundle
                 ("srdemo.dataError.userEmailMatch",FacesMessage.SEVERITY_FATAL));
                return -1;
            }
        }
        else {
            //This can happen if the ADF filter is missing from the web.xml
            FacesContext ctx = FacesContext.getCurrentInstance();
            ctx.addMessage(null,JSFUtils.getMessageFromBundle
               ("srdemo.setupError.missingFilter",FacesMessage.SEVERITY_FATAL));
            return -1;
        }
    }    /**
     * @return the String role name
     */
    public String getUserRole() {
        return ROLE_NAMES[_userRole];
    }    /**
     * Get the security container user name of the current user.
     * As an additional precaution make it clear when we are running in     * Dev mode
     * @return users login name which in this case is also their email id     */
    public String getUserName() {
      StringBuffer name = new StringBuffer(_userName);
      if (_devMode) {
        name.append(" (Development Mode)");
      }
      return name.toString();
    }    /**
     * Function designed to be used from Expression Language
     * for swiching UI Features based on role.
     * @return boolean
     */
    public boolean isCustomer() {
        return (_userRole==USER_ROLE);
    }    /**
     * Function designed to be used from Expression Language
     * for switching UI Features based on role.
     * @return boolean
     */
    public boolean isTechnician() {
        return (_userRole==TECHNICIAN_ROLE);
    }    /**
     * Function designed to be used from Expression Language
     * for switching UI Features based on role.
     * @return boolean
     */
    public boolean isManager() {
        return (_userRole==MANAGER_ROLE);
    }    /**
     * Function designed to be used from Expression Language
     * for switching UI Features based on role.
     * This particular function indicates if the user is either
     * a technician or manager
     * @return boolean
     */
    public boolean isStaff() {
        return (_userRole>USER_ROLE);
    }    /**
     * Function designed to be used from Expression Language
     * for switching UI Features based on role.
     * This particular function indicates if the session is actually authenticated
     * @return boolean
     */
    public boolean isAuthenticated() {
        return (_userRole>NOT_AUTHENTICATED);
    }
}

18.7.1.2 セキュリティ情報用のマネージドBeanの作成

UserInfo Beanは、JSF faces-config.xmlファイルでuserInfoというマネージドBeanとして登録されます。マネージドBeanでは、UserInfo.javaクラスが実装する管理プロパティの式を使用します。

たとえば、SRDemoアプリケーションのUserInfoマネージドBeanには次の式があります。

  • #{userInfo.userName}は、ログインIDまたは文字列「Not Authenticated」を返します。

  • #{userInfo.userRole}は、managerなどの文字列値で、現行ユーザーのロールを返します。

  • #{userInfo.staff}は、ユーザーがtechnicianまたはmanagerの場合にTrueを返します。

  • #{userInfo.customer}は、ユーザーがuserというロールに属しているときにTrueを返します。

  • #{userInfo.manager}は、ユーザーがmanagerの場合にTrueを返します。

マネージドBeanのプロパティと式の定義方法:

  1. アプリケーション・ナビゲータで、ユーザー・インタフェースのWEB-INFフォルダのfaces-config.xmlファイルを開きます。

  2. ウィンドウで「概要」タブを選択します。

  3. 左側の要素リストで「Managed Bean」を選択し、「新規」をクリックします。

  4. 「マネージドBeanの作成」ダイアログで、マネージドBeanのクラス情報を指定します。クラスを作成していない場合は、18.7.1.1項「ロールを管理するクラスの作成」を参照してください。

  5. マネージドBeanで定義されたセキュリティ情報に複数のWebページがアクセスできるようにするには、「有効範囲」「セッション」に設定します。たとえば、SRDemoアプリケーションでは、UserInfo.javaクラスに対応するuserInfoというマネージドBeanが定義されています。

  6. 概要ウィンドウで、「管理プロパティ」バー(マネージドBeanリストの下に表示)の横の矢印をクリックして、Beanのプロパティを表示します。

  7. 「新規」をクリックして、#{data.<ManagedBeanName+PageDefID}という値で一意のマネージドBeanプロパティbindingsを作成します。Oracle ADF Modelでは、変数bindingsは、EL式がバインディング・オブジェクトにアクセスできるようにします。SRDemoアプリケーションでは、UserInfoPageDefとしてbindingsプロパティが定義されています。この式の重要性については、18.7.2.3項「メソッドをELからアクセス可能なオブジェクトにするページ定義の作成」で説明します。

  8. オプションで、「新規」をクリックして、アプリケーションがアクセスするセキュリティのプロパティを作成します。たとえば、SRDemoアプリケーションでは、userNameプロパティとuserRoleプロパティは文字列として定義されています。図18-9は、SRDemoアプリケーション用に作成されたマネージドBeanの概要です。

    図18-9 Faces構成ファイルでのuserInfoマネージドBeanの概要

    基本的なモデル・プロジェクトを示すナビゲータ

例18-8は、SRDemoアプリケーションのセキュリティ情報を保持するマネージドBean userInfoを定義する、faces-config.xmlファイルの一部です。マネージドBeanでは管理プロパティbindingsも定義されています。管理プロパティuserNameおよびuserRoleとして示した値は、SRDemoアプリケーションでは無視されます。これらはテスト用です。

例18-8 SRDemoのfaces-config.xmlファイルのマネージドBean

<!-- The managed bean used to hold security information -->
  <managed-bean>
    <managed-bean-name>userInfo</managed-bean-name>
    <managed-bean-class>oracle.srdemo.view.UserInfo</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
      <property-name>bindings</property-name>
      <value>#{data.UserInfoPageDef}</value>
    </managed-property>
    <!-- Test Data ignored if real security is in use-->
    <managed-property>
      <property-name>userName</property-name>
      <property-class>java.lang.String</property-class>
      <value>sking</value>
    </managed-property>
    <managed-property>
      <property-name>userRole</property-name>
      <property-class>java.lang.String</property-class>
      <value>manager</value>
    </managed-property>
  <!-- End Test Data -->
</managed-bean>

18.7.2 マネージドBeanとOracle ADF Modelの統合

マネージドBeanは、Oracle ADF Modelレイヤーとある程度対話します。ユーザーがログインし、ログインIDが取得されると、アプリケーションはログインIDを、ユーザーを識別するための一意のユーザーIDに変換する必要があります。この情報は、表示するメニューや機能を判断するためにアプリケーション全体で使用できます。たとえば、SRDemoアプリケーションでは、ログインしたユーザーがmanagerロールに属している場合、SRListページには「編集」ボタンのみが表示されます。同じ認可制約はSRCreateページにも適用されます。

データ・バインドされたWebページが認可に使用できる一意のユーザーIDの取得方法:

  • 特定ID(コンテナ・セキュリティから取得される値)のユーザー・オブジェクトを返すTopLinkの名前付き問合せを作成します。

  • このlookupメソッドをラップするセッションBeanファサードにメソッドを作成します。

  • マネージドBeanに、セッションBeanでのこのlookupメソッドの使用方法を説明するADFページ定義ファイルを作成します。

  • ADF Modelレイヤーへのアクセスを提供し、セッションBeanでメソッドを起動するために、バインディング情報をUserInfo Beanにインジェクトします。

  • 認可のために特定のIDが初めて必要になったときに、UserInfo Beanからカスタム・メソッドを実行します。

18.7.2.1 ユーザー・オブジェクトを返すTopLinkの名前付き問合せの作成

名前付き問合せを使用して、アプリケーションにログインするユーザーを識別できます。この問合せは、特定の電子メールIDなど、コンテナ・セキュリティから受け取る一意の識別子のユーザー・オブジェクトを返します。クエリーは読取り専用で、識別子を含む文字列パラメータをとります。

名前付き問合せを作成するには、USERS表に対応するTopLink SRMapファイルのディスクリプタを使用します。SRDemoアプリケーションの問合せは電子メールIDに基づき、値をセキュリティ・コンテナから受け取ります。

TopLinkの名前付き問合せの詳細は、3.8項「作業ユニットでのオブジェクトの作成と変更」を参照してください。

ユーザー・エンティティの名前付き問合せの作成方法:

  1. アプリケーション・ナビゲータで、データ・モデル・プロジェクトを展開し、SRMapを開いてマッピング・エディタを表示します。

  2. 構造ウィンドウで、エンティティ・パッケージを展開します。

  3. マッピング・エディタで、ディスクリプタUserを選択し、「追加」をクリックして、新しいTopLinkの名前付き問合せを定義します。たとえば、SRDemoアプリケーションではfindUserByEmailを使用します。

  4. 「一般」パネルを使用して、一意の属性を識別するパラメータを追加します。たとえば、アプリケーションでは、データ型がjava.lang.StringemailParamを使用します。

  5. フォーマット・パネルを使用して、名前付き問合せの式を定義します。たとえば、SRDemoアプリケーションではemail EQUAL emailParamを使用します。

  6. 問合せを保存します。

18.7.2.2 名前付き問合せをラップするセッション・ファサード・メソッドの作成

サービスをクライアントに公開するには、セッション・ファサードを使用してエンティティとメソッドにアクセスすることをお薦めします。セッション・ファサード設計パターンを実装するセッションBeanが、アプリケーションのOracle ADFデータ・コントロールの入り口となります。第3章では、ADFデータ・コントロールを使用してサービスを公開する方法について説明しています。アプリケーションの実行時に起動される他のメソッドと同様、名前付き問合せのfinderメソッドをプロジェクトのOracle ADF EJBデータ・コントロールに登録する必要があります。この手順により、ADF Modelレイヤーが一意に識別されたユーザーのユーザー・セキュリティ情報にアクセスするためのプロセスが始まります。

TopLink問合せをラップするセッション・ファサードを作成していない場合は、第3章「アプリケーション・サービスの作成と使用」を参照してください。

既存のセッション・ファサードへのfinderメソッドの追加方法:

  1. ADF EJBデータ・コントロールを作成したセッションBeanが含まれているデータ・モデル・パッケージを展開します。

  2. セッションBeanの.javaファイルをダブルクリックして、ソース・エディタに開きます。

  3. 新しいメソッドを追加します。例18-9は、SRDemoアプリケーションで実装されているセッション・ファサードのfinderメソッドです。

  4. アプリケーション・ナビゲータでセッションBeanを右クリックし、「セッション・ファサードの編集」を選択します。

  5. アプリケーション・ナビゲータで、新しいメソッドをリモート・インタフェースに追加します。

  6. .javaファイルを保存して再コンパイルします。

  7. アプリケーション・ナビゲータでセッションBeanを右クリックし、「データ・コントロールの作成」を選択します。新しいメソッドが、データ・コントロール・パレットに表示されます。

例18-9 SRDemoの一意のIDを公開するSRPublicFacadeBean.java Finderメソッド

public User findUserByEmail(String emailParam) {    Session session = getSessionFactory().acquireSession();
    Vector params = new Vector(1);
    params.add(emailParam);
    User result =
      (User)session.executeQuery("findUserByEmail", User.class, params);
    session.release();

    return result;
}

18.7.2.3 メソッドをELからアクセス可能なオブジェクトにするページ定義の作成

ユーザーの一意のIDを返すためのfinderメソッドをADFデータ・コントロールに登録した後、finderメソッドをOracle ADF Modelレイヤーに公開するには、ページ定義の説明を提供します。この定義はメソッド・アクション・バインディングとして定義されます。Oracle ADF Modelによってバインディングが公開されたら、アプリケーション・ページ全体で使用できます。

通常、各Webページは1つのページ定義ファイルにマップされます。ただし、アプリケーション全体からアクション・バインディングにアクセスする場合、バインディング定義は独自のページ定義、つまり対応するWebページのない「ヘッドレス」定義に属する必要があります。

ユーザー・インタフェース・プロジェクトのヘッドレス・ページ定義ファイルの作成方法:

  1. アプリケーション・ナビゲータで、ページ定義ファイルを含むユーザー・インタフェース・パッケージを展開します。

  2. pageDefsパッケージ・ノードを右クリックし、「新規」を選択します。

  3. 新規ギャラリで、「General」「XML」カテゴリからXMLドキュメントを作成します。

  4. 「XMLファイルの作成」ダイアログで、セキュリティ・プロパティを定義するマネージドBeanのファイル名を指定し、PageDefを追加します。たとえば、SRDemoアプリケーションでは、ヘッドレス・ページ定義には、headless_UserInfoPageDef.xmlという名前が付いています。

  5. ソース・エディタにXMLファイルを開き、メソッド・バインディング定義を追加します。例18-10は、SRDemoアプリケーション用に作成されたバインディング定義です。

  6. ファイルを保存します。

methodBindingのactionプロパティで設定されている値999(またはCUSTOM)は、起動するメソッドがアプリケーション・サービスで定義されたカスタムのメソッドであることを表します。

例18-10 SRDemoのheadless_UserInfoPageDef.xmlページ定義ファイル

<?xml version="1.0" encoding="UTF-8" ?>
<pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel"
                version="10.1.3.35.65" id="UserInfoPageDef"
                Package="oracle.srdemo.view.pageDefs">
  <bindings>
    <methodAction id="findUserByEmail"
                  InstanceName="SRPublicFacade.dataProvider"
                  DataControl="SRPublicFacade"
                  MethodName="findUserByEmail" RequiresUpdateModel="true"
                  Action="999"
                  ReturnName="SRPublicFacade.methodResults.
                        SRPublicFacade_dataProvider_findUserByEmail_result">
      <NamedData NDName="emailParam" NDType="java.lang.String"/>
    </methodAction>
  </bindings>
</pageDefinition>

ADF Modelレイヤーは、DataBinding.cpxファイルのパス参照からページ定義をロードします。新しいページ定義ファイルには、DataBindings.cpx内のID「UserInfoPageDef」へのこの参照が必要です。この指定は、CPXファイルの構造ウィンドウから行います。

ユーザー・インタフェース・プロジェクトのヘッドレス・ページ定義ファイルの作成方法:

  1. アプリケーション・ナビゲータで、ルート・ユーザー・インタフェース・パッケージを展開し、DataBindings.cpxファイルを探します。パッケージは、Application Sourcesフォルダにあります。

  2. DataBindings.cpxをダブルクリックし、構造ウィンドウを開きます。

  3. 構造ウィンドウで、pageDefinitionUsagesノードを選択し、「pageDefinitionUsagesの中に挿入」「page」を選択します。

  4. 「ID」をヘッドレス・ページ定義ファイル(1つのmethodActionバインディングを含む)に指定した名前に設定します。たとえば、SRDemoアプリケーションではUserInfoPageDefを使用します。

  5. 「パス」を、ページ定義ファイルを追加したパッケージに設定します。たとえば、SRDemoアプリケーションでは、パスはoracle.srdemo.view.pageDefs.userInfoです。

実行時、data.<Headless_PageDefID>への参照が、このバインディング定義に解決されます。例18-11は、SRDemoアプリケーションでヘッドレス・ページ定義ファイルに指定されたIDを示しています。

例18-11 SRDemoのDataBindings.cpxページ定義参照

<?xml version="1.0" encoding="UTF-8" ?>
<Application xmlns="http://xmlns.oracle.com/adfm/application" ...
  <pageDefinitionUsages>
    <page id="SRListPageDef"
          path="oracle.srdemo.view.pageDefs.app_SRListPageDef"/>
    <page id="UserInfoPageDef"
          path="oracle.srdemo.view.pageDefs.headless_UserInfoPageDef"/>
     ...
</Application>

18.7.2.4 UserInfo Beanからのセッション・ファサード・メソッドの実行

マネージドBean定義userInfoでは、値が#{data.UserInfoPageDef}の管理プロパティbindingsがすでに定義されていることがあります。詳細は、18.7.1.2項「セキュリティ情報用のマネージドBeanの作成」を参照してください。

式を補足するために、セキュリティ・メソッドを実装するクラス(UseInfo.java)にはbindingsプロパティ用の対応するgetterおよびsetterメソッドが必要です。

public void setBindings(BindingContainer bindings) {
   this._bindings = bindings;
 }
public BindingContainer getBindings() {    return _bindings;
}

アプリケーションで初めてUserIdが必要になると、セッションBeanメソッドがコールされます。このコールには、UserInfo.javagetUserId()メソッドが使用されます。getUserId()メソッドは、UserIdに現在値が入力されているかどうかをチェックします。値がない場合、実際にセッション・ファサード・メソッドをコールするプライベート・メソッドlookupUserId()をコールします。

public Integer getUserId() {
   if (_userId == null){
    _userId = lookupUserId(_userName);
   }
   return _userId;
}

lookupUserId()メソッドは、ユーザーIDを取得するように定義されたセッション・ファサード・メソッドをコールするmethodActionバインディングを起動します。

private Integer lookupUserId(String userName) {
        if (getBindings() != null) {
            OperationBinding oper = (OperationBinding)getBindings().
                                 getOperationBinding("findUserByEmail");
            //now set the argument to the function with the username we
            //are interested in
            Map params = oper.getParamsMap();
            params.put("emailParam",userName);
            // And execute
            User user = (User)oper.execute();
            setUserobject(user);
            return user.getUserId();
        }
}

メソッドはgetBindings()を使用して、Faces構成からインジェクトされたバインディング・コンテナを取得します。バインディング・コンテナの取得後、メソッドはセッション・ファサード・メソッドとの調整を行うmethodActionバインディングを検索します。セッション・ファサード・メソッドの詳細は、18.7.2.4項「UserInfo Beanからのセッション・ファサード・メソッドの実行」を参照してください。