第25章 Red Hat JBoss Data Grid セキュリティー: 認証および承認

25.1. Red Hat JBoss Data Grid セキュリティー: 認証および承認

Red Hat JBoss Data Grid は、CacheManager および Cache での承認を実行できます。JBoss Data Grid 承認は、JAAS および SecurityManager などの JDK で利用できる標準的なセキュリティー機能に基づいています。

アプリケーションがセキュアな CacheManager および Cache と対話する場合、JBoss Data Grid のセキュリティーレイヤーが必須ロールおよびパーミッションのセットに対して検証できるアイデンティティーを指定する必要があります。検証されると、クライアントに後続操作のトークンが発行されます。アクセスが拒否されると、セキュリティー違反を示す例外が発生します。

キャッシュの承認が設定される場合、キャッシュが取得されると SecureCache のインスタンスが返されます。SecureCache はキャッシュの単純なラッパーであり、「現行ユーザー」が操作の実行に必要なパーミッションを持っているかどうかを確認します。「現行ユーザー」は AccessControlContext に関連する Subject です。

JBoss Data Grid はプリンシパル名を、1 つ以上のパーミッションを表すロールにマップします。以下の図はこれらの関係を示しています。

図25.1 ロールとパーミッションのマッピング

Roles and Permissions Security Mapping

25.2. パーミッション

CacheManager または Cache へのアクセスは必要なパーミッションセットを使用して制御されます。パーミッションは、操作されているデータのタイプではなく、CacheManager または Cache で実行されるアクションのタイプを制御します。これらのパーミッションの一部は、名前付きキャッシュなどの名前エンティティーにとくに適用されます。エンティティーによって使用できるタイプのパーミッションが異なります。

表25.1 CacheManager パーミッション

パーミッション関数説明

CONFIGURATION

defineConfiguration

新規キャッシュ設定を定義できるかどうか。

LISTEN

addListener

リスナーをキャッシュマネージャーに対して登録できるかどうか。

LIFECYCLE

stop, start

キャッシュマネージャーを停止または開始できるかどうか。

ALL

 

上記すべてを含む便利なパーミッション。

表25.2 キャッシュパーミッション

パーミッション関数説明

READ

get, contains

エントリーをキャッシュから取得できるかどうか。

WRITE

put, putIfAbsent, replace, remove, evict

データをキャッシュから書き込み、置き換え、エビクトできるかどうか。

EXEC

distexec, mapreduce

コード実行をキャッシュに対して実行できるかどうか。

LISTEN

addListener

リスナーをキャッシュに対して登録できるかどうか。

BULK_READ

keySet, values, entrySet,query

一括取得操作を実行できるかどうか。

BULK_WRITE

g

一括書き込み操作を実行できるかどうか。

LIFECYCLE

start, stop

キャッシュを開始または停止できるかどうか。

ADMIN

getVersion, addInterceptor*, removeInterceptor, getInterceptorChain, getEvictionManager, getComponentRegistry, getDistributionManager, getAuthorizationManager, evict, getRpcManager, getCacheConfiguration, getCacheManager, getInvocationContextContainer, setAvailability, getDataContainer, getStats, getXAResource

基礎となるコンポーネントまたは内部構造へのアクセスが可能かどうか。

ALL

 

上記すべてを含む便利なパーミッション。

ALL_READ

 

READ と BULK_READ の組み合わせ。

ALL_WRITE

 

WRITE と BULK_WRITE の組み合わせ。

注記

使いやすさを強化するために一部のパーミッションを他のパーミッションに組み合わせることが必要になる場合があります。たとえば、EXEC を READ または WRITE と組み合わせることがあります。

25.3. ロールマッピング

Subject のプリンシパルを承認で使用される一連のロールに変換するには、 PrincipalRoleMapper をグローバル設定に指定する必要があります。Red Hat JBoss Data Grid には 3 つのマッパーが含まれ、さらにカスタムマッパーを使用することもできます。

表25.3 マッパー

マッパー名JavaXML説明

IdentityRoleMapper

org.infinispan.security.impl.IdentityRoleMapper

<identity-role-mapper />

ロール名としてプリンシパル名を使用します。

CommonNameRoleMapper

org.infinispan.security.impl.CommonRoleMapper

<common-name-role-mapper />

プリンシパル名が識別名 (DN) の場合、このマッパーは共通名 (CN) を抽出し、これをロール名として使用します。たとえば、DN cn=managers,ou=people,dc=example,dc=com はロールの managers にマップされます。

ClusterRoleMapper

org.infinispan.security.impl.ClusterRoleMapper

<cluster-role-mapper />

ClusterRegistry を使用してプリンシパルをロールマッピングに保存します。これにより、CLI の GRANT および DENY コマンドを使用してロールのプリンシパルへの追加または削除を実行できます。

Custom Role Mapper

 

<custom-role-mapper class="a.b.c" />

org.infinispan.security.impl.PrincipalRoleMapper の実装の完全修飾クラス名を指定します。

25.4. ログインモジュールを使用した認証およびロールマッピングの設定

LDAP からロールクエリー用の認証 login-module を使用する場合、カスタムクラスは使用中であるため、プリンシパルからロールへの独自のマッピングを実装する必要があります。以下の例は、login-module から取得したプリンシパルをロールにマップする方法を示しています。これは、ユーザープリンシパル名をロールにマッピングし、同様のアクションを IdentityRoleMapper に対して実行します。

プリンシパルのマッピング

public class SimplePrincipalGroupRoleMapper implements PrincipalRoleMapper {
   @Override
   public Set<String> principalToRoles(Principal principal) {
      if (principal instanceof SimpleGroup) {
         Enumeration<Principal> members = ((SimpleGroup) principal).members();
         if (members.hasMoreElements()) {
            Set<String> roles = new HashSet<String>();
            while (members.hasMoreElements()) {
               Principal innerPrincipal = members.nextElement();
               if (innerPrincipal instanceof SimplePrincipal) {
                  SimplePrincipal sp = (SimplePrincipal) innerPrincipal;
                  roles.add(sp.getName());
               }
            }
            return roles;
         }
      }
      return null;
   }
}

重要

LDAP サーバーの設定や LDAP サーバーでのユーザーおよびロールの指定についての詳細は、Red Hat Directory Server の『Administration Guide』を参照してください。

25.5. Red Hat JBoss Data Grid の承認の設定

承認はキャッシュコンテナー (CacheManager) と単一キャッシュの 2 つのレベルで設定されます。

各キャッシュコンテナーは以下を決定します。

  • 承認を使用するかどうか。
  • プリンシパルをルールセットにマップするクラス。
  • 名前付きロールのセットとそれらが表すパーミッション。

コンテナーレベルで定義されたロールのサブセットのみを使用することを選択できます。

ロール

ロールは、以下のようにキャッシュコンテナーのレベルで定義されたロールを使用して、キャッシュごとに適用できます。

重要

認証が必要とされるキャッシュには、ロールの一覧が定義されている必要があります。そうでない場合、キャッシュの承認では非匿名ポリシーは定義されないため、認証は強制されません。

プログラムを使用した CacheManager 承認 (ライブラリーモード)

以下の例は、プログラムによる設定を使用して同じ承認パラメーターをライブラリーモードに対して設定する方法を示しています。

プログラムを使用した CacheManager 承認の設定

GlobalConfigurationBuilder global = new GlobalConfigurationBuilder();
  global
     .security()
        .authorization()
           .principalRoleMapper(new IdentityRoleMapper())
           .role("admin")
              .permission(CachePermission.ALL)
           .role("supervisor")
              .permission(CachePermission.EXEC)
              .permission(CachePermission.READ)
              .permission(CachePermission.WRITE)
           .role("reader")
              .permission(CachePermission.READ);
  ConfigurationBuilder config = new ConfigurationBuilder();
  config
     .security()
        .enable()
        .authorization()
           .role("admin")
           .role("supervisor")
           .role("reader");

重要

REST プロトコルの承認での使用はサポートされておらず、承認を有効にした状態でキャッシュにアクセスしようとすると SecurityException が発生します。

25.6. ライブラリーモードのデータセキュリティー

25.6.1. サブジェクトおよびプリンシパルクラス

リソースへのアクセスを承認するには、アプリケーションが最初に要求元を認証する必要があります。JAAS フレームワークは、要求元を表す用語サブジェクトを定義します。Subject クラスは JAAS の重要なクラスです。Subject は人やサービスなどの、単一エンティティーの情報を表します。これには、エンティティーのプリンシパル、パブリックのクレデンシャル、プライベートのクレデンシャルなどが含まれます。JAAS API は既存の Java 2 java.security.Principal インターフェースを使用して、型指定された名前であるプリンシパルを表します。

認証プロセス中、サブジェクトには関連するアイデンティティーまたはプリンシパルが入力されます。サブジェクトに複数のプリンシパルが含まれるようにすることができます。たとえば、一個人は名前のプリンシパル (John Doe)、ソーシャルセキュリティー番号のプリンシパル (123-45-6789)、ユーザー名のプリンシパル (johnd) を持つことができ、これらすべてのプリンシパルはサブジェクトを他のサブジェクトから区別するのに役立ちます。1 つのサブジェクトに関連するプリンシパルを取得する方法は 2 つあります。

public Set getPrincipals() {...}
public Set getPrincipals(Class c) {...}

getPrincipals() はサブジェクトに含まれるすべてのプリンシパルを返します。getPrincipals(Class c) は、クラス c のインスタンスであるプリンシパルまたはそのサブクラスの 1 つのみを返します。サブジェクトに一致するプリンシパルがない場合は、空のセットが返されます。

注記

java.security.acl.Group インターフェースは java.security.Principal のサブインターフェースであるため、プリンシパルのセットのインスタンスは、他のプリンシパルやプリンシパルのグループの論理グループを表すことがあります。

25.6.2. サブジェクトの取得

ライブラリーモードでセキュア化されたキャッシュを使用するには、javax.security.auth.Subject を取得する必要があります。Subject は、人やサービスなどの単一のキャッシュエンティティーの情報を表します。

Red Hat JBoss Data Grid では、コンテナーの機能またはサードパーティーライブラリーのどちらかを使用して JAAS Subject を取得できます。

JBoss コンテナーの場合は以下を使用して取得します。

Subject subject = SecurityContextAssociation.getSubject();

Subject には、LDAP や Active Directory などのセキュリティードメインで属するユーザーおよびグループを表すプリンシパルのセットを指定する必要があります。

Java EE API では、以下のメソッドを用いてコンテナーセットのプリンシパルを取得できます。

  • サーブレット: ServletRequest.getUserPrincipal()
  • EJB: EJBContext.getCallerPrincipal()
  • MessageDrivenBeans: MessageDrivenContext.getCallerPrincipal()

mapper は、Subject と関連するプリンシパルを識別し、コンテナーレベルで定義したものに対応するロールへの変換に使用されます。

プリンシパルは Subject のコンポーネントの 1 つにすぎず、 java.security.AccessControlContext から取得されます。コンテナーが AccessControlContext の Subject を設定するか、Security.doAs() メソッドを使用して呼び出しを JBoss Data Grid API にラッピングする前にユーザーがプリンシパルを適切なサブジェクトへマップする必要があります。

Subject が取得されると、キャッシュは PrivilegedAction のコンテキスト内で対話できます。

サブジェクトの取得

import org.infinispan.security.Security;

Security.doAs(subject, new PrivilegedExceptionAction<Void>() {
public Void run() throws Exception {
    cache.put("key", "value");
}
});

Security.doAs() メソッドは、通常の Subject.doAs() メソッドの代わりになります。アプリケーションのセキュリティーモデルに固有する理由で AccessControlContext を変更しなければならない場合以外は、Security.doAs() を使用するとパフォーマンスが向上します。

現在の Subject を取得するには、Subject を JBoss Data Grid コンテキストまたは AccessControlContext から取得する Security.getSubject(); を使用します。

25.6.3. サブジェクトの認証

サブジェクトの認証には JAAS ログインが必要です。ログイン手順は次のようになります。

  1. アプリケーションは LoginContext をインスタンス化し、ログイン設定の名前と CallbackHandler を渡して、設定 LoginModule が必要とする Callback オブジェクトを追加します。
  2. LoginContext は、名前付きログイン設定に含まれるすべての LoginModules をロードするため Configuration を確認します。このような名前付き設定が存在しない場合は、other 設定がデフォルトで使用されます。
  3. アプリケーションは LoginContext.login メソッドを呼び出します。
  4. ログインメソッドはロードされたすべての LoginModule を呼び出します。各 LoginModule はサブジェクトを認証するため、関連する LoginModule でハンドルメソッドを呼び出し、認証プロセスに必要な情報を取得します。必要な情報は、Callback オブジェクトのアレイの形式でハンドルメソッドに渡されます。認証に成功すると、LoginModule は関連のプリンシパルとクレデンシャルをサブジェクトに関連付けします。
  5. LoginContext は認証ステータスをアプリケーションに返します。ログインメソッドから返されると認証が成功したことになります。ログインメソッドによって LoginException が発生すると認証に失敗したことになります。
  6. 認証に成功すると、アプリケーションは LoginContext.getSubject メソッドを使用して認証されたサブジェクトを取得します。
  7. サブジェクトの認証が完了した後に LoginContext.logout メソッドを呼び出すと、login メソッドによりサブジェクトに関連付けられたすべてのプリンシパルおよび関連情報を削除できます。

LoginContext クラスは、サブジェクト認証の基本メソッドを提供し、基礎となる認証技術に依存しないアプリケーションの開発方法を提供します。LoginContext は、特定のアプリケーション向けに設定された認証サービスを判断するため Configuration を確認します。LoginModule クラスは認証サービスを表します。そのため、アプリケーション自体を変更しなくても、異なるログインモジュールをアプリケーションにプラグ可能です。次のコードは、アプリケーションによるサブジェクトの認証で必要になる手順を示しています。

CallbackHandler handler = new MyHandler();
LoginContext lc = new LoginContext("some-config", handler);

try {
    lc.login();
    Subject subject = lc.getSubject();
} catch(LoginException e) {
    System.out.println("authentication failed");
    e.printStackTrace();
}

// Perform work as authenticated Subject
// ...

// Scope of work complete, logout to remove authentication info
try {
    lc.logout();
} catch(LoginException e) {
    System.out.println("logout failed");
    e.printStackTrace();
}

// A sample MyHandler class
class MyHandler
    implements CallbackHandler
{
    public void handle(Callback[] callbacks) throws
        IOException, UnsupportedCallbackException
    {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof NameCallback) {
                NameCallback nc = (NameCallback)callbacks[i];
                nc.setName(username);
            } else if (callbacks[i] instanceof PasswordCallback) {
                PasswordCallback pc = (PasswordCallback)callbacks[i];
                pc.setPassword(password);
            } else {
                throw new UnsupportedCallbackException(callbacks[i],
                                                       "Unrecognized Callback");
            }
        }
    }
}

開発者は、LoginModule インターフェースの実装を作成することで、認証技術を統合します。これにより、管理者は異なる認証技術を 1 つのアプリケーションにプラグできます。複数の LoginModule をチェーン化し、複数の認証技術を認証プロセスに加えることが可能です。たとえば、1 つの LoginModule がユーザー名およびパスワードベースの認証を行い、別の LoginModule をスマートカードリーダーや生体認証などのハードウェアデバイスへ接続するインターフェースとすることが可能です。

LoginModule のライフサイクルは、クライアントがログインメソッドを作成し公開するLoginContext オブジェクトによって決定されます。このプロセスには 2 つのフェーズがあり、プロセスの手順は次のようになります。

  • LoginContext は引数のないパブリックコンストラクターを使用して、設定された LoginModule を作成します。
  • LoginModule は、初期化メソッドへの呼び出しによって初期化されます。Subject 引数は null 以外になることが保証されます。初期化メソッドのシグネチャーは public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) です。
  • login メソッドは、認証プロセスを開始するために呼び出されます。たとえば、あるメソッド実装はユーザーにユーザー名とパスワードの入力を求め、NIS や LDAP などのネーミングサービスに保存されたデータと照合してこの情報を検証することがあります。別の実装は、スマートカードや生体認証デバイスにインターフェースとして接続したり、基礎となるオペレーティングシステムからユーザー情報を抽出したりすることがあります。各 LoginModule によるユーザーアイデンティティーの検証は、JAAS 認証のフェーズ 1 とみなされます。login メソッドのシグネチャーは boolean login() throws LoginException です。LoginException は失敗を意味します。true の戻り値はメソッドが成功したことを示し、false の戻り値はログインモジュールが無視されることを示します。
  • LoginContext の全体的な認証が成功すると、各 LoginModulecommit が呼び出されます。フェーズ 1 が LoginModule に対して成功すると、コミットメソッドはフェーズ 2 を続行し、関連するプリンシパル、パブリッククレデンシャル、プライベートクレデンシャルをサブジェクトに関連付けます。フェーズ 1 が LoginModule に対して失敗すると、commit はユーザー名やパスワードなどの以前保存した認証状態をすべて削除します。commit メソッドのシグネチャーは boolean commit() throws LoginException です。LoginException の発生は、コミットフェーズの完了に失敗したことを示します。true が返されるとメソッドが成功したことを示し、false が返されるとログインモジュールが無視されることを示します。
  • LoginContext の全体的な認証が失敗すると、各 LoginModuleabort メソッドが呼び出されます。abort メソッドはログインまたは初期化メソッドによって作成されたすべての認証状態を削除または破棄します。abort メソッドのシグネチャーは boolean abort() throws LoginException です。LoginException の発生は、abort フェーズの完了に失敗したことを示します。true が返されるとメソッドが成功したことを示し、false が返されるとログインモジュールが無視されることを示します
  • ログイン成功後に認証状態を削除するため、アプリケーションは LoginContextlogout を呼び出します。これにより、各 LoginModulelogoutメソッドが呼び出されます。logoutメソッドは、commit 操作中に当初サブジェクトに関連付けられていたプリンシパルとクレデンシャルを削除します。クレデンシャルは削除時に破棄されるはずです。logout メソッドのシグネチャーは boolean logout() throws LoginException です。LoginException の発生は、ログアウトプロセスの完了に失敗したことを示します。true が返されるとメソッドが成功したことを示し、false が返されるとログインモジュールが無視されることを示します。

LoginModule がユーザーと通信して認証情報を取得する必要がある場合、CallbackHandler オブジェクトを使用します。アプリケーションはインターフェースを実装して LoginContext に渡し、基礎となるログインモジュールに直接認証情報を送信します。

ログインモジュールは、CallbackHandler を使用して、パスワードやスマートカード PIN などのユーザー入力による情報を取得したり、ステータスなどの情報をユーザーに提供したりします。アプリケーションによる CallbackHandler の指定を可能にすることで、基礎となる LoginModule がアプリケーションとユーザーが対話するさまざまな方法に依存しないようにします。たとえば、GUI アプリケーションの CallbackHandler の実装は、ウィンドウを表示してユーザーの入力を求めることがあります。一方でアプリケーションサーバーなどの GUI でない環境の CallbackHandler 実装は、アプリケーションサーバー API を使用してクレデンシャル情報を取得することがあります。インターフェースには実装するメソッドが 1 つあります。

void handle(Callback[] callbacks)
    throws java.io.IOException,
           UnsupportedCallbackException;

最後に説明する認証クラスは Callback インターフェースです。これは複数のデフォルト実装が提供されているタグ付けインターフェースで、前述の例で使用した NameCallbackPasswordCallback が含まれます。LoginModuleCallback を使用し、認証メカニズムで必要となる情報を要求します。LoginModule は認証のログインフェーズの間に Callback のアレイを直接 CallbackHandler.handle メソッドに渡します。CallbackHandler がハンドルメソッドに渡された Callback オブジェクトの使用方法を理解できない場合は UnsupportedCallbackException が発生し、ログイン呼び出しが中止されます。

25.7. インターフェースのセキュア化

25.7.1. インターフェースのセキュア化

Hot Rod インターフェースはプログラムを使ってセキュア化できますが、memcached および REST インターフェースは宣言的にセキュア化する必要があります。これらのインターフェースをセキュア化する手順は、JBoss Data Grid の『Administration and Configuration Guide』を参照してください。

25.7.2. Hot Rod インターフェースセキュリティー

25.7.2.1. Hot Rod サーバーと Hot Rod クライアント間の通信の暗号化

Hot Rod は TLS/SSL を使用して暗号化でき、証明書ベースのクライアント認証を必要とするオプションを指定できます。

以下の手順にしたがって、SSL を使用して Hot Rod コネクターをセキュア化します。

SSL/TLS を使用した Hot Rod のセキュア化

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;
import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
import org.infinispan.client.hotrod.impl.ConfigurationProperties;

[...]

public class SslConfiguration {

    public static final String ISPN_IP = "127.0.0.1";
    public static final String SERVER_NAME = "node0";
    public static final String SASL_MECH = "EXTERNAL";

    private static final String KEYSTORE_PATH = "./keystore_client.jks";
    private static final String KEYSTORE_PASSWORD = "secret";
    private static final String TRUSTSTORE_PATH = "./truststore_client.jks";
    private static final String TRUSTSTORE_PASSWORD = "secret";

    SslConfiguration(boolean enabled,
                     String keyStoreFileName,
                     char[] keyStorePassword,
                     SSLContext sslContext,
                     String trustStoreFileName,
                     char[] trustStorePassword) {
        ConfigurationBuilder builder = new ConfigurationBuilder();
        builder.addServer()
            .host(ISPN_IP)
            .port(ConfigurationProperties.DEFAULT_HOTROD_PORT);
        //setup auth
        builder.security()
            .authentication()
            .serverName(SERVER_NAME)
            .saslMechanism(SASL_MECH)
            .enable()
            .callbackHandler(new VoidCallbackHandler());
        //setup encrypt
        builder.security()
            .ssl()
            .enable()
            .keyStoreFileName(KEYSTORE_PATH)
            .keyStorePassword(KEYSTORE_PASSWORD.toCharArray())
            .trustStoreFileName(TRUSTSTORE_PATH)
            .trustStorePassword(TRUSTSTORE_PASSWORD.toCharArray());

        RemoteCacheManager cacheManager = new RemoteCacheManager(builder.build());
        RemoteCache<Object, Object> cache = cacheManager.getCache(RemoteCacheManager.DEFAULT_CACHE_NAME);
    }

    private static class VoidCallbackHandler implements CallbackHandler {
        @Override
        public void handle(Callback[] clbcks) throws IOException, UnsupportedCallbackException {
        }
    }
}

重要

プレーンテキストのパスワードが設定またはソースコードに表示されないようにするには、プレーンテキストのパスワードを Vault パスワードに変更する必要があります。Vault パスワードのセットアップ方法についての詳細は、JBoss Enterprise Application Platform『How to Configure Server Security』の「Password Vault」を参照してください。

25.7.2.2. SSL を使用した LDAP サーバーに対する Hot Rod のセキュア化

SSL を有効にして LDAP に接続する際に、適切な証明書が含まれるトラストストアまたはキーストアを指定する必要がある場合があります。

LDAP サーバーに対する Hot Rod クライアントの認証には、SSL 上の PLAIN 認証を使用できます。Hot Rod クライアントはプレーンテキストのクレデンシャルを SSL 上で JBoss Data Grid に送信し、サーバーは提供されたクレデンシャルを指定の LDAP サーバーに対して検証します。さらに、JBoss Data Grid サーバーと LDAP サーバー間にセキュアな接続を設定する必要があります。サーバーが LDAP バックエンドと通信するための設定方法の詳細は、JBoss Data Grid の『Administration and Configuration Guide』を参照してください。以下は、Hot Rod のクライアント側で SSL 上の PLAIN 認証を設定する例になります。

Hot Rod クライアントの LDAP サーバーに対する認証

import static org.infinispan.demo.util.CacheOps.dumpCache;
import static org.infinispan.demo.util.CacheOps.onCache;
import static org.infinispan.demo.util.CacheOps.putTestKV;
import static org.infinispan.demo.util.CmdArgs.LOGIN_KEY;
import static org.infinispan.demo.util.CmdArgs.PASS_KEY;
import static org.infinispan.demo.util.CmdArgs.getCredentials;

import java.util.Map;

import javax.net.ssl.SSLContext;

import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;
import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
import org.infinispan.client.hotrod.impl.ConfigurationProperties;
import org.infinispan.commons.util.SslContextFactory;
import org.infinispan.demo.util.SaslUtils.SimpleLoginHandler;

public class HotRodPlainAuthOverSSL {

    public static final String ISPN_IP = "127.0.0.1";
    public static final String SERVER_NAME = "node0";
    public static final String SASL_MECH = "PLAIN";
    private static final String SECURITY_REALM = "ApplicationRealm";

    private static final String TRUSTSTORE_PATH = "./truststore_client.jks";
    private static final String TRUSTSTORE_PASSWORD = "secret";

    public static void main(String[] args) {
        Map<String, String> userArgs = null;
        try {
            userArgs = getCredentials(args);
        } catch (IllegalArgumentException e) {
            System.err.println(e.getMessage());
            System.err.println(
                    "Invalid credentials format, plase provide credentials (and optionally cache name) with --cache=<cache> --user=<user> --password=<password>");
            System.exit(1);
        }

        ConfigurationBuilder builder = new ConfigurationBuilder();
        builder.addServer().host(ISPN_IP).port(ConfigurationProperties.DEFAULT_HOTROD_PORT);

        //set up PLAIN auth
        builder.security().authentication().serverName(SERVER_NAME).saslMechanism(SASL_MECH).enable().callbackHandler(
                new SimpleLoginHandler(userArgs.get(LOGIN_KEY), userArgs.get(PASS_KEY), SECURITY_REALM));

        //set up SSL
        SSLContext cont = SslContextFactory.getContext(null, null, TRUSTSTORE_PATH, TRUSTSTORE_PASSWORD.toCharArray());
        builder.security().ssl().sslContext(cont).enable();

        RemoteCacheManager cacheManager = new RemoteCacheManager(builder.build());
        RemoteCache<Object, Object> cache = cacheManager.getCache(RemoteCacheManager.DEFAULT_CACHE_NAME);

        onCache(cache, putTestKV.andThen(dumpCache));

        cacheManager.stop();
        System.exit(0);
    }

}

重要

プレーンテキストのパスワードが設定またはソースコードに表示されないようにするには、プレーンテキストのパスワードを Vault パスワードに変更する必要があります。Vault パスワードのセットアップ方法についての詳細は、『Red Hat Enterprise Application Platform Security Guide』を参照してください。

25.7.2.3. SASL を使用した Hot Rod でのユーザー認証

25.7.2.3.1. SASL を使用した Hot Rod でのユーザー認証

Hot Rod でのユーザー認証は、以下の SASL (Simple Authentication and Security Layer) メカニズムを使用して実装できます。

  • PLAIN は、クレデンシャルがプレーンテキスト形式でトランスポートされるため、最も安全性の低いメカニズムになります。ただし、実装が最も単純なメカニズムでもあります。このメカニズムは、セキュリティーを強化するために暗号化 (SSL) と併用できます。
  • DIGEST-MD5 は、クレデンシャルをトランスポートする前にハッシュ化するメカニズムです。その結果、PLAIN メカニズムよりも安全性が高くなります。
  • GSSAPI は、Kerberos チケットを使用するメカニズムです。その結果、正しく設定された Kerberos Domain Controller (例: Microsoft Active Directory) が必要になります。
  • EXTERNAL は、基礎となるトランスポート (例: X.509 クライアント証明書) から必要なクレデンシャルを取得するメカニズムであるため、正常に機能するにはクライアント証明書の暗号化が必要です。
25.7.2.3.2. Hot Rod 認証の設定 (GSSAPI/Kerberos)

以下の手順を使用し、SASL GSSAPI/Kerberos メカニズムを使用して Hot Rod 認証をセットアップします。

SASL GSSAPI/Kerberos 認証の設定: クライアント側の設定

  1. サーバー側の設定が完了していることを確認してください。この設定は宣言的に行われ、JBoss Data Grid の『Administration and Configuration Guide』に記載されています。
  2. クライアント側のログイン設定ファイル (gss.conf) にログインモジュールを定義します。

    [source],options="nowrap"

GssExample {
    com.sun.security.auth.module.Krb5LoginModule required client=TRUE;
};
  1. 以下のシステムプロパティーを設定します。

    java.security.auth.login.config=gss.conf
    java.security.krb5.conf=/etc/krb5.conf
    注記

    krb5.conf ファイルは環境に依存し、Keberos の鍵配布センター (Key Distribution Center) を示している必要があります。

  2. CallbackHandler を実装します。

    public class MyCallbackHandler implements CallbackHandler {
        final private String username;
        final private char[] password;
        final private String realm;
    
        public MyCallbackHandler() { }
    
        public MyCallbackHandler (String username, String realm, char[] password) {
            this.username = username;
            this.password = password;
            this.realm = realm;
        }
    
        @Override
        public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
            for (Callback callback : callbacks) {
                if (callback instanceof NameCallback) {
                    NameCallback nameCallback = (NameCallback) callback;
                    nameCallback.setName(username);
                } else if (callback instanceof PasswordCallback) {
                    PasswordCallback passwordCallback = (PasswordCallback) callback;
                    passwordCallback.setPassword(password);
                } else if (callback instanceof AuthorizeCallback) {
                    AuthorizeCallback authorizeCallback = (AuthorizeCallback) callback;
                    authorizeCallback.setAuthorized(authorizeCallback.getAuthenticationID().equals(
                        authorizeCallback.getAuthorizationID()));
                } else if (callback instanceof RealmCallback) {
                    RealmCallback realmCallback = (RealmCallback) callback;
                    realmCallback.setText(realm);
                } else {
                    throw new UnsupportedCallbackException(callback);
                }
            }
        }
    }
  3. 以下のように Hot Rod クライアントを設定します。

    LoginContext lc = new LoginContext("GssExample", new MyCallbackHandler("krb_user", "krb_password".toCharArra()));
    lc.login();
    Subject clientSubject = lc.getSubject();
    
    ConfigurationBuilder clientBuilder = new ConfigurationBuilder();
    clientBuilder.addServer()
            .host("127.0.0.1")
            .port(11222)
        .socketTimeout(1200000)
        .security()
            .authentication()
                .enable()
                .serverName("infinispan-server")
                .saslMechanism("GSSAPI")
                .clientSubject(clientSubject)
                .callbackHandler(new MyCallbackHandler());
    remoteCacheManager = new RemoteCacheManager(clientBuilder.build());
    RemoteCache<String, String> cache = remoteCacheManager.getCache("secured");
25.7.2.3.3. Hot Rod 認証 (MD5) の設定

以下の手順にしたがって、SASL MD5 メカニズムを使用して Hot Rod 認証をセットアップします。

  1. サーバーに MD5 認証が設定されていることを確認してください。この設定を行う手順は、JBoss Data Grid の『Administration and Configuration Guide』に記載されています。
  2. CallbackHandler を実装します。

    public class MyCallbackHandler implements CallbackHandler {
       final private String username;
       final private char[] password;
       final private String realm;
    
       public MyCallbackHandler (String username, String realm, char[] password) {
          this.username = username;
          this.password = password;
          this.realm = realm;
       }
    
       @Override
       public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
          for (Callback callback : callbacks) {
             if (callback instanceof NameCallback) {
                NameCallback nameCallback = (NameCallback) callback;
                nameCallback.setName(username);
             } else if (callback instanceof PasswordCallback) {
                PasswordCallback passwordCallback = (PasswordCallback) callback;
                passwordCallback.setPassword(password);
             } else if (callback instanceof AuthorizeCallback) {
                AuthorizeCallback authorizeCallback = (AuthorizeCallback) callback;
                authorizeCallback.setAuthorized(authorizeCallback.getAuthenticationID().equals(
                      authorizeCallback.getAuthorizationID()));
             } else if (callback instanceof RealmCallback) {
                RealmCallback realmCallback = (RealmCallback) callback;
                realmCallback.setText(realm);
             } else {
                throw new UnsupportedCallbackException(callback);
             }
          }
       }
    }
  3. 以下のように、クライアントを設定された Hot Rod コネクターに接続します。

    ConfigurationBuilder clientBuilder = new ConfigurationBuilder();
    clientBuilder.addServer()
            .host("127.0.0.1")
            .port(11222)
        .socketTimeout(1200000)
        .security()
            .authentication()
                .enable()
                .serverName("myhotrodserver")
                .saslMechanism("DIGEST-MD5")
                .callbackHandler(new MyCallbackHandler("myuser", "ApplicationRealm", "qwer1234!".toCharArray()));
    remoteCacheManager = new RemoteCacheManager(clientBuilder.build());
    RemoteCache<String, String> cache = remoteCacheManager.getCache("secured");
25.7.2.3.4. Hot Rod C++ 認証の設定 (GSSAPI/Kerberos)

以下の手順にしたがって、SASL GSSAPI/Kerberos メカニズムを使用して Hot Rod C++ クライアント認証をセットアップします。

SASL GSSAPI/Kerberos 認証の設定: クライアント側の設定

  1. サーバー側の設定が完了していることを確認してください。この設定は宣言的に行われ、JBoss Data Grid の『Administration and Configuration Guide』に記載されています。

以下は、Hot Rod C++ クライアントに Kerberos を使用した完全な例になります。

#include "infinispan/hotrod/ConfigurationBuilder.h"
#include "infinispan/hotrod/RemoteCacheManager.h"
#include "infinispan/hotrod/RemoteCache.h"
#include "infinispan/hotrod/Version.h"

#include "infinispan/hotrod/JBasicMarshaller.h"
#include <sasl/saslplug.h>
#include <krb5.h>
#include <err.h>
#include <stdlib.h>

using namespace infinispan::hotrod;

int kinit();
void kdestroy();

 /* Hotrod SASL is based on Cyrus Sasl libraries.
  * Check cyrus docs for more info on how to setup callbacks
  * https://www.cyrusimap.org/sasl/
  */
static int simple(void*  context , int id, const char **result, unsigned *len) {
    *result = *(char**)context;
    if (len)
        *len = strlen(*result);
    return SASL_OK;
}

static int getsecret(void* /* conn */, void*  context, int id, sasl_secret_t **psecret) {
    char *secret_data=*(char**)context;
    size_t len = strlen(secret_data);
    static sasl_secret_t *x;
    x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
    x->len = len;
    strcpy((char *) x->data, secret_data);
    *psecret = x;
    return SASL_OK;
}

char *pusername;
char *psecret;

static std::vector<sasl_callback_t> callbackHandler {
        { SASL_CB_USER, (sasl_callback_ft) &simple, &pusername },
        {SASL_CB_PASS, (sasl_callback_ft) &getsecret, &psecret },
        {SASL_CB_LIST_END, NULL, NULL } };

int kinit();
void kdestroy();

int main(int argc, char** argv) {
    int result = 0;
    {
        kinit();
        ConfigurationBuilder builder;
        char username[]="supervisor@INFINISPAN.ORG";
        char secret_data[]="lessStrongPassword";
        pusername=username;
        psecret=secret_data;
        builder.addServer().host(argc > 1 ? argv[1] : "127.0.0.1").port(argc > 2 ? atoi(argv[2]) : 11222);
        builder.protocolVersion(Configuration::PROTOCOL_VERSION_24);
        builder.security().authentication().saslMechanism("GSSAPI").serverFQDN(
                "node0").callbackHandler(callbackHandler).enable();
        builder.balancingStrategyProducer(nullptr);
        RemoteCacheManager cacheManager(builder.build(), false);
        BasicMarshaller<std::string> *km = new BasicMarshaller<std::string>();
        BasicMarshaller<std::string> *vm = new BasicMarshaller<std::string>();
        RemoteCache<std::string, std::string> cache = cacheManager.getCache<std::string, std::string>(km,
                &Marshaller<std::string>::destroy, vm, &Marshaller<std::string>::destroy, std::string("authCache"));
        cacheManager.start();
        try {
            cache.put("key", "value");
            std::shared_ptr<std::string> ret(cache.get("key"));
            result = 0;
        } catch (Exception& ex) {
            std::cerr << "FAIL: 'supervisor' should read and write" << std::endl;
            result = -1;
        }
        cacheManager.stop();
        std::cout << "PASS: 'GSSAPI' sasl authorization" << std::endl;
        kdestroy();
    }
    return result;
}

krb5_context context;
krb5_creds creds;
krb5_principal client_princ = NULL;

int kinit() {
    // Delegate Kerberos setup to the system
    setenv("KRB5CCNAME", "krb5cc_hotrod", 1);
    setenv("KRB5_CONFIG", "krb5.conf", 1);
    std::system("echo lessStrongPassword | kinit -c krb5cc_hotrod supervisor@INFINISPAN.ORG");
}
void kdestroy() {
    std::system("kdestroy");
}
25.7.2.3.5. Hot Rod C++ 認証の設定 (MD5)

以下の手順にしたがって、SASL MD5 メカニズムを使用して Hot Rod C++ クライアント認証をセットアップします。

SASL MD5 認証の設定 - クライアント側の設定

  1. サーバー側の設定が完了していることを確認してください。この設定は宣言的に行われ、JBoss Data Grid の『Administration and Configuration Guide』に記載されています。

以下は、Hot Rod C++ クライアントに SASL MD5 を使用した完全な例になります。

#include "infinispan/hotrod/ConfigurationBuilder.h"
#include "infinispan/hotrod/RemoteCacheManager.h"
#include "infinispan/hotrod/RemoteCache.h"
#include "infinispan/hotrod/Version.h"

#include "infinispan/hotrod/JBasicMarshaller.h"
#include <sasl/saslplug.h>
#include <krb5.h>


using namespace infinispan::hotrod;

 /* Hotrod SASL is based on Cyrus Sasl libraries.
  * Check cyrus docs for more info on how to setup callbacks
  * https://www.cyrusimap.org/sasl/
  */
static int simple(void*  context , int id, const char **result, unsigned *len) {
    *result = *(char**)context;
    if (len)
        *len = strlen(*result);
    return SASL_OK;
}

static int getsecret(void* /* conn */, void*  context, int id, sasl_secret_t **psecret) {
    char *secret_data=*(char**)context;
    size_t len = strlen(secret_data);
    static sasl_secret_t *x;
    x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
    x->len = len;
    strcpy((char *) x->data, secret_data);
    *psecret = x;
    return SASL_OK;
}

char *pusername;
char *psecret;

static std::vector<sasl_callback_t> callbackHandler {
        { SASL_CB_AUTHNAME, (sasl_callback_ft) &simple, &pusername },
        {SASL_CB_PASS, (sasl_callback_ft) &getsecret, &psecret },
        {SASL_CB_LIST_END, NULL, NULL } };

/* This sample authenticates the client with
 * user=reader
 * password=password
 * credential, which is an account that can only do WRITE
 * on the server.
 */
int main(int argc, char** argv) {
    int result = 0;
    {
        ConfigurationBuilder builder;
        char username[]="reader";
        char secret_data[]="password";
        pusername=username;
        psecret=secret_data;
        builder.addServer().host("127.0.0.1").port(11222);
        builder.protocolVersion(Configuration::PROTOCOL_VERSION_24);
        builder.security().authentication().saslMechanism("DIGEST-MD5").serverFQDN("node0").callbackHandler(callbackHandler).enable();
        RemoteCacheManager cacheManager(builder.build(), false);
        BasicMarshaller<std::string> *km = new BasicMarshaller<std::string>();
        BasicMarshaller<std::string> *vm = new BasicMarshaller<std::string>();
        auto cache = cacheManager.getCache<std::string, std::string>(km, &Marshaller<std::string>::destroy, vm, &Marshaller<std::string>::destroy, std::string("authCache"));
        cacheManager.start();
        std::shared_ptr<std::string> ret(cache.get("key"));
        try {
            cache.put("key", "value");
            std::cerr << "FAIL: 'reader' should not write" << std::endl;
            return -1;
        } catch (Exception& ex) {

        }
        std::cout << "PASS: 'DIGEST-MD5' sasl authorization" << std::endl;
        cacheManager.stop();
    }
    return result;
}
25.7.2.3.6. Hot Rod C++ 認証の設定 (PLAIN)

以下の手順にしたがって、SASL PLAIN メカニズムを使用して Hot Rod C++ クライアント認証をセットアップします。

SASL PLAIN 認証の設定 - クライアント側の設定

  1. サーバー側の設定が完了していることを確認してください。この設定は宣言的に行われ、JBoss Data Grid の『Administration and Configuration Guide』に記載されています。

以下は、Hot Rod C++ クライアントに SASL PLAIN を使用した完全な例になります。

#include "infinispan/hotrod/ConfigurationBuilder.h"
#include "infinispan/hotrod/RemoteCacheManager.h"
#include "infinispan/hotrod/RemoteCache.h"
#include "infinispan/hotrod/Version.h"

#include "infinispan/hotrod/JBasicMarshaller.h"
#include <sasl/saslplug.h>
#include <krb5.h>

using namespace infinispan::hotrod;

 /* Hotrod SASL is based on Cyrus Sasl libraries.
  * Check cyrus docs for more info on how to setup callbacks
  * https://www.cyrusimap.org/sasl/
  */
static int simple(void*  context , int id, const char **result, unsigned *len) {
    *result = *(char**)context;
    if (len)
        *len = strlen(*result);
    return SASL_OK;
}

static int getsecret(void* /* conn */, void*  context, int id, sasl_secret_t **psecret) {
    char *secret_data=*(char**)context;
    size_t len = strlen(secret_data);
    static sasl_secret_t *x;
    x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
    x->len = len;
    strcpy((char *) x->data, secret_data);
    *psecret = x;
    return SASL_OK;
}

char *pusername;
char *psecret;

static std::vector<sasl_callback_t> callbackHandler {
        { SASL_CB_AUTHNAME, (sasl_callback_ft) &simple, &pusername },
        {SASL_CB_PASS, (sasl_callback_ft) &getsecret, &psecret },
        {SASL_CB_LIST_END, NULL, NULL } };

/* This sample authenticates the client with
 * user=writer
 * password=somePassword
 * credential, which is an account that can only do WRITE
 * on the server.
 */
int main(int argc, char** argv) {
    int result = 0;
    {
        ConfigurationBuilder builder;
        char username[]="writer";
        char secret_data[]="somePassword";
        pusername=username;
        psecret=secret_data;
        builder.addServer().host("127.0.0.1").port(11222);
        builder.protocolVersion(Configuration::PROTOCOL_VERSION_24);
        builder.security().authentication().saslMechanism("PLAIN").serverFQDN("node0").callbackHandler(callbackHandler).enable();
        RemoteCacheManager cacheManager(builder.build(), false);
        BasicMarshaller<std::string> *km = new BasicMarshaller<std::string>();
        BasicMarshaller<std::string> *vm = new BasicMarshaller<std::string>();
        auto cache = cacheManager.getCache<std::string, std::string>(km, &Marshaller<std::string>::destroy, vm, &Marshaller<std::string>::destroy, std::string("authCache"));
        cacheManager.start();
        cache.put("key", "value");
        try {
            std::shared_ptr<std::string> ret(cache.get("key"));
            std::cerr << "FAIL: 'writer' should not read" << std::endl;
            return -1;
        } catch (Exception& ex) {

        }
        std::cout << "PASS: 'PLAIN' sasl authorization" << std::endl;
        cacheManager.stop();
    }
    return result;
}
25.7.2.3.7. Hot Rod C# 認証の設定 (EXTERNAL)

以下の手順にしたがって、SASL EXTERNAL メカニズムを使用して Hot Rod C# クライアント認証をセットアップします。

SASL EXTERNAL 認証の設定 - クライアント側の設定

  1. サーバー側の設定が完了していることを確認してください。この設定は宣言的に行われ、JBoss Data Grid の『Administration and Configuration Guide』に記載されています。

以下は、Hot Rod C++ クライアントに SASL EXTERNAL を使用した完全な例になります。

using Infinispan.HotRod;
using Infinispan.HotRod.Config;
using System;
using System.Text;

namespace Authentication
{
    class Program
    {

        static void Main(string[] args)
        {
            ConfigurationBuilder conf = new ConfigurationBuilder();
            conf.AddServer()
                    .Host("127.0.0.1")
                    .Port(11222)
                    .ConnectionTimeout(90000)
                    .SocketTimeout(900);
// Enable EXTERNAL mechanism for SASL
            conf.Security().Authentication()
                                .Enable()
                                .SaslMechanism("EXTERNAL")
                                .ServerFQDN("node0");
// Enable SSL (EXTERNAL is based on the client certificate)
            conf.Ssl().Enable()
                .ServerCAFile("infinispan-ca.pem")
                .ClientCertificateFile("keystore_client.p12");
// end of SASL configuration
// The subject specified in the truststore_client.p12 cert will be used to identify the client
            IMarshaller marshaller = new JBasicMarshaller();
            conf.Marshaller(marshaller);
            Configuration c = conf.Build();
            RemoteCacheManager remoteManager = new RemoteCacheManager(c, true);
            IRemoteCache<string, string> authCache = remoteManager.GetCache<string, string>("authCache");
            authCache.Put("K1", "V1");
            authCache.Get("K1");
            authCache.Clear();

        }
    }
}
25.7.2.3.8. Hot Rod C# 認証の設定 (MD5)

以下の手順にしたがって、SASL MD5 メカニズムを使用して Hot Rod C# クライアント認証をセットアップします。

SASL MD5 認証の設定 - クライアント側の設定

  1. サーバー側の設定が完了していることを確認してください。この設定は宣言的に行われ、JBoss Data Grid の『Administration and Configuration Guide』に記載されています。

以下は、Hot Rod C# クライアントに SASL MD5 を使用した完全な例になります。

using Infinispan.HotRod;
using Infinispan.HotRod.Config;
using System;
using System.Text;

namespace Authentication
{
    class Program
    {
        static void Main(string[] args)
        {
            ConfigurationBuilder conf = new ConfigurationBuilder();
            conf.AddServer()
                    .Host("127.0.0.1")
                    .Port(11222)
                    .ConnectionTimeout(90000)
                    .SocketTimeout(900);
// Enable authentication use PLAIN as mechanism  (DIGEST-MD5 can be used the same way)
// and setup user password and realm
            conf.Security().Authentication()
                           .Enable()
                           .SaslMechanism("DIGEST-MD5")
                           .ServerFQDN("node0")
                           .SetupCallback("writer", "somePassword", "ApplicationRealm");
// end of SASL configuration
            IMarshaller marshaller = new JBasicMarshaller();
            conf.Marshaller(marshaller);
            Configuration c = conf.Build();
            RemoteCacheManager remoteManager = new RemoteCacheManager(c, true);
            IRemoteCache<string, string> authCache = remoteManager.GetCache<string, string>("authCache");
            authCache.Put("K1", "V1");
            authCache.Get("K1");
            authCache.Clear();
        }
    }
}

25.7.3. Hot Rod C++ クライアントの暗号化

デフォルトでは、リモートサーバーとの通信はすべて暗号化されていませんが、SslConfigurationBuilderserverCAFile メソッドを使用してサーバーのキーを定義すると、TLS による暗号化を有効にすることができます。さらに、clientCertificateFile でクライアントの証明書を定義すると、クライアント認証を有効にできます。

以下は、任意のクライアント証明書でサーバーキーを定義する例になります。

Hot Rod C++ での TLS の例

#include "infinispan/hotrod/ConfigurationBuilder.h"
#include "infinispan/hotrod/RemoteCacheManager.h"
#include "infinispan/hotrod/RemoteCache.h"
#include "infinispan/hotrod/Version.h"

#include "infinispan/hotrod/JBasicMarshaller.h"
#include <stdlib.h>
#include <iostream>
#include <memory>
#include <typeinfo>

using namespace infinispan::hotrod;

int main(int argc, char** argv) {
    std::cout << "TLS Test" << std::endl;
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " server_ca_file [client_ca_file]" << std::endl;
        return 1;
    }
    {
      ConfigurationBuilder builder;
      builder.addServer().host("127.0.0.1").port(11222).protocolVersion(Configuration::PROTOCOL_VERSION_24);
      // Enable the TLS layer and install the server public key
      // this ensure that the server is authenticated
      builder.ssl().enable().serverCAFile(argv[1]);
      if (argc > 2) {
          // Send a client certificate for authentication (optional)
          // without this the socket will only be encrypted
          std::cout << "Using supplied client certificate for authentication against the server" << std::endl;
          builder.ssl().clientCertificateFile(argv[2]);
      }
      // That's all. Now do business as usual
      RemoteCacheManager cacheManager(builder.build(), false);
      BasicMarshaller<std::string> *km = new BasicMarshaller<std::string>();
      BasicMarshaller<std::string> *vm = new BasicMarshaller<std::string>();
      RemoteCache<std::string, std::string> cache = cacheManager.getCache<std::string, std::string>(km,
          &Marshaller<std::string>::destroy, vm, &Marshaller<std::string>::destroy );
      cacheManager.start();
      cache.clear();
      std::string k1("key13");
      std::string v1("boron");

      cache.put(k1, v1);
      std::unique_ptr<std::string> rv(cache.get(k1));
      if (rv->compare(v1)) {
          std::cerr << "get/put fail for " << k1 << " got " << *rv << " expected " << v1 << std::endl;
          return 1;
      }
      cacheManager.stop();
    }
    return 0;
}

クライアントは、sniHostName 関数に値を提供して TLS/SNI ハンドシェイク処理の開始時に接続を試みるホスト名を示すこともできます。たとえば、以下を使用できます。

[...]
    builder.ssl().enable().serverCAFile(argv[1]).sniHostName("sni");
[...]

25.7.4. Hot Rod C# クライアントの暗号化

デフォルトでは、リモートサーバーとの通信はすべて暗号化されていませんが、SslConfigurationBuilderServerCAFile メソッドを使用してサーバーのキーを定義すると、TLS による暗号化を有効にすることができます。さらに、ClientCertificateFile でクライアントの証明書を定義すると、クライアント認証を有効にできます。

以下は、任意のクライアント証明書でサーバーキーを定義する例になります。

Hot Rod C# での TLS の例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Infinispan.HotRod;
using Infinispan.HotRod.Config;

namespace TLS
{
    /// <summary>
    /// This sample code shows how to perform operations over TLS using the C# client
    /// </summary>

    class TLS
    {
        static void Main(string[] args)
        {
            // Cache manager setup
            RemoteCacheManager remoteManager;
            ConfigurationBuilder conf = new ConfigurationBuilder();
            conf.AddServer().Host("127.0.0.1").Port(11222).ConnectionTimeout(90000).SocketTimeout(900);
            SslConfigurationBuilder sslConfB = conf.Ssl();
            // Retrieve the server public certificate, needed to do server authentication. Mandatory
            if (!System.IO.File.Exists("resources/infinispan-ca.pem"))
            {
                Console.WriteLine("File not found: resources/infinispan-ca.pem.");
                Environment.Exit(-1);
            }
            sslConfB.Enable().ServerCAFile("resources/infinispan-ca.pem");
            // Retrieve the client public certificate, needed if the server requires client authentication. Optional
            if (!System.IO.File.Exists("resources/keystore_client.p12"))
            {
                Console.WriteLine("File not found: resources/keystore_client.p12.");
                Environment.Exit(-1);
            }
            sslConfB.ClientCertificateFile("resources/keystore_client.p12");

            // Usual business now
            conf.Marshaller(new JBasicMarshaller());
            remoteManager = new RemoteCacheManager(conf.Build(), true);
            IRemoteCache<string, string> testCache = remoteManager.GetCache<string, string>();
            testCache.Clear();
            string k1 = "key13";
            string v1 = "boron";
            testCache.Put(k1, v1);
        }
    }
}

クライアントは、SniHostName に値を提供して TLS/SNI ハンドシェイク処理の開始時に接続を試みるホスト名を示すこともできます。たとえば、ServerCAFile を定義した直後に以下の呼び出しを含めることができます。

[...]
sslConfB.ServerCAFile("resources/infinispan-ca.pem").SniHostName("sni");
[...]

25.7.5. Hot Rod Node.js の暗号化

The Node.js クライアントは SSL/TLS 経由の暗号化と任意の TLS/SNI をサポートします。クライアントで設定を行うには、JDK に含まれる keytool アプリケーションを使用して Java KeyStore (JKS) を作成する必要があります。作成されたキーストアには、JBoss Data Grid サーバーが接続を承認するために必要なキーと証明書が含まれる必要があり、暗号化に対して JBoss Data Grid サーバーを設定する必要があります。暗号化に対してサーバーを設定するための詳細は、JBoss Data Grid の『Administration and Configuration Guide』を参照してください。

重要

TLS/SSL の Node.js クライアント実装は自己署名証明書を許可しません。以前証明書が自己署名されていた場合は、ローカルの証明機関を設定して証明書に署名するか、オープンな証明機関を使用することが推奨されます。

信頼できる証明書の場所を定義すると、クライアントの接続がサーバーによって承認されます。

var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
  {
    ssl: {
      enabled: true,
      trustCerts: ['my-root-ca.crt.pem']
    }
  }
);

また、クライアントは PKCS#12 または PFX 形式のキーストアから信頼できる証明書を読み取ることもできます。

var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
  {
    ssl: {
      enabled: true,
      cryptoStore: {
        path: 'my-truststore.p12',
        passphrase: 'secret'
      }
    }
  }
);

さらに、クライアントを暗号化された認証と設定することもできます。認証を設定するには、クライアントのプライベートキー、パスフレーズ、および証明書キーを提供する必要があります。

var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
  {
    ssl: {
      enabled: true,
      trustCerts: ['my-root-ca.crt.pem'],
      clientAuth: {
        key: 'privkey.pem',
        passphrase: 'secret',
        cert: 'cert.pem'
      }
    }
  }
);

クライアントは、sniHostName ディレクティブを含めることで、TLS/SNI ハンドシェイク処理の開始時に接続を試みるホスト名を示すこともできます

var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
  {
    ssl: {
      enabled: true,
      trustCerts: ['my-root-ca.crt.pem']
      sniHostName: 'example.com'
    }
  }
);
注記

sniHostName が提供されない場合、クライアントは localhost を SNI パラメーターとして送信します。サーバーのデフォルトレルムが localhost と一致しない場合、エラーが発生します。

25.8. セキュリティー監査ロガー

25.8.1. セキュリティー監査ロガー

Red Hat JBoss Data Grid には、キャッシュまたはキャッシュマネージャーの操作が各種操作で許可または拒否されたかどうかを確認するために、キャッシュのセキュリティーログを監査するロガーが含まれます。

デフォルトの監査ロガーは org.infinispan.security.impl.DefaultAuditLogger です。このロガーは、利用可能なロギングフレームワーク (JBoss Logging など) を使用して監査ログを出力し、TRACE レベルおよび AUDIT カテゴリーで結果を提供します。

AUDIT カテゴリーを、ログファイル、JMS キュー、またはデータベースのいずれかに送信するには、適切なログアペンダーを使用します。

25.8.2. セキュリティー監査ロガーの設定 (ライブラリーモード)

以下のように、Red Hat JBoss Data Grid の監査ロガーを設定します。

GlobalConfigurationBuilder global = new GlobalConfigurationBuilder();
   global.security()
      .authorization()
         .auditLogger(new DefaultAuditLogger());

25.8.3. カスタム監査ロガー

ユーザーは、カスタム監査ロガーを Red Hat JBoss Data Grid のライブラリーおよびリモートクライアントサーバーモードで実装できます。カスタムロガーは org.infinispan.security.AuditLogger インターフェースを実装する必要があります。カスタムロガーが指定されない場合、デフォルトのロガー (DefaultAuditLogger) が使用されます。