Microsoft & .NET.NETAuditing in SharePoint 2007

Auditing in SharePoint 2007

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Tracking the complex trail of information within an organization is a major task. To address this issue, Microsoft introduced Audit support possibilities in SharePoint 2007. Audit undertakes the verification and validation of systems, and then processes the results in automated technologies to guarantee the integrity and accuracy of the information. The Audit mechanism ensures that each activity in the system is saved in a repository.

Because SharePoint is Microsoft’s primary system to store information, it is essential that it includes a built-in Audit system. In legacy versions, SharePoint lacked a proper default system; although it was possible to program a kind of audit mechanism in SharePoint 2003, it was not a default component. SharePoint 2007 introduced a default system that covers Site Collections, Lists, Libraries, and includes an Object Model to implement custom applications if necessary.

Many companies have strict policies and guidelines related to storing records concerned with the flow and activity of information. With a nod to assuring enterprise transparency, governments require sophisticated tracing procedures to determine juridical responsibility. SharePoint Audit mechanism ensures that each activity that occurs at Site Collection, List/Library, Content Type, and Document/Item is stored in the database, with sufficient security to avoid alterations.

Although the Audit mechanism is a general SharePoint component, only Microsoft Office SharePoint Server (MOSS) has an interface to activate and configure it. Windows SharePoint Services (WSS) can duplicate the process, but developers need to program the appropriate interfaces to utilize it.

Auditing in MOSS

The Audit mechanism in MOSS is not activated by default. Go to Site actions, Site settings, Site collection Audit settings to activate at the Site Collection level.

Figure 1: Configuration of Audit for a Site Collection

At Site settings, you can reach the Informs Audit log reports page. The default Audit reports (elimination, modification, revision, and so forth) is displayed in Excel format; it’s also possible to define new custom reports. The Excel report has two tabs: one for a summary of the activities and a second for detailed information, including site and element identifiers, date, event type, and user.

To activate Audit at a Library level, from the configuration page of the Library or List use the Settings page, Information management policy settings, Define a policy…, ‘Ok, and Enable Auditing.

Figure 2: Configuration of Audit for a List or Library

Activity reports can be found in the same place as the Audit reports for the Site Collection.

It also is possible to activate Audit for Content Types. The procedure is the same as with Libraries: Create the Content type or select an existing one from the Content type gallery, use the Information management policy settings option, and create the policy.

Finally, Audit can be activated at a document or item level, but neither MOSS nor WSS have interfaces to activate, configure, or review them. In this instance, developers can use the Object Model to create an interface.

Programming Audit

The objects for Site Collection, Lists, and Items (SPSite, SPList, and SPListItem) each have a public property ‘Audit’ of the SPAudit type. This class permits total control over the respective Audit.

The class SPAudit has an interesting property, ‘AuditFlags’, making it possible to read or configure the events to be registered (read, change, delete) and the following four methods:

  • DeleteEntries: Eliminates all the entries in the Registery. To guarantee Audit integrity, the elimination is saved as a new activity that cannot be deleted. In this way, if records are removed, a permanent trace ‘saves’ the procedural history
  • GetEntries: Displays the Registry collection
  • Update: Saves changes made to a Registry
  • WriteAuditEvent: Writes a new entry in the Registry

To enumerate all the Audit entries of a Site, it is possible to use the method ‘GetEntries’ in this way:

SPSite mySite = new SPSite("http://ServerName");
SPAudit myAuditCol = mySite.Audit;
foreach (SPAuditEntry myEntry in myAuditCol)
{
   Console.WriteLine(myEntry.DocLocation + " - " +
      myEntry.Occurred.ToLongDateString()
      " - " + myEntry.UserId.ToString() + " - " +
      myEntry.Event.ToString());
}

In the code, after the creation of an object containing the Site Collection information and another object for the Audit entries, a loop reads each entry and prints some properties.

In a similar way, after creating the Audit object, it is possible to eliminate all its entries:

myAuditCol.DeleteEntries(DateTime.Now.AddMilliseconds(1)); 

The delete method uses as input parameters a future date and time, and the code uses the actual time plus a millisecond. Remember that this code generates a new entry in the Audit to register the elimination and is impossible to delete.

As explained earlier, SharePoint saves some default activities if it has been configured. The Object Model sanctions the creation of new types of entries using the method ‘WriteAuditEvent’. For example, to save a document modified by an unauthorized user, the exception can be trapped using an Event Handler or WorkFlow and registered in the Audit:

myAuditCol.WriteAuditEvent(SPAuditEventType.Custom,
   "NotAuthorized",
   "<myXml>Modification Not Authorized</myXml>”);

The code to detect the exception is not shown in the example, and the latest parameter may include all the information about the user and exception time. The method accepts three parameters: the event type (‘Custom’ in this case), the title, and the description of the event. Note also that the description has been written inside a ‘<Name>’ XML tag.

What You Can Achieve with Programming

MOSS and WSS lack interfaces to configure and see Audits at the document level, but the SharePoint Object Model provides the tools to manipulate them programmatically. The following example will show the creation of two Windows applications to configure Audit at a Document level, and to view the created registers.

Note: The source code (Visual Studio 2008) of the examples can be downloaded from this site.

The configuration program uses the names of the Site Collection and Document Library as input parameters and gives you the ability to configure the Audit level of each individual document in the Library.

Figure 3: Audit configuration program for documents in a Document Library

The OnLoad event in the program calls a routine that uses the names of Site Collection and Library to fill the Document ComboBox. Bear in mind that the code is only to explain the concepts of Audit programming and it is not sufficient for production code (doesn’t have any type of validation of try/catch statements, for example).

The possible event types can be found in the SPAuditMaskType enumeration, and using a loop can be displayed onscreen:

for (int
   intCounter = 0; intCounter <
      Enum.GetNames(typeof(SPAuditMaskType)).Count();
   intCounter++)
{
   clbAudit.Items.Add(Enum.GetNames(typeof(SPAuditMaskType))
   .ElementAt(intCounter));
}

‘clbAudt’ is a control of the type ‘System.Windows.Forms.CheckedListBox’. When one document has been chosen, the change event of the ComboBox calls the routine to read all the selected Audits and to show them onscreen:

SPSite mySite = new SPSite(txtMySiteURL.Text);
SPWeb myWeb = mySite.OpenWeb();
SPList myList = myWeb.Lists[txtLibraryName.Text];
SPListItem myItem = myList.Items.GetItemById(Convert.ToInt32
   (ddlDocs.SelectedIndex + 1));

if ((int)myItem.Audit.AuditFlags == -1)
{
   clbAudit.SetItemChecked(0, true);
}
else
{
   string myAuditBin = DecimalToBin((int)myItem.Audit.AuditFlags);
   if (string.IsNullOrEmpty(myAuditBin) == false)
   {
      for (int intCounter = myAuditBin.ToString().Length - 1;
         intCounter >= 0; intCounter--)
      {
         int myInversor = myAuditBin.ToString().Length -
            intCounter;
         if (myAuditBin.ToString().Substring(intCounter, 1) == "1"
      )
      clbAudi.SetItemChecked(myInversor, true);
   }
}
else
   clbAudit.SetItemChecked(15, true);
}

After creating the objects to contain the Site, Web, Listm and Document information, the ‘AuditFlags’ property generates the necessary information. The value ‘-1’ indicates that all the event types have been chosen for auditing, and if the value is null, no audit will occur.

The ‘AuditFlags’ property conserves the Audit values encrypted in the form of a binary ‘OR’ operation of each of the values of the ‘SPAuditMaskType’ enumeration converted to a decimal value. The variable ‘myAuditBin’ reads the decimal value, converts it to a binary value using the routine ‘DecimalToBin’ and then reads each bit one by one. If the bit is ‘1’, the correspondent element in the list is checked. Note that the binary value is read from the highest value using a loop in this direction.

The event of the save button keeps the data in a similar way, but reads the selected elements from the screen, encrypting them in the correct way and saving them in the property:

SPAudit myAuditItem = myItem.Audit;
if(clbAudit.GetItemChecked(0) == true)
   myAuditItem.AuditFlags = SPAuditMaskType.All;
else
{
   for (int intCounter = 1; intCounter < clbAuditar.Items.Count;
      intCounter++)
   {
      if (clbAudit.GetItemChecked(intCounter) == true)
         myAuditBin += "1";
      else
         myAuditBin += "0";
   }

   int myAuditDecimal = BinToDecimal(myAuditBin);
   myAuditItem.AuditFlags = (SPAuditMaskType)miAuditDecimal;
}
myAuditItem.Update();

By using the statement ‘For’, it is possible to read each check box onscreen, and build the string variable ‘myAuditBin’ again. The binary string is converted to the decimal equivalent using the routine ‘BinToDecimal’ and stores it in the ‘AuditFlags’ property. Finally, the ‘Update’ method persists the data in SharePoint. There are many algorithms to make the binary-to-decimal and decimal-to-binary conversions (a concatenation of OR operations, for example); the two routines presented are only for demonstration, and not to be used as an example of algorithms theory.

After the document has been configured to Audit the events, it also is necessary to review what has occurred. The second program displays the Audit registry of the chosen document:

Figure 4: Program to read the Audit registry of a document

Similar to the first program, the Site Collection and Library names are used to fill the ComboBox with documents, and the change event from the ComboBox runs the code to view the Audit:

lblMensage.Text = string.Empty;
dgvAudit.DataSource = null;
dgvAudit.Refresh();

SPSite mySite = new SPSite(txtMySiteURL.Text);
SPWeb myWeb = mySite.OpenWeb();
SPList myList = myWeb.Lists[txtLibraryName.Text];

if (ddlDocs.SelectedIndex >= 0)
{
   SPListItem myDoc = myList.Items.GetItemById
      (Convert.ToInt32(ddlDocs.SelectedIndex + 1));
   SPAuditQuery myAuditQuery = new SPAuditQuery(mySite);
   miAuditQuery.RestrictToListItem(myDoc);
   SPAuditEntryCollection myAuditColeccion =
      myList.Audit.GetEntries(myAuditQuery);

   DataTable myTable = CrearDataTable();

   if (myAuditColeccion.Count > 0)
   {
      foreach (SPAuditEntry myEntry in myAuditColeccion)
      {
         DataRow myLinea = myTabla.NewRow();
         myRow["Date"] = myEntry.Occurred.ToString();
         SPUser myUser = myWeb.SiteUsers.GetByID(myEntry.UserId);
         myLinea["User"] = myUser.Name;
         myLinea["Type Action"] = myEntry.Event.ToString();
         myTable.Rows.Add(myLinea);
      }

      dgvAudit.DataSource = myTable;
      dgvAudit.AutoResizeColumns();
   }
   else
      lblMessage.Text = "No audit information for this document";
}

DataGrid ‘dgvAudit’ and DataTable ‘myTable’ show the data onscreen. After creating the objects in the normal way, the code uses a query to find the specific data of the document. All the Audit entries of the Portal are saved in one table of the Content DataBase, and the ‘GetEntries’ method returns the entire Table content. By using the queries of the type ‘SPAuditQuery’ and the method ‘RestricToListItem’, it is possible to filter the data of the selected document.

The pertinent data can be read by using a loop to create each row in the DataTable. Finally, the DataTable is connected to the DataGrid, and parameters are configured to display it onscreen. A Label is used to indicate whether any events are available for the document.

Conclusion

Careful registration of information in a Portal can be vitally important to a company, not only internally but also for possible juridical consequences. SharePoint 2007 has the necessary infrastructure to gather and conserve the entries in a secure way. MOSS can configure Audits for some parts of the system and is able to generate reports in Excel spreadsheets. WSS has no interface for configuration or reporting, but the SharePoint Object Model provides the necessary tools to create, configure, and review Audits.

Download the Code

You can download the code for this article here.

About the Author

Gustavo Velez is a MCSD Senior Application Developer for Winvision (http://www.winvision.nl), a Microsoft Gold Partner in the Netherlands. He has many years of experience developing Windows and Office applications, and more than five years of daily programming experience with SharePoint. The author’s articles can be found in many of the leading trade magazines in English, Dutch, and Spanish. He is also pleased to be Webmaster of http://www.gavd.net/servers, the only Spanish-language site dedicated to SharePoint. Spanish-language readers may want to consult Velez’s new book, Programación con SharePoint 2007 (http://www.dotnetmania.com/Libros/index.html).

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories