Doug,

Having a global hook for supplying the credentials may be the way to go
but I would first like to explore using the config file to attach an
object to a property on a specified appender.

This would allow the credential object to be specified for each appender
that supported credentials.
A user could write something like this in the config file:

<appender type="log4net.Appender.FileAppender">

        <credential type="log4net.Util.WindowsCredential">
                <username value="DOMAIN\User"/>
                <password value="****"/>
        </credential>

        ...
</appender> 

Obviously we would have other implementations of IExternalCredential
that would not encourage users to embed system passwords in plain text
files, but you see how it could instead specify registry keys to read.
Alternatively it could be a type specified by the application developer
which retrieves the credentials from the calling application.

<appender type="log4net.Appender.FileAppender">

        <credential type="MyApp.MyCredential, MyAssembly" />

        ...
</appender>

What do you think?

Another question is where in the Appender inheritance hierarchy do we
put the credential? We could put it only onto classes that require it or
we could put it on to the AppenderSkeleton and just let the appenders
decide to use it or not. Putting it on the actual appenders that use it
will mean that users won't get confused as to why the property exists on
the appenders that don't use it.

I have thought long and hard about the API syntax for the
IExternalCredential. I think that I prefer the C# using syntax. i.e.
where the Impersonate() method returns an IDisposable instance. In the
default or null case this work well because if Impersonate() returns
null to the using block this does not cause a problem. I generally like
the syntax:

protected void RollFile(string fromFile, string toFile) 
{
  ...
  using(credential.Impersonate())
  {
    target.Delete();
  }
}

In the default case this should be fast because Impersonate would return
null. By default the credential object would be a NullCredential
singleton instance. This is probably slightly slower than checking
against null, but you don't really know how good a job the JIT will do.

Returning an object to do the revert will be slower than calling a
Revert method directly, however it should not be significant relative to
the cost of doing some sort of impersonation.

I'm not sure that we have got the terminology quite right. While I don't
necessarily want to just use the MS Windows terminology it seems
slightly odd to impersonate a credential as in windows you would
impersonate an identity. We either need to use
ExternalIdentity.Impersonate() or Identity.Impersonate() or
ExternalCredential.Enable() / Activate() something like that maybe.

What do you think?

Nicko


> -----Original Message-----
> From: de la Torre, Douglas [mailto:[EMAIL PROTECTED] 
> Sent: 25 September 2004 00:43
> To: Log4NET Dev
> Subject: RE: Allow log4net to impersonate a user via 
> app-specific mechanism.
> 
> Hi All,
> 
> Here's some sample code to illustrate how impersonation could 
> easily be added to the appender classes.  The goal would be 
> to let the application that consumes log4net be able to 
> handle the impersonation when needed.
> The sample's I'm including use an attribute called 
> ImpersonationFactoryAttribute that log4net can check for on 
> the user's DLL to let that DLL override the factory that 
> supplies objects which do the impersonation.
> 
> Here's how this would work.
> 
> 1)  User adds this attribute to their DLL in the 
> AssemblyInfo.cs file, and specify the type of factory to read 
> from their own DLL
> 
> [assembly:
> log4net.Appender.Impersonation.ImpersonationFactoryAttribute(I
> mpersonati
> onFactoryType=typeof(LoggingTestApp.MyImpersonationFactory))]
> 
> 2)  In the user DLL, the factory class would look something like this
> 
>       public class MyImpersonationFactory : IImpersonationFactory
>       {
>               public IExternalCredential
> Create(log4net.Appender.IAppender appender)
>               {
>                       if( appender is
> log4net.Appender.RollingFileAppender  || appender is 
> log4net.Appender.FileAppender )
>                       {
>                               return new MyImpersonator();
>                       }
>                       return null;
>               }
>       }
> 
> 3)  The appender would add code to instantiate the 
> IExternalCredential object to use for impersonation.  For 
> example, in RollingFileAppender
> 
>               override public void ActivateOptions() 
>               {
>                       this.credential =
> Impersonation.ImpersonationFactory.Instance.Create( this );
> 
>                       ...
>               }
> 
> 4)  The appender would impersonate around operations that 
> access system resources.  For example, when the 
> RollingFileAppender tries to delete a
> file:
> 
>               protected void RollFile(string fromFile, string toFile) 
>               {
>                       ...
> 
>                       LogLog.Debug("RollingFileAppender: 
> Deleting existing target file ["+target+"]");
>                       try
>                       {
>                               this.credential.Impersonate();
>                               target.Delete();
>                       }
>                       finally
>                       {
>                               this.credential.Revert();
>                       }
> 
>                       ...
>               }
> 
> This is the basic mechanism, and you can see how easy this is 
> both from the external DLL that consumes log4net to extend, 
> as well as how simple it is for log4net to support.
> 
> Note the above code is using a NullImpersonation class, which 
> has empty Impersonate and Revert methods, allowing us to 
> eliminate null checks for better readability.  Alternatively, 
> we could make the code add the null check guard clauses, in 
> which case the appender code above would change to this:
> 
>               protected void RollFile(string fromFile, string toFile) 
>               {
>                       ...
> 
>                       LogLog.Debug("RollingFileAppender: 
> Deleting existing target file ["+target+"]");
>                       try
>                       {
>                               if( null != this.credential )
> this.credential.Impersonate();
>                               target.Delete();
>                       }
>                       finally
>                       {
>                               if( null != this.credential )
> this.credential.Revert();
>                       }
> 
>                       ...
>               }
> 
> What do you all think of this approach?  
> 
> This seems like a clean way to let external code handle the 
> impersonation.  For example, we would like this capability so 
> we can impersonate as a single user for file I/O operations, 
> thus allowing us to simplify our deployments for an ASP.NET 
> application.  Currently, any site user must have full 
> permissions in the log directory.  A change like this to the 
> appenders would allow us to increase security and simplify 
> management of the logging folder by impersonating as a single user.
> 
> Can we go ahead with adding this into the project?  If this 
> approach seems sound, the files I've attached can be added to 
> CVS first, then once added, the next stage of work in the 
> appenders could begin, changing the resource access to 
> account for the impersonation calls.
> 
> I appreciate your feedback and consideration!
> 
> -Doug
> 

Reply via email to