9 Replies Latest reply on Jun 24, 2010 6:05 AM by ashish.patel22

    Adding custom column to audit tables

      We have a requirement to add a custom column(hashvalue) to audit table of individual entities.

      This column is added to make audit logs tempor resistant based on hashvalue so it makes sense to add it only to audit tables and not the actual entity table. Is it possible?

        • 1. Re: Adding custom column to audit tables
          adamw

          Hello,

           

          no, that's not currently possible, but it would be a simple modification of the source code.

          If there's a good use case, I can include it in the distribution.

           

          Adam

          • 2. Re: Adding custom column to audit tables

            Hi Adam,

             

            We have a requirement to make audit logs tempor resistant so that if some one modifies audit tables directly we should be able to track it. For this we need to compute a hashvalue and store it in the audit table. Hence we require an additional column in the audit table. This is not a very common use case and therefore may not be added in the main distribution. It would be great if you can provide some pointers about the files that we need to modify so that we can make these changes at our end.

            • 3. Re: Adding custom column to audit tables
              adamw

              Hello,

               

              to map the column properly, lookin the MetadataGenerators.

              to calculate the values, modify the WorkUnits.

               

              Adam

              • 4. Re: Adding custom column to audit tables
                ashish.patel22

                Hi Adam,

                we tried to add hashcode column by making changes to the AuditMetadaGenerator which is working fine. Also modified WorkUnit code for adding hashcode column support. Inside the AuditEventListener methods postInsert and postUpdate to calculate the hashcode we are fetching the property values of the entity, below is the snippet for the same :-

                -- >

                Object[] propertyValues = event.getPersister().getPropertyValues(event.getEntity(), EntityMode.POJO);

                -- >

                 

                Writing above code causes exception while postFlush() on collection entries. here is the exception which is thrown from org.hibernate.engine.CollectionEntry class "collection [" + collection.getRole() + "] was not processed by flush()".

                Can you please put some light on what is going wrong here ?

                 

                Thanks in advance,

                Ashish

                • 5. Re: Adding custom column to audit tables
                  ashish.patel22

                  Hi Adam,  can you please provide some input, I need entity tuple values for hashcode calculation and not the collection entities but this way all the collection entities are getting initialized and creating problem as there are neither marked as ignored nor they are marked processed at the time of postFlush validation. Is there better way I can access only tuple values of an entity ?   Regards, Ashish

                  • 6. Re: Adding custom column to audit tables
                    adamw

                    Hello,

                     

                    well, basically you can't load anything new, which mostly means you can't fetch associated collections. I don't know your use case but including related entities in the hashcode can lead to very long chains of loading entities and possibly even loops.

                     

                    Adam

                    • 7. Re: Adding custom column to audit tables
                      ashish.patel22

                      Hi,

                      as a solution the approach I am following here is fetching value objects of all the non-collection type properties of an entity. Here is the code snippet for the same,

                             Type[] propertyTypes = event.getPersister().getPropertyTypes();            

                                String[] propertyNames = event.getPersister().getPropertyNames();            

                                propertyValues = new Object[propertyTypes.length];           

                                int i = -1;            

                                int j = -1;            

                                for (Type type : propertyTypes) {                

                                     ++j;                

                                     if (!type.isCollectionType()) {                  

                                          propertyValues[++i] = event.getPersister().getPropertyValue(event.getEntity(), propertyNames[j],  EntityMode.POJO);

                                     }           

                                }            

                                hashCode = getHashCode(propertyValues);

                       

                      This has resolved the above mentioned issue. Consequently I encountered another problem with api -

                      public AuditWorkUnit merge(ModWorkUnit second) () where the hashcode value is getting lost, so need to provide hashcode support there.

                       

                      -Ashish

                      • 8. Re: Adding custom column to audit tables
                        adamw

                        So what's the problem with the API?

                         

                        Adam

                        • 9. Re: Adding custom column to audit tables
                          ashish.patel22

                          The constructor chain called from mentioned API merge(ModWorkUnit second) overrides the hashcode value to blank. This was causing insertion of null to hashcode column in some of the Audit tables. Here is code snippet from AddWorkUnit -

                            public AuditWorkUnit merge(ModWorkUnit second) {
                                  return new AddWorkUnit(sessionImplementor, entityName, verCfg, id, second.getData());
                              }
                              public AddWorkUnit(SessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg, Serializable id, Map<String, Object> data) {
                                  super(sessionImplementor, entityName, verCfg, id);
                                  this.data = data;
                              }

                          Now even if data map from old WorkUnit has valid hashcode value, the super constructor will set the hashcode to blank which in turn will override the value in the data map to blank in method fillDataWithId(). Here is the code snnipet from AbstractAuditWorkUnit -

                            protected AbstractAuditWorkUnit(SessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg, Serializable id) {
                                  **********************************
                                  this.hashCode = "";
                              }
                              protected void fillDataWithId(Map<String, Object> data, Object revision, RevisionType revisionType) {
                                 ***********************************
                                  data.put("hashCode",hashCode);
                              }

                          To fix it I have written another overloaded constructor of AddWorkUnit (making the old one of no use, can be removed) where we are taking care of hashcode value from the old work unit to the new one.

                          -Ashish