ヘッダーをスキップ
Oracle® Fusion Middlewareアプリケーション・セキュリティ・ガイド
11g リリース1(11.1.1)
B56235-06
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

24 資格証明ストア・フレームワークを使用した開発

この章の次の各項では、資格証明ストア・フレームワーク(CSF)のAPIの使用方法について説明します。

24.1 資格証明ストア・フレームワークAPIについて

資格証明ストアは、資格証明のセキュアな保存のために使用します。資格証明ストア・フレームワーク(CSF) APIは、資格証明ストアの操作へのアクセスと実行に使用します。

資格証明ストア・フレームワークには、次の機能があります。

CSF APIは、次のような重要な機能(作成、更新、削除)を提供します。

CredentialStoreに対する操作は、CSFで使用されるファイングレイン・アクセス制御モデルを実装するCredentialAccessPermissionによって保護されます。

24.2 CSFを使用したアプリケーション開発の概要

次の領域に関する知識は、アプリケーションで資格証明ストア・フレームワークを使用する場合に役立ちます。

以降の項で、それぞれのタスクについて詳しく説明します。

24.3 Javaセキュリティ・ポリシーのパーミッションの設定

Oracle Platform Security Servicesのポリシー・プロバイダは、サーバーの起動時に設定されます。プロバイダがファイルベースの場合、ポリシー・データはsystem-jazn-data.xmlに格納されます。

CSFは、資格証明の保護を次のようにサポートしています。


注意:

  • CSF APIに適切にアクセスするには、ポリシー・ストアにJavaパーミッションを付与する必要があります。

  • CSF APIを呼び出すコードには、コード・ソースのパーミッションが必要です。パーミッションは通常、特定のコードjarに与えられるものであり、アプリケーション全体には与えられません。


24.3.1 パーミッション付与のガイドライン

資格証明ストア・フレームワークでは、Javaパーミッションに基づいて、資格証明ストアのオブジェクトにパーミッションを付与します。

必要なパーミッションのみを付与して、それ以外は付与しないことを強くお薦めします。


警告:

不要なパーミッション、特にすべてのマップやキーにアクセスできるパーミッションを付与することは危険であり、お薦めできません。


24.3.2 パーミッション付与例1


注意:

この例では、アプリケーションのjarファイル名はAppName.jarです。


CredentialStoreは、マップ名と資格証明マップ間のマッピングを保持します。各マップ名は、CredentialオブジェクトのキーのセキュアなマップであるCredentialMapにマップされます。

この例では、特定のマップ名と、そのマップの特定のキー名に対してパーミッションを付与しています。

<jazn-policy>
    <grant>
        <grantee>
            <principals>...</principals>
            <!-- This is the location of the jar -->
            <!-- as loaded with the run-time -->
            <codesource>
      <url>file:${oracle.deployed.app.dir}/<MyApp>${oracle.deployed.app.ext}</url>
            </codesource>
        </grantee>
        <permissions>
            <permission>
               <class>oracle.security.jps.service.credstore.
                      CredentialAccessPermission</class>
               <name>context=SYSTEM,mapName=myMap,keyName=myKey</name>
              <!-- All actions are granted -->
              <actions>*</actions>
            </permission>
        </permissions>
    </grant>
</jazn-policy>

説明:

  • MapNameは、これらのパーミッション(ワイルドカード・アクションで示した読取り、書込み、更新および削除)を付与するマップの名前(通常はアプリケーション名)です。

  • KeyNameは、使用するキー名です。

24.3.3 パーミッション付与例2

この例では、特定のマップ名と、そのすべてのキー名に対してパーミッションを付与しています。

<jazn-policy>
    <grant>
        <grantee>
            <principals>...</principals>
            <codesource>
      <url>file:${oracle.deployed.app.dir}/<MyApp>${oracle.deployed.app.ext}</url>
            </codesource>
        </grantee>
        <permissions>
           <permission>
              <class>oracle.security.jps.service.credstore.
                     CredentialAccessPermission</class>
              <name>context=SYSTEM,mapName=myMap,keyName=*</name>
              <!-- Certain actions are explicitly specified -->
              <!-- Compare to wild-card grant in previous example -->
              <actions>read,write,update,delete</actions>
        </permission>
        </permissions>
    </grant>
</jazn-policy>

24.4 マップ名のガイドライン

ドメインレベルの資格証明ストアが使用される場合は、ストア内に異なるアプリケーション用の様々なマップ名が存在していることから、名前の競合が発生する場合があります。これを避けるために、各アプリケーションはストア内で一意なマップ名を持つ必要があります。

そのためには、使用するマップ名でアプリケーションが一意に識別されるようにすることをお薦めします。

アプリケーションは、特定のマップ名の中に、それぞれが特定のキーで識別される複数の資格証明を持つことができます。このマップ名とキーの組合せが、特定の資格証明ストア内の主キーになります。

アプリケーションで複数のマップ名を使用する必要が生じた場合でも、その一意性は維持されます。

たとえば、次の3つのアプリケーションを考えます。

RCUの場合は、RCUというマップ名が選択され、3つの資格証明のキーが次のようにKey1、Key2、Key3になっています。


注意:

ここで使用しているマップ名とキー名は任意であり、説明用に選択したものにすぎません。ユーザーのアプリケーションでは、まったく異なるマップ名とキー名が使用できます。


MapName -> RCU, Key -> Key1 and Credential -> PasswordCredential1
MapName -> RCU, Key -> Key2 and Credential -> PasswordCredential2
MapName -> RCU, Key -> Key3 and Credential -> GenericCredential1

Oracle WebCenterの場合は、マップ名がWebで、単一の資格証明のキーはKey1です。

MapName -> Web, Key -> Key1 and Credential -> PasswordCredential3

Fusion Middleware Controlでは、マップ名はEMで示され、2つの資格証明のキーは、それぞれKey1とKey2です。

MapName -> EM, Key -> Key1 and Credential -> PasswordCredential4
MapName -> EM, Key -> Key2 and Credential -> GenericCredential2

マップ名とキー名は、2つの任意の文字列にすぎないため、実際には任意の有効な文字列値を持つことができます。ただし、このように実装することにより、マップ名を容易に管理することができます。

24.5 資格証明ストアの構成

管理者は、資格証明ストアの場所とプロバイダ・クラスに関する情報が含まれている構成ファイル内で、資格証明ストア・インスタンスを定義する必要があります。構成ファイルは、次の場所にあります。

$DOMAIN_HOME/config/fmwconfig

名前は次のとおりです。

詳細は、第10章「資格証明ストアの管理」を参照してください。

24.6 APIの使用手順

資格証明ストア・フレームワークは、Oracle WebLogic Server内でもスタンドアロン環境でも使用できます。

24.6.1 スタンドアロン環境でのCSF APIの使用方法

スタンドアロン環境でAPIを使用する手順は、次のとおりです。

  1. クラスパスを設定します。jps-manifest.jarファイルがそのクラスパスに入っていることを確認します。詳細は、第1.5.3項「シナリオ3: Java SEアプリケーションの保護」の「クラスパスで指定する必要のあるJAR」を参照してください。

  2. ポリシーを設定します。CSF APIにアクセスできるようにするには、参照ポリシー・ストアでアクセス・パーミッションを構成する必要があります。例は、第24.3項「Javaセキュリティ・ポリシーのパーミッションの設定」を参照してください。

  3. アプリケーションを実行します。

コマンドライン・オプションは次のとおりです。

  • -Doracle.security.jps.config
    

    構成ファイルのフルパスを指定します。

  • -Djava.security.policy
    

    OPSSおよびOracle WebLogic Serverのポリシー・ファイルの場所を指定します。

  • -Djava.security.debug=all
    

    デバッグに役立ちます。

24.6.2 Oracle WebLogic ServerでのCSF APIの使用方法

Oracle WebLogic Server環境でAPIを使用する手順は、次のとおりです。

  1. jps-config.xmlファイルの資格証明ストアのサービス・プロバイダ・セクションは、次のディレクトリにすぐに使用できるように構成されています。

    $DOMAIN_HOME/config/fmwconfig
    

    必要に応じて、LDAP資格証明ストアへの再関連付けを行ってください。

  2. ポリシーを設定します。CSF APIにアクセスできるようにするには、参照ポリシー・ストアでアクセス・パーミッションを構成する必要があります。例は、第24.3項「Javaセキュリティ・ポリシーのパーミッションの設定」を参照してください。

  3. Oracle WebLogic Serverを起動します。

  4. アプリケーションをデプロイしてテストします。

24.7

この項では、資格証明ストア・フレームワークAPIの使用例をいくつか示します。次の例を示します。

それぞれの例では、パーミッションが資格証明ストアの操作にどのような影響を与えるかを示すようにテスト・コードが設定されています。それぞれの例では、ポリシー・ファイル、テスト・コードおよび構成ファイルが用意され、プロバイダ情報の指定方法を示し、マップとキーに定義されたパーミッションとコード内で試行されている操作を比較できるようになっています。

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

24.7.1 CSF操作のコード

次の共通ユーティリティ・プログラムによってCSF API操作が実行されます。これはサンプル・プログラムによって呼び出されます。

package demo.util;
 
import java.security.AccessController;
import java.security.PrivilegedAction;
 
import oracle.security.jps.JpsException;
import oracle.security.jps.service.credstore.Credential;
import oracle.security.jps.service.credstore.CredentialAlreadyExistsException;
import oracle.security.jps.service.credstore.CredentialFactory;
import oracle.security.jps.service.credstore.CredentialStore;
import oracle.security.jps.service.credstore.PasswordCredential;
 
public class CsfUtil {
    final CredentialStore store;
    public CsfUtil(CredentialStore store) {
        super();
        this.store = store;
    }
    
    private void doOperation() {
        try {
            PasswordCredential pc = null;
            try {
                // this call requires read privilege
                pc = (PasswordCredential)store.getCredential("pc_map", "pc_key");
                if (pc == null) {
                    // key not found, create one
                    pc = CredentialFactory.newPasswordCredential("jdoe",
                          "password".toCharArray());
                    // this call requires write privilege
                    store.setCredential("pc_map", "pc_key", pc);
                    System.out.print("Created ");
                }
                else {
                    System.out.print("Found ");
                }
 
                System.out.println("password credential: Name=" + pc.getName() +
                                   ",Password=" +
                                   new String(pc.getPassword()));
 
            } catch (CredentialAlreadyExistsException e) {
                // ignore since credential already exists.
                System.out.println("Credential already exists for 
                <pc_map, pc_key>: " + pc.getName() + ":" +
                new String(pc.getPassword()));
            }
 
            try {
                // permission corresponding to 
                // "context=SYSTEM,mapName=gc_map,keyName=gc_key"
                byte[] secret =
                    new byte[] { 0x7e, 0x7f, 0x3d, 0x4f, 0x10,
                                 0x20, 0x30 };
                Credential gc =
                    CredentialFactory.newGenericCredential(secret);
                store.setCredential("gc_map", "gc_key", gc);
                System.out.println("Created generic credential");
            } catch (CredentialAlreadyExistsException e) {
                // ignore since credential already exists.
                System.out.println("Generic credential already exists 
                  for <gc_map,gc_key>");
            }
 
            try {
                //no permission for pc_map2 & pc_key2 to perform 
                //operation on store
                Credential pc2 =
                    CredentialFactory.newPasswordCredential("pc_jode2",
                    "pc_password".toCharArray());
                store.setCredential("pc_map2", "pc_key2", pc2);
 
            } catch (Exception expected) {
                //CredentialAccess Exception expected here. Not enough permission
                System.out.println("This is expected :" +
                                   expected.getLocalizedMessage());
            }
 
        } catch (JpsException e) {
            e.printStackTrace();
        }
        
    }
    
    /*
     * This method performs a non-privileged operation. Either all code 
     * in the call stack must have CredentialAccessPermission  
     * OR
     * the caller must have the CredentialAccessPermission only and 
     * invoke this operation in doPrivileged block
     */
    public void doCredOperation() {
        doOperation();
    }
    
    /*
     * Since this method performs a privileged operation, only current class or
     * jar containing this class needs CredentialAccessPermission
     */
    public void doPrivilegedCredOperation() {
        AccessController.doPrivileged(new PrivilegedAction<String>() {
                public String run() {
                    doOperation();
                    return "done";
                }
            });
    }
}

24.7.2 例1: ウォレット・ストアを使用するJava SEアプリケーション

この例では、ウォレット資格証明(つまりファイルベースのプロバイダ)を使用するサンプルJava SEアプリケーションを示します。

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

  • xmlベースのポリシー・ストア(jazn-data-xml)でのパーミッションの設定方法

  • 構成ファイルの設定方法

  • Java SEコード

jazn-data.xmlファイル

この例では、ストアから特定の資格証明へのアクセスに必要とされる適切なパーミッションを持つxmlベースのポリシー・ストアを使用して説明しています。このファイルでは、マップ名(別名)とキーの様々な組合せに対するパーミッションを定義します。他の組合せや、ここで定義されたパーミッションを超えたストアへのアクセスは、許可されません。


注意:

この権限付与が追加されるデフォルトのポリシー・ストアは$DOMAIN_HOME/config/fmwconfig/system-jazn-data.xmlです。


ここでは、システム・プロパティprojectsrc.homeはJava SEアプリケーションを格納しているディレクトリを指し示すように設定されており、clientApp.jarはサブディレクトリdistにあるアプリケーションjarファイルです。

対応するポリシー付与は、次のようになります。

<grant>
   <grantee>
      <codesource>
         <url>file:${projectsrc.home}/dist/clientApp.jar</url>
      </codesource>
   </grantee>
   <permissions>
      <permission>
         <class>oracle.security.jps.service.credstore.CredentialAccessPermission
         </class>
         <name>context=SYSTEM,mapName=pc_map,keyName=*</name>
         <actions>read,write</actions>
      </permission>
      <permission>
         <class>oracle.security.jps.service.credstore.CredentialAccessPermission
         </class>
         <name>context=SYSTEM,mapName=gc_map,keyName=gc_key</name>
         <actions>write</actions>
      </permission>                          
   </permissions>
</grant>

mapName=pc_map2,keyName=pc_key2にはどのようなパーミッションも付与されていないので、第24.7.1項「CSF操作のコード」に示したこのマップとキーの組合せに対するsetCredentialのコールは失敗すると考えられます。

jps-config-jse.xmlファイル


注意:

完全な構成ファイルについては、製品に付属しているデフォルトのファイル($DOMAIN_HOME/config/fmwconfig/jps-config-jse.xml)を参照してください。


資格証明ストア・サービスの場所プロパティは、ウォレット・ファイルを格納しているディレクトリを示しています。

<jpsConfig>
 ...
    <serviceInstances>
        <serviceInstance name="credstore_file_instance"
                         provider="credstore_file_provider">
            <property name="location" value="store" />
        </serviceInstance>
    </serviceInstances>
 ...
</jpsConfig>

注意:

場所のデフォルト値は./です。つまり、jps-config-jse.xmlの場所を基準とする相対パスでの現行のディレクトリです。別のパスを使用する場合は、必ずフルパスを指定してください。


ウォレット名は常にcwallet.ssoであり、これはデフォルトのファイルベースのOracleウォレットです。

Javaコード

次に、ユーティリティ・プログラムをコールするJava SEコードを示します。

package demo;
 
import java.io.ByteArrayInputStream;
 
import java.security.AccessController;
import java.security.PrivilegedAction;
 
import oracle.security.jps.JpsContext;
import oracle.security.jps.JpsContextFactory;
import oracle.security.jps.JpsException;
import oracle.security.jps.internal.policystore.JavaPolicyProvider;
import oracle.security.jps.jaas.JavaPolicy;
import oracle.security.jps.service.credstore.Credential;
import oracle.security.jps.service.credstore.CredentialAlreadyExistsException;
import oracle.security.jps.service.credstore.CredentialFactory;
import oracle.security.jps.service.credstore.CredentialStore;
import oracle.security.jps.service.credstore.PasswordCredential;
import oracle.security.jps.service.policystore.PolicyStore;
import oracle.security.jps.service.policystore.PolicyStoreException;
 
import demo.util.CsfUtil;
 
 
public class CsfApp {
 
 // set the OPSS policy provider explicitly, as required in a Java SE application
    static {
        java.security.Policy.setPolicy(new oracle.security.jps.internal.policystore.JavaProvider());
    }
 
    public CsfApp() {
        super();
    }
 
    public static void main(String[] a) {
        // perform operation as privileged code
        JpsContextFactory ctxFactory;
        try {
            ctxFactory = JpsContextFactory.getContextFactory();
            JpsContext ctx = ctxFactory.getContext();
 
            CredentialStore store =
                ctx.getServiceInstance(CredentialStore.class);
            CsfUtil csf = new CsfUtil(store);
            // #1 - this call is in a doPrivileged block
            // #1 - this should succeed.
            csf.doPrivilegedCredOperation();
 
            // #2 - this will also pass since granted all application
            // code necessary permission
            // NOTE: Since this call is not in a doPrivileged block,
            // this call would have failed if CredentialAccessPermission 
            // wasn't granted to this class.
            /*
            csf.doCredOperation();
            */
        } catch (JpsException e) {
            e.printStackTrace();
        }
 
    }
}

注意:

  • JDK全体に及ぶポリシー・オブジェクトを置き換える必要はありません。この付与例は、OPSS XMLポリシー・ストアに従っているので、ポリシー・プロバイダをOPSSプロバイダに設定することが妥当です。

  • サポートされるアプリケーション・サーバーへのJRFインストールのJava EE環境では、OPSSポリシー・プロバイダが初期化されています。


24.7.3 例2: ウォレット・ストアを使用するJava EEアプリケーション

この例では、ウォレットの資格証明を使用するサンプルJava EEアプリケーションを示します。シンプルなサーブレットがCSF APIをコールしています。

jazn-data.xmlファイル

この例のjazn-data.xmlファイルには、ストアから特定の資格証明にアクセスするために必要とされる適切なパーミッションが定義されています。このファイルでは、コードソース・パーミッションおよびマップ名(別名)とキーの様々な組合せに対するパーミッションの両方を定義します。他の組合せや、ここで定義されたパーミッションを超えたストアへのアクセスは、許可されません。

対応するポリシー付与を示しているポリシー・ファイルの断片は次のようになります。

<grant>
   <grantee>
      <codesource>
      <url>file:${oracle.deployed.app.dir}/<MyApp>${oracle.deployed.app.ext}</url>
      </codesource>
   </grantee>
   <permissions>
      <permission>
         <class>oracle.security.jps.service.credstore.CredentialAccessPermission
         </class>
         <name>context=SYSTEM,mapName=pc_map,keyName=*</name>
         <actions>read,write</actions>
      </permission>
      <permission>
         <class>oracle.security.jps.service.credstore.CredentialAccessPermission
         </class>
         <name>context=SYSTEM,mapName=gc_map,keyName=gc_key</name>
         <actions>write</actions>
      </permission>                 
   </permissions>
</grant> 

最初のマップおよびキーのパーミッションでは読取り操作と書込み操作の両方が有効になりますが、2番目のパーミッションでは書込み操作のみが有効になり、読取り操作は有効にならないことに注意してください。

jps-config.xmlファイル

資格証明ストアの構成を示すデフォルトの構成ファイルjps-config.xmlの一部を次に示します。

<jpsConfig>
    <serviceProviders>
        <serviceProvider type="CREDENTIAL_STORE" name="credstoressp"
    class="oracle.security.jps.internal.credstore.ssp.SspCredentialStoreProvider">
            <description>SecretStore-based CSF provider</description>
        </serviceProvider>
    </serviceProviders>
 
    <serviceInstances>
        <serviceInstance name="credstore" provider="credstoressp">
            <property name="location" value="./" />
        </serviceInstance>
    </serviceInstances>
 
    <jpsContexts default="default">
        <jpsContext name="default">
        ...
            <serviceInstanceRef ref="credstore"/>
        ...
        </jpsContext>
    </jpsContexts>
</jpsConfig>

locationプロパティはウォレットの場所を指定します。この指定は本質的には例1と同じですが、この例ではウォレットが構成ディレクトリ内に配置されている点が異なります。ウォレット名は常にcwallet.ssoです。

Javaコード

package demo;
 
import demo.util.CsfUtil;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import java.net.URL;
 
import java.util.Date;
 
import javax.servlet.*;
import javax.servlet.http.*;
 
import oracle.security.jps.JpsException;
import oracle.security.jps.service.JpsServiceLocator;
import oracle.security.jps.service.credstore.CredentialStore;
 
public class CsfDemoServlet extends HttpServlet {
    private static final String CONTENT_TYPE = "text/html; charset=windows-1252";
 
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }
 
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException,
                                                           IOException {
        response.setContentType(CONTENT_TYPE);
        PrintWriter out = response.getWriter();
        //ServletOutputStream out = response.getOutputStream();
        try {
            response.setContentType("text/html");
            out.println("<html><body bgcolor=\"#FFFFFF\">");
            out.println("<b>Current Time: </b>" + new Date().toString() +
                        "<br><br>");
 
            //This is to get hold of app-level CSF service store
            //Outside app context, this call returns domain-level CSF store
            //This call also works in Java SE env
            final CredentialStore store =
              JpsServiceLocator.getServiceLocator().lookup(CredentialStore.class);
            CsfUtil csf = new CsfUtil(store);
            
            csf.doPrivilegedCredOperation();
            out.println("Credential operations completed using privileged code.");
        } catch (JpsException e) {
            e.printStackTrace(out);
        }
    }
}

資格証明作成操作は、権限のあるコードを使用して実行されます。操作が正常に行われたことを確認するには、次のようにWLST listCredコマンドを使用します。

listCred(map="pc_map", key="pc_key")

Java SE環境に関する注意

Java SE環境では、次の2つのコールは同等です。

CredentialStore store = JpsServiceLocator.getServiceLocator().lookup(CredentialStore.class);

および

CredentialStore store = JpsContextFactory.getContextFactory().getContext().getServiceInstance(CredentialStore.class); 

後者のコールは、第24.7.2項「例1: ウォレット・ストアを使用するJava SEアプリケーション」で紹介しています。

24.7.4 例3: LDAPストアを使用するJava EEアプリケーション

この例では、例2で使用したものと同じJava EEアプリケーションを使用しています。資格証明ストアが、ファイル(ウォレット)ベースではなく、LDAPベースである点だけが異なります。

ドメインレベルのjps-config.xmlファイルに、次のプロパティを構成する必要があります。

  • ルート名

    <property name="oracle.security.jps.ldap.root.name" value="cn=OracleJpsContainer"/>
    
  • ファーム名

    <property name="oracle.security.jps.farm.name" value="cn=OracleFarmContainer" />
    

jps-config.xml内のLDAPストアの構成は、次のとおりです。

<jpsConfig>
    <serviceProviders>
        <serviceProvider name="credstore_ldap_provider"
 class="oracle.security.jps.internal.credstore.ldap.LdapCredentialStoreProvider">
            <description>Prototype LDAP-based CSF provider</description>
        </serviceProvider>
    </serviceProviders>
 
    <serviceInstances>
       <serviceInstance provider="ldap.credentialstore.provider" 
          name="credstore.ldap">
          <property value="bootstrap" 
             name="bootstrap.security.principal.key"/>
          <property value="cn=wls-jrfServer" 
             name="oracle.security.jps.farm.name"/>
          <property value="cn=jpsTestNode"
             name="oracle.security.jps.ldap.root.name"/>
          <property value="ldap://mynode.us.mycorp.com:1234" 
             name="ldap.url"/>
       </serviceInstance>
    </serviceInstances>
 
    <jpsContexts default="appdefault">
        <jpsContext name="appdefault">
            <serviceInstanceRef ref="credstore_ldap_instance"/>
        </jpsContext>
    </jpsContexts>
</jpsConfig>

強調表示された行では、資格証明を検索するために必要なLDAPパラメータが定義されています。

24.8 ベスト・プラクティス

クラスタ環境では、資格証明ストア・フレームワークAPI上で資格証明ストアMbean APIを使用して、アプリケーションの資格証明の作成、取得、更新および削除を行います。

ただし、単に資格証明を読み取るだけの場合は、いずれのAPIも使用できます。