この章では、Coherence*Extendクライアントにセキュリティを適用する方法について説明します。Coherence*Extendでは、より幅広いコンシューマによるCoherenceキャッシュへのアクセスが可能となります。これらのコンシューマには、デスクトップ・アプリケーション、リモート・サーバー、WANに接続されたマシンなどが含まれます。
この章の内容は次のとおりです。
Coherence*Extendは、クラスタの外部で実行されるExtendクライアントと、クラスタの内部で実行され、1つ以上のキャッシュ・サーバーによってホストされるプロキシ・サービスで構成されます。クライアントAPIにより、すべてのリクエストはプロキシにルーティングされます。プロキシは、パーティション・キャッシュ・サービスやレプリケーション・キャッシュ・サービス、起動サービスなどのCoherenceクラスタ・サービスに委任することによってクライアント・リクエストに応答します。
Extendクライアントはクラスタの外部に存在するため、クラスタへのアクセスを保護することが重要な問題になります。この章では、クライアントとクラスタ間のアクセス保護に使用できる3つのテクニックを示します。これらは、IDのトークンベース・パスワードを使用するテクニック、資格のあるキャッシュ・サービスを使用するテクニック、起動サービスを使用するテクニックの3つです。
これらのセキュリティ・テクニックおよびExtendクライアントの詳しい説明は、このチュートリアルの範囲外となります。詳細は、『Oracle Coherenceクライアント・ガイド』を参照してください。
トークンベースのセキュリティを実装して、Extendクライアントとクラスタ内の拡張プロキシ間のアクセスを有効にできます。Extendクライアントと拡張プロキシ間のアクセスを有効にするには、一般的に次のファイルが必要です。
クライアント・アプリケーション・ファイル: クラスタにアクセスする機能について説明します。
キャッシュ構成ファイル: Extendクライアントおよび拡張プロキシそれぞれのキャッシュ構成が格納されます。
オペレーション・オーバーライド・ファイル: デフォルトのオペレーション・デプロイメント・ディスクリプタのオペレーション設定およびランタイム設定をオーバーライドします。
サーバー起動ファイル: クラスタ内の拡張プロキシとキャッシュ・サーバーの起動ファイルがあります。
POF構成デプロイメント・ディスクリプタ: オブジェクトのシリアライズにPOFを使用している場合、カスタムのデータ型を指定します。
トークンベースのセキュリティを追加するには、さらにIDトランスフォーマおよびアサーション・プロバイダを実装する必要があります。トランスフォーマはクライアント側でトークンを生成し、アサーション・プロバイダはクラスタ側でこれを検証します。
次の手順では、クラスタへのアクセスにトークンベースのセキュリティを使用するExtendクライアント用アプリケーションを作成および実行する方法について説明します。
この章に示す例では、ロールベースのセキュリティ・ポリシーおよびキャッシュへのアクセス制御を定義するセキュリティ・ヘルパー・ファイルを参照します。ここでは、マッピングを簡略化したファイルを提供します。
キャッシュ・アクセスは、ユーザーのロールにより決定されます。セキュリティ・ヘルパー・ファイルでは、role_reader
、role_writer
およびrole_admin
の各ロールを定義します。BuckarooBanzai
からROLE_ADMIN
など様々なユーザーからロールへのマッピング、およびROLE_ADMIN
から9
などロールから整数値IDへのマッピングも定義します。さらに、例で使用するキャッシュ名や起動サービス名も定義します。
このファイルの主な機能は、login
メソッドとcheckAccess
メソッドです。login
メソッドは、ユーザー名を使用して簡略化された識別名(DN)を構築します。そして、ロールをその名前に関連付けます。PofPrincipalは、Principal
を実装します。
checkAccess
メソッドは、認証コードが配置される場所を示します。これにより、指定されたユーザー・ロールに基づいてキャッシュにアクセスできるかどうかが決まります。
新しいプロジェクトおよびセキュリティ・ヘルパー・ファイルを作成する手順は次のとおりです。
JDeveloperで、Security
という新規プロジェクトを作成します。パッケージ・パスがcom.oracle.handson
であることを確認します。
プロジェクト作成の詳細は、「既存アプリケーションでの新規プロジェクトの作成」を参照してください。
SecurityExampleHelper.java
という新規Javaファイルを作成します。
Javaクラスの作成の詳細は、「Javaクラスの作成」を参照してください。
例10-1に示すコードをファイルにコピーします。
例10-1 セキュリティ・ヘルパー・ファイル
package com.oracle.handson; import com.tangosol.io.pof.PofPrincipal; import com.tangosol.net.security.SecurityHelper; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.security.Principal; import javax.security.auth.Subject; /** * This class provides extremely simplified role based policies and access control. * */ public class SecurityExampleHelper { // ----- static methods ------------------------------------------------- /** * Login the user. * * @param sName the user name * * @return the authenticated user */ public static Subject login(String sName) { // For simplicity, just create a Subject. Normally, this would be // done using JAAS. String sUserDN = "CN=" + sName + ",OU=Yoyodyne"; Set setPrincipalUser = new HashSet(); setPrincipalUser.add(new PofPrincipal(sUserDN)); // Map the user to a role setPrincipalUser.add(new PofPrincipal((String) s_mapUserToRole.get(sName))); return new Subject(true, setPrincipalUser, new HashSet(), new HashSet()); } /** * Assert that a Subject is associated with the calling thread with a * Principal representing the required role. * * @param sRoleRequired the role required for the operation * * @throws SecurityException if a Subject is not associated with the * calling thread or does not have the specified role Principal */ public static void checkAccess(String sRoleRequired) { Subject subject = SecurityHelper.getCurrentSubject(); if (subject == null) { throw new SecurityException("Access denied, authentication required"); } Map mapRoleToId = s_mapRoleToId; Integer nRoleRequired = (Integer) mapRoleToId.get(sRoleRequired); for (Iterator iter = subject.getPrincipals().iterator(); iter.hasNext();) { Principal principal = (Principal) iter.next(); String sName = principal.getName(); if (sName.startsWith("role_")) { Integer nRolePrincipal = (Integer) mapRoleToId.get(sName); if (nRolePrincipal == null) { // invalid role break; } if (nRolePrincipal.intValue() >= nRoleRequired.intValue()) { return; } } } throw new SecurityException("Access denied, insufficient privileges"); } // ----- constants ----------------------------------------------------- public static final String ROLE_READER = "role_reader"; public static final String ROLE_WRITER = "role_writer"; public static final String ROLE_ADMIN = "role_admin"; /** * The cache name for security examples */ public static final String SECURITY_CACHE_NAME = "security"; /** * The name of the InvocationService used by security examples. */ public static String INVOCATION_SERVICE_NAME = "ExtendTcpInvocationService"; // ----- static data --------------------------------------------------- /** * The map keyed by user name with the value being the user's role. * Represents which user is in which role. */ private static Map s_mapUserToRole = new HashMap(); /** * The map keyed by role name with the value the role id. * Represents the numeric role identifier. */ private static Map s_mapRoleToId = new HashMap(); // ----- static initializer --------------------------------------------- static { // User to role mapping s_mapUserToRole.put("BuckarooBanzai", ROLE_ADMIN); s_mapUserToRole.put("JohnWhorfin", ROLE_WRITER); s_mapUserToRole.put("JohnBigboote", ROLE_READER); // Role to Id mapping s_mapRoleToId.put(ROLE_ADMIN, Integer.valueOf(9)); s_mapRoleToId.put(ROLE_WRITER, Integer.valueOf(2)); s_mapRoleToId.put(ROLE_READER, Integer.valueOf(1)); } }
IDトランスフォーマ(com.tangosol.net.security.IdentityTransformer
)は、サブジェクトまたはプリンシパルをIDトークンに変換するクライアント側のコンポーネントです。トークンは、Coherenceがシリアライズ方法を認識しているタイプである必要があります。Coherenceでは、実行時に自動的にトークンをシリアライズし、これを接続リクエストの一部としてプロキシに送信します。
IDトランスフォーマの実装を作成する手順は次のとおりです。
Security
プロジェクトにPasswordIdentityTransformer
という新規Javaクラスを作成します。
詳細は、「Javaクラスの作成」を参照してください。
IdentityTransformer
インタフェースをインポートします。PasswordIdentityTransformer
にIdentityTransformer
が実装されていることを確認します。
次のタスクを実行するように、transformIdentity
メソッドを実装します。
Subject
が存在し、完全であることをテストする。
Subject
からプリンシパル名を取得し、String
配列に保存する。
トークンを、パスワードとPOF対応タイプのPrincipal
名の組合せとして構築する。
例10-2に、PasswordIdentityTransformer
の可能な実装を示します。
例10-2 IDトランスフォーマ実装のサンプル
package com.oracle.handson; import com.tangosol.net.security.IdentityTransformer; import java.security.Principal; import java.util.Iterator; import java.util.Set; import javax.security.auth.Subject; /** * PasswordIdentityTransformer creates a security token that contains the * required password and then adds a list of Principal names. * */ public class PasswordIdentityTransformer implements IdentityTransformer { // ----- IdentityTransformer interface ---------------------------------- /** * Transform a Subject to a token that asserts an identity. * * @param subject the Subject representing a user. * * @return the token that asserts identity. * * @throws SecurityException if the identity transformation fails. */ public Object transformIdentity(Subject subject) throws SecurityException { if (subject == null) { throw new SecurityException("Incomplete Subject"); } Set setPrincipals = subject.getPrincipals(); if (setPrincipals.isEmpty()) { throw new SecurityException("Incomplete Subject"); } String[] asPrincipalName = new String[setPrincipals.size() + 1]; int i = 0; asPrincipalName[i++] = System.getProperty("coherence.password", "secret-password"); for (Iterator iter = setPrincipals.iterator(); iter.hasNext();) { asPrincipalName[i++] = ((Principal) iter.next()).getName(); } // The token consists of the password plus the principal names as an // array of pof-able types, in this case strings. return asPrincipalName; } }
IDアサーション・プロバイダ(com.tangosol.net.security.IdentityAsserter
)は、拡張プロキシ・サービスをホストするキャッシュ・サーバー上にあるクラスタ側のコンポーネントです。アサーション・プロバイダは、ExtendクライアントでIDトランスフォーマにより作成されたトークンに、クラスタへのアクセスに必要な資格証明が含まれていることを検証します。
IDアサーション・プロバイダの実装を作成する手順は次のとおりです。
SecurityプロジェクトにPasswordIdentityAsserter
という新規Javaクラスを作成します。
詳細は、「Javaクラスの作成」を参照してください。
IdentityAsserter
インタフェースをインポートします。PasswordIdentityAsserter
にIdentityAsserter
が実装されていることを確認します。
次を実行するように、assertIdentity
メソッドを実装します。
トークンに正しいパスワードが含まれ、そのパスワードがトークンでの最初の名前であることを検証する。
例10-3に、PasswordIdentityAsserter
の可能な実装を示します。
例10-3 IDアサーション・プロバイダ実装のサンプル
package com.oracle.handson; import com.tangosol.io.pof.PofPrincipal; import com.tangosol.net.security.IdentityAsserter; import java.util.HashSet; import java.util.Set; import javax.security.auth.Subject; /** * PasswordIdentityAsserter asserts that the security token contains the * required password and then constructs a Subject based on a list of * Principal names. * */ public class PasswordIdentityAsserter implements IdentityAsserter { // ----- IdentityAsserter interface ------------------------------------- /** * Asserts an identity based on a token-based identity assertion. * * @param oToken the token that asserts identity. * * @return a Subject representing the identity. * * @throws SecurityException if the identity assertion fails. */ public Subject assertIdentity(Object oToken) throws SecurityException { if (oToken instanceof Object[]) { String sPassword = System.getProperty( "coherence.password", "secret-password"); Set setPrincipalUser = new HashSet(); Object[] asName = (Object[]) oToken; // first name must be password if (((String) asName[0]).equals(sPassword)) { // prints the user name to server shell to ensure we are // communicating with it and to ensure user is validated System.out.println("Password validated for user: " + asName[1]); for (int i = 1, len = asName.length; i < len; i++) { setPrincipalUser.add(new PofPrincipal((String)asName[i])); } return new Subject(true, setPrincipalUser, new HashSet(), new HashSet()); } } throw new SecurityException("Access denied"); } }
キャッシュへの参照の取得にパスワードを必要とするJavaファイルを作成します。SecurityExampleHelper.login("BuckarooBanzai")
を使用してSecurityExampleHelper
内のlogin
メソッドをコールし、トークンを生成します。実行時に、ユーザー名がSecurityExampleHelper
ファイルで定義されているそのサブジェクトと関連付けられます。PasswordIdentityTransformer
によってこのサブジェクトからトークンが生成され、接続リクエストの一部としてPasswordIdentityAsserter
により検証されます。検証が成功すると、プロキシへの接続とキャッシュへの参照が承認されます。Subject.doas
を使用して、Subject
をセキュリティ・コンテキストで有効にします。
Security
プロジェクトで、main
メソッドを含むPasswordExample
という名前の新規Javaクラスを作成します。
詳細は、「Javaクラスの作成」を参照してください。
キャッシュへの参照を取得するmain
を実装します。
SecurityExampleHelper.login
を使用して、ユーザーBuckarooBanzai
のサブジェクトを取得します。
doAs
メソッドを実装して、サブジェクトをJavaセキュリティ・コンテキストの一部とします。サブジェクトが後続のコードすべてに対して有効になります。この場合、doAs
の実装により、ユーザーが定義されたロールに基づいてキャッシュにアクセスできるかどうかが検証されます。
例10-4に、PasswordExample
の可能な実装を示します。
例10-4 パスワード例を実行するための実装サンプル
package com.oracle.handson; import com.tangosol.net.CacheFactory; import com.tangosol.net.NamedCache; import java.io.IOException; import java.security.PrivilegedExceptionAction; import javax.security.auth.Subject; /** * This class shows how a Coherence Proxy can require a password to get a * reference to a cache. * <p> * The PasswordIdentityTransformer will generate a security token that * contains the password. The PasswordIdentityAsserter will validate the * security token to enforce the password. The token generation and * validation occurs automatically when a connection to the proxy is made. * */ public class PasswordExample { // ----- static methods ------------------------------------------------- /** * Get a reference to the cache. Password will be required. */ public static void main (String[] args){ getCache(); } public static void getCache() { System.out.println("------password example begins------"); Subject subject = SecurityExampleHelper.login("BuckarooBanzai"); try { NamedCache cache = (NamedCache) Subject.doAs( subject, new PrivilegedExceptionAction() { public Object run() throws Exception { NamedCache cache; cache = CacheFactory.getCache( SecurityExampleHelper.SECURITY_CACHE_NAME); System.out.println("------password example succeeded------"); return cache; } }); } catch (Exception e) { // get exception if the password is invalid System.out.println("Unable to connect to proxy"); e.printStackTrace(); } System.out.println("------password example completed------"); } }
オペレーション・オーバーライド・ファイル(tangosol-coherence-override.xml
)を構成し、IDトランスフォーマ(ExtendクライアントでSubject
をトークンに変換するクラス)とIDアサーション・プロバイダ(クラスタでそのトークンを検証するクラス)を定義するクラスを指定します。
JDeveloperで、XMLファイルを作成します。このファイルにtangosol-coherence-override.xml
という名前を付け、C:\home\oracle\labs\
ディレクトリに保存します。
security-config
行内でidentity-transformer
要素とidentity-asserter
要素を使用して、それぞれPasswordIdentityTransformer
実装クラスとPasswordIdentityAsserter
実装クラスのフルパスを指定します。subject-scope
をtrue
に設定し、現在のセキュリティ・コンテキストからのIDを、クライアントに返されるキャッシュおよびリモート起動サービスの参照と関連付けます。
例10-5に、tangosol-coherence-override.xml
の可能な実装を示します。
例10-5 IDトランスフォーマおよびアサーション・プロバイダの指定
<?xml version='1.0'?> <!DOCTYPE coherence SYSTEM "coherence.dtd"> <coherence> <security-config> <identity-transformer> <class-name>com.oracle.handson.PasswordIdentityTransformer</class-name> </identity-transformer> <identity-asserter> <class-name>com.oracle.handson.PasswordIdentityAsserter</class-name> </identity-asserter> <subject-scope>true</subject-scope> </security-config> </coherence>
Extendクライアントのキャッシュ構成ファイルは、キャッシュ処理をクラスタ内の拡張プロキシにルーティングします。実行時、キャッシュ処理はローカルに実行されるのではなく、拡張プロキシ・サービスに送信されます。
Extendクライアントのキャッシュ構成ファイルを作成する手順は次のとおりです。
JDeveloperで、XMLファイルを作成します。このファイルにclient-cache-config.xml
という名前を付け、C:\home\oracle\labs\
ディレクトリに保存します。
Extendクライアントのキャッシュ構成を記述します。いくつかの主要な要素について次に説明します。
例10-6に、client-cache-config.xml
の可能な実装を示します。
例10-6 Extendクライアント用キャッシュ構成ファイルのサンプル
<?xml version="1.0"?> <!DOCTYPE cache-config SYSTEM "cache-config.dtd"> <cache-config> <defaults> <serializer>pof</serializer> </defaults> <caching-scheme-mapping> <cache-mapping> <cache-name>security</cache-name> <scheme-name>examples-remote</scheme-name> </cache-mapping> </caching-scheme-mapping> <caching-schemes> <remote-cache-scheme> <scheme-name>examples-remote</scheme-name> <service-name>ExtendTcpCacheService</service-name> <initiator-config> <tcp-initiator> <remote-addresses> <socket-address> <address system-property="tangosol.coherence.proxy.address">localhost</address> <port system-property="tangosol.coherence.proxy.port">9099</port> </socket-address> </remote-addresses> </tcp-initiator> </initiator-config> </remote-cache-scheme> <remote-invocation-scheme> <scheme-name>remote-invocation-scheme</scheme-name> <service-name>ExtendTcpInvocationService</service-name> <initiator-config> <tcp-initiator> <remote-addresses> <socket-address> <address system-property="tangosol.coherence.proxy.address">localhost</address> <port system-property="tangosol.coherence.proxy.port">9099</port> </socket-address> </remote-addresses> <connect-timeout>2s</connect-timeout> </tcp-initiator> <outgoing-message-handler> <request-timeout>5s</request-timeout> </outgoing-message-handler> </initiator-config> </remote-invocation-scheme> </caching-schemes> </cache-config>
拡張プロキシ・サービス用キャッシュ構成ファイルを作成します。
JDeveloperで、XMLファイルを作成します。このファイルにexamples-cache-config.xml
という名前を付け、C:\home\oracle\labs\
ディレクトリに保存します。
拡張プロキシのキャッシュ構成ファイルを構成します。いくつかの主要な要素について次に説明します。
cache-name
要素を使用して、キャッシュ名としてsecurity
を定義する。Extendクライアントのキャッシュ構成にもsecurity
という名前のキャッシュが定義されている必要があります。
acceptor-config
行でaddress
要素およびport
要素を使用して、アドレスlocalhost
、ポート9099
でリスニングする拡張プロキシ・サービスを指定する。
autostart
要素をtangosol.coherence.extend.enabled
システム・プロパティで使用して、キャッシュ・サーバーがプロキシ・サービスを実行しないようにする。
defaults
およびserializer
を値pof
で使用して、カスタムPOF構成ファイル(この章の後半で作成)のシリアライザをコールする。
例10-7に、examples-cache-config.xml
の可能な実装を示します。
例10-7 プロキシ・サーバー用キャッシュ構成ファイルのサンプル
<?xml version="1.0"?> <!DOCTYPE cache-config SYSTEM "cache-config.dtd"> <cache-config> <defaults> <serializer>pof</serializer> </defaults> <caching-scheme-mapping> <cache-mapping> <cache-name>security</cache-name> <scheme-name>ExamplesPartitionedPofScheme</scheme-name> </cache-mapping> </caching-scheme-mapping> <caching-schemes> <distributed-scheme> <scheme-name>ExamplesPartitionedPofScheme</scheme-name> <service-name>PartitionedPofCache</service-name> <backing-map-scheme> <local-scheme> <!-- each node will be limited to 32MB --> <high-units>32M</high-units> <unit-calculator>binary</unit-calculator> </local-scheme> </backing-map-scheme> <autostart>true</autostart> </distributed-scheme> <!-- Proxy Service scheme that allows remote clients to connect to the cluster over TCP/IP. --> <proxy-scheme> <scheme-name>secure-proxy</scheme-name> <service-name>ProxyService</service-name> <thread-count system-property="tangosol.coherence.extend.threads">2</thread-count> <acceptor-config> <tcp-acceptor> <local-address> <address system-property="tangosol.coherence.extend.address">localhost</address> <port system-property="tangosol.coherence.extend.port">9099</port> <reusable>true</reusable> </local-address> </tcp-acceptor> </acceptor-config> <autostart system-property="tangosol.coherence.extend.enabled">false</autostart> </proxy-scheme> </caching-schemes> </cache-config>
キャッシュ・サーバーのクラスタ・ノード用起動ファイルを作成します。起動ファイルには、プロキシ・サービスとクラスタ側のキャッシュ構成ファイルを指定するシステム・プロパティを含める必要があります。クラスパスに、アプリケーション・クラス・ファイルとXML構成ファイルを含める必要もあります。
キャッシュ・サーバー用起動ファイルを作成する手順は次のとおりです。
JDeveloperで、起動ファイルを作成します。Securityプロジェクトを右クリックし、「新規」を選択します。「新規ギャラリ」で、「カテゴリ」フィールドの「一般」および「アイテム」フィールドの「ファイル」を選択します。「新規ファイル」ダイアログで、ファイル名としてsecurity-cache-server.cmd
を入力し、Coherenceの\bin
ディレクトリ(この場合はC:\oracle\product\coherence\bin
)に保存します。
コマンドを入力してキャッシュ・サーバーを起動します。主なコマンドは次のとおりです。
クラスタ側のキャッシュ構成ファイル(この場合はexamples-cache-config.xml
)のパスを示すtangosol.coherence.cacheconfig
システム・プロパティ
coherence.jar
(C:\oracle\product\lib\coherence.jar
)、Security
プロジェクト・クラス(C:\home\oracle\labs\Security\classes
)、およびXML構成ファイル(C:\home\oracle\labs
)のパスを含めるよう定義されたクラスパス
注意: クラスパスで、XML構成ファイル(C:\home\oracle\labs の下)はcoherence.jar より前に指定してください。クラス・ローダーは、coherence.jar でカスタムのPOF構成ファイル(この章の後半で作成)を参照する前に、この構成ファイルを見つける必要があります。 |
例10-8に、security-cache-server.cmd
の可能な実装を示します。
例10-8 キャッシュ・サーバー用起動ファイル
@echo off @ @rem This will start a cache server @ setlocal :config @rem specify the Coherence installation directoryset coherence_home=c:\oracle\product\coherence
@rem specify the JVM heap size set memory=512m :start if not exist "%coherence_home%\lib\coherence.jar" goto instructions if "%java_home%"=="" (set java_exec=java) else (set java_exec=%java_home%\bin\java) :launch set COH_OPTS=%COH_OPTS%-Dtangosol.coherence.cacheconfig=\home\oracle\labs\examples-cache-config.xml
"%java_exec%" -server -showversion %COH_OPTS%-cp C:\home\oracle\labs;"%coherence_home%\lib\coherence.jar";C:\home\oracle\labs\Security\classes
-Xms128m -Xmx128m com.tangosol.net.DefaultCacheServer %2 %3 %4 %5 %6 %7 goto exit :instructions echo Usage: echo ^<coherence_home^>\bin\cache-server.cmd goto exit :exit endlocal @echo on
クラスタ内のキャッシュ・サーバーで拡張プロキシ・サービスを起動するファイルを作成します。Extendクライアントはこのサービスに接続します。起動ファイルには、プロキシ・サービスとクラスタ側のキャッシュ構成ファイルを指定するシステム・プロパティを含める必要があります。クラスパスに、アプリケーション・クラス・ファイルとXML構成ファイルを含める必要もあります。
これらの例で、プロキシ・サービスのあるキャッシュ・サーバーの起動ファイルは、キャッシュ・サーバーの起動ファイルと同じ構成を持ちますが、これには拡張プロキシを有効にするシステム・プロパティが含まれます。
プロキシ・サービスのあるキャッシュ・サーバーの起動ファイルを作成する手順は次のとおりです。
JDeveloperで、起動ファイルを作成します。Securityプロジェクトを右クリックし、「新規」を選択します。「新規ギャラリ」で、「カテゴリ」フィールドの「一般」および「アイテム」フィールドの「ファイル」を選択します。「新規ファイル」ダイアログで、ファイル名としてsecurity-run-proxy.cmd
を入力し、これをCoherenceの\bin
ディレクトリ(この場合はC:\oracle\product\coherence\bin
)に保存します。
コマンドを入力してキャッシュ・サーバーを起動します。主なコマンドは次のとおりです。
注意: クラスパスで、XML構成ファイル(C:\home\oracle\labs の下)はcoherence.jar より前に指定してください。クラス・ローダーは、coherence.jar でカスタムのPOF構成ファイル(この章の後半で作成)を参照する前に、この構成ファイルを見つける必要があります。 |
例10-9に、プロキシ・サービスのあるクラスタ側キャッシュ・サーバーの起動ファイルsecurity-run-proxy.cmd
の可能な実装を示します。
例10-9 プロキシ・サービスのあるキャッシュ・サーバー用起動ファイル
@echo off @ @REM this will start a proxy cache server @ setlocal :config @rem specify the Coherence installation directoryset coherence_home=c:\oracle\product\coherence
@rem specify the JVM heap size set memory=512m :start if not exist "%coherence_home%\lib\coherence.jar" goto instructions if "%java_home%"=="" (set java_exec=java) else (set java_exec=%java_home%\bin\java) :launch set COH_OPTS=%COH_OPTS%-Dtangosol.coherence.extend.enabled=true -Dtangosol.coherence.cacheconfig=\home\oracle\labs\examples-cache-config.xml
"%JAVA_HOME%"\bin\java -server -showversion %COH_OPTS%-cp C:\home\oracle\labs;"%coherence_home%\lib\coherence.jar";C:\home\oracle\labs\Security\classes
-Xms128m -Xmx128m com.tangosol.net.DefaultCacheServer %2 %3 %4 %5 %6 %7 goto exit :instructions echo Usage: echo ^<coherence_home^>\bin\security-run-proxy.cmd goto exit :exit endlocal
プロジェクトのクラスパスおよびランタイム・プロパティを構成します。
JDeveloperで、プロジェクト内のJavaファイルをコンパイルします。Security
プロジェクトを右クリックし、「Security.jprのメイク」を選択します。
プロジェクトのJavaランタイム・オプションを設定します。
Security
プロジェクトを右クリックし、「プロジェクト・プロパティ」を選択します。「実行/デバッグ/プロファイル」を選択し、「デフォルト」実行構成を編集します。「Javaオプション」フィールドで、ローカル記憶域を無効にし、クライアント側のキャッシュ構成ファイルclient-cache-config.xml
を指定するよう、システム・プロパティを入力します。
-Dtangosol.coherence.distributed.localstorage=false -Dtangosol.coherence.cacheconfig=\home\oracle\labs\client-cache-config.xml
「OK」をクリックし、「実行構成の編集」ウィンドウを閉じます。
プロジェクトのライブラリおよびクラスパスを設定します。「プロジェクト・プロパティ」ウィンドウで、「ライブラリとクラスパス」をクリックします。coherence.jar
、Security
プロジェクトのJavaクラス(C:\home\oracle\labs\Security\classes
)、およびXML構成ファイルを含むディレクトリ(C:\home\oracle\labs
)をプロジェクト・クラスパスに追加します。
注意: クラスパスで、XML構成ファイル(C:\home\oracle\labs の下)はcoherence.jar より前に指定してください。クラス・ローダーは、coherence.jar でカスタムのPOF構成ファイル(この章の後半で作成)を参照する前に、この構成ファイルを見つける必要があります。 |
「ライブラリとクラスパス」ウィンドウは図10-1のようになります。
ライブラリおよびクラスパスの設定の詳細は、「プロジェクト・プロパティの変更によるランタイム構成の設定」を参照してください。
「OK」をクリックして「ライブラリとクラスパス」ダイアログ・ボックスを閉じ、さらに「OK」をクリックして「プロジェクト・プロパティ」ダイアログ・ボックスを閉じます。
プロジェクトを保存してコンパイルします。プロジェクトを右クリックし、「Security.jprのメイク」を選択します。
パスワード例を実行し、トークンを生成および検証して、プロキシ・サービスに渡します。
Securityプロジェクト内のファイルがまだコンパイルされていない場合は、これらをコンパイルします。
稼働しているキャッシュ・サーバーがあれば停止します。コマンド・プロンプトを開き、プロキシ・サーバーsecurity-run.proxy.cmd
を実行します。
別のコマンド・プロンプトを開き、キャッシュ・サーバーsecurity-cache-server.cmd
を実行します。
PasswordExample.java
を右クリックし、「実行」を選択して、パスワード例を実行します。
JDeveloperログ・ウィンドウに、例10-10のような出力が表示されます。出力には、パスワード例の開始、プロキシ・サーバーへのソケットのオープン、およびこの例の完了が示されます。
例10-10 JDeveloperログ・ウィンドウでのパスワード例の出力
...------password example begins------
2010-06-09 11:50:49.220/0.344 Oracle Coherence 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/product/coherence_3.5/lib/coherence.jar!/tangosol-coherence.xml" 2010-06-09 11:50:49.220/0.344 Oracle Coherence 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/product/coherence_3.5/lib/coherence.jar!/tangosol-coherence-override-dev.xml" 2010-06-09 11:50:49.220/0.344 Oracle Coherence 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/labs/tangosol-coherence-override.xml" 2010-06-09 11:50:49.235/0.359 Oracle Coherence 3.6.0.0 DPR3 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified Oracle Coherence Version 3.6.0.0 DPR3 Build 16141 Grid Edition: Development mode Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 2010-06-09 11:50:49.470/0.594 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded cache configuration from "file:/C:/home/oracle/labs/client-cache-config.xml" 2010-06-09 11:50:49.673/0.797 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=ExtendTcpCacheService:TcpInitiator, member=n/a): Loaded POF configuration from "jar:file:/C:/oracle/product/coherence_3.5/lib/coherence.jar!/pof-config.xml" 2010-06-09 11:50:49.688/0.812 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=ExtendTcpCacheService:TcpInitiator, member=n/a): Loaded included POF configuration from "jar:file:/C:/oracle/product/coherence_3.5/lib/coherence.jar!/coherence-pof-config.xml" 2010-06-09 11:50:49.782/0.906 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=ExtendTcpCacheService:TcpInitiator, member=n/a): Started: TcpInitiator{Name=ExtendTcpCacheService:TcpInitiator, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), Serializer=com.tangosol.io.pof.ConfigurablePofContext, PingInterval=0, PingTimeout=0, RequestTimeout=0, ConnectTimeout=0, SocketProvider=SystemSocketProvider, RemoteAddresses=[hostname/130.35.99.213:9099], KeepAliveEnabled=true, TcpDelayEnabled=false, ReceiveBufferSize=0, SendBufferSize=0, LingerTimeout=-1} 2010-06-09 11:50:49.798/0.922 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=main, member=n/a):Opening Socket connection to 130.35.99.213:9099
2010-06-09 11:50:49.798/0.922 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Connected to 130.35.99.213:9099------password example succeeded------
------password example completed------
Process exited with exit code 0.
プロキシ・サーバーのシェルには、例10-11のようなレスポンスが表示されます。ここには、識別名のCN
およびOU
の各値と、パスワードが検証されたかどうかが一覧表示されます。
例10-11 プロキシ・サービス・シェルを実行するキャッシュ・サーバーからのレスポンス
... 2010-06-09 11:50:39.829/2.781 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=2): Services ( ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=3.6, OldestMemberId=1} InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=3.1, OldestMemberId=6} PartitionedCache{Name=PartitionedPofCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=128, BackupPartitions=129} ProxyService{Name=ProxyService, State=(SERVICE_STARTED), Id=7, Version=3.2, OldestMemberId=6} ) Started DefaultCacheServer...Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne
Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne
Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne
この項では、クラスタへのアクセスにロールベースのポリシーを採用する例を作成する方法について説明します。コードでは、ログインしてユーザーIDが特定のロールに割り当てられているSubject
を取得します。Subject
のコンテキストで実行されているキャッシュ参照を取得し、さらに様々なキャッシュ処理を試みます。ユーザーに付与されたロールにより、キャッシュ処理が許可または拒否されます。この例のロール・マッピングおよびロールベースの認証は簡略化されており、実際のセキュリティ向けではありません。
たとえば、writerロールのユーザーは入力と取得が許可されます。readerロールのユーザーの場合、取得はできますが入力はできません。writerロールのユーザーがキャッシュを破棄することはできません。しかし、adminロールのユーザーはキャッシュを破棄できます。
Subject
のコンテキストでキャッシュ参照が作成されると、そのIDはその参照に永久的に関連付けられます。そのキャッシュ参照はすべて、そのIDのために使用されます。
例では、前項で作成したPasswordIdentityTransformer
クラスおよびPasswordIdentityAsserter
クラスを使用します。PasswordIdentityTransformer
は、パスワード、ユーザーIDおよびロールを含むセキュリティ・トークンを生成します。PasswordIdentityAsserter
(プロキシで実行)は、パスワードを適用するセキュリティ・トークンを検証し、適切なユーザーIDおよびロールでSubject
を構築します。セキュリティ・トークンの生成およびアサーションは自動的に行われます。
次の手順に従い、例を作成します。
ユーザーのロールに基づいてキャッシュ・メソッドへのアクセスを許可するJavaファイルを作成します。このためには、Coherence*Extendを使用してクライアントから渡されたSubject
を使用し、ラップされたNamedCache
へのアクセス権限を適用します。この実装では、特定ロールのクライアントのみがラップされたNamedCache
にアクセスできます。
この項で作成するクラスは、com.tangosol.net.cache.WrapperNamedCache
クラスを拡張したものです。このクラスは、NamedCache
インタフェース上のメソッドを保護できる便利な機能です。
キャッシュ・メソッドにアクセスできるユーザー・ロールを指定するには、各キャッシュ・メソッドの実装にSecurityExampleHelper.checkAccess
のコールを含めます。checkAccess
への引数として、メソッドへのアクセスが許可されるユーザー・ロールを指定します。super
のコールで実装を閉じます。
たとえば次のコードは、admin
ロールのユーザーがキャッシュを破棄できることを示します。
public void destroy() { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_ADMIN); super.destroy(); }
この例で、reader
ロールのユーザーはaggregate
メソッドをコールできます。
public Object aggregate(Filter filter, EntryAggregator agent) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.aggregate(filter, agent); }
キャッシュ・メソッドをコールできるユーザーを指定するファイルを作成する手順は次のとおりです。
SecurityプロジェクトにEntitledNamedCache
という新規Javaクラスを作成します。
詳細は、「Javaクラスの作成」を参照してください。
クラスがWrapperNamedCache
をインポートおよび拡張することを確認します。
Filter
、MapListener
、ValueExtractor
、Collection
、Comparator
、Map
、およびSet
の各クラスをインポートします。WrapperNamedCache
(EntitledNamedCache
も含む)内のメソッドは、これらのタイプで引数を使用します。
特定のロールのユーザーのみがメソッドをコールできるように、EntitledNamedCache
にメソッドを実装します。
例10-12に、EntitledNamedCache
の可能な実装を示します。
例10-12 資格のある名前付きキャッシュ
package com.oracle.handson; import com.tangosol.net.NamedCache; import com.tangosol.net.cache.WrapperNamedCache; import com.tangosol.util.Filter; import com.tangosol.util.MapListener; import com.tangosol.util.ValueExtractor; import java.util.Collection; import java.util.Comparator; import java.util.Map; import java.util.Set; /** * Example WrapperNamedCache that demonstrates how entitlements can be applied * to a wrapped NamedCache using the Subject passed from the client through * Coherence*Extend. This implementation only allows clients with a specified * role to access the wrapped NamedCache. * */ public class EntitledNamedCache extends WrapperNamedCache { /** * Create a new EntitledNamedCache. * * @param cache the wrapped NamedCache */ public EntitledNamedCache(NamedCache cache) { super(cache, cache.getCacheName()); } // ----- NamedCache interface ------------------------------------------- /** * {@inheritDoc} */ public void release() { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); super.release(); } /** * {@inheritDoc} */ public void destroy() { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_ADMIN); super.destroy(); } /** * {@inheritDoc} */ public Object put(Object oKey, Object oValue, long cMillis) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); return super.put(oKey, oValue, cMillis); } /** * {@inheritDoc} */ public void addMapListener(MapListener listener) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); super.addMapListener(listener); } /** * {@inheritDoc} */ public void removeMapListener(MapListener listener) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); super.removeMapListener(listener); } /** * {@inheritDoc} */ public void addMapListener(MapListener listener, Object oKey, boolean fLite) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); super.addMapListener(listener, oKey, fLite); } /** * {@inheritDoc} */ public void removeMapListener(MapListener listener, Object oKey) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); super.removeMapListener(listener, oKey); } /** * {@inheritDoc} */ public void addMapListener(MapListener listener, Filter filter, boolean fLite) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); super.addMapListener(listener, filter, fLite); } /** * {@inheritDoc} */ public void removeMapListener(MapListener listener, Filter filter) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); super.removeMapListener(listener, filter); } /** * {@inheritDoc} */ public int size() { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.size(); } /** * {@inheritDoc} */ public void clear() { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); super.clear(); } /** * {@inheritDoc} */ public boolean isEmpty() { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.isEmpty(); } /** * {@inheritDoc} */ public boolean containsKey(Object oKey) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.containsKey(oKey); } /** * {@inheritDoc} */ public boolean containsValue(Object oValue) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.containsValue(oValue); } /** * {@inheritDoc} */ public Collection values() { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.values(); } /** * {@inheritDoc} */ public void putAll(Map map) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); super.putAll(map); } /** * {@inheritDoc} */ public Set entrySet() { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.entrySet(); } /** * {@inheritDoc} */ public Set keySet() { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.keySet(); } /** * {@inheritDoc} */ public Object get(Object oKey) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.get(oKey); } /** * {@inheritDoc} */ public Object remove(Object oKey) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); return super.remove(oKey); } /** * {@inheritDoc} */ public Object put(Object oKey, Object oValue) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); return super.put(oKey, oValue); } /** * {@inheritDoc} */ public Map getAll(Collection colKeys) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.getAll(colKeys); } /** * {@inheritDoc} */ public boolean lock(Object oKey, long cWait) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); return super.lock(oKey, cWait); } /** * {@inheritDoc} */ public boolean lock(Object oKey) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); return super.lock(oKey); } /** * {@inheritDoc} */ public boolean unlock(Object oKey) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); return super.unlock(oKey); } /** * {@inheritDoc} */ public Set keySet(Filter filter) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.keySet(filter); } /** * {@inheritDoc} */ public Set entrySet(Filter filter) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.entrySet(filter); } /** * {@inheritDoc} */ public Set entrySet(Filter filter, Comparator comparator) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.entrySet(filter, comparator); } /** * {@inheritDoc} */ public void addIndex(ValueExtractor extractor, boolean fOrdered, Comparator comparator) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); super.addIndex(extractor, fOrdered, comparator); } /** * {@inheritDoc} */ public void removeIndex(ValueExtractor extractor) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); super.removeIndex(extractor); } /** * {@inheritDoc} */ public Object invoke(Object oKey, EntryProcessor agent) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); return super.invoke(oKey, agent); } /** * {@inheritDoc} */ public Map invokeAll(Collection collKeys, EntryProcessor agent) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); return super.invokeAll(collKeys, agent); } /** * {@inheritDoc} */ public Map invokeAll(Filter filter, EntryProcessor agent) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); return super.invokeAll(filter, agent); } /** * {@inheritDoc} */ public Object aggregate(Collection collKeys, EntryAggregator agent) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.aggregate(collKeys, agent); } /** * {@inheritDoc} */ public Object aggregate(Filter filter, EntryAggregator agent) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return super.aggregate(filter, agent); } // ----- helper methods ------------------------------------------------- /** * Return the wrapped NamedCache. * * @return the wrapped CacheService */ public NamedCache getNamedCache() { return (NamedCache) getMap(); } }
Coherence*Extendによりクライアントから渡されたSubject
を使用して、ラップされたCacheService
に対するアクセス権限を適用する方法を示すファイルを作成します。この実装では、前項で作成したEntitledNamedCache
に、キャッシュ処理のアクセス制御を委任する必要があります。
作成するクラスは、com.tangosol.net.WrapperCacheService
を拡張する必要があります。このクラスは、CacheService
上のメソッドを保護できる便利な機能です。プロキシのキャッシュ・サービスとクライアント・リクエスト間で委任を行うメカニズムも提供します。
特定ロールのユーザーのみが使用できるように、メソッドensureCache
、releaseCache
およびdestroyCache
を実装します。これには、特定のユーザー・ロールを引数とするSecurityExampleHelper
.checkAccess
のコールが含まれます。たとえば次のコードは、admin
ロールのユーザーのみがキャッシュを破棄できるようにします。
public void destroyCache(NamedCache map) { if (map instanceof EntitledNamedCache) { EntitledNamedCache cache = (EntitledNamedCache) map; SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_ADMIN); map = cache.getNamedCache(); } super.destroyCache(map); }
キャッシュ・サービスにアクセスする資格を適用するファイルを作成する手順は次のとおりです。
Security
プロジェクトにEntitledCacheService
という新規Javaクラスを作成します。
クラスがWrapperCacheService
をインポートおよび拡張することを確認します。
特定ロールのユーザーのみが使用できるように、ensureCache
、releaseCache
およびdestroyCache
の各メソッドを実装します。
例10-13に、EntitledCacheService
の可能な実装を示します。
例10-13 資格のあるキャッシュ・サービス
package com.oracle.handson; import com.tangosol.net.CacheService; import com.tangosol.net.NamedCache; import com.tangosol.net.WrapperCacheService; /** * Example WrapperCacheService that demonstrates how entitlements can be * applied to a wrapped CacheService using the Subject passed from the * client through Coherence*Extend. This implementation delegates access control * for cache operations to the EntitledNamedCache. * */ public class EntitledCacheService extends WrapperCacheService { /** * Create a new EntitledCacheService. * * @param service the wrapped CacheService */ public EntitledCacheService(CacheService service) { super(service); } // ----- CacheService interface ----------------------------------------- /** * {@inheritDoc} */ public NamedCache ensureCache(String sName, ClassLoader loader) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); return new EntitledNamedCache(super.ensureCache(sName, loader)); } /** * {@inheritDoc} */ public void releaseCache(NamedCache map) { if (map instanceof EntitledNamedCache) { EntitledNamedCache cache = (EntitledNamedCache) map; SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER); map = cache.getNamedCache(); } super.releaseCache(map); } /** * {@inheritDoc} */ public void destroyCache(NamedCache map) { if (map instanceof EntitledNamedCache) { EntitledNamedCache cache = (EntitledNamedCache) map; SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_ADMIN); map = cache.getNamedCache(); } super.destroyCache(map); } }
アクセス制御例を実行するファイルを作成します。ロール・ポリシーは、SecurityExampleHelper
に定義されます。EntitledCacheService
ファイルおよびEntitledNamedCache
ファイルでポリシーが適用されます。
プログラムは、SecurityHelperFile.login
への引数として様々なユーザーを指定し、さらにキャッシュでの読取りや書込み、および処理の破棄を試みます。処理は、EntitledCacheService
およびEntitledNamedCache
で定義された資格ポリシーに基づいて成功または失敗します。
Securityプロジェクトで、main
メソッドを含むAccessControlExample
という名前の新規Javaクラスを作成します。
詳細は、「Javaクラスの作成」を参照してください。
キャッシュにアクセスするmain
を実装します。
login
メソッドに対する引数として、SecurityExampleHelper
ファイルで定義したユーザーを指定します。
ユーザーごとに、キャッシュ上で読取り(get
)、書込み(put
)およびdestroy
処理を試み、それに応じて成功または失敗のメッセージを表示します。
例10-14に、AccessControlExample.java
の可能な実装を示します。
例10-14 アクセス制御例を実行するサンプル・プログラム
package com.oracle.handson; import com.tangosol.net.CacheFactory; import com.tangosol.net.InvocationService; import com.tangosol.net.NamedCache; import java.security.PrivilegedExceptionAction; import java.util.Map; import javax.security.auth.Subject; /** * This class demonstrates simplified role based access control. * <p> * The role policies are defined in SecurityExampleHelper. Enforcmenent * is done by EntitledCacheService and EntitledNamedCache. * */ public class AccessControlExample { // ----- static methods ------------------------------------------------- public static void main (String[] args){ accessCache(); } /** * Demonstrate role based access to the cache. */ public static void accessCache() { System.out.println("------cache access control example begins------"); Subject subject = SecurityExampleHelper.login("JohnWhorfin"); // Someone with writer role can write and read try { NamedCache cache = (NamedCache) Subject.doAs( subject, new PrivilegedExceptionAction() { public Object run() throws Exception { return CacheFactory.getCache(SecurityExampleHelper.SECURITY_CACHE_NAME); } }); cache.put("myKey", "myValue"); cache.get("myKey"); System.out.println(" Success: read and write allowed"); } catch (Exception e) { // get exception if not allowed to perform the operation e.printStackTrace(); } // Someone with reader role can read but not write subject = SecurityExampleHelper.login("JohnBigboote"); try { NamedCache cache = (NamedCache) Subject.doAs( subject, new PrivilegedExceptionAction() { public Object run() throws Exception { return CacheFactory.getCache(SecurityExampleHelper.SECURITY_CACHE_NAME); } }); cache.get("myKey"); System.out.println(" Success: read allowed"); cache.put("anotherKey", "anotherValue"); } catch (Exception e) { // get exception if not allowed to perform the operation System.out.println(" Success: Correctly cannot write"); } // Someone with writer role cannot call destroy subject = SecurityExampleHelper.login("JohnWhorfin"); try { NamedCache cache = (NamedCache) Subject.doAs( subject, new PrivilegedExceptionAction() { public Object run() throws Exception { return CacheFactory.getCache(SecurityExampleHelper.SECURITY_CACHE_NAME); } }); cache.destroy(); } catch (Exception e) { // get exception if not allowed to perform the operation System.out.println(" Success: Correctly cannot " + "destroy the cache"); } // Someone with admin role can call destroy subject = SecurityExampleHelper.login("BuckarooBanzai"); try { NamedCache cache = (NamedCache) Subject.doAs( subject, new PrivilegedExceptionAction() { public Object run() throws Exception { return CacheFactory.getCache(SecurityExampleHelper.SECURITY_CACHE_NAME); } }); cache.destroy(); System.out.println(" Success: Correctly allowed to " + "destroy the cache"); } catch (Exception e) { // get exception if not allowed to perform the operation e.printStackTrace(); } System.out.println("------cache access control example completed------"); } }
クラスタ側のキャッシュ構成ファイルexamples-cache-config.xml
を編集します。proxy-config
の下のcache-service-proxy
行に、キャッシュ・サービスのクラス名のフルパスを指定します。cache-service-proxy
行には、プロキシ・サービスによって管理されるキャッシュ・サービス・プロキシの構成情報を記述します。
この場合、キャッシュ・サービス・クラス名はcom.oracle.handson.EntitledCacheService
プロキシで、param-type
はcom.tangosol.net.CacheService
とします。
例10-15に、構成に追加するXMLコードを示します。
例10-15 クラスタ側のキャッシュ構成のキャッシュ・サービス・プロキシ構成
... <proxy-config> <cache-service-proxy> <class-name>com.oracle.handson.EntitledCacheService</class-name> <init-params> <init-param> <param-type>com.tangosol.net.CacheService</param-type> <param-value>{service}</param-value> </init-param> </init-params> </cache-service-proxy> </proxy-config> ...
アクセス制御例を実行し、ユーザーのロールに基づいてキャッシュへのアクセスを付与または拒否する方法を示します。
Securityプロジェクト内のファイルがまだコンパイルされていない場合は、これらをコンパイルします。
稼働しているキャッシュ・サーバーがあれば停止します。security-run-proxy.cmd
により、プロキシ・サービスを実行するキャッシュ・サーバーを起動します。
security-cache-server.cmd
により、クラスタ内のキャッシュ・サーバーを起動します。
AccessControlExample.java
ファイルを右クリックし、「実行」を選択します。
JDeveloperログ・ウィンドウに、例10-16のような出力が表示されます。メッセージは、キャッシュで読取り、書込み、および破棄の処理を試みる、AccessControlExample
で指定された様々なユーザーに対応します。
Success: read and write allowed
メッセージ: キャッシュからの読取りおよびキャッシュへの書込みを試みる、ロールwriter
を持つユーザーに対応します。
Success: read allowed
メッセージ: キャッシュからの読取りを試みる、ロールreader
を持つユーザーに対応します。
Success: Correctly cannot write
メッセージ: キャッシュへの書込みを試みる、ロールreader
を持つユーザーに対応します。
Success: Correctly cannot destroy the cache
メッセージ: キャッシュの破棄を試みる、ロールwriter
を持つユーザーに対応します。
Success: Correctly allowed to destroy the cache
メッセージ: キャッシュの破棄を試みる、ロールadmin
を持つユーザーに対応します。
例10-16 JDeveloperログ・ウィンドウでのアクセス制御例の出力
... ------cache access control example begins------ 2010-06-10 17:07:51.500/0.344 Oracle Coherence 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/product0529/coherence_3.5/lib/coherence.jar!/tangosol-coherence.xml" 2010-06-10 17:07:51.500/0.344 Oracle Coherence 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/product0529/coherence_3.5/lib/coherence.jar!/tangosol-coherence-override-dev.xml" 2010-06-10 17:07:51.500/0.344 Oracle Coherence 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/labs/tangosol-coherence-override.xml" 2010-06-10 17:07:51.500/0.344 Oracle Coherence 3.6.0.0 DPR3 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified Oracle Coherence Version 3.6.0.0 DPR3 Build 16141 Grid Edition: Development mode Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 2010-06-10 17:07:51.703/0.547 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded cache configuration from "file:/C:/home/oracle/labs/client-cache-config.xml" 2010-06-10 17:07:51.906/0.750 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=ExtendTcpCacheService:TcpInitiator, member=n/a): Loaded POF configuration from "jar:file:/C:/oracle/product0529/coherence_3.5/lib/coherence.jar!/pof-config.xml" 2010-06-10 17:07:51.906/0.750 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=ExtendTcpCacheService:TcpInitiator, member=n/a): Loaded included POF configuration from "jar:file:/C:/oracle/product0529/coherence_3.5/lib/coherence.jar!/coherence-pof-config.xml" 2010-06-10 17:07:52.015/0.859 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=ExtendTcpCacheService:TcpInitiator, member=n/a): Started: TcpInitiator{Name=ExtendTcpCacheService:TcpInitiator, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), Serializer=com.tangosol.io.pof.ConfigurablePofContext, PingInterval=0, PingTimeout=0, RequestTimeout=0, ConnectTimeout=0, SocketProvider=SystemSocketProvider, RemoteAddresses=[tpfaeffl-lap7/130.35.99.213:9099], KeepAliveEnabled=true, TcpDelayEnabled=false, ReceiveBufferSize=0, SendBufferSize=0, LingerTimeout=-1} 2010-06-10 17:07:52.031/0.875 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=main, member=n/a): Opening Socket connection to 130.35.99.213:9099 2010-06-10 17:07:52.031/0.875 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Connected to 130.35.99.213:9099 Success: read and write allowed 2010-06-10 17:07:52.125/0.969 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=ExtendTcpCacheService:TcpInitiator, member=n/a): Started: TcpInitiator{Name=ExtendTcpCacheService:TcpInitiator, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), Serializer=com.tangosol.io.pof.ConfigurablePofContext, PingInterval=0, PingTimeout=0, RequestTimeout=0, ConnectTimeout=0, SocketProvider=SystemSocketProvider, RemoteAddresses=[tpfaeffl-lap7/130.35.99.213:9099], KeepAliveEnabled=true, TcpDelayEnabled=false, ReceiveBufferSize=0, SendBufferSize=0, LingerTimeout=-1} 2010-06-10 17:07:52.125/0.969 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=main, member=n/a): Opening Socket connection to 130.35.99.213:9099 2010-06-10 17:07:52.125/0.969 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Connected to 130.35.99.213:9099 Success: read allowed Success: Correctly cannot write Success: Correctly cannot destroy the cache 2010-06-10 17:07:52.187/1.031 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=ExtendTcpCacheService:TcpInitiator, member=n/a): Started: TcpInitiator{Name=ExtendTcpCacheService:TcpInitiator, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), Serializer=com.tangosol.io.pof.ConfigurablePofContext, PingInterval=0, PingTimeout=0, RequestTimeout=0, ConnectTimeout=0, SocketProvider=SystemSocketProvider, RemoteAddresses=[tpfaeffl-lap7/130.35.99.213:9099], KeepAliveEnabled=true, TcpDelayEnabled=false, ReceiveBufferSize=0, SendBufferSize=0, LingerTimeout=-1} 2010-06-10 17:07:52.187/1.031 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=main, member=n/a): Opening Socket connection to 130.35.99.213:9099 2010-06-10 17:07:52.187/1.031 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Connected to 130.35.99.213:9099 Success: Correctly allowed to destroy the cache ------cache access control example completed------ Process exited with exit code 0.
例10-17に、キャッシュ・サーバーがプロキシ・サービスを実行しているシェルの出力を示します。出力内のセキュリティの例外は、JDeveloperログ・ウィンドウのSuccess: Correctly cannot write
メッセージおよびSuccess: Correctly cannot destroy the cache
メッセージに対応します。
例10-17 プロキシ・サービスを実行するキャッシュ・サーバーの出力
2010-06-10 17:07:25.468/18.156 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=Cluster, member=1): Member 2 joined Service ProxyService with senior member 1 Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne Password validated for user: role_writer Password validated for user: role_writer Password validated for user: role_writer Password validated for user: role_reader Password validated for user: role_reader Password validated for user: role_reader 2010-06-10 17:07:52.140/44.828 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=Proxy:ProxyService:TcpAcceptorWorker:0, member=1): An exception occurred while processing a PutRequest for Service=Proxy:ProxyService:TcpAcceptor: java.lang.SecurityException: Access denied, insufficient privileges at com.oracle.handson.SecurityExampleHelper.checkAccess(SecurityExampleHelper.java:91) at com.oracle.handson.EntitledNamedCache.put(EntitledNamedCache.java:66) at com.tangosol.coherence.component.net.extend.proxy.NamedCacheProxy.put$Router(NamedCacheProxy.CDB:1) at com.tangosol.coherence.component.net.extend.proxy.NamedCacheProxy.put(NamedCacheProxy.CDB:2) at com.tangosol.coherence.component.net.extend.messageFactory.NamedCacheFactory$PutRequest.onRun(NamedCacheFactory.CDB:6) at com.tangosol.coherence.component.net.extend.message.Request.run(Request.CDB:4) at com.tangosol.coherence.component.net.extend.proxy.NamedCacheProxy.onMessage(NamedCacheProxy.CDB:11) at com.tangosol.coherence.component.net.extend.Channel$MessageAction.run(Channel.CDB:13) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:337) at com.tangosol.coherence.component.net.extend.Channel.execute(Channel.CDB:29) at com.tangosol.coherence.component.net.extend.Channel.receive(Channel.CDB:26) at com.tangosol.coherence.component.util.daemon.queueProcessor.service.Peer$DaemonPool$WrapperTask.run(Peer.CDB:9) at com.tangosol.coherence.component.util.DaemonPool$WrapperTask.run(DaemonPool.CDB:32) at com.tangosol.coherence.component.util.DaemonPool$Daemon.onNotify(DaemonPool.CDB:63) at com.tangosol.coherence.component.util.Daemon.run(Daemon.CDB:42) at java.lang.Thread.run(Thread.java:619) 2010-06-10 17:07:52.140/44.828 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=Proxy:ProxyService:TcpAcceptorWorker:1, member=1): An exception occurred while processing a DestroyCacheRequest for Service=Proxy:ProxyService:TcpAcceptor: java.lang.SecurityException: Access denied, insufficient privileges at com.oracle.handson.SecurityExampleHelper.checkAccess(SecurityExampleHelper.java:91) at com.oracle.handson.EntitledCacheService.destroyCache(EntitledCacheService.java:64) at com.tangosol.coherence.component.net.extend.messageFactory.CacheServiceFactory$DestroyCacheRequest.onRun(CacheServiceFactory.CDB:6) at com.tangosol.coherence.component.net.extend.message.Request.run(Request.CDB:4) at com.tangosol.coherence.component.net.extend.proxy.serviceProxy.CacheServiceProxy.onMessage(CacheServiceProxy.CDB:9) at com.tangosol.coherence.component.net.extend.Channel$MessageAction.run(Channel.CDB:13) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:337) at com.tangosol.coherence.component.net.extend.Channel.execute(Channel.CDB:29) at com.tangosol.coherence.component.net.extend.Channel.receive(Channel.CDB:26) at com.tangosol.coherence.component.util.daemon.queueProcessor.service.Peer$DaemonPool$WrapperTask.run(Peer.CDB:9) at com.tangosol.coherence.component.util.DaemonPool$WrapperTask.run(DaemonPool.CDB:32) at com.tangosol.coherence.component.util.DaemonPool$Daemon.onNotify(DaemonPool.CDB:63) at com.tangosol.coherence.component.util.Daemon.run(Daemon.CDB:42) at java.lang.Thread.run(Thread.java:619) Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne
起動サービス・クラスタ・サービスにより、Extendクライアントはクラスタ上の起動可能なオブジェクトを実行できます。この例は、起動可能なオブジェクトを実行できるユーザーを決定するロールベースのポリシーを使用する方法を示します。
たとえば、writerロールのユーザーは起動可能なオブジェクトを実行できます。readerロールのユーザーは実行できません。
この例では、クライアント・プログラムからコールできる簡単な起動可能オブジェクトを作成します。これはシリアライズできるため、POF構成ファイルにリストすることも必要です。ロールに基づいてユーザーがサービス上でメソッドを実行できるかどうかをテストする起動サービス・プログラムも作成します。
前述の例と同様に、この例ではPasswordIdentityTransformer
を使用して、パスワード、ユーザーIDおよびロールを含むセキュリティ・トークンを生成します。PasswordIdentityAsserter
(プロキシで実行)を使用して、パスワードを適用するセキュリティ・トークンを検証し、適切なユーザーIDおよびロールでSubject
を構築します。セキュリティ・トークンの生成およびアサーションは自動的に行われます。
次の手順に従い、例を作成します。
資格のある起動サービスにより使用される簡単な起動可能オブジェクトの実装を作成します。たとえば、起動可能なオブジェクトは、増分して整数を返すように記述できます。
起動可能なオブジェクトを作成する手順は次のとおりです。
Security
プロジェクトにExampleInvocable
という新規Javaクラスを作成します。
詳細は、「Javaクラスの作成」を参照してください。
Invocable
およびInvocationService
の各インタフェースをインポートします。このクラスはシリアライズ可能なオブジェクトを扱うため、PortableObject
、PofReader
およびPofWriter
もインポートします。
ExampleInvocable
クラスがInvocable
およびPortableObject
を実装することを確認します。
整数を増分して結果を返すExampleInvocable
を実装します。
PofReader.readExternal
メソッドおよびPofWriter.writeExternal
メソッドを実装します。
例10-18に、ExampleInvocable.java
の可能な実装を示します。
例10-18 起動可能なオブジェクトのサンプル
package com.oracle.handson; import com.tangosol.io.pof.PortableObject; import com.tangosol.io.pof.PofReader; import com.tangosol.io.pof.PofWriter; import com.tangosol.net.Invocable; import com.tangosol.net.InvocationService; import java.io.IOException; /** * Invocable implementation that increments and returns a given integer. */ public class ExampleInvocable implements Invocable, PortableObject { // ----- constructors --------------------------------------------- /** * Default constructor. */ public ExampleInvocable() { } // ----- Invocable interface -------------------------------------- /** * {@inheritDoc} */ public void init(InvocationService service) { m_service = service; } /** * {@inheritDoc} */ public void run() { if (m_service != null) { m_nValue++; } } /** * {@inheritDoc} */ public Object getResult() { return new Integer(m_nValue); } // ----- PortableObject interface --------------------------------- /** * {@inheritDoc} */ public void readExternal(PofReader in) throws IOException { m_nValue = in.readInt(0); } /** * {@inheritDoc} */ public void writeExternal(PofWriter out) throws IOException { out.writeInt(0, m_nValue); } // ----- data members --------------------------------------------- /** * The integer value to increment. */ private int m_nValue; /** * The InvocationService that is executing this Invocable. */ private transient InvocationService m_service; }
この例は、リモートの起動サービスをラップしてアクセス制御を行う方法を示します。Coherence*Extendを使用してクライアントから渡されたSubject
を使用し、ラップされたInvocationService
へのアクセス権限を適用できます。この実装では、特定ロールのクライアントのみがラップされた起動サービスにアクセスできます。
作成するクラスは、com.tangosol.net.WrapperInvocationServiceクラスを拡張する必要があります。このクラスは、InvocationService
上のメソッドを保護できる便利な機能です。プロキシの起動サービスとクライアント・リクエスト間で委任を行うメカニズムも提供します。
資格のある起動サービスを作成する手順は次のとおりです。
Security
プロジェクトにEntitledInvocationService
という新規Javaクラスを作成します。
Invocable
、InvocationObserver
、InvocationService
、WrapperInvocationService
、Map
、およびSet
の各インタフェースをインポートします。EntitledInvocationService
クラスがWrapperInvocationService
を拡張していることを確認します。
query
メソッドおよびexecute
メソッドを実装します。この実装に、特定のユーザー・ロール(この場合はROLE_WRITER
)がこれらの処理にアクセスできるかどうかを決定するSecurityExampleHelper.checkAccess
のコールを含めます。
例10-19に、EntitledInvocationService.java
の可能な実装を示します。
例10-19 資格のある起動サービスのサンプル
package com.oracle.handson; import com.tangosol.net.Invocable; import com.tangosol.net.InvocationObserver; import com.tangosol.net.InvocationService; import com.tangosol.net.WrapperInvocationService; import java.util.Map; import java.util.Set; /** * Example WrapperInvocationService that demonstrates how entitlements can be * applied to a wrapped InvocationService using the Subject passed from the * client through Coherence*Extend. This implementation only allows clients with a * specified role to access the wrapped InvocationService. * */ public class EntitledInvocationService extends WrapperInvocationService { /** * Create a new EntitledInvocationService. * * @param service the wrapped InvocationService */ public EntitledInvocationService(InvocationService service) { super(service); } // ----- InvocationService interface ------------------------------------ /** * {@inheritDoc} */ public void execute(Invocable task, Set setMembers, InvocationObserver observer) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); super.execute(task, setMembers, observer); } /** * {@inheritDoc} */ public Map query(Invocable task, Set setMembers) { SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER); return super.query(task, setMembers); } }
起動サービスへのアクセス例を実行するプログラムを作成します。プログラムの目的は、SecurityExampleHelper
で定義された様々なユーザーが起動可能なオブジェクトにアクセスし、これを実行することができるかどうかをテストすることです。ロールベースのポリシーの適用は、EntitledInvocationService
で指定します。
起動サービスへのアクセス例を実行するプログラムを作成する手順は次のとおりです。
Security
プロジェクト内に、main
メソッドを含むAccessInvocationServiceExample.java
というJavaクラスを作成します。
詳細は、「Javaクラスの作成」を参照してください。
その他のクラスの中から、ExampleInvocable
、CacheFactory
およびInvocationService
をインポートします。
accessInvocationService
メソッドを起動するmain
メソッドを実装します。
accessInvocationService
を実装し、SecurityExampleHelper
で定義された様々なユーザーが、サービスへのログインおよびExampleInvocable
で定義されたオブジェクトの実行を試みるようにします。SecurityExampleHelper.login
メソッドを使用し、様々なユーザーが起動可能なサービスにアクセスできるかどうかをテストします。
例10-20に、AccessInvocationServiceExample.java
の可能な実装を示します。
例10-20 起動サービスへのアクセス例を実行するサンプル・プログラム
package com.oracle.handson; import com.oracle.handson.ExampleInvocable; import com.tangosol.net.CacheFactory; import com.tangosol.net.InvocationService; import java.security.PrivilegedExceptionAction; import javax.security.auth.Subject; /** * This class demonstrates simplified role based access control for the * invocation service. * <p> * The role policies are defined in SecurityExampleHelper. Enforcmenent * is done by EntitledInvocationService. * */ public class AccessInvocationServiceExample { /** * Invoke the example * * @param asArg command line arguments (ignored in this example) */ public static void main(String[] asArg) { accessInvocationService(); } /** * Access the invocation service */ public static void accessInvocationService() { System.out.println("------InvocationService access control example " + "begins------"); // Someone with writer role can run invocables Subject subject = SecurityExampleHelper.login("JohnWhorfin"); try { InvocationService service = (InvocationService) Subject.doAs( subject, new PrivilegedExceptionAction() { public Object run() { return CacheFactory.getService( SecurityExampleHelper.INVOCATION_SERVICE_NAME); } }); service.query(new ExampleInvocable(), null); System.out.println(" Success: Correctly allowed to " + "use the invocation service"); } catch (Exception e) { // get exception if not allowed to perform the operation e.printStackTrace(); } // Someone with reader role cannot cannot run invocables subject = SecurityExampleHelper.login("JohnBigboote"); try { InvocationService service = (InvocationService) Subject.doAs( subject, new PrivilegedExceptionAction() { public Object run() { return CacheFactory.getService( SecurityExampleHelper.INVOCATION_SERVICE_NAME); } }); service.query(new ExampleInvocable(), null); } catch (Exception ee) { System.out.println(" Success: Correctly unable to " + "use the invocation service"); } System.out.println("------InvocationService access control example " + "completed------"); } }
examples-cache-config.xml
ファイルを編集し、proxy-config
の下のinvocation-service-proxy
行に起動サービスのフルパスを追加します。invocation-service-proxy
行には、プロキシ・サービスによって管理される起動サービス・プロキシの構成情報を記述します。
この場合、起動サービス・クラス名はcom.oracle.handson.EntitledInvocationService
で、param-type
はcom.tangosol.net.InvocationService
とします。
例10-21 クラスタ側キャッシュの起動サービス・プロキシ構成
... <proxy-config> ... <invocation-service-proxy> <class-name>com.oracle.handson.EntitledInvocationService</class-name> <init-params> <init-param> <param-type>com.tangosol.net.InvocationService</param-type> <param-value>{service}</param-value> </init-param> </init-params> </invocation-service-proxy> </proxy-config> ...
C:\home\oracle\labs
ディレクトリにsecurity-pof-config.xml
というPOF構成ファイルを作成します。ここでユーザー定義型としてExampleInvocable
が宣言されます。
例10-22 ExampleInvocableユーザー定義型のPOF構成ファイル
<?xml version="1.0"?> <!DOCTYPE pof-config SYSTEM "pof-config.dtd"> <pof-config> <user-type-list> <!-- coherence POF user types --> <include>coherence-pof-config.xml</include> <!-- com.tangosol.examples package --> <user-type> <type-id>1007</type-id> <class-name>com.oracle.handson.ExampleInvocable</class-name> </user-type> </user-type-list> <allow-interfaces>true</allow-interfaces> <allow-subclasses>true</allow-subclasses> </pof-config>
起動サービスへのアクセス例を実行し、ユーザーのロールに基づいて起動可能なオブジェクトへのアクセスを付与または拒否する方法を示します。
稼働しているキャッシュ・サーバーがあれば停止します。security-run-proxy.cmd
により、プロキシ・サービスを実行するキャッシュ・サーバーを起動します。
security-cache-server.cmd
により、クラスタ内のキャッシュ・サーバーを起動します。
JDeveloperで、Security
プロジェクトがまだコンパイルされていない場合は、これをコンパイルします。
AccessInvocationServiceExample.java
ファイルを右クリックし、「実行」を選択します。
JDeveloperログ・ウィンドウに、例10-23のような出力が表示されます。メッセージは、起動可能なオブジェクトExampleInvocable
の実行を試みる、AccessInvocationServiceExample
に指定されたユーザーに対応します。
Success: Correctly allowed to use the invocation service
メッセージ: ExampleInvocable
の実行を試みる、ロールwriter
を持つユーザーに対応します。
Success: Correctly unable to use the invocation service
メッセージ: ExampleInvocable
の実行を試みる、ロールreader
を持つユーザーに対応します。
例10-23 JDeveloperログ・ウィンドウ
C:\oracle\product0529\jdk160_18\bin\javaw.exe -client -classpath C:\home\oracle\labs\.adf;C:\home\oracle\labs\Security\classes;C:\home\oracle\labs;C:\oracle\product0529\coherence_3.5\lib\coherence.jar -Dweblogic.webservice.client.proxyusername=tom.pfaeffle -Dweblogic.webservice.client.proxypassword=p3rtha -Djavax.net.ssl.trustStore=C:\oracle\product\wlserver_10.3\server\lib\DemoTrust.jks -Dhttp.proxyHost=www-proxy.us.oracle.com -Dhttp.proxyPort=80 -Dhttp.nonProxyHosts=*.local|*oraclecorp.com|*oracle.com|localhost|localhost.localdomain|127.0.0.1|::1|tpfaeffl-lap7.us.oracle.com|tpfaeffl-lap7 -Dhttps.proxyHost=www-proxy.us.oracle.com -Dhttps.proxyPort=80 -Dhttps.nonProxyHosts=*.local|*oraclecorp.com|*oracle.com|localhost|localhost.localdomain|127.0.0.1|::1|tpfaeffl-lap7.us.oracle.com|tpfaeffl-lap7 -Dtangosol.coherence.distributed.localstorage=false -Dtangosol.coherence.cacheconfig=\home\oracle\labs\client-cache-config.xml com.oracle.handson.AccessInvocationServiceExample ------InvocationService access control example begins------ 2010-06-17 12:17:04.362/0.391 Oracle Coherence 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/product0529/coherence_3.5/lib/coherence.jar!/tangosol-coherence.xml" 2010-06-17 12:17:04.362/0.391 Oracle Coherence 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/product0529/coherence_3.5/lib/coherence.jar!/tangosol-coherence-override-dev.xml" 2010-06-17 12:17:04.362/0.391 Oracle Coherence 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/labs/tangosol-coherence-override.xml" 2010-06-17 12:17:04.362/0.391 Oracle Coherence 3.6.0.0 DPR3 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified Oracle Coherence Version 3.6.0.0 DPR3 Build 16141 Grid Edition: Development mode Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 2010-06-17 12:17:04.580/0.609 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded cache configuration from "file:/C:/home/oracle/labs/client-cache-config.xml" 2010-06-17 12:17:04.799/0.828 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=ExtendTcpInvocationService:TcpInitiator, member=n/a): Loaded POF configuration from "file:/C:/home/oracle/labs/security-pof-config.xml" 2010-06-17 12:17:04.799/0.828 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=ExtendTcpInvocationService:TcpInitiator, member=n/a): Loaded included POF configuration from "jar:file:/C:/oracle/product0529/coherence_3.5/lib/coherence.jar!/coherence-pof-config.xml" 2010-06-17 12:17:04.877/0.906 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=ExtendTcpInvocationService:TcpInitiator, member=n/a): Started: TcpInitiator{Name=ExtendTcpInvocationService:TcpInitiator, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), Serializer=com.tangosol.io.pof.ConfigurablePofContext, PingInterval=0, PingTimeout=5000, RequestTimeout=5000, ConnectTimeout=2000, SocketProvider=SystemSocketProvider, RemoteAddresses=[tpfaeffl-lap7/130.35.99.213:9099], KeepAliveEnabled=true, TcpDelayEnabled=false, ReceiveBufferSize=0, SendBufferSize=0, LingerTimeout=-1} 2010-06-17 12:17:04.877/0.906 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=main, member=n/a): Opening Socket connection to 130.35.99.213:9099 2010-06-17 12:17:04.893/0.922 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Connected to 130.35.99.213:9099 Success: Correctly allowed to use the invocation service 2010-06-17 12:17:04.955/0.984 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=ExtendTcpInvocationService:TcpInitiator, member=n/a): Started: TcpInitiator{Name=ExtendTcpInvocationService:TcpInitiator, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), Serializer=com.tangosol.io.pof.ConfigurablePofContext, PingInterval=0, PingTimeout=5000, RequestTimeout=5000, ConnectTimeout=2000, SocketProvider=SystemSocketProvider, RemoteAddresses=[tpfaeffl-lap7/130.35.99.213:9099], KeepAliveEnabled=true, TcpDelayEnabled=false, ReceiveBufferSize=0, SendBufferSize=0, LingerTimeout=-1} 2010-06-17 12:17:04.955/0.984 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=main, member=n/a): Opening Socket connection to 130.35.99.213:9099 2010-06-17 12:17:04.955/0.984 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Connected to 130.35.99.213:9099 Success: Correctly unable to use the invocation service ------InvocationService access control example completed------ Process exited with exit code 0.
例10-24に、キャッシュ・サーバーがプロキシ・サービスを実行しているシェルの出力を示します。出力内のセキュリティの例外は、JDeveloperログ・ウィンドウのSuccess: Correctly unable to use the invocation service
メッセージ(この場合、reader
ロールのユーザーがExampleInvocable
の実行を試みます)に対応します。
例10-24 プロキシ・サービス・ウィンドウ
... Started DefaultCacheServer... Password validated for user: role_writer Password validated for user: role_writer Password validated for user: role_reader Password validated for user: role_reader 2010-06-17 12:17:04.971/41.250 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=Proxy:ProxyService:TcpAcceptorWorker:1, member=3): An exception occurred while processing a InvocationRequest for Service=Proxy:ProxyService:TcpAcceptor: java.lang.SecurityException: Access denied, insufficient privileges at com.oracle.handson.SecurityExampleHelper.checkAccess(SecurityExampleHelper.java:91) at com.oracle.handson.EntitledInvocationService.query(EntitledInvocationService.java:51) at com.tangosol.coherence.component.net.extend.messageFactory.InvocationServiceFactory$InvocationRequest.onRun(InvocationServiceFactory.CDB:12 ) at com.tangosol.coherence.component.net.extend.message.Request.run(Request.CDB:4) at com.tangosol.coherence.component.net.extend.proxy.serviceProxy.InvocationServiceProxy.onMessage(InvocationServiceProxy.CDB:9) at com.tangosol.coherence.component.net.extend.Channel$MessageAction.run(Channel.CDB:13) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:337) at com.tangosol.coherence.component.net.extend.Channel.execute(Channel.CDB:29) at com.tangosol.coherence.component.net.extend.Channel.receive(Channel.CDB:26) at com.tangosol.coherence.component.util.daemon.queueProcessor.service.Peer$DaemonPool$WrapperTask.run(Peer.CDB:9) at com.tangosol.coherence.component.util.DaemonPool$WrapperTask.run(DaemonPool.CDB:32) at com.tangosol.coherence.component.util.DaemonPool$Daemon.onNotify(DaemonPool.CDB:63) at com.tangosol.coherence.component.util.Daemon.run(Daemon.CDB:42) at java.lang.Thread.run(Thread.java:619)