Search in sources :

Example 46 with StorageFile

use of org.apache.derby.io.StorageFile in project derby by apache.

the class RawStore method applyBulkCryptoOperation.

/*
     * Configure the database for encryption, with the  specified 
     * encryption  properties.
     *
     * Basic idea is to encrypt all the containers with new password/key 
     * specified by the user and keep old versions of the data to 
     * rollback the database to the state before the configuration of database 
     * with new encryption attributes. Users can configure the database with 
     * new encryption  attributes at boot time only; advantage of this approach
     * is that there will not be any concurrency issues to handle because
     * no users will be modifying the data. 
     *
     * First step is to encrypt the existing data with new encryption 
     * attributes  and then update the encryption properties for 
     * the database. Configuring  an un-encrypted database for 
     * encryption problem is a minor variation of  re-encrypting an 
     * encrypted database with new encryption key. The database 
     * reconfiguration with new encryption attributes is done under one
     * transaction, if there is a crash/error before it is committed, 
     * then it  is rolled back and the database will be brought back to the
     * state it was before the encryption.  
     *
     * One trickey case in (re) encrypion of database is 
     * unlike standard protocol transaction  commit means all done, 
     * database (re) encryption process has to perform a checkpoint
     *  with a newly generated key then only database  (re) encrption 
     * is complete, Otherwise the problem  is recovery has to deal 
     * with transaction log that is encrypted with old encryption key and 
     * the new encryption key. This probelm is avoided  writing COMMIT
     * and new  CHECKPOINT log record  to a new log file and encrypt the 
     * with a new key, if there is  crash before checkpoint records 
     * are updated , then on next boot the log file after the checkpoint 
     * is deleted before reovery,  which will be the one that is  
     * written with new encryption key and also contains COMMIT record, 
     * so the COMMIT record is also gone when  log file is deleted. 
     * Recovery will not see the commit , so it will  rollback the (re)
     * encryption and revert all the containers to the 
     * original versions. 
     * 
     * Old container versions are deleted only when the check point 
     * with new encryption key is successful, not on post-commit. 
     *
     * @param properties  properties related to this database.
     * @exception StandardException Standard Derby Error Policy
     */
private void applyBulkCryptoOperation(Properties properties, CipherFactory newCipherFactory) throws StandardException {
    boolean decryptDatabase = (isEncryptedDatabase && isTrue(properties, Attribute.DECRYPT_DATABASE));
    boolean reEncrypt = (isEncryptedDatabase && (isSet(properties, Attribute.NEW_BOOT_PASSWORD) || isSet(properties, Attribute.NEW_CRYPTO_EXTERNAL_KEY)));
    if (SanityManager.DEBUG) {
        SanityManager.ASSERT(decryptDatabase || reEncrypt || (!isEncryptedDatabase && isSet(properties, Attribute.DATA_ENCRYPTION)));
    }
    // Check if the cryptographic operation can be performed.
    cryptoOperationAllowed(reEncrypt, decryptDatabase);
    boolean externalKeyEncryption = isSet(properties, Attribute.CRYPTO_EXTERNAL_KEY);
    // check point the datase, so that encryption does not have
    // to encrypt the existing transactions logs.
    logFactory.checkpoint(this, dataFactory, xactFactory, true);
    // start a transaction that is to be used for encryting the database
    RawTransaction transaction = xactFactory.startTransaction(this, getContextService().getCurrentContextManager(), AccessFactoryGlobals.USER_TRANS_NAME);
    try {
        if (decryptDatabase) {
            dataFactory.decryptAllContainers(transaction);
        } else {
            dataFactory.encryptAllContainers(transaction);
        }
        if (SanityManager.DEBUG) {
            crashOnDebugFlag(TEST_REENCRYPT_CRASH_BEFORE_COMMT, reEncrypt);
        }
        // after setting up a new encryption key
        if (!logFactory.isCheckpointInLastLogFile()) {
            // perfrom a checkpoint, this is a reference checkpoint
            // to find if the re(encryption) is complete.
            logFactory.checkpoint(this, dataFactory, xactFactory, true);
        }
        // database is encrypted.
        if (decryptDatabase) {
            isEncryptedDatabase = false;
            logFactory.setDatabaseEncrypted(false, true);
            dataFactory.setDatabaseEncrypted(false);
        } else {
            // Let the log factory know that database is
            // (re-)encrypted and ask it to flush the log
            // before enabling encryption of the log with
            // the new key.
            logFactory.setDatabaseEncrypted(true, true);
            if (reEncrypt) {
                // Switch the encryption/decryption engine to the new ones.
                decryptionEngine = newDecryptionEngine;
                encryptionEngine = newEncryptionEngine;
                currentCipherFactory = newCipherFactory;
            } else {
                // Mark in the raw store that the database is encrypted.
                isEncryptedDatabase = true;
                dataFactory.setDatabaseEncrypted(true);
            }
        }
        // make the log factory ready to encrypt
        // the transaction log with the new encryption
        // key by switching to a new log file.
        // If re-encryption is aborted for any reason,
        // this new log file will be deleted, during
        // recovery.
        logFactory.startNewLogFile();
        // mark that re-encryption is in progress in the
        // service.properties, so that (re) encryption
        // changes that can not be undone using the transaction
        // log can be un-done before recovery starts.
        // (like the changes to service.properties and
        // any log files the can not be understood by the
        // old encryption key), incase engine crashes
        // after this point.
        // if the crash occurs before this point, recovery
        // will rollback the changes using the transaction
        // log.
        properties.put(RawStoreFactory.DB_ENCRYPTION_STATUS, String.valueOf(RawStoreFactory.DB_ENCRYPTION_IN_PROGRESS));
        if (reEncrypt) {
            if (externalKeyEncryption) {
                // save the current copy of verify key file.
                StorageFile verifyKeyFile = storageFactory.newStorageFile(Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE);
                StorageFile oldVerifyKeyFile = storageFactory.newStorageFile(RawStoreFactory.CRYPTO_OLD_EXTERNAL_KEY_VERIFY_FILE);
                if (!privCopyFile(verifyKeyFile, oldVerifyKeyFile))
                    throw StandardException.newException(SQLState.RAWSTORE_ERROR_COPYING_FILE, verifyKeyFile, oldVerifyKeyFile);
                // update the verify key file with the new key info.
                currentCipherFactory.verifyKey(reEncrypt, storageFactory, properties);
            } else {
                // save the current generated encryption key
                String keyString = properties.getProperty(RawStoreFactory.ENCRYPTED_KEY);
                if (keyString != null)
                    properties.put(RawStoreFactory.OLD_ENCRYPTED_KEY, keyString);
            }
        } else if (decryptDatabase) {
            // We cannot remove the encryption properties here, as we may
            // have to revert back to the encrypted database. Instead we set
            // dataEncryption to false and leave all other encryption
            // attributes unchanged. This requires that Derby doesn't store
            // dataEncryption=false for un-encrypted database, otherwise
            // handleIncompleteDbCryptoOperation will be confused.
            properties.put(Attribute.DATA_ENCRYPTION, "false");
        } else {
            // save the encryption block size;
            properties.put(RawStoreFactory.ENCRYPTION_BLOCKSIZE, String.valueOf(encryptionBlockSize));
        }
        // save the new encryption properties into service.properties
        currentCipherFactory.saveProperties(properties);
        if (SanityManager.DEBUG) {
            crashOnDebugFlag(TEST_REENCRYPT_CRASH_AFTER_SWITCH_TO_NEWKEY, reEncrypt);
        }
        // commit the transaction that is used to
        // (re) encrypt the database. Note that
        // this will be logged with newly generated
        // encryption key in the new log file created
        // above.
        transaction.commit();
        if (SanityManager.DEBUG) {
            crashOnDebugFlag(TEST_REENCRYPT_CRASH_AFTER_COMMT, reEncrypt);
        }
        // force the checkpoint with new encryption key.
        logFactory.checkpoint(this, dataFactory, xactFactory, true);
        if (SanityManager.DEBUG) {
            crashOnDebugFlag(TEST_REENCRYPT_CRASH_AFTER_CHECKPOINT, reEncrypt);
        }
        // once the checkpont makes it to the log, re-encrption
        // is complete. only cleanup is remaining ; update the
        // re-encryption status flag to cleanup.
        properties.put(RawStoreFactory.DB_ENCRYPTION_STATUS, String.valueOf(RawStoreFactory.DB_ENCRYPTION_IN_CLEANUP));
        // database is (re)encrypted successfuly,
        // remove the old version of the container files.
        dataFactory.removeOldVersionOfContainers();
        if (decryptDatabase) {
            // By now we can remove all cryptographic properties.
            removeCryptoProperties(properties);
        } else if (reEncrypt) {
            if (externalKeyEncryption) {
                // remove the saved copy of the verify.key file
                StorageFile oldVerifyKeyFile = storageFactory.newStorageFile(RawStoreFactory.CRYPTO_OLD_EXTERNAL_KEY_VERIFY_FILE);
                if (!privDelete(oldVerifyKeyFile))
                    throw StandardException.newException(SQLState.UNABLE_TO_DELETE_FILE, oldVerifyKeyFile);
            } else {
                // remove the old encryption key property.
                properties.remove(RawStoreFactory.OLD_ENCRYPTED_KEY);
            }
        }
        // (re) encrypion is done,  remove the (re)
        // encryption status property.
        properties.remove(RawStoreFactory.DB_ENCRYPTION_STATUS);
        // close the transaction.
        transaction.close();
    } catch (StandardException se) {
        throw StandardException.newException(SQLState.DATABASE_ENCRYPTION_FAILED, se, se.getMessage());
    } finally {
        // clear the new encryption engines.
        newDecryptionEngine = null;
        newEncryptionEngine = null;
    }
}
Also used : StandardException(org.apache.derby.shared.common.error.StandardException) RawTransaction(org.apache.derby.iapi.store.raw.xact.RawTransaction) StorageFile(org.apache.derby.io.StorageFile)

Example 47 with StorageFile

use of org.apache.derby.io.StorageFile in project derby by apache.

the class EncryptOrDecryptData method restoreContainer.

/* Restore the contaier to the state it was before
     * it was encrypted with new encryption key. This function is
     * called during undo of the EncryptContainerOperation log record
     * incase of a error/crash before database was successfuly configured with
     * new encryption properties.
     * @param ckey the key of the container that needs to be restored.
     * @exception StandardException Standard Derby error policy
     */
void restoreContainer(ContainerKey containerId) throws StandardException {
    if (!dataFactory.getContainerCache().discard(containerId)) {
        if (SanityManager.DEBUG)
            SanityManager.THROWASSERT("unable to discard  container from cache:" + containerId);
    }
    StorageFile currentFile = dataFactory.getContainerPath(containerId, false);
    StorageFile oldFile = getFile(containerId, true);
    StorageFile newFile = getFile(containerId, false);
    // container with the backup copy.
    if (privExists(oldFile)) {
        if (privExists(currentFile)) {
            // rename the current container file to be the new file.
            if (!privRename(currentFile, newFile)) {
                throw StandardException.newException(SQLState.RAWSTORE_ERROR_RENAMING_FILE, currentFile, newFile);
            }
        }
        if (!privRename(oldFile, currentFile)) {
            throw StandardException.newException(SQLState.RAWSTORE_ERROR_RENAMING_FILE, oldFile, currentFile);
        }
    }
    // if the new copy of the container file exists, remove it.
    if (privExists(newFile)) {
        if (!privDelete(newFile))
            throw StandardException.newException(SQLState.UNABLE_TO_DELETE_FILE, newFile);
    }
}
Also used : StorageFile(org.apache.derby.io.StorageFile)

Example 48 with StorageFile

use of org.apache.derby.io.StorageFile in project derby by apache.

the class RawStore method handleIncompleteDbCryptoOperation.

/**
 * Engine might have crashed during encryption of un-encrypted datbase
 * or while re-encryptin an already encrypted database with a new key
 * after all the containers or (re) encrypted. If crash has occured
 * before all containers are encrypted, recovery wil un-do re-encryption
 * using the transaction log, nothing to be done here.
 *
 * If crash has occured after database encryption status flag
 * (RawStoreFactory.DB_ENCRYPTION_STATUS) is set, this method
 * will do any cleanup necessary for the recovery to correctly
 * perform the rollback if required.
 *
 * @param properties  properties related to this database.
 * @exception StandardException Standard Derby Error Policy
 */
public void handleIncompleteDbCryptoOperation(Properties properties) throws StandardException {
    // find what was the encryption status before database crashed.
    int dbEncryptionStatus = 0;
    String dbEncryptionStatusStr = properties.getProperty(RawStoreFactory.DB_ENCRYPTION_STATUS);
    if (dbEncryptionStatusStr != null)
        dbEncryptionStatus = Integer.parseInt(dbEncryptionStatusStr);
    boolean reEncryption = false;
    boolean decryptionFailed = isSet(properties, Attribute.DATA_ENCRYPTION) && !isTrue(properties, Attribute.DATA_ENCRYPTION);
    // check if engine crashed when (re) encryption was in progress.
    if (dbEncryptionStatus == RawStoreFactory.DB_ENCRYPTION_IN_PROGRESS) {
        if (logFactory.isCheckpointInLastLogFile()) {
            // database (re)encryption was successful, only
            // cleanup is remaining. change the status to cleanup.
            dbEncryptionStatus = RawStoreFactory.DB_ENCRYPTION_IN_CLEANUP;
        } else {
            // crash occured before re-encrytion was completed.
            // update the db re-encryption status and write to
            // the service.properties that re-encryption
            // needs to be undone. The reason this status need
            // to be made persistent, it will help to correctly
            // handle a crash in this routine after the log file
            // encrypted with new key is deleted. If this flag
            // is not set, on next reboot, above check
            // will find checkpoint in the last log file and
            // incorrecly assume (re) encryption is
            // successful.
            dbEncryptionStatus = RawStoreFactory.DB_ENCRYPTION_IN_UNDO;
            properties.put(RawStoreFactory.DB_ENCRYPTION_STATUS, String.valueOf(dbEncryptionStatus));
        }
    }
    if (dbEncryptionStatus == RawStoreFactory.DB_ENCRYPTION_IN_UNDO) {
        // delete the log file after the log file that has the checkpoint ,
        // it has the data encrypted with the new key, including the commit
        // record for the transaction that was used to (re)encrypt
        // the database. By Deleting the log file, we are forcing the
        // recovery to rollback the (re)encryption of the database.
        logFactory.deleteLogFileAfterCheckpointLogFile();
        if (SanityManager.DEBUG) {
            crashOnDebugFlag(TEST_REENCRYPT_CRASH_AFTER_RECOVERY_UNDO_LOGFILE_DELETE, reEncryption);
        }
        // Note : If a crash occurs at this point, then on reboot
        // it will again be in the DB_ENRYPTION_IN__UNDO state,
        // there will not be a file after the checkpoint log file,
        // so no file will be deleted.
        // check if this is a external key encryption and
        // if it replace the current verify key file with
        // the old copy.
        StorageFile verifyKeyFile = storageFactory.newStorageFile(Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE);
        if (privExists(verifyKeyFile)) {
            StorageFile oldVerifyKeyFile = storageFactory.newStorageFile(RawStoreFactory.CRYPTO_OLD_EXTERNAL_KEY_VERIFY_FILE);
            if (privExists(oldVerifyKeyFile)) {
                if (!privCopyFile(oldVerifyKeyFile, verifyKeyFile))
                    throw StandardException.newException(SQLState.RAWSTORE_ERROR_COPYING_FILE, oldVerifyKeyFile, verifyKeyFile);
                // only incase of re-encryption there should
                // be old verify key file.
                reEncryption = true;
            } else if (!decryptionFailed) {
                // remove the verify key file.
                if (!privDelete(verifyKeyFile))
                    throw StandardException.newException(SQLState.UNABLE_TO_DELETE_FILE, verifyKeyFile);
            }
        } else {
            // database enrypted with boot password.
            // replace the current encryption key with the old key
            // in the service.properties file.
            // retreive the old encryption key
            String OldKeyString = properties.getProperty(RawStoreFactory.OLD_ENCRYPTED_KEY);
            if (OldKeyString != null) {
                // set the current encrypted key to the old one.
                properties.put(RawStoreFactory.ENCRYPTED_KEY, OldKeyString);
                // only incase of re-encryption there should
                // be old encryted key .
                reEncryption = true;
            }
        }
        if (SanityManager.DEBUG) {
            SanityManager.ASSERT(!(decryptionFailed && reEncryption));
            crashOnDebugFlag(TEST_REENCRYPT_CRASH_AFTER_RECOVERY_UNDO_REVERTING_KEY, reEncryption);
        }
        if (!decryptionFailed && !reEncryption) {
            // Crash occurred when an un-encrypted database was being
            // encrypted, all encryption properties should be removed from
            // service.properties since we are undoing the attempt.
            removeCryptoProperties(properties);
        }
    }
    if (dbEncryptionStatus == RawStoreFactory.DB_ENCRYPTION_IN_CLEANUP) {
        // remove all the old versions of the  containers.
        dataFactory.removeOldVersionOfContainers();
    }
    if (SanityManager.DEBUG) {
        crashOnDebugFlag(TEST_REENCRYPT_CRASH_BEFORE_RECOVERY_FINAL_CLEANUP, reEncryption);
    }
    // either the (re) encryption was complete ,
    // or undone (except for rollback that needs to be
    // done by the recovery). Remove re-encryption specific
    // flags from the service.properties and old copy
    // of the verify key file.
    // delete the old verify key file , if it exists.
    StorageFile oldVerifyKeyFile = storageFactory.newStorageFile(RawStoreFactory.CRYPTO_OLD_EXTERNAL_KEY_VERIFY_FILE);
    if (privExists(oldVerifyKeyFile)) {
        if (!privDelete(oldVerifyKeyFile))
            throw StandardException.newException(SQLState.UNABLE_TO_DELETE_FILE, oldVerifyKeyFile);
    } else {
        // remove the old encryption key property.
        properties.remove(RawStoreFactory.OLD_ENCRYPTED_KEY);
    }
    // Finalize cleanup for failed decryption attempts.
    if (decryptionFailed) {
        if (dbEncryptionStatus == RawStoreFactory.DB_ENCRYPTION_IN_UNDO) {
            // This action is not idempotent in the sense that once set
            // Derby can't detect that what failed was a decryption attempt
            // if DB_ENCRYPTION_STATUS is kept unchanged. Too reduce the
            // window of opportunity this is done here, but should really
            // be atomic with the removal of DB_ENCRYPTION_STATUS.
            properties.setProperty(Attribute.DATA_ENCRYPTION, "true");
        } else {
            removeCryptoProperties(properties);
        }
    }
    // remove the re-encryptin status flag.
    properties.remove(RawStoreFactory.DB_ENCRYPTION_STATUS);
}
Also used : StorageFile(org.apache.derby.io.StorageFile)

Example 49 with StorageFile

use of org.apache.derby.io.StorageFile in project derby by apache.

the class LuceneQueryVTI method initScan.

// ///////////////////////////////////////////////////////////////////
// 
// MINIONS
// 
// ///////////////////////////////////////////////////////////////////
/**
 * Initialize the metadata and scan
 */
private void initScan() throws SQLException {
    try {
        // read the execution context for this AwareVTI
        VTIContext context = getContext();
        _schema = context.vtiSchema();
        String[] nameParts = LuceneSupport.decodeFunctionName(context.vtiTable());
        _table = nameParts[LuceneSupport.TABLE_PART];
        _column = nameParts[LuceneSupport.COLUMN_PART];
        // divine the column names
        VTITemplate.ColumnDescriptor[] returnColumns = getReturnTableSignature(_connection);
        String[] columnNames = new String[returnColumns.length];
        for (int i = 0; i < returnColumns.length; i++) {
            columnNames[i] = returnColumns[i].columnName;
        }
        setColumnNames(columnNames);
        _scoreColumnID = getColumnCount();
        _docIDColumnID = _scoreColumnID - 1;
        _maxKeyID = _docIDColumnID - 1;
        _minKeyID = 1;
        // make sure the user has SELECT privilege on all relevant columns of the underlying table
        vetPrivileges();
        String delimitedColumnName = LuceneSupport.delimitID(_column);
        DerbyLuceneDir derbyLuceneDir = LuceneSupport.getDerbyLuceneDir(_connection, _schema, _table, delimitedColumnName);
        StorageFile propertiesFile = LuceneSupport.getIndexPropertiesFile(derbyLuceneDir);
        Properties indexProperties = readIndexProperties(propertiesFile);
        String indexDescriptorMaker = indexProperties.getProperty(LuceneSupport.INDEX_DESCRIPTOR_MAKER);
        LuceneIndexDescriptor indexDescriptor = getIndexDescriptor(indexDescriptorMaker);
        Analyzer analyzer = indexDescriptor.getAnalyzer();
        QueryParser qp = indexDescriptor.getQueryParser();
        vetLuceneVersion(indexProperties.getProperty(LuceneSupport.LUCENE_VERSION));
        _indexReader = getIndexReader(derbyLuceneDir);
        _searcher = new IndexSearcher(_indexReader);
        Query luceneQuery = qp.parse(_queryText);
        TopScoreDocCollector tsdc = TopScoreDocCollector.create(_windowSize, true);
        if (_scoreCeiling != null) {
            tsdc = TopScoreDocCollector.create(_windowSize, new ScoreDoc(0, _scoreCeiling), true);
        }
        searchAndScore(luceneQuery, tsdc);
    } catch (IOException ioe) {
        throw ToolUtilities.wrap(ioe);
    } catch (ParseException pe) {
        throw ToolUtilities.wrap(pe);
    } catch (PrivilegedActionException pae) {
        throw ToolUtilities.wrap(pae);
    }
}
Also used : IndexSearcher(org.apache.lucene.search.IndexSearcher) VTIContext(org.apache.derby.vti.VTIContext) Query(org.apache.lucene.search.Query) TopScoreDocCollector(org.apache.lucene.search.TopScoreDocCollector) PrivilegedActionException(java.security.PrivilegedActionException) IOException(java.io.IOException) Properties(java.util.Properties) Analyzer(org.apache.lucene.analysis.Analyzer) ScoreDoc(org.apache.lucene.search.ScoreDoc) QueryParser(org.apache.lucene.queryparser.classic.QueryParser) LuceneIndexDescriptor(org.apache.derby.optional.api.LuceneIndexDescriptor) StorageFile(org.apache.derby.io.StorageFile) ParseException(org.apache.lucene.queryparser.classic.ParseException)

Example 50 with StorageFile

use of org.apache.derby.io.StorageFile in project derby by apache.

the class LuceneListIndexesVTI method getRowProperties.

/**
 * get the properties of the current row
 */
private Properties getRowProperties() throws SQLException {
    if (rowProperties == null) {
        try {
            readSchemaTableColumn();
            String delimitedColumnName = LuceneSupport.delimitID(column);
            StorageFile indexPropertiesFile = LuceneSupport.getIndexPropertiesFile(connection, schema, table, delimitedColumnName);
            rowProperties = readIndexProperties(indexPropertiesFile);
        } catch (IOException ioe) {
            throw ToolUtilities.wrap(ioe);
        } catch (PrivilegedActionException pae) {
            throw ToolUtilities.wrap(pae);
        }
    }
    return rowProperties;
}
Also used : PrivilegedActionException(java.security.PrivilegedActionException) StorageFile(org.apache.derby.io.StorageFile) IOException(java.io.IOException)

Aggregations

StorageFile (org.apache.derby.io.StorageFile)53 IOException (java.io.IOException)21 StorageRandomAccessFile (org.apache.derby.io.StorageRandomAccessFile)13 File (java.io.File)12 PrivilegedActionException (java.security.PrivilegedActionException)9 StandardException (org.apache.derby.shared.common.error.StandardException)9 StorageFactory (org.apache.derby.io.StorageFactory)6 FileNotFoundException (java.io.FileNotFoundException)4 Properties (java.util.Properties)4 RawTransaction (org.apache.derby.iapi.store.raw.xact.RawTransaction)4 WritableStorageFactory (org.apache.derby.io.WritableStorageFactory)4 OutputStreamWriter (java.io.OutputStreamWriter)3 PrivilegedExceptionAction (java.security.PrivilegedExceptionAction)3 FileInputStream (java.io.FileInputStream)2 InvocationTargetException (java.lang.reflect.InvocationTargetException)2 PreparedStatement (java.sql.PreparedStatement)2 ResultSet (java.sql.ResultSet)2 ContextManager (org.apache.derby.iapi.services.context.ContextManager)2 DataStore (org.apache.derby.impl.io.vfmem.DataStore)2 VirtualFile (org.apache.derby.impl.io.vfmem.VirtualFile)2