tnicolaysen / ConfigRemedy

1 stars 0 forks source link

Keep an audit log #2

Open tnicolaysen opened 10 years ago

tnicolaysen commented 10 years ago

As a user of the configuration system I want to see who changed what So that I can review this in case of any problem

(WIP)

As an official auditer auditing an enterprise I want to see proof of what changes has been made to certain configuration properties So that I can perform an audit

Details

If the system propagates events like SettingCreated( ...), SettingDeleted(...), SettingChanged(...) a component can subscribe to these and keep a proper audit log.

Proposed format for audit log:

public struct SettingHistory
{
    public string Who { get; set; }
    public ChangeType What { get; set; }
    public DateTime When { get; set; }
    public string Where{ get; set; }
    public string From { get; set; }
    public string To { get; set; }
}
evgenyb commented 10 years ago

I think we should treat audit as autonomous service that knows nothing about domain. API / domain also should know nothing about audit. API (or domain actually) just publishes domain events and Audit subscribes to them and persists them.

For instance we can have the following events:

Each event should contain the information about who did the change, when and what kind of change. The depending on the event type event can contain both previous version and new versions, or just one - current version.

Here are some code samples...

public class AuditEvent<T> where T : IDomainEntity
{
        public AuditEvent(T @from, T to, string who, DateTime when, ChangeType what)
        {
            From = @from;
            To = to;
            Who = who;
            When = when;
            What = what;
        }

        public T From { get; protected set; }
        public T To { get; protected set; }
        public string Who { get; protected set; }
        public DateTime When { get; protected set; }
        public ChangeType What { get; set; }
}

public class ApplicationCreatedEvent : AuditEvent<Application>
{
    public ApplicationCreatedEvent(Application to, string who, DateTime when) : 
        base(null, to, who, when, ChangeType.Created)
    {}
} 

public class ApplicationUpdatedEvent : AuditEvent<Application>
{
    public ApplicationUpdatedEvent(Application @from, Application to, string who, DateTime when) : 
        base(@from, to, who, when, ChangeType.Edited)
    {}
}

public interface IDomainEntity
{
}

[UsedImplicitly]
public class Application : IEquatable<Application>, IDomainEntity
{
  ...
}

then from api / repository / domain when events occur we publish these events. For instance when new application is created we should publish ApplicationCreatedEvent.

private dynamic CreateApplication()
    {
        var app = this.Bind<Application>(a => a.Id);

        if (GetApplication(_session, app.Name) != null)
        {
            return new TextResponse(HttpStatusCode.Forbidden, "Duplicates are not allowed")
            {
                ReasonPhrase = "Duplicates are not allowed"
            };
        }

        _session.Store(app);
        _session.SaveChanges();

        _bus.Publish(new ApplicationCreatedEvent(app, userId, DateTime.UtcNow));

        return Negotiate
            .WithModel(app)
            .WithHeader("Location", Request.Path + app.Name)
            .WithStatusCode(HttpStatusCode.Created);
    }

Then Audit "service" subscribes to these events and persists them into audit log repository. Audit service can be hosted inside the same process and then handling of the events will happen synchronously. Or we can use some sort of "real" message bus with queues and process them asynchronously.