diff --git a/config/alfresco/.keystore b/config/alfresco/.keystore deleted file mode 100644 index 7e966eebae..0000000000 Binary files a/config/alfresco/.keystore and /dev/null differ diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index 17fa24849a..747afa79de 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -1013,7 +1013,7 @@ - + diff --git a/config/alfresco/encryption-context.xml b/config/alfresco/encryption-context.xml index b05dccd1bb..219741adec 100644 --- a/config/alfresco/encryption-context.xml +++ b/config/alfresco/encryption-context.xml @@ -11,7 +11,9 @@ + + @@ -19,6 +21,7 @@ + @@ -30,6 +33,21 @@ + + + + + + + + + + @@ -40,6 +58,7 @@ + @@ -56,6 +75,7 @@ + @@ -86,20 +106,6 @@ - - - - - - - - - - - - - - diff --git a/config/alfresco/keystore/browser.p12 b/config/alfresco/keystore/browser.p12 new file mode 100644 index 0000000000..3288f49129 Binary files /dev/null and b/config/alfresco/keystore/browser.p12 differ diff --git a/config/alfresco/keystore/keystore b/config/alfresco/keystore/keystore index 7e966eebae..22d2b69a41 100644 Binary files a/config/alfresco/keystore/keystore and b/config/alfresco/keystore/keystore differ diff --git a/config/alfresco/keystore/keystore-passwords.properties b/config/alfresco/keystore/keystore-passwords.properties index 06a5dd76ec..cbdb6fb66c 100644 --- a/config/alfresco/keystore/keystore-passwords.properties +++ b/config/alfresco/keystore/keystore-passwords.properties @@ -4,8 +4,4 @@ keystore.password=mp6yc0UD9e # The password protecting the alias: metadata metadata.keyData= metadata.algorithm=DESede -metadata.password=oKIWzVdEdA -# The password protecting the alias: solr -#solr.keyData= -#solr.algorithm=DESede -#solr.password=TxHTtOnrwQ \ No newline at end of file +metadata.password=oKIWzVdEdA \ No newline at end of file diff --git a/config/alfresco/messages/system-messages.properties b/config/alfresco/messages/system-messages.properties index 03e1508c2e..3bda362996 100644 --- a/config/alfresco/messages/system-messages.properties +++ b/config/alfresco/messages/system-messages.properties @@ -37,6 +37,9 @@ system.mt.warn.upgrade_mt_admin_context=Please update your alfresco/extension/mt system.usage.err.no_txn=RepoUsageComponent must be called in a transaction. system.usage.err.no_txn_readwrite=RepoUsageComponent must be called in a read-write transaction. +# Re-encryptor +reencryptor.batchprocessor.name=Reencryptor + # START TRANSLATION system.usage.warn.limit_users_approached=The allowable user limit of {0} is being approached. There are {1} users in the system. system.usage.warn.limit_users_reached=The allowable user limit of {0} has been reached. There are {1} users in the system. diff --git a/config/alfresco/node-services-context.xml b/config/alfresco/node-services-context.xml index 33361054f9..b2a06e01ca 100644 --- a/config/alfresco/node-services-context.xml +++ b/config/alfresco/node-services-context.xml @@ -249,5 +249,16 @@ - + + + + + + + + + + + + diff --git a/source/java/org/alfresco/encryption/EncryptionTests.java b/source/java/org/alfresco/encryption/EncryptionTests.java index e5874bd0ca..38a28edf49 100644 --- a/source/java/org/alfresco/encryption/EncryptionTests.java +++ b/source/java/org/alfresco/encryption/EncryptionTests.java @@ -56,7 +56,6 @@ import org.springframework.context.ApplicationContext; public class EncryptionTests extends TestCase { private static final String TEST_MODEL = "org/alfresco/encryption/reencryption_model.xml"; -// private static final String TEST_BUNDLE = "org/alfresco/encryption/encryptiontest_model"; private static int NUM_PROPERTIES = 500; private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); @@ -72,11 +71,13 @@ public class EncryptionTests extends TestCase private MetadataEncryptor metadataEncryptor; private ReEncryptor reEncryptor; private String cipherAlgorithm = "DESede/CBC/PKCS5Padding"; - private KeyStoreParameters keyStoreParameters; private KeyStoreParameters backupKeyStoreParameters; + private AlfrescoKeyStoreImpl backupKeyStore; private KeyResourceLoader keyResourceLoader; private EncryptionKeysRegistryImpl encryptionKeysRegistry; private KeyStoreChecker keyStoreChecker; + private DefaultEncryptor mainEncryptor; + private DefaultEncryptor backupEncryptor; private AuthenticationComponent authenticationComponent; private DictionaryDAO dictionaryDAO; @@ -102,8 +103,10 @@ public class EncryptionTests extends TestCase reEncryptor = (ReEncryptor)ctx.getBean("reEncryptor"); backupKeyStoreParameters = (KeyStoreParameters)ctx.getBean("backupKeyStoreParameters"); keyStoreChecker = (KeyStoreChecker)ctx.getBean("keyStoreChecker"); - keyStoreParameters = (KeyStoreParameters)ctx.getBean("keyStoreParameters"); encryptionKeysRegistry = (EncryptionKeysRegistryImpl)ctx.getBean("encryptionKeysRegistry"); + backupKeyStore = (AlfrescoKeyStoreImpl)ctx.getBean("backupKeyStore"); + mainEncryptor = (DefaultEncryptor)ctx.getBean("encryptor"); + 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); @@ -162,18 +165,26 @@ public class EncryptionTests extends TestCase { return keys.get(keyAlias); } + + @Override + public void refresh() + { + // nothing to do + } }; return keyProvider; } - protected Encryptor getEncryptor(KeyProvider keyProvider) + protected Encryptor getFallbackEncryptor(KeyProvider keyProvider) { DefaultEncryptor encryptor = new DefaultEncryptor(); encryptor.setCipherAlgorithm(cipherAlgorithm); encryptor.setCipherProvider(null); encryptor.setKeyProvider(keyProvider); + + DefaultFallbackEncryptor fallbackEncryptor = new DefaultFallbackEncryptor(encryptor, mainEncryptor); - return encryptor; + return fallbackEncryptor; } protected MetadataEncryptor getMetadataEncryptor(Encryptor encryptor) @@ -185,7 +196,7 @@ public class EncryptionTests extends TestCase return metadataEncryptor; } - protected void createEncryptedProperties(List nodes, MetadataEncryptor metadataEncryptor) + protected void createEncryptedProperties(List nodes) { for(int i = 0; i < NUM_PROPERTIES; i++) { @@ -218,20 +229,26 @@ public class EncryptionTests extends TestCase public void testReEncrypt() { + KeyProvider backupKeyProvider = backupEncryptor.getKeyProvider(); + KeyProvider mainKeyProvider = mainEncryptor.getKeyProvider(); try { // Create encrypted properties using the configured encryptor and key provider - createEncryptedProperties(before, metadataEncryptor); + createEncryptedProperties(before); // Create encrypted properties using the new encryptor and key provider KeyProvider newKeyProvider = getKeyProvider(newKeys); - Encryptor newEncryptor = getEncryptor(newKeyProvider); - MetadataEncryptor newMetadataEncryptor = getMetadataEncryptor(newEncryptor); - createEncryptedProperties(after, newMetadataEncryptor); - + + // 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(); - reEncryptor.reEncrypt(newKeyProvider); + 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 @@ -239,7 +256,7 @@ public class EncryptionTests extends TestCase for(NodeRef nodeRef : before) { Map props = nodeService.getProperties(nodeRef); - props = newMetadataEncryptor.decrypt(props); + props = metadataEncryptor.decrypt(props); assertNotNull("", props.get(PROP)); assertEquals("", nodeRef.toString(), props.get(PROP)); } @@ -247,11 +264,15 @@ public class EncryptionTests extends TestCase for(NodeRef nodeRef : after) { Map props = nodeService.getProperties(nodeRef); - props = newMetadataEncryptor.decrypt(props); + props = metadataEncryptor.decrypt(props); assertNotNull("", props.get(PROP)); assertEquals("", nodeRef.toString(), props.get(PROP)); } } + catch(MissingKeyStoreException e) + { + fail(e.getMessage()); + } catch(AlfrescoRuntimeException e) { if(e.getCause() instanceof InvalidKeyException) @@ -260,12 +281,21 @@ public class EncryptionTests extends TestCase 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(); + reEncryptor.bootstrapReEncrypt(); fail("Should have caught missing backup key store"); } diff --git a/source/java/org/alfresco/encryption/KeyStoreKeyProviderTest.java b/source/java/org/alfresco/encryption/KeyStoreKeyProviderTest.java index a764bdd4ad..8f782bdf7f 100644 --- a/source/java/org/alfresco/encryption/KeyStoreKeyProviderTest.java +++ b/source/java/org/alfresco/encryption/KeyStoreKeyProviderTest.java @@ -61,7 +61,7 @@ public class KeyStoreKeyProviderTest extends TestCase passwords.put(AlfrescoKeyStore.KEY_KEYSTORE_PASSWORD, "ksPwd2"); passwords.put(ALIAS_ONE, "aliasPwd1"); passwords.put(ALIAS_TWO, "aliasPwd2"); - KeyStoreParameters encryptionParameters = new KeyStoreParameters("JCEKS", "SunJCE", null, FILE_TWO); + KeyStoreParameters encryptionParameters = new KeyStoreParameters("test", "JCEKS", "SunJCE", null, FILE_TWO); KeystoreKeyProvider keyProvider = new KeystoreKeyProvider(encryptionParameters, getKeyStoreLoader(passwords)); // FILE_TWO, // getKeyStoreLoader(), @@ -77,7 +77,7 @@ public class KeyStoreKeyProviderTest extends TestCase // passwords.put(KeyStoreManager.KEY_KEYSTORE_PASSWORD, "ksPwd2"); // passwords.put(ALIAS_ONE, "aliasPwd1"); // passwords.put(ALIAS_TWO, "aliasPwd2"); - KeyStoreParameters encryptionParameters = new KeyStoreParameters("JCEKS", "SunJCE", null, keyStoreLocation); + KeyStoreParameters encryptionParameters = new KeyStoreParameters("test", "JCEKS", "SunJCE", null, keyStoreLocation); KeystoreKeyProvider keyProvider = new KeystoreKeyProvider(encryptionParameters, getKeyStoreLoader(passwords)); // FILE_TWO, // getKeyStoreLoader(), diff --git a/source/java/org/alfresco/encryption/ReEncryptor.java b/source/java/org/alfresco/encryption/ReEncryptor.java index a1299e4a29..9a250c1637 100644 --- a/source/java/org/alfresco/encryption/ReEncryptor.java +++ b/source/java/org/alfresco/encryption/ReEncryptor.java @@ -35,11 +35,14 @@ import org.alfresco.repo.domain.node.NodePropertyEntity; import org.alfresco.repo.domain.node.NodePropertyKey; import org.alfresco.repo.domain.node.NodePropertyValue; import org.alfresco.repo.domain.qname.QNameDAO; +import org.alfresco.repo.lock.JobLockService; +import org.alfresco.repo.lock.LockAcquisitionException; import org.alfresco.repo.node.encryption.MetadataEncryptor; import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; @@ -49,7 +52,6 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.extensions.surf.util.I18NUtil; -// TODO lock so that only one encryptor can run at a time /** * Re-encrypts encryptable repository properties using a new set of encryption keys. * Decrypts the repository properties using the default encryptor, falling back to @@ -59,8 +61,8 @@ import org.springframework.extensions.surf.util.I18NUtil; * Can run in one of two ways: * *
    - *
  • during bootstrap (used by the community edition of the software) - *
  • by using JMX. In this case, the system can stay running while the re-encryption takes place. + *
  • during bootstrap. + *
  • by using JMX (available only to Enterprise). In this case, the system can stay running while the re-encryption takes place. *
* * @since 4.0 @@ -71,32 +73,28 @@ public class ReEncryptor implements ApplicationContextAware private NodeDAO nodeDAO; private DictionaryDAO dictionaryDAO; - private DictionaryService dictionaryService; - private TransactionService transactionService; private QNameDAO qnameDAO; private MetadataEncryptor metadataEncryptor; -// private KeyStoreParameters keyStoreParameters; -// private KeyStoreParameters backupKeyStoreParameters; - private AlfrescoKeyStore backupKeyStore; - private AlfrescoKeyStore keyStore; private KeyProvider backupKeyProvider; private KeyProvider keyProvider; -// private KeyResourceLoader keyResourceLoader; private ApplicationContext applicationContext; + private TransactionService transactionService; private RetryingTransactionHelper transactionHelper; - private String cipherAlgorithm; private int chunkSize; private boolean splitTxns = true; + + private static final QName LOCK = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "OrphanReaper"); + private JobLockService jobLockService; /** * Set the transaction provider so that each execution can be performed within a transaction */ public void setTransactionService(TransactionService transactionService) { - this.transactionService = transactionService; + this.transactionService = transactionService; this.transactionHelper = transactionService.getRetryingTransactionHelper(); this.transactionHelper.setForceWritable(true); } @@ -106,6 +104,16 @@ public class ReEncryptor implements ApplicationContextAware this.metadataEncryptor = metadataEncryptor; } + public MetadataEncryptor getMetadataEncryptor() + { + return metadataEncryptor; + } + + public void setJobLockService(JobLockService jobLockService) + { + this.jobLockService = jobLockService; + } + public void setChunkSize(int chunkSize) { this.chunkSize = chunkSize; @@ -126,47 +134,11 @@ public class ReEncryptor implements ApplicationContextAware this.dictionaryDAO = dictionaryDAO; } - public void setDictionaryService(DictionaryService dictionaryService) - { - this.dictionaryService = dictionaryService; - } - public void setQnameDAO(QNameDAO qnameDAO) { this.qnameDAO = qnameDAO; } - public void setCipherAlgorithm(String cipherAlgorithm) - { - this.cipherAlgorithm = cipherAlgorithm; - } - -// public void setKeyStoreParameters(KeyStoreParameters keyStoreParameters) -// { -// this.keyStoreParameters = keyStoreParameters; -// } -// -// public void setBackupKeyStoreParameters(KeyStoreParameters backupKeyStoreParameters) -// { -// this.backupKeyStoreParameters = backupKeyStoreParameters; -// } - -// protected KeyProvider getKeyProvider(AlfrescoKeyStore keyStore) -// { -// KeyProvider keyProvider = new KeystoreKeyProvider(keyStore); -// return keyProvider; -// } - - public void setBackupKeyStore(AlfrescoKeyStore backupKeyStore) - { - this.backupKeyStore = backupKeyStore; - } - - public void setKeyStore(AlfrescoKeyStore keyStore) - { - this.keyStore = keyStore; - } - public void setBackupKeyProvider(KeyProvider backupKeyProvider) { this.backupKeyProvider = backupKeyProvider; @@ -176,87 +148,44 @@ public class ReEncryptor implements ApplicationContextAware { this.keyProvider = keyProvider; } - -// public void setKeyResourceLoader(KeyResourceLoader keyResourceLoader) -// { -// this.keyResourceLoader = keyResourceLoader; -// } - -// public MetadataEncryptor getMetadataEncryptor() -// { -// DefaultEncryptor backupEncryptor = new DefaultEncryptor(); -// backupEncryptor.setCipherProvider(null); // TODO parameterize -// backupEncryptor.setCipherAlgorithm(cipherAlgorithm); -// backupEncryptor.setKeyProvider(backupKeyProvider); -// -// DefaultEncryptor encryptor = new DefaultEncryptor(); -// encryptor.setCipherProvider(null); // TODO parameterize -// encryptor.setCipherAlgorithm(cipherAlgorithm); -// encryptor.setKeyProvider(keyProvider); -// -// DefaultFallbackEncryptor fallbackEncryptor = new DefaultFallbackEncryptor(encryptor, backupEncryptor); -// MetadataEncryptor metadataEncryptor = new MetadataEncryptor(); -// metadataEncryptor.setEncryptor(fallbackEncryptor); -// metadataEncryptor.setDictionaryService(dictionaryService); -// return metadataEncryptor; -// } -// -// public MetadataEncryptor getMetadataEncryptor(KeyProvider backupKeyProvider, KeyProvider newKeyProvider) -// { -// DefaultEncryptor backupEncryptor = new DefaultEncryptor(); -// backupEncryptor.setCipherProvider(null); // TODO parameterize -// backupEncryptor.setCipherAlgorithm(cipherAlgorithm); -// backupEncryptor.setKeyProvider(backupKeyProvider); -// -// DefaultEncryptor encryptor = new DefaultEncryptor(); -// encryptor.setCipherProvider(null); // TODO parameterize -// encryptor.setCipherAlgorithm(cipherAlgorithm); -// encryptor.setKeyProvider(newKeyProvider); -// -// DefaultFallbackEncryptor fallbackEncryptor = new DefaultFallbackEncryptor(encryptor, backupEncryptor); -// MetadataEncryptor metadataEncryptor = new MetadataEncryptor(); -// metadataEncryptor.setEncryptor(fallbackEncryptor); -// metadataEncryptor.setDictionaryService(dictionaryService); -// return metadataEncryptor; -// } -// protected KeyProvider getKeyProvider(final Map keys) -// { -// KeyProvider keyProvider = new KeyProvider() -// { -// @Override -// public Key getKey(String keyAlias) -// { -// return keys.get(keyAlias); -// } -// }; -// return keyProvider; -// } + /** + * Attempts to get the lock. If the lock couldn't be taken, then null is returned. + * + * @return Returns the lock token or null + */ + private String getLock(long time) + { + try + { + return jobLockService.getLock(LOCK, time); + } + catch (LockAcquisitionException e) + { + return null; + } + } - protected Encryptor getEncryptor(KeyProvider keyProvider) - { - DefaultEncryptor encryptor = new DefaultEncryptor(); - encryptor.setCipherProvider(null); // TODO parameterize - encryptor.setCipherAlgorithm(cipherAlgorithm); - encryptor.setKeyProvider(keyProvider); + /** + * Attempts to get the lock. If it fails, the current transaction is marked for rollback. + * + * @return Returns the lock token + */ + private void refreshLock(String lockToken, long time) + { + if (lockToken == null) + { + throw new IllegalArgumentException("Must provide existing lockToken"); + } + jobLockService.refreshLock(lockToken, LOCK, time); + } - return encryptor; - } - - /** - * For testing use. - * - * @param keyProvider - */ - void reEncrypt(KeyProvider keyProvider) - { - metadataEncryptor.setEncryptor(getEncryptor(keyProvider)); - reEncryptImpl(); - } - - protected void reEncrypt(final MetadataEncryptor metadataEncryptor, final List properties) + protected void reEncryptProperties(final List properties, final String lockToken) { final Iterator it = properties.iterator(); + + // TODO use BatchProcessWorkerAdaptor? + BatchProcessor.BatchProcessWorker worker = new BatchProcessor.BatchProcessWorker() { public String getIdentifier(NodePropertyEntity entity) @@ -266,6 +195,7 @@ public class ReEncryptor implements ApplicationContextAware public void beforeProcess() throws Throwable { + refreshLock(lockToken, chunkSize * 100L); } public void afterProcess() throws Throwable @@ -287,9 +217,9 @@ public class ReEncryptor implements ApplicationContextAware // decrypt... Serializable decrypted = metadataEncryptor.decrypt(propertyQName, sealed); - // ...and then re-encrypt. The new keys will be used. + // ...and then re-encrypt. The new key will be used. Serializable resealed = metadataEncryptor.encrypt(propertyQName, decrypted); - + // TODO update resealed using batch update? // does the node DAO do batch updating? nodeDAO.setNodeProperties(entity.getNodeId(), Collections.singletonMap(propertyQName, resealed)); @@ -315,12 +245,16 @@ public class ReEncryptor implements ApplicationContextAware @Override public Collection getNextWork() { - int count = 0; List sublist = new ArrayList(chunkSize); - while(it.hasNext() && count < chunkSize) + + synchronized(it) { - sublist.add(it.next()); - count++; + int count = 0; + while(it.hasNext() && count < chunkSize) + { + sublist.add(it.next()); + count++; + } } return sublist; @@ -329,12 +263,12 @@ public class ReEncryptor implements ApplicationContextAware // TODO, "propertize" these numbers new BatchProcessor( - I18NUtil.getMessage(""), + I18NUtil.getMessage("reencryptor.batchprocessor.name"), // TODO i18n name transactionHelper, provider, - 2, 20, + 2, 100, applicationContext, - logger, 20).process(worker, splitTxns); + logger, 100).process(worker, splitTxns); } /** @@ -342,7 +276,7 @@ public class ReEncryptor implements ApplicationContextAware */ public int bootstrapReEncrypt() throws MissingKeyStoreException { - if(backupKeyStore.getKey(KeyProvider.ALIAS_METADATA) == null) + if(backupKeyProvider.getKey(KeyProvider.ALIAS_METADATA) == null) { throw new MissingKeyStoreException("Backup key store is either not present or does not contain a metadata encryption key"); } @@ -353,39 +287,59 @@ public class ReEncryptor implements ApplicationContextAware * Re-encrypt by decrypting using the configured keystore and encrypting using a keystore configured using the provided new key store parameters. * Called from e.g. JMX. * - * Note: it is the responsibility of the end user to ensure that the keystore configured by newKeyStoreParameters is - * placed in the repository keystore directory. This can be done while the repository is running and it will be picked - * up automatically the next time the repository restarts. + * Note: it is the responsibility of the end user to ensure that the underlying keystores have been set up appropriately + * i.e. the old key store is backed up to the location defined by the property '${dir.keystore}/backup-keystore' and the new + * key store replaces it. This can be done while the repository is running. */ public int reEncrypt() throws MissingKeyStoreException { - backupKeyStore.reload(); - keyStore.reload(); - if(keyStore.getKey(KeyProvider.ALIAS_METADATA) == null) + // refresh the key providers to pick up changes made + backupKeyProvider.refresh(); + keyProvider.refresh(); + + if(keyProvider.getKey(KeyProvider.ALIAS_METADATA) == null) { throw new MissingKeyStoreException("Main key store is either not present or does not contain a metadata encryption key"); } - if(backupKeyStore.getKey(KeyProvider.ALIAS_METADATA) == null) + if(backupKeyProvider.getKey(KeyProvider.ALIAS_METADATA) == null) { throw new MissingKeyStoreException("Backup key store is either not present or does not contain a metadata encryption key"); } - return reEncryptImpl(); + + int numProps = reEncryptImpl(); + return numProps; } protected int reEncryptImpl() { - // get properties that are encrypted + RetryingTransactionCallback txnWork = new RetryingTransactionCallback() + { + public String execute() throws Exception + { + String lockToken = getLock(20000L); + return lockToken; + } + }; + + String lockToken = transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, false, true); + if(lockToken == null) + { + logger.warn("Can't get lock. Assume multiple re-encryptors ..."); + return 0; + } + + // get encrypted properties Collection propertyDefs = dictionaryDAO.getPropertiesOfDataType(DataTypeDefinition.ENCRYPTED); - // TODO use callback mechanism + // TODO use callback mechanism, or select based on set of nodes? List properties = nodeDAO.selectProperties(propertyDefs); - + if(logger.isDebugEnabled()) { logger.debug("Found " + properties.size() + " properties to re-encrypt..."); } - // reencrypt these properties - reEncrypt(metadataEncryptor, properties); + // reencrypt these properties TODO don't call if num props == 0 + reEncryptProperties(properties, lockToken); if(logger.isDebugEnabled()) { @@ -396,8 +350,7 @@ public class ReEncryptor implements ApplicationContextAware } @Override - public void setApplicationContext(ApplicationContext applicationContext) - throws BeansException + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } diff --git a/source/java/org/alfresco/encryption/reencryption_model.xml b/source/java/org/alfresco/encryption/reencryption_model.xml index 4850508c10..762ab23bc8 100644 --- a/source/java/org/alfresco/encryption/reencryption_model.xml +++ b/source/java/org/alfresco/encryption/reencryption_model.xml @@ -7,6 +7,7 @@ + @@ -23,7 +24,7 @@ Base The Base Type - + cm:content diff --git a/source/java/org/alfresco/repo/search/impl/solr/SolrQueryHTTPClient.java b/source/java/org/alfresco/repo/search/impl/solr/SolrQueryHTTPClient.java index 173ca8bbde..1d807e1aab 100644 --- a/source/java/org/alfresco/repo/search/impl/solr/SolrQueryHTTPClient.java +++ b/source/java/org/alfresco/repo/search/impl/solr/SolrQueryHTTPClient.java @@ -42,8 +42,11 @@ import org.alfresco.service.cmr.search.SearchParameters.FieldFacetSort; import org.alfresco.service.cmr.search.SearchParameters.SortDefinition; import org.alfresco.service.cmr.security.PermissionService; import org.apache.commons.codec.net.URLCodec; +import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; @@ -303,13 +306,23 @@ public class SolrQueryHTTPClient body.put("textAttributes", textAttributes); PostMethod post = new PostMethod(url.toString()); - // TOOD deal with redirects for SSL post.setRequestEntity(new ByteArrayRequestEntity(body.toString().getBytes("UTF-8"), "application/json")); try { httpClient.executeMethod(post); + if(post.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY || post.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY) + { + Header locationHeader = post.getResponseHeader("location"); + if (locationHeader != null) + { + String redirectLocation = locationHeader.getValue(); + post.setURI(new URI(redirectLocation, true)); + httpClient.executeMethod(post); + } + } + if (post.getStatusCode() != HttpServletResponse.SC_OK) { throw new LuceneQueryParserException("Request failed " + post.getStatusCode() + " " + url.toString());