Application Security Testing: An Integral Part of DevOps
The Enterprise Library 2.0 (EL2) is the second major release of the robust frameworks released by the Microsoft Patterns and Practices team. At the time this article was written, EL2 is a "Community Technology Preview (CTP)", so features are subject to change.
EL2 consists of six main application blocks: Logging and Instrumentation, Caching, Data Access, Cryptography, Security, and Exception Handling. Along with the application blocks, EL2 is built on a number of core components, which can be consumed by the general public, but are primarily used internally by the application blocks. These core components can be classified as: Configuration, Instrumentation, and the ObjectBuilder. In the previous version of the Enterprise Library, Configuration was the seventh application block. In EL2, the functionality has been replaced by the .NET 2.0 System.Configuration namespace and has been moved into the core architecture.
Although EL2 will ship with a series of excellent "QuickStart" applications, these quick starts don't always explore all the features and have been known to lack sufficient documentation. In addition, logging (for example, debug, trace, error, and so on) is far from standardized in most organizations, making it important to have as much content on the subject as possible. For example, a number of organizations have multiple ASP.NET applications that all log information differently.
The Logging Application Block and EL2 are not turnkey solutions; however, they provide people with a mechanism to create a unified logging strategy. The goal of this article is to investigate some basic logging scenarios, explain and define some of the required terminology, and help you take those first steps to more efficient logging.
Major Changes in the Logging Block
There are too many changes in the Logging Application Block between the Enterprise Library (EL1) and EL2 to cover in this short article, but I want to highlight some of the major changes in the Logging Application Block.
First, the previous version of the Logging Application Block (in fact, most of the original version of EL1) was based on Avanade's ACA.NET framework. The word "based" is used very loosely, because in many cases the only change between ACA.NET and EL1 is the namespace. Although ACA.NET and EL1 are both great pieces of code, EL2 has simplified the logging strategy and has aligned better with the .NET 2.0 framework.
For example, Trace Listeners (A.K.A. LogSinks in previous versions) were custom code. In the new version, they derive from the very established TraceListener class in the System.Diagnostics namespace. Additionally, the frequently used LogEntry class now supports multiple categories. This may not sound like a big deal; however, this feature allows you to create a more standardized logging policy across applications. Multiple categories provide you with the ability to log different event types (for example, debug, audit, and so forth) specified in different application tiers (as in UI, Business, and the like) to different locations (for example, database, text, and so on), a big improvement from previous versions.
Along with the code improvements, the new logging application block has also simplified the "strategy" aspect. This was done by eliminating the concept of "distribution strategies" that were tedious and complicated in EL1. Instead, EL2 utilizes a far superior architecture of linking TraceListener classes together, which further aligns its design with the .NET 2.0 frameworks.
Logging Block Definitions
Before jumping into some examples of working with the EL2 Logging Application Block, you should first understand some terminology. The following is a summary of some of the definitions that you will need to know before using the Logging Application Block:
- Trace Listeners: Collects, stores, and routes messages
- Database Trace Listener: Logs to a Database
- E-mail Trace Listener: Logs to an E-mail
- Flat File Trace Listener: Logs to Flat File
- Formatted Event Log Trace Listener: Logs to Windows event log
- Msmq Trace Listener: Logs to MSMQ
- System Diagnostic Trace Listener: Logs to an event to an implementation of System.Diagnostic
- WMI Trace Listener: Logs a Windows Management Instrumentation event
- Custom Trace Listener: Logs to custom implementation of trace listener
- Filters: Provides log filtering based on pre-defined criteria
- Category Filter: Filter based on category
- Custom Filter: Extension point for creating custom filters
- Log Enabled Filter: Boolean to enable or disable log entries
- Priorty Filter: Filter based on priority
- Category Sources: This is the grouping mechanism used to classify a type of a message. A category can consist of multiple Trace Listeners or a single Trace Listener.
- Special Sources: Out-of-the-box sources for use in your application. As far as I can tell, you cannot remove or add to these, you can only wire them up for use in your application by specifying a Trace Listener. These can be used as a generic or general way of logging information if you want to avoid the generation of categories.
- Logging Errors & Warnings: Logs errors and warnings
- Unprocessed Category: Logs unprocessed categories
- All Events: Logs all events
- Formatters: Used to format a message
- Text Formatter: The default formatter comes with a customizable template driven system
- Binary Formatter: Used for object serialization/deserialization and in some queue scenarios
- Custom Formatter: Extension point
Jumping into Logging...
The best way to understand EL2's logging features is to jump right into a few examples. Let me set the stage a bit. The first example is very simple and its purpose is to get the wheels spinning; it demonstrates a simple database logging scenario. The second example extends the logging application block. Both examples demonstrate the extensibility points in EL2.
I assume you have the EL2 already. If not, you can obtain it from here. If you are using the December CTP, it is highly recommended that you build the EL2 configuration console prior to working with the examples in this article. The configuration console allows you to manipulate the configuration files through a simple GUI.
Along with the configuration console, the following examples require that you have Visual Studio 2005 and a MS SQL Server database installed. I used SQL 2005 Express, but I believe that, with some minor tweaks, any version should work.
EL2 Database Logging
To start the first example showing a simple database logging, navigate to the install directory of the Enterprise Library 2.0 and locate the "..\Src\Logging\TraceListeners\Database\Scripts\" directory. In this directory, you should find a batch file, "CreateLoggingDb.cmd," which will need to be executed (first ensure that SQL Server is running). This batch file executes the SQL script, which is located in the same directory and called LoggingDatabase.sql, creating the logging database natively used by EL2. The native logging database used in this example, "Logging," is very full-featured, but you do also have the choice to design and create your own database for use with the logging block.
Continue by creating a new C# Windows application in Visual Studio 2005; for ease of use, for this and all of the examples, Windows forms applications will be used. Add a new application configuration file, and open the Enterprise Library console.
EL2 is heavily driven through meta-data stored in application configuration files. The console creates a visual interpretation of the XML stored in these configuration files and makes it easy to manipulate the data. Navigate to File, Open Application, and select the app.config file that you just created. Another way to do this is to create the app config file in the EL2 console, but both methods have the same result.
The next step is to add a new node to the configuration by right-clicking (or navigating to "Action") in the console on the top-level node, and selecting "Logging Application Block."
Figure 1: The EL2 console is a straightforward GUI that reduces the time it takes to generate the required configuration information.
By default, the Logging application block gets configured with the EventLog trace listener enabled for the "General" category, and the "Special Source" category of "Logging Errors & Warnings." The event log is a fine logging store if you have a single server, but in most cases you want something more centralized that you can query against, such as a database.
For this example, you will need to remove all of the event log references by highlighting their nodes and going to "Action, Remove" or by right-clicking on their nodes and selecting "Remove." Add a new "Database Trace Listener" by highlighting the "Trace Listeners" node by right-clicking or going to "Action" again. You should see a new database trace listener and a new reference to the data access application block. The granular details about the data access block will be saved for another time, but do know that a new connection reference (which defaults to "Connection String") has been created. The setting attributes will need to be modified appropriately to reflect your database setup.
The next step is to associate the "Database Trace Listener" with the new database connection reference, and provide it a formatter; in this case, the default text formatter is used.
The final configuration step is to add a new category called "Audit" under "Category Sources" and reference the new "Database Trace Listener."
Rest assured, even though these steps are slightly time consuming, they are far simpler than editing the configuration files by hand. Downloading the example will help make sense of the process.
With the application configuration out of the way, the next step is very simple. Just add a reference in VS 2005 to Microsoft.Practices.EnterpriseLibrary.Logging, add the using statement (Using Microsoft.Practices.EnterpriseLibrary.Logging), and add the following code to a button:
LogEntry le = new LogEntry(); le.Categories.Add("Audit"); le.Message = "Testing our DB Logging"; le.EventId = 1234; le.Title = "Database Message"; le.Priority = 1; Logger.Write(le);