認証APIの使用

SSLの構成
ストアへの認証
期限切れのログイン資格証明の更新
無認可アクセス

Oracle NoSQL Databaseは、クライアント・コードのストアへの認証が必要ない場合にインストールできます。(これを明確にするために、この本に示すほとんどの例では認証が実行されていなません。)ただし、ストアを安全な方法で操作する場合には、認証を必要とすることができます。その場合は、SSLと認証を使用するためのオーバーヘッドが必要になるため、パフォーマンス・コストがかかることに注意してください。本番環境のストアにはSSLを使用した認証を必要とするのがベスト・プラクティスですが、パフォーマンスが重要視されるサイトでは、そこまでのレベルのセキュリティを求めない場合があります。

認証では、ストア・ハンドルを取得した時点で、ストアにユーザー名とパスワード資格証明を送信します。認証をサポートするように構成されたストアでは、認証およびその他の機密情報が確実に保護されるように、クライアントとの通信にはSSLを使用することが自動的に構成されます。SSLを使用する場合、アクセス先のストアが信頼できることを検証するために、クライアント・コードが実行されるマシンにSSL証明書をインストールする必要があります。

ストアの認証用の構成については、『Oracle NoSQL Databaseセキュリティ・ガイド』で説明しています。

SSLの構成

セキュアなストアを使用している場合、クライアント・コードとストア間のすべての通信は、認証資格証明も含めて、SSLを介してトランスポートされます。そのため、クライアント・コードでSSLを使用するように構成する必要があります。これを行うには、SSL証明書データがある場所を識別し、SSLトランスポートを使用することを別途指定します。

トラスト・ストアの識別

Oracle NoSQL DatabaseストアでSSLトランスポートを使用するように構成されると、セキュリティ構成ツールを使用して一連のセキュリティ・ファイルが生成されます。これらのファイルの1つであるclient.trustファイルを、Oracle NoSQL Databaseのクライアント・コードを実行するすべてのマシンにコピーする必要があります。

セキュリティ構成ツールの使用方法の詳細は、『Oracle NoSQL Databaseセキュリティ・ガイド』を参照してください。

client.trustファイルには、クライアントがストアとのSSL接続を確立するために必要な証明書が含まれているため、このファイルがある場所をコードに指定する必要があります。このファイルが置かれているマシン上の物理的なロケーションを指定するには、oracle.kv.ssl.trustStoreプロパティを使用します。このプロパティを設定するには、次の2つの方法を使用します。

  1. トラスト・ストアの場所の識別にPropertiesオブジェクトを使用してoracle.kv.ssl.trustStoreプロパティを設定します。次に、KVStoreConfig.setSecurityProperties()を使用してPropertiesオブジェクトをKVStoreハンドルに渡します。

    このメソッドを使用する場合は、プロパティ名としてKVSecurityConstants.SSL_TRUSTSTORE_FILE_PROPERTYを使用します。

  2. oracle.kv.securityプロパティを使用してclient.trustファイルなどのプロパティ・ファイルを参照します。そのファイルにoracle.kv.ssl.trustStoreプロパティを設定します。

SSLトランスポート・プロパティの設定

client.trustファイルの場所の識別に加えて、SSLトランスポートを使用することをクライアント・コードに指定する必要があります。これを行うには、次の2つのうち1つの方法を使用して、oracle.kv.transportプロパティを設定します。

  1. トラスト・ストアの場所の識別にPropertiesオブジェクトを使用してoracle.kv.transportプロパティを設定します。次に、KVStoreConfig.setSecurityProperties()を使用してPropertiesオブジェクトをKVStoreハンドルに渡します。

    このメソッドを使用する場合は、プロパティ名としてKVSecurityConstants.TRANSPORT_PROPERTYを使用し、プロパティの値としてKVSecurityConstants.SSL_TRANSPORT_NAMEを使用します。

  2. oracle.kv.securityプロパティを使用してclient.trustファイルなどのプロパティ・ファイルを参照します。そのファイルにoracle.kv.transportプロパティを設定します。

ストアへの認証

ストアへの認証を行うには、LoginCredentials実装インスタンスにKVStoreFactory.getStore()を指定します。Oracle NoSQL DatabaseではPasswordCredentialsクラスがLoginCredentials実装として提供されます。ストアでのトランスポートにSSLの使用が必要とされている場合は、認証を実行する前にこれを構成します。(詳細は前の項を参照してください。)

認証の失敗を処理できるように、コードを準備しておく必要があります。認証が失敗した場合は、KVStoreFactory.getStore()によってAuthenticationFailureがスローされます。その例外を捕捉して問題に対処します。

セキュアなストアのストア・ハンドルを取得するための簡単な例を次に示します。この例ではSSLトランスポートを使用しています。

import java.util.Properties;

import oracle.kv.AuthenticationFailure;
import oracle.kv.PasswordCredentials;
import oracle.kv.KVSecurityConstants;
import oracle.kv.KVStoreConfig;
import oracle.kv.KVStoreFactory;



KVStore store = null;
try {
    /*
     * storeName, hostName, port, username, and password are all
     * strings that would come from somewhere else in your 
     * application.
     */
    KVStoreConfig kconfig = 
        new KVStoreConfig(storeName, hostName + ":" + port);

    /* Set the required security properties */
    Properties secProps = new Properties();
    secProps.setProperty(KVSecurityConstants.TRANSPORT_PROPERTY,
                         KVSecurityConstants.SSL_TRANSPORT_NAME);
    secProps.setProperty
        (KVSecurityConstants.SSL_TRUSTSTORE_FILE_PROPERTY,
        "/home/kv/client.trust");
    kconfig.setSecurityProperties(secProps);

    store =
        KVStoreFactory.getStore(kconfig,
            new PasswordCredentials(username,
                                    password.toCharArray()));
            null /* ReauthenticateHandler */);
} catch (AuthenticationFailureException afe) {
    /* 
     * Could potentially retry the login, possibly with different
     * credentials, but in this simple example, we just fail the
     * attempt.
     */
    System.out.println("authentication failed!")
    return;
} 

ログインを処理するもう1つの方法として、認証に必要なすべてのプロパティを含んだ認証資格証明をフラット・テキスト・ファイルで用意する方法があります。これが機能するためには、Oracle NoSQL Databaseストア用のパスワード・ストアを構成してあることが必要になります。(パスワード・ストアの設定の詳細は、『Oracle NoSQL Databaseセキュリティ・ガイド』を参照してください。)

たとえば、パスワード・ファイルのパスワード・ストアを使用するようにストアが構成されており、パスワードがlogin.pwdというファイルに含まれているとします。その場合、login.txtという名前の次のようなログイン・プロパティ・ファイルを作成する必要があります。

oracle.kv.auth.username=clientUID1
oracle.kv.auth.pwdfile.file=/home/nosql/login.pwd
oracle.kv.transport=ssl
oracle.kv.ssl.trustStore=/home/nosql/client.trust 

この場合、次のようにして認証を実行できます。

import oracle.kv.AuthenticationFailure;
import oracle.kv.PasswordCredentials;
import oracle.kv.KVStoreConfig;
import oracle.kv.KVStoreFactory;

/* the client gets login credentials from the login.txt file */
/* can be set on command line as well */
System.setProperty("oracle.kv.security", "/home/nosql/login.txt");

KVStore store = null;
try {
    /*
     * storeName, hostName, port are all strings that would come 
     * from somewhere else in your application.
     *
     * Notice that we do not pass in any login credentials.
     * All of that information comes from login.txt
     */
    myStoreHandle =
        KVStoreFactory.getStore(
            new KVStoreConfig(storeName, hostName + ":" + port)) 
} catch (AuthenticationFailureException afe) {
    /* 
     * Could potentially retry the login, possibly with different
     * credentials, but in this simple example, we just fail the
     * attempt.
     */
    System.out.println("authentication failed!")
    return;
} 

期限切れのログイン資格証明の更新

認証セッションは期限切れになることがあります。これにはいくつかの理由が考えられます。1つには、ストアの管理者がセッションの延長を許可しないようにストアを構成しており、セッションがタイムアウトした場合です。これらのプロパティは、sessionExtendAllowsessionTimeoutを使用して構成します。これらのプロパティの詳細は、『Oracle NoSQL Databaseセキュリティ・ガイド』を参照してください。

ストアになんらかの重大な混乱が生じて認証セッションが無効化された場合には、再認証も必要になります。これは、本番環境のストアでは起こることがほとんどない異常な状況です。開発環境にインストールされているストアの場合、特に再起動が頻繁に行われるようなストアでは、この状況が発生することがあります。

認証セッションは、ライフタイムのあらゆる時点において、アプリケーションによって期限切れとして検出される場合があるため、認証セッションの期限切れに対応できる、エラーで停止しない堅牢なコードを記述する必要があります。

認証セッションが期限切れになった場合、デフォルトでは、ストアへのアクセスを試行するメソッドによってAuthenticationRequiredExceptionがスローされます。これを確認したら、ストアへの再認証を行い、失敗した操作を再試行するようにコードを記述します。

KVStore.login()メソッドを使用して、ストアへの再認証を手動で行うことができます。このメソッドでは、LoginCredentialsクラス・インスタンス(PasswordCredentialsなど)を使用してしてログイン資格証明を指定することが必要になります。

try {
    ...
    /* Store access code happens here */
    ...
} catch (AuthenticationRequiredException are) {
    /*
     * myStoreHandle is a KVStore class instance.
     * 
     * pwCreds is a PasswordCredentials class instance, obtained
     * from somewhere else in your code.
     */
    myStoreHandle.login(pwCreds);
} 

これは、前の項で説明したoracle.kv.auth.usernameプロパティとoracle.kv.auth.pwdfile.fileプロパティを使用している場合には必要ありません。その場合、Oracle NoSQL Databaseクライアント・コードは、それらのプロパティで指定された値を使用してクライアントを自動的かつ暗黙的に再認証します。

3つ目の選択肢として、再認証を実行するためのReauthenticationHandlerクラス実装を作成する方法があります。この方法は、KVStoreFactory.getStore()のコールにLoginCredentials実装インスタンス(つまりPasswordCredentials)を指定しており、AuthenticationRequiredExceptionの捕捉による後続の再試行操作を行わない場合にのみ必要です。

このマニュアルでは、ReauthenticationHandlerの完全な実装例を示していません(実装例は非常に詳細な固有の要件に基づくものであり、すべてのサイトに適用できるものではないと考えられるからです)。ただし参考までに、非常に簡素で大まかなReauthenticationHandlerの実装例を次に示します。

package kvstore.basicExample

import oracle.kv.ReauthenticationHandler;
import oracle.kv.PasswordCredentials;

public class MyReauthHandler implements ReauthenticationHandler {
    public void reauthenticate(KVStore reauthStore) {
        /*
         * The code to obtain the username and password strings would
         * go here. This should be consistent with the code to perform
         * simple authentication for your client.
         */
        PasswordCredentials cred = new PasswordCredentials(username,
            password.toCharArray());

        reauthStore.login(cred);
    }
} 

ストア・ハンドルを取得したら、MyReauthHandlerインスタンスを指定します。

import java.util.Properties;

import oracle.kv.AuthenticationFailure;
import oracle.kv.PasswordCredentials;
import oracle.kv.KVSecurityConstants;
import oracle.kv.KVStoreConfig;
import oracle.kv.KVStoreFactory;

import kvstore.basicExample.MyReauthHandler;

KVStore store = null;
try {
    /*
     * storeName, hostName, port, username, and password are all
     * strings that would come from somewhere else in your 
     * application. The code you use to obtain your username
     * and password should be consistent with the code used to
     * obtain that information in MyReauthHandler.
     */
    KVStoreConfig kconfig = 
        new KVStoreConfig(storeName, hostName + ":" + port);

    /* Set the required security properties */
    Properties secProps = new Properties();
    secProps.setProperty(KVSecurityConstants.TRANSPORT_PROPERTY,
                         KVSecurityConstants.SSL_TRANSPORT_NAME);
    secProps.setProperty
        (KVSecurityConstants.SSL_TRUSTSTORE_FILE_PROPERTY,
        "/home/kv/client.trust");
    kconfig.setSecurityProperties(secProps);

    store =
        KVStoreFactory.getStore(kconfig,
            new PasswordCredentials(username,
                                    password.toCharArray()));
            new MyReauthHandler());
} catch (AuthenticationFailureException afe) {
    /* 
     * Could potentially retry the login, possibly with different
     * credentials, but in this simple example, we just fail the
     * attempt.
     */
    System.out.println("authentication failed!")
    return;
} 

無認可アクセス

ストアを認証する必要のあるクライアントには、ストアに対する一定のアクセス権限が付与されます。この範囲は、権限の一部からすべての、完全なアクセス権限までになります。アクセス権限の量は、認証ユーザーに付与されるロールおよび権限によって定義されます。このため、Oracle NoSQL Database APIへのコールは、操作を実行する認可がないために失敗する可能性があります。このような場合には、UnauthorizedExceptionがスローされるようになります。

ユーザーにロールおよび権限を定義する方法の詳細は、『Oracle NoSQL Databaseセキュリティ・ガイド』を参照してください。

UnauthorizedExceptionがスローされた場合、操作は再試行されません。かわりに、操作が完全に中止されるか、操作の実行に必要な権限を持つ別の資格証明を使用して、コードによる再認証が試行されます。クライアントはKVStore.logout()を使用してストアからログアウトできます。前の項で説明したように、コードのログインが戻る方法はストアのアクセス権の構成によって決まります。

// Open a store handle, and perform authentication as you do
// as described earlier in this section.

...


try {
    // When you attempt some operation (such as a put or delete)
    // to a secure store, you should catch UnauthorizedException
    // in case the user credentials you are using do not have the
    // privileges necessary to perform the operation.
} catch (UnauthorizedException ue) {
    /* 
     * When you see this, either abandon the operation entirely,
     * or log out and log back in with credentials that might
     * have the proper permissions for the operation.
     */
    System.out.println("authorization failed!")
    return;
}