この章では、資格証明ストア・フレームワーク(CSF)のAPIの使用方法を説明します。
前の章では、アプリケーションでCSFを使用して外部システム(Webサイト、データベースなど)の資格証明を資格証明ストアに安全に保存する方法と、資格証明ストアの操作に対する監査機能や共通のOracle Fusion Middlewareユーザー・インタフェースの使用機能など、CSFに関するその他の利点について説明しました。
この章の情報によりCSF APIを使用する前に、これらのAPIが使用されているコンテキストに精通しておくことを強くお薦めします。詳細は、次の章または項を参照してください。
第19章「Oracle Platform Security Servicesを使用したセキュアなアプリケーションの開発」
第19.2.4項「資格証明ストア・フレームワークAPI」(一般的な使用シナリオを示しています)
この章の内容は次のとおりです。
資格証明ストアは、資格証明のセキュアな保存のために使用します。資格証明ストア・フレームワーク(CSF)APIは、資格証明ストアの操作へのアクセスと実行に使用します。
資格証明ストア・フレームワークには、次の機能があります。
資格証明の安全な管理を可能にします。
各種バックエンド・リポジトリでの資格証明の格納、取得および管理のためのAPIを提供します。
ファイルベース(Oracleウォレット)およびLDAPベースの資格証明管理をサポートします。
CSF APIは、次のような重要な機能(作成、更新、削除)を提供します。
資格証明マップ(特定のキーを持つ資格証明)がストア内に存在するかどうかを確認します。
<mapname, key>に関連付けられた資格証明を返します。
資格証明を<mapname, key>に割り当てます。
特定のマップ名、または特定のマップ名とキーに関連付けられた資格証明を削除します。
指定された<mapname, key>の資格証明をリセットします。
CredentialStoreに対する操作は、CSFで使用されるファイングレイン・アクセス制御モデルを実装するCredentialAccessPermissionによって保護されます。
次の領域に関する知識は、アプリケーションで資格証明ストア・フレームワークを使用する場合に役立ちます。
使用する適切なマップ名とキー名の決定。これは、複数のアプリケーションが資格証明を共通の資格証明ストアに格納する環境では非常に重要です。
Javaセキュリティ・ポリシーのプロビジョニング。
ポリシー・パーミッションは、ファイルベース(system-jazn-data.xml)またはLDAPベースのポリシー・ストアに設定されます。データのセキュリティを損なわずにアプリケーションの使用を可能にする適切なパーミッションを設定するには、十分な配慮が必要です。
jps-config.xmlでの資格証明ストア・インスタンスの定義方法。
jps-config.xmlでのサービス・インスタンスの定義は、構成ファイルをマニュアルで作成する場合のみ必要です。
環境の設定手順。
スタンドアロン・アプリケーションの場合と、Oracle WebLogic Server環境で動作するアプリケーションの場合は手順が異なります。
以降の項で、それぞれのタスクについて詳しく説明します。
Oracle Platform Security Servicesのポリシー・プロバイダは、サーバーの起動時に設定されます。プロバイダがファイルベースの場合、ポリシー・データはsystem-jazn-data.xmlに格納されます。
CSFは、資格証明の保護を次のようにサポートしています。
マップ・レベルでの保護、または
特定の<mapname, key>に対するきめ細かな保護
|
注意:
|
資格証明ストア・フレームワークでは、Javaパーミッションに基づいて、資格証明ストアのオブジェクトにパーミッションを付与します。
必要なパーミッションのみを付与して、それ以外は付与しないことを強くお薦めします。
|
警告: 不要なパーミッション、特にすべてのマップやキーにアクセスできるパーミッションを付与することは危険であり、お薦めできません。 |
|
注意: この例では、アプリケーションの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は、使用するキー名です。
この例では、特定のマップ名と、そのすべてのキー名に対してパーミッションを付与しています。
<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>
ドメインレベルの資格証明ストアが使用される場合は、ストア内に異なるアプリケーション用の様々なマップ名が存在していることから、名前の競合が発生する場合があります。これを避けるために、各アプリケーションはストア内で一意なマップ名を持つ必要があります。
そのためには、使用するマップ名でアプリケーションが一意に識別されるようにすることをお薦めします。
アプリケーションは、特定のマップ名の中に、それぞれが特定のキーで識別される複数の資格証明を持つことができます。このマップ名とキーの組合せが、特定の資格証明ストア内の主キーになります。
アプリケーションで複数のマップ名を使用する必要が生じた場合でも、その一意性は維持されます。
たとえば、次の3つのアプリケーションを考えます。
リポジトリ作成ユーティリティ(RCU)ベースのアプリケーション
Oracle WebCenterアプリケーション
Fusion Middleware Controlアプリケーション
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つの任意の文字列にすぎないため、実際には任意の有効な文字列値を持つことができます。ただし、このように実装することにより、マップ名を容易に管理することができます。
管理者は、資格証明ストアの場所とプロバイダ・クラスに関する情報が含まれている構成ファイル内で、資格証明ストア・インスタンスを定義する必要があります。構成ファイルは、次の場所にあります。
$DOMAIN_HOME/config/fmwconfig
名前は次のとおりです。
jps-config.xml(Oracle WebLogic Serverの場合)
jps-config-jse.xml(Java SEの場合)
詳細は、第10章「資格証明ストアの管理」を参照してください。
資格証明ストア・フレームワークは、Oracle WebLogic Server内でもスタンドアロン環境でも使用できます。
スタンドアロン環境でAPIを使用する手順は、次のとおりです。
クラスパスを設定します。jps-manifest.jarファイルがそのクラスパスに入っていることを確認します。詳細は、第1.5.3項「シナリオ3: Java SEアプリケーションの保護」の「クラスパスで指定する必要のあるJAR」を参照してください。
ポリシーを設定します。CSF APIにアクセスできるようにするには、参照ポリシー・ストアでアクセス・パーミッションを構成する必要があります。例は、第24.3項「Javaセキュリティ・ポリシーのパーミッションの設定」を参照してください。
アプリケーションを実行します。
コマンドライン・オプションは次のとおりです。
-Doracle.security.jps.config
構成ファイルのフルパスを指定します。
-Djava.security.policy
OPSSおよびOracle WebLogic Serverのポリシー・ファイルの場所を指定します。
-Djava.security.debug=all
デバッグに役立ちます。
Oracle WebLogic Server環境でAPIを使用する手順は、次のとおりです。
jps-config.xmlファイルの資格証明ストアのサービス・プロバイダ・セクションは、次のディレクトリにすぐに使用できるように構成されています。
$DOMAIN_HOME/config/fmwconfig
必要に応じて、LDAP資格証明ストアへの再関連付けを行ってください。
ポリシーを設定します。CSF APIにアクセスできるようにするには、参照ポリシー・ストアでアクセス・パーミッションを構成する必要があります。例は、第24.3項「Javaセキュリティ・ポリシーのパーミッションの設定」を参照してください。
Oracle WebLogic Serverを起動します。
アプリケーションをデプロイしてテストします。
この項では、資格証明ストア・フレームワークAPIの使用例をいくつか示します。次の例を示します。
すべての例でコールされ、資格証明ストアの実際の操作を実行するユーティリティJavaプログラム
ユーティリティ・プログラムをコールするJava SEコードまたはJava EEコード
ポリシー・ストアのセットアップ
構成ファイル
それぞれの例では、パーミッションが資格証明ストアの操作にどのような影響を与えるかを示すようにテスト・コードが設定されています。それぞれの例では、ポリシー・ファイル、テスト・コードおよび構成ファイルが用意され、プロバイダ情報の指定方法を示し、マップとキーに定義されたパーミッションとコード内で試行されている操作を比較できるようになっています。
この項の内容は次のとおりです。
次の共通ユーティリティ・プログラムによって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";
}
});
}
}
この例では、ウォレット資格証明(つまりファイルベースのプロバイダ)を使用するサンプル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();
}
}
}
|
注意:
|
この例では、ウォレットの資格証明を使用するサンプル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アプリケーション」で紹介しています。
この例では、例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パラメータが定義されています。
クラスタ環境では、資格証明ストア・フレームワークAPI上で資格証明ストアMbean APIを使用して、アプリケーションの資格証明の作成、取得、更新および削除を行います。
ただし、単に資格証明を読み取るだけの場合は、いずれのAPIも使用できます。