I'm working on a project where I need to secure a specific content field in Apache Solr by encrypting the data during indexing and decrypting it during search.
First approach: I've already attempted to implement a custom UpdateRequestProcessorFactory and a search component, but I'm facing challenges in achieving the desired encryption and decryption.
Second approach: I have also tried with another approach i.e How to create a custom search component in solr In second approach, solr is not storing the content in encrypted form. Also when I pass the keyword in analysis section (UI), it properly encrypts and decrypts the data.
Is there any tried and tested way to implement such scenario.
For the first approach I tried following code: Here encryption is working fine but not decryption. responseBuilder.getResponseDocs() returns null.
package com.emorphis.solr.search.component;
import com.emorphis.solr.encrypt.util.EncryptUtil;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.handler.component.ResponseBuilder;
import org.apache.solr.handler.component.SearchComponent;
import org.apache.solr.search.DocIterator;
import org.apache.solr.search.DocList;
import org.apache.solr.search.SolrIndexSearcher;
import java.io.IOException;
public class MyDecryptionSearchComponent extends SearchComponent {
@Override
public void prepare(ResponseBuilder responseBuilder) throws IOException {
// Implement decryption logic
// ...
System.out.println("Executing MyDecryptionSearchComponent - prepare");
executeDecryptionLogic(responseBuilder);
}
@Override
public void process(ResponseBuilder responseBuilder) throws IOException {
// Implement decryption logic
// ...
System.out.println("Executing MyDecryptionSearchComponent - process");
executeDecryptionLogic(responseBuilder);
}
@Override
public void finishStage(ResponseBuilder rb) {
System.out.println("Executing MyDecryptionSearchComponent - finishStage");
executeDecryptionLogic(rb);
super.finishStage(rb);
}
@Override
public String getDescription() {
return "MyDecryptionSearchComponent";
}
private static void executeDecryptionLogic(ResponseBuilder responseBuilder) {
System.out.println("=======responseBuilder==========="+responseBuilder.getResults().docList);
SolrDocumentList results = responseBuilder.getResponseDocs();
if (results == null) {
System.out.println("No documents found for decryption.");
return;
} else {
System.out.println("Document found for decryption." + results.size());
}
for (SolrDocument document : results) {
Object fieldValue = document.getFieldValue("content");
System.out.println("======fieldValue===="+fieldValue);
if (fieldValue != null && fieldValue instanceof String) {
String encryptedContent = (String) fieldValue;
System.out.println("==========encryptedContent============"+encryptedContent);
// Decrypt the content
String decryptedContent = EncryptUtil.decrypt(encryptedContent);
System.out.println("============decryptedContent==============="+decryptedContent);
// Replace the encrypted content with the decrypted content
document.setField("content", decryptedContent);
}
}
}
}
In second approach I have added fieldType and custom classes. The problem with second approach is the logs are printed for encryption but encrypted data is not stored. And when I search the data using /select it does not call decryption logic.
+ <fieldType name="encrypted_content_text" class="solr.TextField" positionIncrementGap="100" multiValued="false">
+ <analyzer type="index">
+ <tokenizer name="standard"/>
+ <filter name="stop" words="stopwords.txt" ignoreCase="true"/>
+ <filter name="lowercase"/>
+ <filter class="com.emorphis.solr.filter.EncryptionFilterFactory" />
+ </analyzer>
+ <analyzer type="query">
+ <tokenizer name="whitespace"/>
+ <filter class="com.emorphis.solr.filter.DecryptionFilterFactory" />
+ <filter name="stop" words="stopwords.txt" ignoreCase="true"/>
+ <filter expand="true" name="synonymGraph" synonyms="synonyms.txt" ignoreCase="true"/>
+ <filter name="lowercase"/>
+ </analyzer>
+ </fieldType>
+