If your application uses Hibernate we can leverage it to gather insights about how users access or change personal or sensitive data.
In this guide, we'll explore ways of intercepting operations within Hibernate's abstracted relational mapping implementation.
The Interceptors allow us to react to certain events that occur within Hibernate.
When these interceptors are registered as callbacks, they provide communication links between Hibernate's session and application. Thus, allowing your application to intercept core operations such as save, update, delete, etc.
The EmptyInterceptor class (Documentation) has a number of methods which can be used to capture information about the data that is being accessed or modified - these methods include onLoad()
, onSave()
and onDelete()
.
For instance, if we want to intercept data saving operations before being executed, but only for the User entity, we override onSave()
method like this:
@Overridepublic boolean onSave(Object entity,Serializable id,Object[] state,String[] propertyNames,Type[] types) {if (entity instanceof User) {logger.info(((User) entity).toString());}return super.onSave(entity, id, state, propertyNames, types);}
Interceptors can be used in conjunction with our Java SDK, to submit query information to our services. You can follow our example above, the PrivataInterceptor
.
It is important to know which user performed a certain operation, for instance, who was the user that deleted a certain entity.
PrivataInterceptor.javapublic class PrivataInterceptor extends EmptyInterceptor {// Instantiate privataAuditprivate PrivataAudit privataAudit = new PrivataAudit(false,apiUrl);​protected PrivataInterceptor() {// Initialise privataAudit with the required variablesthis.privataAudit.initialize(dbKey, dbSecret)}​@Overridepublic boolean onSave(Object entity,Serializable id,Object[] state,String[] propertyNames,Type[] types) {// We need to know which user is performing the operation on sensitive data// Context it's an example of an application specific object// which we can get information about the userUser AuthenticatedUser = Context.getAuthenticatedUser();​if (AuthenticatedUser != null && !AuthenticatedUser.getAllRoles().isEmpty()) {String auditUser = AuthenticatedUser.getUuid();String auditRoles = AuthenticatedUser.getAllRoles().toString();String auditEntity = entity.getClass().getSimpleName();JsonArray queries = new JsonArray();JsonObject query = new JsonObject();JsonArray tables = new JsonArray();JsonObject table = new JsonObject();table.addProperty("table", auditEntity);table.add("columns", new JsonArray(propertyNames));tables.add(table);​query.add("tables", tables);query.addProperty("action", "Read");query.addProperty("timestamp", new Date());query.addProperty("user", auditUser);query.addProperty("group", auditRoles;query.addProperty("returnedRows", 1);queries.add(query)this.privataAudit.sendQueries(queries);}return super.onSave(entity, id, state, propertyNames, types);}​@Overridepublic boolean onLoad(Object entity,Serializable id,Object[] state,String[] propertyNames,Type[] types) {User AuthenticatedUser = Context.getAuthenticatedUser();if (AuthenticatedUser != null && !AuthenticatedUser.getAllRoles().isEmpty()) {String auditUser = AuthenticatedUser.getUuid();String auditRoles = AuthenticatedUser.getAllRoles().toString();String auditEntity = entity.getClass().getSimpleName();JsonArray queries = new JsonArray();JsonObject query = new JsonObject();JsonArray tables = new JsonArray();JsonObject table = new JsonObject();table.addProperty("table", auditEntity);table.add("columns", new JsonArray(propertyNames));tables.add(table);​query.add("tables", tables);query.addProperty("action", "Read");query.addProperty("timestamp", new Date());query.addProperty("user", auditUser);query.addProperty("group", auditRoles;query.addProperty("returnedRows", 1);queries.add(query)this.privataAudit.sendQueries(queries);}return super.onLoad(entity, id, state, propertyNames, types);}​@Overridepublic void onDelete(Object entity,Serializable id,Object[] state,String[] propertyNames,Type[] types) {User AuthenticatedUser = Context.getAuthenticatedUser();if (AuthenticatedUser != null && !AuthenticatedUser.getAllRoles().isEmpty()) {String auditUser = AuthenticatedUser.getUuid();String auditRoles = AuthenticatedUser.getAllRoles().toString();String auditEntity = entity.getClass().getSimpleName();JsonArray queries = new JsonArray();JsonObject query = new JsonObject();JsonArray tables = new JsonArray();JsonObject table = new JsonObject();table.addProperty("table", auditEntity);table.add("columns", new JsonArray(propertyNames));tables.add(table);​query.add("tables", tables);query.addProperty("action", "Read");query.addProperty("timestamp", new Date());query.addProperty("user", auditUser);query.addProperty("group", auditRoles;query.addProperty("returnedRows", 1);queries.add(query)this.privataAudit.sendQueries(queries);}super.onDelete(entity, id, state, propertyNames, types);}}
An interceptor can either be registered as Session
scoped or SessionFactory
scoped.
A Session
-scoped interceptor is specified when a session is opened, and is only used for that specific session.
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);​Session session = sessionFactory.withOptions().interceptor( new PrivataInterceptor() ).openSession();
A SessionFactory
-scoped interceptor is registered with the Configuration
object prior to building the SessionFactory
. It will be applied to all sessions opened from that SessionFactory
.
SessionFactory sessionFactory = new MetadataSources( new StandardServiceRegistryBuilder().build() ).addAnnotatedClass( User.class ).getMetadataBuilder().build().getSessionFactoryBuilder().applyInterceptor( new PrivataInterceptor() ).build();
You can read more about Interceptors on the following links:
​