mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Merged HEAD-QA to HEAD (4.2) (including moving test classes into separate folders)
51903 to 54309 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@54310 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
411
source/test-java/org/alfresco/encryption/EncryptionTests.java
Normal file
411
source/test-java/org/alfresco/encryption/EncryptionTests.java
Normal file
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.encryption;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.DESedeKeySpec;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.dictionary.DictionaryBootstrap;
|
||||
import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||
import org.alfresco.repo.node.encryption.MetadataEncryptor;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
public class EncryptionTests extends TestCase
|
||||
{
|
||||
private static final String TEST_MODEL = "org/alfresco/encryption/reencryption_model.xml";
|
||||
|
||||
private static int NUM_PROPERTIES = 500;
|
||||
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||
|
||||
private static QName NODE_TYPE = QName.createQName("http://www.alfresco.org/test/reencryption_test/1.0", "base");
|
||||
private static QName PROP = QName.createQName("http://www.alfresco.org/test/reencryption_test/1.0", "prop1");
|
||||
|
||||
private NodeRef rootNodeRef;
|
||||
|
||||
private TransactionService transactionService;
|
||||
private DictionaryService dictionaryService;
|
||||
private NodeService nodeService;
|
||||
private MetadataEncryptor metadataEncryptor;
|
||||
private ReEncryptor reEncryptor;
|
||||
private String cipherAlgorithm = "DESede/CBC/PKCS5Padding";
|
||||
private KeyStoreParameters backupKeyStoreParameters;
|
||||
private AlfrescoKeyStoreImpl mainKeyStore;
|
||||
//private AlfrescoKeyStoreImpl backupKeyStore;
|
||||
private KeyResourceLoader keyResourceLoader;
|
||||
private EncryptionKeysRegistryImpl encryptionKeysRegistry;
|
||||
private KeyStoreChecker keyStoreChecker;
|
||||
private DefaultEncryptor mainEncryptor;
|
||||
private DefaultEncryptor backupEncryptor;
|
||||
|
||||
private AuthenticationComponent authenticationComponent;
|
||||
private DictionaryDAO dictionaryDAO;
|
||||
private TenantService tenantService;
|
||||
|
||||
private String keyAlgorithm;
|
||||
private KeyMap newKeys = new KeyMap();
|
||||
private List<NodeRef> before = new ArrayList<NodeRef>();
|
||||
private List<NodeRef> after = new ArrayList<NodeRef>();
|
||||
|
||||
private UserTransaction tx;
|
||||
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
dictionaryService = (DictionaryService)ctx.getBean("dictionaryService");
|
||||
nodeService = (NodeService)ctx.getBean("nodeService");
|
||||
transactionService = (TransactionService)ctx.getBean("transactionService");
|
||||
tenantService = (TenantService)ctx.getBean("tenantService");
|
||||
dictionaryDAO = (DictionaryDAO)ctx.getBean("dictionaryDAO");
|
||||
metadataEncryptor = (MetadataEncryptor)ctx.getBean("metadataEncryptor");
|
||||
authenticationComponent = (AuthenticationComponent)ctx.getBean("authenticationComponent");
|
||||
keyResourceLoader = (KeyResourceLoader)ctx.getBean("springKeyResourceLoader");
|
||||
reEncryptor = (ReEncryptor)ctx.getBean("reEncryptor");
|
||||
backupKeyStoreParameters = (KeyStoreParameters)ctx.getBean("backupKeyStoreParameters");
|
||||
keyStoreChecker = (KeyStoreChecker)ctx.getBean("keyStoreChecker");
|
||||
encryptionKeysRegistry = (EncryptionKeysRegistryImpl)ctx.getBean("encryptionKeysRegistry");
|
||||
//backupKeyStore = (AlfrescoKeyStoreImpl)ctx.getBean("backupKeyStore");
|
||||
mainKeyStore = (AlfrescoKeyStoreImpl)ctx.getBean("keyStore");
|
||||
mainEncryptor = (DefaultEncryptor)ctx.getBean("mainEncryptor");
|
||||
backupEncryptor = (DefaultEncryptor)ctx.getBean("backupEncryptor");
|
||||
|
||||
// reencrypt in one txn (since we don't commit the model, the qnames won't be available across transactions)
|
||||
reEncryptor.setSplitTxns(false);
|
||||
|
||||
this.authenticationComponent.setSystemUserAsCurrentUser();
|
||||
|
||||
tx = transactionService.getUserTransaction();
|
||||
tx.begin();
|
||||
|
||||
StoreRef storeRef = nodeService.createStore(
|
||||
StoreRef.PROTOCOL_WORKSPACE,
|
||||
"ReEncryptor_" + System.currentTimeMillis());
|
||||
rootNodeRef = nodeService.getRootNode(storeRef);
|
||||
|
||||
keyAlgorithm = "DESede";
|
||||
newKeys.setKey(KeyProvider.ALIAS_METADATA, generateSecretKey(keyAlgorithm));
|
||||
|
||||
// Load models
|
||||
DictionaryBootstrap bootstrap = new DictionaryBootstrap();
|
||||
List<String> bootstrapModels = new ArrayList<String>();
|
||||
bootstrapModels.add(TEST_MODEL);
|
||||
// List<String> labels = new ArrayList<String>();
|
||||
// labels.add(TEST_BUNDLE);
|
||||
bootstrap.setModels(bootstrapModels);
|
||||
// bootstrap.setLabels(labels);
|
||||
bootstrap.setDictionaryDAO(dictionaryDAO);
|
||||
bootstrap.setTenantService(tenantService);
|
||||
bootstrap.bootstrap();
|
||||
}
|
||||
|
||||
protected KeyProvider getKeyProvider(KeyStoreParameters keyStoreParameters)
|
||||
{
|
||||
KeyProvider backupKeyProvider = new KeystoreKeyProvider(keyStoreParameters, keyResourceLoader);
|
||||
return backupKeyProvider;
|
||||
}
|
||||
|
||||
public void setBackupKeyStoreParameters(KeyStoreParameters backupKeyStoreParameters)
|
||||
{
|
||||
this.backupKeyStoreParameters = backupKeyStoreParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
authenticationComponent.clearCurrentSecurityContext();
|
||||
tx.rollback();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
protected KeyProvider getKeyProvider(final KeyMap keys)
|
||||
{
|
||||
KeyProvider keyProvider = new KeyProvider()
|
||||
{
|
||||
@Override
|
||||
public Key getKey(String keyAlias)
|
||||
{
|
||||
return keys.getCachedKey(keyAlias).getKey();
|
||||
}
|
||||
};
|
||||
return keyProvider;
|
||||
}
|
||||
|
||||
protected void createEncryptedProperties(List<NodeRef> nodes)
|
||||
{
|
||||
for(int i = 0; i < NUM_PROPERTIES; i++)
|
||||
{
|
||||
NodeRef nodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("assoc1"), NODE_TYPE).getChildRef();
|
||||
nodes.add(nodeRef);
|
||||
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(PROP, nodeRef.toString());
|
||||
props = metadataEncryptor.encrypt(props);
|
||||
nodeService.setProperties(nodeRef, props);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] generateKeyData() throws NoSuchAlgorithmException
|
||||
{
|
||||
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
|
||||
random.setSeed(System.currentTimeMillis());
|
||||
byte bytes[] = new byte[DESedeKeySpec.DES_EDE_KEY_LEN];
|
||||
random.nextBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
protected Key generateSecretKey(String keyAlgorithm) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException
|
||||
{
|
||||
DESedeKeySpec keySpec = new DESedeKeySpec(generateKeyData());
|
||||
SecretKeyFactory kf = SecretKeyFactory.getInstance(keyAlgorithm);
|
||||
SecretKey secretKey = kf.generateSecret(keySpec);
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void testReEncrypt()
|
||||
{
|
||||
KeyProvider backupKeyProvider = backupEncryptor.getKeyProvider();
|
||||
KeyProvider mainKeyProvider = mainEncryptor.getKeyProvider();
|
||||
try
|
||||
{
|
||||
// Create encrypted properties using the configured encryptor and key provider
|
||||
createEncryptedProperties(before);
|
||||
|
||||
// Create encrypted properties using the new encryptor and key provider
|
||||
KeyProvider newKeyProvider = getKeyProvider(newKeys);
|
||||
|
||||
// set backup encryptor key provider to main encryptor key provider and drop in
|
||||
// new key provider for main encryptor
|
||||
backupEncryptor.setKeyProvider(mainEncryptor.getKeyProvider());
|
||||
mainEncryptor.setKeyProvider(newKeyProvider);
|
||||
|
||||
createEncryptedProperties(after);
|
||||
|
||||
// re-encrypt
|
||||
long start = System.currentTimeMillis();
|
||||
System.out.println(reEncryptor.reEncrypt() + " properties re-encrypted");
|
||||
System.out.println("Re-encrypted " + NUM_PROPERTIES*2 + " properties in " + (System.currentTimeMillis() - start) + "ms");
|
||||
|
||||
// check that the nodes have been re-encrypted properly i.e. check that the properties
|
||||
// decrypted using the new keys match the expected values.
|
||||
for(NodeRef nodeRef : before)
|
||||
{
|
||||
Map<QName, Serializable> props = nodeService.getProperties(nodeRef);
|
||||
props = metadataEncryptor.decrypt(props);
|
||||
assertNotNull("", props.get(PROP));
|
||||
assertEquals("", nodeRef.toString(), props.get(PROP));
|
||||
}
|
||||
|
||||
for(NodeRef nodeRef : after)
|
||||
{
|
||||
Map<QName, Serializable> props = nodeService.getProperties(nodeRef);
|
||||
props = metadataEncryptor.decrypt(props);
|
||||
assertNotNull("", props.get(PROP));
|
||||
assertEquals("", nodeRef.toString(), props.get(PROP));
|
||||
}
|
||||
}
|
||||
catch(MissingKeyException e)
|
||||
{
|
||||
fail(e.getMessage());
|
||||
}
|
||||
catch(AlfrescoRuntimeException e)
|
||||
{
|
||||
if(e.getCause() instanceof InvalidKeyException)
|
||||
{
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
backupEncryptor.setKeyProvider(backupKeyProvider);
|
||||
mainEncryptor.setKeyProvider(mainKeyProvider);
|
||||
}
|
||||
}
|
||||
|
||||
public void testBootstrapReEncrypt()
|
||||
{
|
||||
try
|
||||
{
|
||||
// ensure that the backup key store is not available
|
||||
backupKeyStoreParameters.setLocation("");
|
||||
//backupKeyStore.reload();
|
||||
mainKeyStore.reload();
|
||||
|
||||
reEncryptor.bootstrapReEncrypt();
|
||||
fail("Should have caught missing backup key store");
|
||||
}
|
||||
catch(MissingKeyException e)
|
||||
{
|
||||
System.out.println("Successfully caught missing key exception");
|
||||
}
|
||||
catch(InvalidKeystoreException e)
|
||||
{
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected void testChangeKeysImpl(boolean cacheCiphers) throws Throwable
|
||||
{
|
||||
// on a single thread
|
||||
// create an encryptor, encrypt a string, change encryptor keys, decrypt -> should result in Invalid Key
|
||||
|
||||
Pair<byte[], AlgorithmParameters> pair = null;
|
||||
DefaultEncryptor encryptor = null;
|
||||
Key secretKey1 = null;
|
||||
Key secretKey2 = null;
|
||||
String test = "hello world";
|
||||
final KeyMap keys = new KeyMap();
|
||||
byte[] decrypted = null;
|
||||
String test1 = null;
|
||||
|
||||
secretKey1 = generateSecretKey("DESede");
|
||||
keys.setKey("test", secretKey1);
|
||||
KeyProvider keyProvider = new KeyProvider()
|
||||
{
|
||||
@Override
|
||||
public Key getKey(String keyAlias)
|
||||
{
|
||||
return keys.getCachedKey(keyAlias).getKey();
|
||||
}
|
||||
};
|
||||
|
||||
encryptor = new DefaultEncryptor();
|
||||
encryptor.setCipherAlgorithm("DESede/CBC/PKCS5Padding");
|
||||
encryptor.setCipherProvider(null);
|
||||
encryptor.setKeyProvider(keyProvider);
|
||||
encryptor.setCacheCiphers(cacheCiphers);
|
||||
pair = encryptor.encrypt("test", null, test.getBytes("UTF-8"));
|
||||
|
||||
decrypted = encryptor.decrypt("test", pair.getSecond(), pair.getFirst());
|
||||
test1 = new String(decrypted, "UTF-8");
|
||||
|
||||
assertEquals("Expected encrypt,decrypt to end up with the original value", test, test1);
|
||||
System.out.println("1:" + new String(decrypted, "UTF-8"));
|
||||
|
||||
secretKey2 = generateSecretKey("DESede");
|
||||
keys.setKey("test", secretKey2);
|
||||
|
||||
assertNotNull(encryptor);
|
||||
assertNotNull(pair);
|
||||
|
||||
try
|
||||
{
|
||||
decrypted = encryptor.decrypt("test", pair.getSecond(), pair.getFirst());
|
||||
test1 = new String(decrypted, "UTF-8");
|
||||
}
|
||||
catch(AlfrescoRuntimeException e)
|
||||
{
|
||||
// ok - decryption failed expected.
|
||||
}
|
||||
}
|
||||
|
||||
public void testChangeKeys() throws Throwable
|
||||
{
|
||||
testChangeKeysImpl(false);
|
||||
}
|
||||
|
||||
public void testChangeKeysCachedCiphers() throws Throwable
|
||||
{
|
||||
testChangeKeysImpl(true);
|
||||
}
|
||||
|
||||
public void testFailedEncryptionWithCachedCiphers() throws Throwable
|
||||
{
|
||||
Pair<byte[], AlgorithmParameters> pair = null;
|
||||
DefaultEncryptor encryptor = null;
|
||||
Key secretKey1 = null;
|
||||
Key secretKey2 = null;
|
||||
String test = "hello world";
|
||||
final KeyMap keys = new KeyMap();
|
||||
byte[] decrypted = null;
|
||||
String test1 = null;
|
||||
|
||||
secretKey1 = generateSecretKey("DESede");
|
||||
keys.setKey("test", secretKey1);
|
||||
KeyProvider keyProvider = new KeyProvider()
|
||||
{
|
||||
@Override
|
||||
public Key getKey(String keyAlias)
|
||||
{
|
||||
return keys.getCachedKey(keyAlias).getKey();
|
||||
}
|
||||
};
|
||||
|
||||
encryptor = new DefaultEncryptor();
|
||||
encryptor.setCipherAlgorithm("DESede/CBC/PKCS5Padding");
|
||||
encryptor.setCipherProvider(null);
|
||||
encryptor.setKeyProvider(keyProvider);
|
||||
encryptor.setCacheCiphers(true);
|
||||
pair = encryptor.encrypt("test", null, test.getBytes("UTF-8"));
|
||||
|
||||
secretKey2 = generateSecretKey("DESede");
|
||||
keys.setKey("test", secretKey2);
|
||||
|
||||
assertNotNull(encryptor);
|
||||
assertNotNull(pair);
|
||||
|
||||
try
|
||||
{
|
||||
decrypted = encryptor.decrypt("test", pair.getSecond(), pair.getFirst());
|
||||
test1 = new String(decrypted, "UTF-8");
|
||||
fail("Decryption should have failed");
|
||||
}
|
||||
catch(AlfrescoRuntimeException e)
|
||||
{
|
||||
// ok - decryption failed expected - changed key
|
||||
}
|
||||
|
||||
keys.setKey("test", secretKey1);
|
||||
try
|
||||
{
|
||||
decrypted = encryptor.decrypt("test", pair.getSecond(), pair.getFirst());
|
||||
test1 = new String(decrypted, "UTF-8");
|
||||
}
|
||||
catch(AlfrescoRuntimeException e)
|
||||
{
|
||||
fail("Expected decryption to work ok");
|
||||
}
|
||||
}
|
||||
}
|
98
source/test-java/org/alfresco/encryption/EncryptorTest.java
Normal file
98
source/test-java/org/alfresco/encryption/EncryptorTest.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.encryption;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.KeyException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.util.Pair;
|
||||
|
||||
/**
|
||||
* @since 4.0
|
||||
*/
|
||||
public class EncryptorTest extends TestCase
|
||||
{
|
||||
private DefaultEncryptor encryptor;
|
||||
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
encryptor = new DefaultEncryptor(
|
||||
KeyStoreKeyProviderTest.getTestKeyStoreProvider(),
|
||||
"DESede/CBC/PKCS5Padding",
|
||||
null);
|
||||
encryptor.init(); // Not currently necessary
|
||||
}
|
||||
|
||||
public void testBasicBytes_NoKey()
|
||||
{
|
||||
byte[] bytes = new byte[] {11, 12, 13};
|
||||
|
||||
Pair<byte[], AlgorithmParameters> encryptedPair = encryptor.encrypt("fluff", null, bytes);
|
||||
byte[] decrypted = encryptor.decrypt(
|
||||
"fluff",
|
||||
encryptedPair.getSecond(),
|
||||
encryptedPair.getFirst());
|
||||
assertTrue("Encryption round trip failed. ", Arrays.equals(bytes, decrypted));
|
||||
}
|
||||
|
||||
public void testBasicBytes_WithKey()
|
||||
{
|
||||
byte[] bytes = new byte[] {11, 12, 13};
|
||||
|
||||
Pair<byte[], AlgorithmParameters> encryptedPair = encryptor.encrypt("mykey1", null, bytes);
|
||||
byte[] decrypted = encryptor.decrypt(
|
||||
"mykey1",
|
||||
encryptedPair.getSecond(),
|
||||
encryptedPair.getFirst());
|
||||
assertTrue("Encryption round trip failed. ", Arrays.equals(bytes, decrypted));
|
||||
}
|
||||
|
||||
public void testBasicObject()
|
||||
{
|
||||
Object testObject = " This is a string, but will be serialized ";
|
||||
|
||||
Pair<byte[], AlgorithmParameters> encryptedPair = encryptor.encryptObject("mykey2", null, testObject);
|
||||
Object output = encryptor.decryptObject(
|
||||
"mykey2",
|
||||
encryptedPair.getSecond(),
|
||||
encryptedPair.getFirst());
|
||||
assertEquals("Encryption round trip failed. ", testObject, output);
|
||||
}
|
||||
|
||||
public void testSealedObject()
|
||||
{
|
||||
Serializable testObject = " This is a string, but will be serialized ";
|
||||
|
||||
Serializable sealedObject = encryptor.sealObject("mykey2", null, testObject);
|
||||
try
|
||||
{
|
||||
Object output = encryptor.unsealObject("mykey2", sealedObject);
|
||||
assertEquals("Encryption round trip failed. ", testObject, output);
|
||||
}
|
||||
catch(KeyException e)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("", e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.encryption;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStore;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Tests {@link KeystoreKeyProvider}
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @since 4.0
|
||||
*/
|
||||
public class KeyStoreKeyProviderTest extends TestCase
|
||||
{
|
||||
private static final String FILE_ONE = "classpath:alfresco/keystore-tests/ks-test-1.jks";
|
||||
private static final String FILE_TWO = "classpath:alfresco/keystore-tests/ks-test-2.jks";
|
||||
private static final String FILE_THREE = "classpath:alfresco/keystore-tests/ks-test-3.jks";
|
||||
private static final String ALIAS_ONE = "mykey1";
|
||||
private static final String ALIAS_TWO = "mykey2";
|
||||
private static final String ALIAS_THREE = "mykey3";
|
||||
|
||||
/**
|
||||
* Helper utility to create a two-alias keystore.
|
||||
* <p/>
|
||||
* TODO: Allow the required aliases and key types to be specified and generate
|
||||
* a keystore on the fly
|
||||
*/
|
||||
/* package */ static KeystoreKeyProvider getTestKeyStoreProvider()
|
||||
{
|
||||
Map<String, String> passwords = new HashMap<String, String>(5);
|
||||
passwords.put(AlfrescoKeyStore.KEY_KEYSTORE_PASSWORD, "ksPwd2");
|
||||
passwords.put(ALIAS_ONE, "aliasPwd1");
|
||||
passwords.put(ALIAS_TWO, "aliasPwd2");
|
||||
KeyStoreParameters encryptionParameters = new KeyStoreParameters("test", "JCEKS", "SunJCE", null, FILE_TWO);
|
||||
KeystoreKeyProvider keyProvider = new KeystoreKeyProvider(encryptionParameters, getKeyStoreLoader(passwords));
|
||||
// FILE_TWO,
|
||||
// getKeyStoreLoader(),
|
||||
// "SunJCE",
|
||||
// "JCEKS",
|
||||
// passwords);
|
||||
return keyProvider;
|
||||
}
|
||||
|
||||
/* package */ static KeystoreKeyProvider getTestKeyStoreProvider(String keyStoreLocation, Map<String, String> passwords)
|
||||
{
|
||||
// Map<String, String> passwords = new HashMap<String, String>(5);
|
||||
// passwords.put(KeyStoreManager.KEY_KEYSTORE_PASSWORD, "ksPwd2");
|
||||
// passwords.put(ALIAS_ONE, "aliasPwd1");
|
||||
// passwords.put(ALIAS_TWO, "aliasPwd2");
|
||||
KeyStoreParameters encryptionParameters = new KeyStoreParameters("test", "JCEKS", "SunJCE", null, keyStoreLocation);
|
||||
KeystoreKeyProvider keyProvider = new KeystoreKeyProvider(encryptionParameters, getKeyStoreLoader(passwords));
|
||||
// FILE_TWO,
|
||||
// getKeyStoreLoader(),
|
||||
// "SunJCE",
|
||||
// "JCEKS",
|
||||
// passwords);
|
||||
return keyProvider;
|
||||
}
|
||||
|
||||
private static class TestKeyResourceLoader extends SpringKeyResourceLoader
|
||||
{
|
||||
private Properties props;
|
||||
|
||||
TestKeyResourceLoader(Map<String, String> passwords)
|
||||
{
|
||||
StringBuilder aliases = new StringBuilder();
|
||||
props = new Properties();
|
||||
|
||||
int i = 0;
|
||||
for(Map.Entry<String, String> password : passwords.entrySet())
|
||||
{
|
||||
props.put(password.getKey() + ".password", password.getValue());
|
||||
|
||||
aliases.append(password.getKey());
|
||||
if(i < passwords.size() - 1)
|
||||
{
|
||||
aliases.append(",");
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
props.put("aliases", aliases.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties loadKeyMetaData(String keyMetaDataFileLocation)
|
||||
throws IOException, FileNotFoundException
|
||||
{
|
||||
return props;
|
||||
}
|
||||
}
|
||||
|
||||
protected static KeyResourceLoader getKeyStoreLoader(Map<String, String> passwords)
|
||||
{
|
||||
return new TestKeyResourceLoader(passwords);
|
||||
}
|
||||
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void testNoKeyStorePasswords() throws Exception
|
||||
{
|
||||
KeystoreKeyProvider keyProvider = getTestKeyStoreProvider(FILE_ONE, Collections.<String,String>emptyMap());
|
||||
|
||||
// KeystoreKeyProvider keyProvider = new KeystoreKeyProvider(
|
||||
// FILE_ONE,
|
||||
// getKeyStoreLoader(),
|
||||
// "SunJCE",
|
||||
// "JCEKS",
|
||||
// Collections.<String,String>emptyMap());
|
||||
// This has succeeded because we have not attempted to access it
|
||||
assertNull("Should be no keys available", keyProvider.getKey(ALIAS_ONE));
|
||||
}
|
||||
|
||||
public void testKeyStoreWithOnlyAliasPasswords() throws Exception
|
||||
{
|
||||
KeystoreKeyProvider keyProvider = getTestKeyStoreProvider(FILE_ONE, Collections.singletonMap(ALIAS_ONE, "aliasPwd1"));
|
||||
|
||||
// KeystoreKeyProvider keyProvider = new KeystoreKeyProvider(
|
||||
// FILE_TWO,
|
||||
// getKeyStoreLoader(),
|
||||
// "SunJCE",
|
||||
// "JCEKS",
|
||||
// Collections.singletonMap(ALIAS_ONE, "aliasPwd1"));
|
||||
// This has succeeded because we have not attempted to access it
|
||||
assertNotNull("Should be able to key alias with same password", keyProvider.getKey(ALIAS_ONE));
|
||||
}
|
||||
|
||||
public void testAliasWithIncorrectPassword_One() throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
getTestKeyStoreProvider(FILE_ONE, Collections.singletonMap(ALIAS_ONE, "password_fail"));
|
||||
|
||||
// new KeystoreKeyProvider(
|
||||
// FILE_ONE,
|
||||
// getKeyStoreLoader(),
|
||||
// "SunJCE",
|
||||
// "JCEKS",
|
||||
// Collections.singletonMap(ALIAS_ONE, "password_fail"));
|
||||
fail("Expect to fail because password is incorrect");
|
||||
}
|
||||
catch (AlfrescoRuntimeException e)
|
||||
{
|
||||
// Expected
|
||||
assertTrue(e.getCause() instanceof UnrecoverableKeyException);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAliasWithIncorrectPassword_Two() throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
getTestKeyStoreProvider(FILE_TWO, Collections.singletonMap(ALIAS_TWO, "password_fail"));
|
||||
// new KeystoreKeyProvider(
|
||||
// FILE_TWO,
|
||||
// getKeyStoreLoader(),
|
||||
// "SunJCE",
|
||||
// "JCEKS",
|
||||
// Collections.singletonMap(ALIAS_TWO, "password_fail"));
|
||||
fail("Expect to fail because password is incorrect");
|
||||
}
|
||||
catch (AlfrescoRuntimeException e)
|
||||
{
|
||||
// Expected
|
||||
assertTrue(e.getCause() instanceof UnrecoverableKeyException);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAliasWithCorrectPassword_One() throws Exception
|
||||
{
|
||||
KeystoreKeyProvider ks = getTestKeyStoreProvider(FILE_ONE, Collections.singletonMap(ALIAS_ONE, "aliasPwd1"));
|
||||
|
||||
// KeystoreKeyProvider ks = new KeystoreKeyProvider(
|
||||
// FILE_ONE,
|
||||
// getKeyStoreLoader(),
|
||||
// "SunJCE",
|
||||
// "JCEKS",
|
||||
// Collections.singletonMap(ALIAS_ONE, "aliasPwd1"));
|
||||
Key keyOne = ks.getKey(ALIAS_ONE);
|
||||
assertNotNull(keyOne);
|
||||
}
|
||||
|
||||
public void testAliasWithCorrectPassword_Two() throws Exception
|
||||
{
|
||||
Map<String, String> passwords = new HashMap<String, String>(5);
|
||||
passwords.put(ALIAS_ONE, "aliasPwd1");
|
||||
passwords.put(ALIAS_TWO, "aliasPwd2");
|
||||
|
||||
KeystoreKeyProvider ks = getTestKeyStoreProvider(FILE_TWO, passwords);
|
||||
|
||||
// KeystoreKeyProvider ks = new KeystoreKeyProvider(
|
||||
// FILE_TWO,
|
||||
// getKeyStoreLoader(),
|
||||
// "SunJCE",
|
||||
// "JCEKS",
|
||||
// passwords);
|
||||
|
||||
assertNotNull(ks.getKey(ALIAS_ONE));
|
||||
assertNotNull(ks.getKey(ALIAS_TWO));
|
||||
}
|
||||
|
||||
public void testAliasWithCorrectPassword_Three() throws Exception
|
||||
{
|
||||
Map<String, String> passwords = new HashMap<String, String>(5);
|
||||
passwords.put(ALIAS_ONE, "aliasPwd1");
|
||||
passwords.put(ALIAS_TWO, "aliasPwd2");
|
||||
passwords.put(ALIAS_THREE, "aliasPwd3");
|
||||
KeystoreKeyProvider ks = getTestKeyStoreProvider(FILE_THREE, passwords);
|
||||
|
||||
// KeystoreKeyProvider ks = new KeystoreKeyProvider(
|
||||
// FILE_THREE,
|
||||
// getKeyStoreLoader(),
|
||||
// "SunJCE",
|
||||
// "JCEKS",
|
||||
// passwords);
|
||||
assertNotNull(ks.getKey(ALIAS_ONE));
|
||||
assertNotNull(ks.getKey(ALIAS_TWO));
|
||||
assertNull(ks.getKey(ALIAS_THREE));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Do we need spring-crypto when it is V1.0?
|
||||
*/
|
||||
public void DISABLED_testSpringCrypto() throws Throwable
|
||||
{
|
||||
ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(
|
||||
new String[] {"alfresco/keystore-tests/encryption-test-context.xml"});
|
||||
@SuppressWarnings("unused")
|
||||
KeyStore ks1 = (KeyStore) ctx.getBean("ks-test-1");
|
||||
}
|
||||
}
|
418
source/test-java/org/alfresco/encryption/KeyStoreTests.java
Normal file
418
source/test-java/org/alfresco/encryption/KeyStoreTests.java
Normal file
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.encryption;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.Key;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.DESedeKeySpec;
|
||||
import javax.transaction.NotSupportedException;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
*/
|
||||
public class KeyStoreTests
|
||||
{
|
||||
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||
|
||||
private TransactionService transactionService;
|
||||
private KeyStoreChecker keyStoreChecker;
|
||||
private EncryptionKeysRegistry encryptionKeysRegistry;
|
||||
private UserTransaction txn = null;
|
||||
private KeyResourceLoader keyResourceLoader;
|
||||
private List<String> toDelete;
|
||||
private DefaultEncryptor backupEncryptor;
|
||||
|
||||
@Before
|
||||
public void setup() throws SystemException, NotSupportedException
|
||||
{
|
||||
transactionService = (TransactionService)ctx.getBean("transactionService");
|
||||
keyStoreChecker = (KeyStoreChecker)ctx.getBean("keyStoreChecker");
|
||||
encryptionKeysRegistry = (EncryptionKeysRegistry)ctx.getBean("encryptionKeysRegistry");
|
||||
keyResourceLoader = (KeyResourceLoader)ctx.getBean("springKeyResourceLoader");
|
||||
backupEncryptor = (DefaultEncryptor)ctx.getBean("backupEncryptor");
|
||||
|
||||
toDelete = new ArrayList<String>(10);
|
||||
|
||||
AuthenticationUtil.setRunAsUserSystem();
|
||||
UserTransaction txn = transactionService.getUserTransaction();
|
||||
txn.begin();
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() throws IllegalStateException, SecurityException, SystemException
|
||||
{
|
||||
if(txn != null)
|
||||
{
|
||||
txn.rollback();
|
||||
}
|
||||
|
||||
for(String guid : toDelete)
|
||||
{
|
||||
File file = new File(guid);
|
||||
if(file.exists())
|
||||
{
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String generateEncodedKey()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Base64.encodeBase64String(generateKeyData());
|
||||
}
|
||||
catch(Throwable e)
|
||||
{
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] generateKeyData() throws NoSuchAlgorithmException
|
||||
{
|
||||
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
|
||||
random.setSeed(System.currentTimeMillis());
|
||||
byte bytes[] = new byte[DESedeKeySpec.DES_EDE_KEY_LEN];
|
||||
random.nextBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
protected String generateKeystoreName()
|
||||
{
|
||||
String guid = GUID.generate();
|
||||
toDelete.add(guid);
|
||||
return guid;
|
||||
}
|
||||
|
||||
protected Key generateSecretKey(String keyAlgorithm)
|
||||
{
|
||||
try
|
||||
{
|
||||
DESedeKeySpec keySpec = new DESedeKeySpec(generateKeyData());
|
||||
SecretKeyFactory kf = SecretKeyFactory.getInstance(keyAlgorithm);
|
||||
SecretKey secretKey = kf.generateSecret(keySpec);
|
||||
return secretKey;
|
||||
}
|
||||
catch(Throwable e)
|
||||
{
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected TestAlfrescoKeyStore getKeyStore(String name, String type, final Map<String, String> passwords, final Map<String, String> encodedKeyData,
|
||||
String keyStoreLocation, String backupKeyStoreLocation)
|
||||
{
|
||||
KeyResourceLoader testKeyResourceLoader = new KeyResourceLoader()
|
||||
{
|
||||
@Override
|
||||
public InputStream getKeyStore(String keyStoreLocation)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
return keyResourceLoader.getKeyStore(keyStoreLocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties loadKeyMetaData(String keyMetaDataFileLocation)
|
||||
throws IOException, FileNotFoundException
|
||||
{
|
||||
Properties p = new Properties();
|
||||
p.put("keystore.password", "password");
|
||||
StringBuilder aliases = new StringBuilder();
|
||||
for(String keyAlias : passwords.keySet())
|
||||
{
|
||||
p.put(keyAlias + ".password", passwords.get(keyAlias));
|
||||
if(encodedKeyData != null && encodedKeyData.get(keyAlias) != null)
|
||||
{
|
||||
p.put(keyAlias + ".keyData", encodedKeyData.get(keyAlias));
|
||||
}
|
||||
p.put(keyAlias + ".algorithm", "DESede");
|
||||
aliases.append(keyAlias);
|
||||
aliases.append(",");
|
||||
}
|
||||
if(aliases.length() > 0)
|
||||
{
|
||||
// remove trailing comma
|
||||
aliases.delete(aliases.length() - 1, aliases.length());
|
||||
}
|
||||
p.put("aliases", aliases.toString());
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
KeyStoreParameters keyStoreParameters = new KeyStoreParameters(name, type, null, "", keyStoreLocation);
|
||||
KeyStoreParameters backupKeyStoreParameters = new KeyStoreParameters(name + ".backup", type, null, "", backupKeyStoreLocation);
|
||||
TestAlfrescoKeyStore keyStore = new TestAlfrescoKeyStore();
|
||||
keyStore.setKeyStoreParameters(keyStoreParameters);
|
||||
keyStore.setBackupKeyStoreParameters(backupKeyStoreParameters);
|
||||
keyStore.setKeyResourceLoader(testKeyResourceLoader);
|
||||
keyStore.setValidateKeyChanges(true);
|
||||
keyStore.setEncryptionKeysRegistry(encryptionKeysRegistry);
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1()
|
||||
{
|
||||
// missing keystore, missing backup keystore, no registered keys -> create key store with metadata key and register key
|
||||
|
||||
TestAlfrescoKeyStore missingMainKeyStore = getKeyStore("main", "JCEKS", Collections.singletonMap(KeyProvider.ALIAS_METADATA, "metadata"),
|
||||
Collections.singletonMap(KeyProvider.ALIAS_METADATA, generateEncodedKey()), generateKeystoreName(), generateKeystoreName());
|
||||
|
||||
encryptionKeysRegistry.unregisterKey(KeyProvider.ALIAS_METADATA);
|
||||
keyStoreChecker.setMainKeyStore(missingMainKeyStore);
|
||||
|
||||
try
|
||||
{
|
||||
keyStoreChecker.validateKeyStores();
|
||||
}
|
||||
catch(InvalidKeystoreException e)
|
||||
{
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
catch (MissingKeyException e)
|
||||
{
|
||||
fail("Unexpected exception : " + e.getMessage());
|
||||
}
|
||||
|
||||
assertTrue("", encryptionKeysRegistry.getRegisteredKeys(missingMainKeyStore.getKeyAliases()).contains(KeyProvider.ALIAS_METADATA));
|
||||
assertTrue("", missingMainKeyStore.exists());
|
||||
assertTrue("", missingMainKeyStore.getKey(KeyProvider.ALIAS_METADATA) != null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2()
|
||||
{
|
||||
// missing main keystore, missing backup keystore, metadata registered key -> error, re-instate the keystore
|
||||
TestAlfrescoKeyStore missingMainKeyStore = getKeyStore("main", "JCEKS", Collections.singletonMap(KeyProvider.ALIAS_METADATA, "metadata"),
|
||||
null, generateKeystoreName(), generateKeystoreName());
|
||||
|
||||
assertTrue("", encryptionKeysRegistry.isKeyRegistered("metadata"));
|
||||
|
||||
keyStoreChecker.setMainKeyStore(missingMainKeyStore);
|
||||
|
||||
try
|
||||
{
|
||||
keyStoreChecker.validateKeyStores();
|
||||
fail("Should have caught missing main keystore");
|
||||
}
|
||||
catch(InvalidKeystoreException e)
|
||||
{
|
||||
fail("Unexpected exception : " + e.getMessage());
|
||||
}
|
||||
catch (MissingKeyException e)
|
||||
{
|
||||
// ok, expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3()
|
||||
{
|
||||
// main keystore exists, no registered metadata key -> register key
|
||||
|
||||
// create main keystore
|
||||
TestAlfrescoKeyStore mainKeyStore = getKeyStore("main", "JCEKS", Collections.singletonMap(KeyProvider.ALIAS_METADATA, "metadata"),
|
||||
null, generateKeystoreName(), generateKeystoreName());
|
||||
createAndPopulateKeyStore(mainKeyStore);
|
||||
|
||||
// de-register metadata key
|
||||
encryptionKeysRegistry.unregisterKey(KeyProvider.ALIAS_METADATA);
|
||||
|
||||
// check keys
|
||||
keyStoreChecker.setMainKeyStore(mainKeyStore);
|
||||
|
||||
try
|
||||
{
|
||||
keyStoreChecker.validateKeyStores();
|
||||
}
|
||||
catch(InvalidKeystoreException e)
|
||||
{
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
catch (MissingKeyException e)
|
||||
{
|
||||
fail("Unexpected exception : " + e.getMessage());
|
||||
}
|
||||
|
||||
assertTrue("", encryptionKeysRegistry.isKeyRegistered(KeyProvider.ALIAS_METADATA));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test4()
|
||||
{
|
||||
// create keystore, change key -> check for exception InvalidKey
|
||||
|
||||
// Firstly, create main keystore to register a well-known key
|
||||
|
||||
encryptionKeysRegistry.unregisterKey(KeyProvider.ALIAS_METADATA);
|
||||
|
||||
TestAlfrescoKeyStore keyStore = getKeyStore("main", "JCEKS", Collections.singletonMap(KeyProvider.ALIAS_METADATA, "metadata"),
|
||||
null, generateKeystoreName(), generateKeystoreName());
|
||||
createAndPopulateKeyStore(keyStore);
|
||||
|
||||
keyStoreChecker.setMainKeyStore(keyStore);
|
||||
|
||||
// check keys
|
||||
try
|
||||
{
|
||||
// should register the metadata key
|
||||
keyStoreChecker.validateKeyStores();
|
||||
}
|
||||
catch(InvalidKeystoreException e)
|
||||
{
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
catch (MissingKeyException e)
|
||||
{
|
||||
fail("Unexpected exception : " + e.getMessage());
|
||||
}
|
||||
|
||||
// check that the metadata key has been registered
|
||||
assertTrue("", encryptionKeysRegistry.isKeyRegistered("metadata"));
|
||||
|
||||
// a changed main keystore with a different metadata key
|
||||
// TestAlfrescoKeyStore changedMainKeyStore = getKeyStore("main", "JCEKS", Collections.singletonMap(KeyProvider.ALIAS_METADATA, "metadata"),
|
||||
// null, generateKeystoreName(), generateKeystoreName());
|
||||
// createAndPopulateKeyStore(changedMainKeyStore);
|
||||
keyStore.changeKey(KeyProvider.ALIAS_METADATA, generateSecretKey("DESede"));
|
||||
|
||||
// keyStoreChecker.setMainKeyStore(changedMainKeyStore);
|
||||
try
|
||||
{
|
||||
keyStoreChecker.validateKeyStores();
|
||||
fail("Expected key store checker to detect changed metadata key");
|
||||
}
|
||||
catch(InvalidKeystoreException e)
|
||||
{
|
||||
// ok, expected
|
||||
}
|
||||
catch (MissingKeyException e)
|
||||
{
|
||||
fail("Unexpected exception : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test5()
|
||||
{
|
||||
// create main keystore, backup main keystore, change main keystore -> check that backup keystore key is ok, re-register new main key
|
||||
// check that the new main keystore key has been re-registered
|
||||
|
||||
// Firstly, re-install main keystore to register a well-known key
|
||||
encryptionKeysRegistry.unregisterKey(KeyProvider.ALIAS_METADATA);
|
||||
|
||||
TestAlfrescoKeyStore keyStore = getKeyStore("main", "JCEKS", Collections.singletonMap(KeyProvider.ALIAS_METADATA, "metadata"),
|
||||
null, generateKeystoreName(), generateKeystoreName());
|
||||
createAndPopulateKeyStore(keyStore);
|
||||
|
||||
try
|
||||
{
|
||||
keyStoreChecker.setMainKeyStore(keyStore);
|
||||
keyStoreChecker.validateKeyStores();
|
||||
}
|
||||
catch(InvalidKeystoreException e)
|
||||
{
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
catch (MissingKeyException e)
|
||||
{
|
||||
fail("Unexpected exception : " + e.getMessage());
|
||||
}
|
||||
|
||||
keyStore.backup();
|
||||
|
||||
// check that the metadata key has been registered
|
||||
assertTrue("", encryptionKeysRegistry.isKeyRegistered("metadata"));
|
||||
|
||||
// change the metadata key
|
||||
keyStore.changeKey(KeyProvider.ALIAS_METADATA, generateSecretKey("DESede"));
|
||||
|
||||
try
|
||||
{
|
||||
// should detect changed metadata key and re-register it
|
||||
keyStoreChecker.validateKeyStores();
|
||||
}
|
||||
catch(InvalidKeystoreException e)
|
||||
{
|
||||
fail("Unexpected exception: " + e.getMessage());
|
||||
}
|
||||
catch (MissingKeyException e)
|
||||
{
|
||||
fail("Unexpected exception : " + e.getMessage());
|
||||
}
|
||||
|
||||
// check that the new metadata key has been successfully re-registered by encrypting and decrypting some content with it
|
||||
assertTrue("", EncryptionKeysRegistry.KEY_STATUS.OK == encryptionKeysRegistry.checkKey(KeyProvider.ALIAS_METADATA,
|
||||
keyStore.getKey(KeyProvider.ALIAS_METADATA)));
|
||||
}
|
||||
|
||||
private void createAndPopulateKeyStore(TestAlfrescoKeyStore keyStore)
|
||||
{
|
||||
KeyMap keyMap = new KeyMap();
|
||||
keyMap.setKey(KeyProvider.ALIAS_METADATA, generateSecretKey("DESede"));
|
||||
keyStore.create(keyMap, null);
|
||||
}
|
||||
|
||||
private static class TestAlfrescoKeyStore extends AlfrescoKeyStoreImpl
|
||||
{
|
||||
public void create(KeyMap keys, KeyMap backupKeys)
|
||||
{
|
||||
this.keys = (keys != null ? keys : new KeyMap());
|
||||
this.backupKeys = (backupKeys != null ? backupKeys : new KeyMap());
|
||||
super.create();
|
||||
}
|
||||
|
||||
void changeKey(String keyAlias, Key key)
|
||||
{
|
||||
keys.setKey(KeyProvider.ALIAS_METADATA, key);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user