認証APIの使用

クライアント・コードでストアに対して認証する必要がないように、Oracle NoSQL Databaseをインストールできます。(これを明確にするために、この本に示すほとんどの例では認証が実行されていなません。)ただし、ストアを安全に運用するために、認証を要求することもできます。認証を要求すると、SSLおよび認証の使用によるオーバーヘッドが原因でパフォーマンス・コストが発生します。本番ストアではSSLを使用した認証を要求することをお薦めしますが、特にパフォーマンスが重要となるサイトでは、そのレベルのセキュリティを実施しないことがあります。

認証では、ストア・ハンドルを取得した時点で、ストアにユーザー名とパスワード資格証明を送信します。

認証をサポートするようにストアを構成する場合、SSLを使用してクライアントと通信するように自動的に構成されます。SSLを使用すると、認証およびその他の機密情報のプライバシが保証されます。SSLを使用するには、クライアント・コードが実行されるマシンにSSL証明書をインストールして、アクセス先のストアが信頼できることを検証する必要があります。

ストアの認証は複数の異なる方法で行うことができます。Kerberosを使用するか、またはKVStoreFactory.getStore()に対してLoginCredentials実装インスタンスを指定できます。(Oracle NoSQL Databaseでは、PasswordCredentialsクラスがLoginCredentials実装として提供されます。)Kerberosを使用する場合、必要なKerberos情報を提供するためにOracle NoSQL Databaseが認識するセキュリティ・プロパティを使用するか、Java Authentication and Authorization Service (JAAS)プログラミング・フレームワークを使用できます。

LoginCredentialsの使用方法の詳細は、LoginCredentialsインスタンスを使用した認証を参照してください。Kerberosの使用方法の詳細は、Kerberosを使用した認証を参照してください。KerberosとともにJAASを使用する方法の詳細は、KerberosおよびJAASを使用した認証を参照してください。

認証用のストアの構成の詳細は、セキュリティ・ガイド認証の構成を参照してください。

SSLの構成

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

トラスト・ストアの識別

Oracle NoSQL DatabaseストアでSSLトランスポートを使用するように構成すると、セキュリティ構成ツールを使用して一連のセキュリティ・ファイルが生成されます。これらのファイルの1つであるclient.trustファイルを、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トランスポートを使用するように指示することも必要です。このためには、oracle.kv.transportプロパティを設定します。 このプロパティを設定するには、次の2つの方法を使用します。

  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()に対してLoginCredentials実装インスタンスを指定します。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ストア用のパスワード・ストアが構成されている必要があります。パスワード・ストアの設定の詳細は、セキュリティ・ガイドを参照してください。

たとえば、パスワード・ファイルのパスワード・ストアを使用するようにストアが構成されており、パスワードが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を使用して構成します。

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

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

認証セッションが期限切れになった場合、デフォルトでは、ストアへのアクセスを試行するメソッドによって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;
} 

Kerberosを使用した認証

Kerberosを使用してストアに対する認証を行うことができます。これを行うには、Kerberosがすでにインストール済で、必要なログインおよびサービス情報を取得してある必要があります。

保護されたストアのストア・ハンドルを取得し、Kerberosを使用して認証する簡単な例を次に示します。Kerberos固有の情報(Kerberosユーザー名など)は、ストア・ハンドルの作成に使用されるKVStoreConfigインスタンスにプロパティとして設定されるKVSecurityConstantsを使用して指定されます。

import java.util.Properties;

import oracle.kv.KVSecurityConstants;
import oracle.kv.KVStore;
import oracle.kv.KVStoreConfig;
import oracle.kv.KVStoreFactory;

KVStore store = null;
/*
 * 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();

/* Set the user name */
secProps.setProperty(KVSecurityConstants.AUTH_USERNAME_PROPERTY,
                    "krbuser");

/* Use Kerberos */
secProps.setProperty(KVSecurityConstants.AUTH_EXT_MECH_PROPERTY,
                     "kerberos");

/* Set SSL for the wire level encryption */
secProps.setProperty(KVSecurityConstants.TRANSPORT_PROPERTY,
                     KVSecurityConstants.SSL_TRANSPORT_NAME);

/* Set the location of the public trust file for SSL */
secProps.setProperty
    (KVSecurityConstants.SSL_TRUSTSTORE_FILE_PROPERTY,
    "/home/kv/client.trust");

/* Set the service principal associated with the helper host */
final String servicesDesc =
        "localhost:oraclenosql/localhost@EXAMPLE.COM";
secProps.setProperty(
        KVSecurityConstants.AUTH_KRB_SERVICES_PROPERTY,
        servicesDesc);

/*
 * Set the default realm name to permit using a short name for the 
 * user principal
 */
secProps.setProperty(KVSecurityConstants.AUTH_KRB_REALM_PROPERTY,
                     "EXAMPLE.COM");

/* Specify the client keytab file location */
secProps.setProperty(KVSecurityConstants.AUTH_KRB_KEYTAB_PROPERTY,
                     "/tmp/krbuser.keytab");

kconfig.setSecurityProperties(secProps);

store = KVStoreFactory.getStore(kconfig); 

KerberosおよびJAASを使用した認証

KerberosおよびJava Authentication and Authorization Service (JAAS)ログインAPIを使用して、ストアに対して認証を行うことができます。これを行うには、Kerberosがすでにインストール済で、必要なログインおよびサービス情報を取得してある必要があります。

保護されたストアのストア・ハンドルを取得し、KerberosをJAASとともに使用して認証する簡単な例を次に示します。

JAASを使用するには、必要なKerberos構成情報を含む構成ファイルを作成します。たとえば、jaas.configという名前のファイルに次のように設定できます。

oraclenosql {
  com.sun.security.auth.module.Krb5LoginModule required
  principal="krbuser"
  useKeyTab="true"
  keyTab="/tmp/krbuser.keytab";
}; 

このファイルをアプリケーションで識別するには、アプリケーションの実行時に-Dオプションを使用してJavaプロパティjava.security.auth.login.configを設定します。

さらに、KVSecurityConstantsを使用して、SSLトランスポートなどの必要なプロパティを指定します。KVSecurityConstantsを使用してKerberosユーザー名などの必要なKerberosプロパティを指定することも、KerberosCredentialsクラスを使用してこれを実行することもできます。

import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Properties;

import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

import oracle.kv.KerberosCredentials;
import oracle.kv.KVSecurityConstants;
import oracle.kv.KVStore;
import oracle.kv.KVStoreConfig;
import oracle.kv.KVStoreFactory;

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

/* Set the required security properties */
Properties secProps = new Properties();

/* Set SSL for the wire level encryption */
secProps.setProperty(KVSecurityConstants.TRANSPORT_PROPERTY,
                     KVSecurityConstants.SSL_TRANSPORT_NAME);

/* Set the location of the public trust file for SSL */
secProps.setProperty
    (KVSecurityConstants.SSL_TRUSTSTORE_FILE_PROPERTY,
    "/home/kv/client.trust");

/* Use Kerberos */
secProps.setProperty(KVSecurityConstants.AUTH_EXT_MECH_PROPERTY,
                     "kerberos");

/* Set Kerberos properties */
final Properties krbProperties = new Properties();

/* Set the service principal associated with the helper host */
final String servicesPpal =
    "localhost:oraclenosql/localhost@EXAMPLE.COM";
krbProperties.setProperty(KVSecurityConstants.AUTH_KRB_SERVICES_PROPERTY,
                          hostName + ":" + servicesPpal);

/* Set default realm name, because the short name
 * for the user principal is used.
 */
krbProperties.setProperty(KVSecurityConstants.AUTH_KRB_REALM_PROPERTY,
                          "EXAMPLE.COM");

/* Specify Kerberos principal */
final KerberosCredentials krbCreds =
    new KerberosCredentials("krbuser", krbProperties);

try {
    /* Get a login context */
    final Subject subj = new Subject();
    final LoginContext lc = new LoginContext("oraclenosql", subj);

    /* Attempt to log in */
    lc.login();

    /* Get the store using the credentials specified in the subject */
    kconfig.setSecurityProperties(secProps);

    store = Subject.doAs(
        subj, new PrivilegedExceptionAction<KVStore>() {
            @Override
            public KVStore run() throws Exception {
                return KVStoreFactory.getStore(kconfig, krbCreds, null);
            }
        });
} catch (LoginException le) {
    // LoginException handling goes here
} catch (PrivilegedActionException pae) {
    // PrivilegedActionException handling goes here
} catch (Exception e) {
    // General Exception handling goes here
}

無認可アクセス

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

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;
}