Auditing question

Posts   
 
    
jovball
User
Posts: 441
Joined: 23-Jan-2005
# Posted on: 07-Feb-2014 19:15:45   

The Information Security team for my agency is imposing new requirements for application logging/audit trails. I am trying to think how I can meet these requirements. (And let me start by saying that I think the security team does not understand how much audit data they are going to generate with these requirements.)

The application is an Intranet ASP.NET application. At this time, it has only two physical tiers, the Web server and the database server. We have plans to add a services layers using either WebAPI or ServiceStack.

We will need to record data changes along with user information including the user name and the workstation IP. I think that part is manageable using the Dependency Injection auditor.

The other thing that we will need to record is information about data that was viewed (database reads) on specific web pages in the application. For example, if a page has a search grid with 20 rows that show a client birthdate, we will need to write 20 audit rows. Another page that uses the same Entity but does not the birthdate will not need to write any audit data.

Any process that reads data (entities) but does not show it on the web page would also NOT need to write any audit data.

Essentially, I need a way to make the auditing conditional based on the calling page rather than the Entity class.

Any thoughts on how I might accomplish this would be appreciated.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 08-Feb-2014 01:22:38   

From what you are saying I can point out a couple comments/recommendations:

  • The Auditor class should help you in your second scenario as well (read operations). You should:

  • Discriminate the Auditor using the decorators mentioned in the documentation to filter just those entities/interfaces you want to be audited.

  • Use the AuditLoadOfEntity method on your Auditor.

  • To discriminate on the read field you could check whether the data is there on your AuditLoadOfEntity method. OR, you could use AuditEntityFieldGet instead of AuditLoadOfEntity. that way you audit just when that field is read This is more general, but tricky, because you could read some involved property in the GUI and not showing it.

  • Use [urldesription="DependencyInjection Scopes"]http://llblgen.com/documentation/4.1/LLBLGen%20Pro%20RTF/hh_goto.htm#Using%20the%20generated%20code/gencode_usingdi.htm#discopes[/url] into your GUI. This allows you to decide when and how to audit right into your GUI code. So, if you know that some page will show the involved auditable field, then activate your scope. You can generalize it if you write your own attribute an apply it just to the involved page controllers (if using MVC).

  • Another idea is to pass some context information into your auditor. Like when you use the Identity object, pass some context to your auditor to know whether or not it should be store the audit trail.

So there you have some ideas to implement this. Please keep us posted on the way you choose and how you did it.

Hope that helps.

David Elizondo | LLBLGen Support Team
jovball
User
Posts: 441
Joined: 23-Jan-2005
# Posted on: 29-Mar-2016 23:29:13   

I hope it's OK to revive an old thread when it is my own. I'm coming back to put in some information that might help someone else in a similar question. Here is what I did to solve this requirement.

If I'm doing something silly here, I'll count on Frans, Daelmo and Walaa to provide some better guidance. smile

1) Create a separate project with references to your DAL.

2) Create auditor classes. Here is a partial code snippet. Look at the LLBLGen demo project for a full example. You'll need to create a similar class for each interface or entity that you need to audit.


namespace MyDatabaseAuditors.Auditors
{
    /// <summary>
    /// Auditor class for a specific type or interface.
    /// Log audit info to the database using LLBLGenPro Auditor Dependency Injection.
    /// </summary>
    /// <remarks>
    /// This Auditor is injected to a specific entity instances. 
    /// You could use a specific interface instead or use IEntity to include all entity types.
    /// For example:
    /// [DependencyInjectionInfo(typeof(IMyAuditInterface), "AuditorToUse")]
    /// </remarks>
    [DependencyInjectionInfo(typeof(CustomerEntity), "AuditorToUse")]
    [Serializable]
    public class CustomerAuditor : AuditorCommon
    {
        // add overrides for the actions you would like to audit
        public override void AuditDeleteOfEntity(IEntityCore entity)
        {
    //audit related code here, see the LLBLGen demos for examples.
    }
        
        public override void AuditUpdateOfEntity(IEntityCore entity)
        {
    //audit related code here, see the LLBLGen demos for examples.      
    }       
        
    //and so on
        

    public override System.Collections.IList GetAuditEntitiesToSave()
    {           
    // Note: If your target database type (e.g. SQL Server, Oracle, DB2, MySQL) for the audit data 
        // is not the same as the source database, persist the audit data directly here and return null from this method.
    // Otherwise, see the LLBLGen demo for a functional example.

    }       
    }
}       

3) The project I was working on was a WebForms project and needed to be able to target auditing some entities on various pages but not other entities (as well as some fields but not others).

This was handled using a class to define the scopes. Imagine that the page is using four entities but we are only interested in two of them, CustomerEntity and OrderEntity. Here is the complete code example for that.


namespace MyDatabaseAuditors.AuditorScopes
{
    public class CustomerOrdersAuditorInjection : DependencyInjectionScope
    {
        //specify the two auditors we want to use in a specific situation
        protected override void InitializeScope()
        {
            AddInjectionInfo(typeof(CustomerAuditor), typeof(CustomerEntity),
                "AuditorToUse", DependencyInjectionTargetKind.Hierarchy,
                DependencyInjectionContextType.NewInstancePerTarget);
                
            AddInjectionInfo(typeof(OrderAuditor), typeof(OrderEntity),
                "AuditorToUse", DependencyInjectionTargetKind.Hierarchy,
                DependencyInjectionContextType.NewInstancePerTarget);               
        }
    }
}

4) Instantiate the AuditorInjection class on the WebForms page to activate it. Nothing else needs to be done. Any CustomerEntity or OrderEntity called by this page will be audited. Note that this approach does not need anything defined in web.config.


private void Page_Init(object sender, EventArgs e)
{
    var auditor = new CustomerOrdersAuditorInjection();
}

Now that it's working, it seems like magic but I got some significant help from Frans and Walaa over the last several weeks. Much of this is in the documentation but not in the step-by-step format that I needed at the time.

Walaa avatar
Walaa
Support Team
Posts: 14986
Joined: 21-Aug-2005
# Posted on: 30-Mar-2016 19:34:29   

Just one comment. You don't need DependencyInjection Attribute on the Auditor if you are going to instantiate it from code. i.e. DIScopes are doing the same thing.

When to use the DI Attributes? Only when you will set DI info in a config file, for manual or automatic discoverability. Dependency Injection