Section 10.14. Security Auditing


10.14. Security Auditing

I will end this chapter with presenting a useful feature WCF supports called security audits. As the name implies, a security audit is a logbook of the security-related events in your services. WCF can log authentication and authorization attempts, their time and location, and the client's identity. The class ServiceSecurityAuditBehavior governs auditing and is listed in Example 10-30 along with its supporting enumerations.

Example 10-30. The ServiceSecurityAuditBehavior class

 public enum AuditLogLocation {    Default,//Decided by the operating system    Application,    Security } public enum AuditLevel {    None,    Success,    Failure,    SuccessOrFailure } public sealed class ServiceSecurityAuditBehavior : IServiceBehavior {    public AuditLogLocation AuditLogLocation    {get;set;}    public AuditLevel MessageAuthenticationAuditLevel    {get;set;}    public AuditLevel ServiceAuthorizationAuditLevel    {get;set;}    //More members } 

ServiceSecurityAuditBehavior is a service behavior. The AuditLogLocation property specifies where to store the log entries, in the application logfile or in the security log, both in the event log on the host computer. The MessageAuthenticationAuditLevel property governs the authentication audit verbosity. For performance's sake, you may want to audit only failures, or both success and failures. For diagnostic purposes you can also audit successful authentication. The default value of MessageAuthenticationAuditLevel is AuditLevel.None. Similarly, you use the ServiceAuthorizationAuditLevel property to control authorization audit verbosity, and it is also disabled by default.

10.14.1. Configuring Security Audits

The typical way of enabling a security audit is in the host config file, by adding a custom behavior section and referencing it at the service declaration, as shown in Example 10-31.

Example 10-31. Configuring a security audit

 <system.serviceModel>    <services>       <service name = "MyService" behaviorConfiguration = "MySecurityAudit" >          ...       </service>    </services>    <behaviors>       <serviceBehaviors>          <behavior name = "MySecurityAudit">             <serviceSecurityAudit                auditLogLocation = "Default"                serviceAuthorizationAuditLevel  = "SuccessOrFailure"                messageAuthenticationAuditLevel = "SuccessOrFailure"             />          </behavior>       </serviceBehaviors>    </behaviors> </system.serviceModel> 

You can also configure security auditing programmatically by adding the behavior at runtime to the host before opening it. Similar to adding other behaviors programmatically, you can check that the host does not already have an audit behavior, to avoid overriding the config file, as shown in Example 10-32.

Example 10-32. Enabling a security audit programmatically

 ServiceHost host = new ServiceHost(typeof(MyService)); ServiceSecurityAuditBehavior securityAudit =                    host.Description.Behaviors.Find<ServiceSecurityAuditBehavior>( ); if(securityAudit == null) {    securityAudit = new ServiceSecurityAuditBehavior( );    securityAudit.MessageAuthenticationAuditLevel = AuditLevel.SuccessOrFailure;    securityAudit.ServiceAuthorizationAuditLevel = AuditLevel.SuccessOrFailure;    host.Description.Behaviors.Add(securityAudit); } host.Open( ); 

You can streamline the code in Example 10-32 by adding the SecurityAuditEnabled Boolean property to ServiceHost<T>:

 public class ServiceHost<T> : ServiceHost {    public bool SecurityAuditEnabled    {get;set;}    //More members } 

Using ServiceHost<T>, Example 10-32 is reduced to:

 ServiceHost<MyService> host = new ServiceHost<MyService>( ); host.SecurityAuditEnabled = true; host.Open( ); 

Example 10-33 shows the implementation of the SecurityAuditEnabled property.

Example 10-33. Implementing the SecurityAuditEnabled property

 public class ServiceHost<T> : ServiceHost {    public bool SecurityAuditEnabled    {       get       {          ServiceSecurityAuditBehavior securityAudit =                         Description.Behaviors.Find<ServiceSecurityAuditBehavior>( );          if(securityAudit != null)          {             return securityAudit.MessageAuthenticationAuditLevel ==                                                         AuditLevel.SuccessOrFailure                    &&                    securityAudit.ServiceAuthorizationAuditLevel ==                                                       AuditLevel.SuccessOrFailure;          }          else          {             return false;          }       }       set       {          if(State == CommunicationState.Opened)          {             throw new InvalidOperationException("Host is already opened");          }          ServiceSecurityAuditBehavior securityAudit =                         Description.Behaviors.Find<ServiceSecurityAuditBehavior>( );          if(securityAudit == null && value == true)          {             securityAudit = new ServiceSecurityAuditBehavior( );             securityAudit.MessageAuthenticationAuditLevel =                                                        AuditLevel.SuccessOrFailure;             securityAudit.ServiceAuthorizationAuditLevel =                                                        AuditLevel.SuccessOrFailure;             Description.Behaviors.Add(securityAudit);          }       }    }    //More members } 

In the get, the SecurityAuditEnabled property accesses the description of the service and looks for an instance of ServiceSecurityAuditBehavior. If one is found, and if both the authentication and the authorization audits are set to AuditLevel.SuccessOrFailure, then SecurityAuditEnabled returns TRue, and false otherwise. In the set, the property enables the security audit only if the description does not contain a previous value as a result of a config file. If no prior behavior is found, SecurityAuditEnabled sets both the authentication and authorization audits to AuditLevel.SuccessOrFailure.

10.14.2. Declarative Security Audit

You can also write an attribute that surfaces the security audit options at the service level. I chose to add that support in the form of a single Boolean property on the SecurityBehavior attribute called SecurityAuditEnabled:

 [AttributeUsage(AttributeTargets.Class)] public class SecurityBehaviorAttribute : Attribute,IServiceBehavior {    public bool SecurityAuditEnabled    {get;set;}    //More members } 

The default of SecurityAuditEnabled is falseno security audit. Using the property complements the rest of the declarative security model; for example:

 [SecurityBehavior(ServiceSecurity.Internet,UseAspNetProviders = true,                   SecurityAuditEnabled = true)] class MyService : IMyContract {...} 

Example 10-34 shows how that support was added to the SecurityBehavior attribute.

Example 10-34. Implementing a declarative security audit

 [AttributeUsage(AttributeTargets.Class)] public class SecurityBehaviorAttribute : Attribute,IServiceBehavior {    bool m_SecurityAuditEnabled;    public bool SecurityAuditEnabled //Accesses m_SecurityAuditEnabled    {get;set;}    void IServiceBehavior.Validate(ServiceDescription description,                                   ServiceHostBase serviceHostBase)    {       if(SecurityAuditEnabled)       {          ServiceSecurityAuditBehavior securityAudit = serviceHostBase.Description.                                     Behaviors.Find<ServiceSecurityAuditBehavior>( );          if(securityAudit == null)          {             securityAudit = new ServiceSecurityAuditBehavior( );             securityAudit.MessageAuthenticationAuditLevel =                                                        AuditLevel.SuccessOrFailure;             securityAudit.ServiceAuthorizationAuditLevel =                                                        AuditLevel.SuccessOrFailure;             serviceHostBase.Description.Behaviors.Add(securityAudit);          }          //Rest same as Example 10-20       }    }    //Rest of the implementation } 

The Validate( ) method of IServiceBehavior enables auditing using the same verbosity level as ServiceHost<T>, while avoiding overriding the config file.




Programming WCF Services
Programming WCF Services
ISBN: 0596526997
EAN: 2147483647
Year: 2004
Pages: 148
Authors: Juval Lowy

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net