Given an entity annotated with @Indexed, is it possible to construct a Lucene Document without indexing that entity through the hibernate search API?
We use hibernate-search 5.6.6 / hibernate-core 5.1
Background
For every entity indexed, we have come up with a row level security where a user is allowed to read the record based on grants expressed by some lucene query.
For example, given a FlightPermit class with a status (active, inactive), we grant permission to a user (Subject) to read all records with: “status: active”.
We would like to extend this to grant permissions on create/update. The idea there is to use the lucene contrib MemoryIndex to construct an in memory document and query it with the grant query before committing it to the database (and thus indexing it).
public boolean isRecordWritable(FlightPermit entity, Subject subject) {
Query query = getWriteGrantQuery(entity, subject);
Document document = getDocument(entity);
MemoryIndex memoryIndex = MemoryIndex.fromDocument(document, analyzer);
return memoryIndex.search(query) > 0.0f;
}
Any pointers on how to write this geDocument(entity) method?
Should I go down the path of ExtendedSearchIntegrator / DocumentBuilderContainedEntity?
This will build a document in Hibernate Search 5.11, and the code for 5.6 should be fairly similar:
Object entity = ...; // Set to your entity
String tenantId = ...; // Set to null if you don't use multi-tenancy
Serializable id = ...; // Set to the entity ID, if available
FullTextSession fullTextSession = Search.getFullTextSession( session );
Class<?> entityType = Hibernate.getClass( entity );
SearchIntegrator integrator = fullTextSession.getSearchFactory().unwrap( SearchIntegrator.class );
DocumentBuilderIndexedEntity documentBuilder = integrator.getIndexBinding( new PojoIndexedTypeIdentifier( entityType ) ); // You'll probably have to pass the entityType directly in Search 5.6
Map<String,String> fieldToAnalyzerMap = new HashMap<String, String>( );
Document document = documentBuilder.getDocument( tenantId, entity, id, fieldToAnalyzerMap, null, new ContextualExceptionBridgeHelper(), null );
That being said, some warnings are in order:
- This code relies on very low-level SPI, definitely not API. We may change these interfaces at any moment, even in micro releases, and it will break your code.
- I’m really not sure it’s a good idea to rely on a secondary source of truth (the index) for security when you have a primary source of truth (the database) at your disposal, but I suppose YMMV.
Thanks for the info. I ended up doing this for hibernate search 5.6
private MemoryIndex getMemoryIndex(T entity) {
ExtendedSearchIntegrator searchIntegrator = ContextHelper.getSearchIntegrator(newFullTextSession());
Class<?> clazz = Hibernate.getClass(entity);
EntityIndexBinding entityIndexBinding = searchIntegrator.getIndexBinding(clazz);
Analyzer analyzer = searchIntegrator.getAnalyzer(clazz);
DocumentBuilderIndexedEntity docBuilder = entityIndexBinding.getDocumentBuilder();
Document document = docBuilder.getDocument(null, entity, entity.getId(), new HashMap<String, String>(), null, new ContextualExceptionBridgeHelper(), null);
return new MemoryIndex.fromDocument(document, analyzer);
}