Automated Coder

Exploring the Code of CruiseControl.Net

Security Enhancements 3: Auditing

Posted by Craig Sutherland on 10 October, 2008

You Did What?!

Authentication and authorisation can be looked at as proactive parts of security – they stop people from doing things that they shouldn’t. Auditing is more of a reactive process – it looks at what has happened and allows an administrator to change settings based on past actions. While being proactive is great, auditing is often critical to understanding why something happened that shouldn’t have. Therefore being able to audit events is often a critical part of security.

This post will look at modifying the security framework to enable adding audit loggers to the system.

The Plan

Since people will have different auditing requirements, I’m going to allow people to add audit loggers as part of the configuration. Audit loggers will be optional and they can also be specified as many times as required.

Ideally audit loggers should be available at both the project and the server level, but for my initial changes I’m only going to add them at the server level. Later on I may look at also adding them to the project level, but as this will add to the overall complexity I’m just going to handle the server level.

Managing the Event

The starting point for this change is ISecurityManager. I have added a new method called LogEvent() – this will send a log request onto a set of event loggers (more on these to come). The signature for this event is as follows:

void LogEvent(string projectName,
     string userName,
     SecurityEvent eventType,
     SecurityRight eventRight,
     string message);

Yes, there is a large amount of arguments. The reason behind this is to provide the audit loggers with as much information as possible, so they can decide what to do with the information. To allow auditing of additional event types (e.g. Login/Logout), I added a new enumeration – SecurityEvent. Initially I used SecurityPermission, but that only had a limited range of possibilities. SecurityEvent allows for the following events:

  • Login
  • Logout
  • ForceBuild
  • AbortBuild
  • StartProject
  • StopProject
  • CancelRequest
  • SendMessage

This covers all the current events that occur in security – later this list will probably expand.

Next, to actually log an event I modified CruiseServer to record events. Since CheckSecurity() is an important method, I added an eventType parameter to the args. Then, based on the result the correct event log can be logged. I also modified this method to log the correct type of event. If the args for LogEvent() are known, then these are added – otherwise they are set to null.

To record login and logout events I modified SessionSecurityManager. These events are logged in the Login() and Logout() methods – mainly because these are the points where the user names are known.

Logging the Event

After I modified ISecurityManager, I modified NullSecurityManager and SessionSecurityManager to include the new method. Initially these changes didn’t actually do anything – for NullSecurityManager it will remain this way. But for SessionSecurityManager I actually want it to do something. To handle this I added a new interface – IAuditLogger. This has the same LogEvent() method as ISecurityManager, but it is where the events will be actually logged. The idea is people can write implementations of this interface to log to whatever logs they want.

Next I’ve added a property to SessionSecurityManager that gets/sets an array of IAuditLogger - which has a ReflectorProperty of audit. Now admins can configure their servers to include as many or as few audit loggers as they like (by default it is an empty array).

Finally, I implemented the LogEvent() method in SessionSecurityManager. This merely iterates through the array and calls LogEvent() on each audit logger.

The Actual Worker

Now it’s time to actual log some audit events.

To help with future logger I’ve added a base class called AuditLoggerBase. This has two reflected properties – LogSuccessfulEvents and LogFailureEvents. This is to allow which events should be logged (later I might expand it to have more fine-grained control). I also added the LogEvent(). This implementation checks the two properties and if required calls a protected abstract method called DoLogEvent() – yes, this is the method to perform the actual logging.

My first implementation of this class is FileXmlLogger. This inherits from AuditLoggerBase and implements FileXmlLogger. It has a ReflectorType of xmlFileAudit, so it can be added to the configuration. It has a reflected property – AuditFileLocation to allow configuring the location of the audit file. This will default to “SecurityAudit.xml”.

Finally I implemented DoLogEvent(). This generates an XML document and adds all the available informaton. This is then written to the audit file – simple.

Where to From Here?

This now includes the basic ability to log security events. However, it is just that – basic. There are a number of enhancements that I can think of, which I might do sometime. These are:

  • Additional loggers (e.g. e-mail, event log, XMPP, etc.)
  • Additional log formats (e.g. plan text, etc.)
  • An ability to read an audit log
  • More fine-grained control over which events are logged

But, other than these, it is working nicely :)

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>