Monday, September 25, 2017

Custom Security on NServiceBus Endpoints

See how to enhance the security on NServiceBus endpoints by using generic and elegant code.


On a previous post, we discussed why as developers, it's important to consider security. Then we discussed how to secure our Asp.Net MVC application using a mix of custom role/claims providers. Today well's see how we can protect our NServiceBus endpoints.

NServiceBus

NServiceBus (NSB) is a messaging and workflow for .NET and .NET Core that,
Supports a variety of messaging patterns and workflows on multiple transports like MSMQ, RabbitMQ, Azure, and Amazon SQS. Developers focus on core logic, fully abstracted from the underlying infrastructure. Runs on .NET or .NET Core on Windows, Linux, or in Docker containers.
In other words, It helps us separating the concerns in our application, create simpler services using distributed messaging, simplify our workflow, easy to test and helping us implement interesting design patterns like CQRS.

Securing NserviceBus Endpoints

But how could we integrate a robust, generic security authorization in a backend?

On previous post we discussed how to implement SecurityController, a db-independent security mechanism to our Asp.Net website. In order to use it in our business layer, we need to inject its dependencies (roles and groups) via its Init factory method described below:
public class SecurityController
{
    public static void Init(List<Role> roles, List<Group> groups)
    {
        allRoles = roles ?? new List<Role>();
        allGroups = groups ?? new List<Group>();
        allPerms = allRoles.SelectMany(r => r.Permissions).Distinct().ToList();
    }
}
How would we integrate our custom groups and roles in the NSB backend?

NServiceBus.INeedInitialization

Within NSB, we can use INeedInitialization interface to hook our code in the NSB initialization pipeline. By using INeedInitialization you are supposed to implement this inerface:
public void Customize(BusConfiguration busConfiguration)

Our custom SecurityRegistry

When we initialize our NSB endpoint, we know that NSB will invoke classes that implement that interface, including our own SecurityRegistry:
 public class SecurityRegistry : INeedInitialization
{
    public void Customize(BusConfiguration busConfiguration)
    {
        // todo :: load roles, groups from your repository...

        // init the security controller...
        SecurityController.Init(roles, groups);
    }
}
Now, let's review how do we plug our validator in the NSB pipeline so it gets executed whenever a new message is executed in our service layer.

NServiceBus.IMutateIncomingMessages

The elegant way of doing that using NSB is trough message mutators. Yes, a fancy name for a plugin, filter or whatever else you want to name it. Message mutators allow we injecting our own business logic before the messages reach your NSB Message handler. With mutators, you can mutate incoming and outcoming messages. Since we're talking about security here, don't think you wanna mutate outcoming messages, right

Creating a MessageMutator

So, let's go back to the code: we know that we need to create a class that would implement IMutateIncomingMessages where we want to validate commands submitted to our service layer. Please, just note that, in order for this to automatically work, we will need:
  • a base generic Command where we can now beforehand who submitted what, when;
  • a common user;
  • the permission associated to a particular message;
  • access to our SecurityController that will validate if that user has access to submit that command or not.
The code below shows a sample validator implementing IMutateIncomingMessages:
public class PermissionValidator : IMutateIncomingMessages
{
    private CommandBase cmd;
    private User user;

    public object MutateIncoming(object message)
    {
        ValitatePermission(message);
        return message;
    }

    private void ValitatePermission(object message)
    {
        cmd = message as CommandBase;
        if (cmd == null)
            return;

        // tries to load custom security permissions from command
        var pa = cmd.GetType().GetCustomAttribute(typeof (RequirePermissionAttribute), true) as RequirePermissionAttribute;
       
        // if class not decorated with RequirePermission, nothing to validate
        if (pa == null)
            return;

        var user = LoadUser();

        if (user is null)
            throw new SecurityException("Is the User null?");

        ValidatePermission(pa.Permission);           
    }

    private User LoadUser()
    {
        if (cmd.SubmittedBy == null)
            return null;

        // todo :: load our user from repo...
        return user;
    }      

    private void ValidatePermission(string permission)
    {
        // todo :: add your custom permission validation...
    }
}

The RequirePermissionAttribute

The last part in the puzzle is how to automatically map permissions to commands. This can be easily done by creating a custom attribute like:
public class RequirePermissionAttribute : Attribute
{
    public string Permission { get; set; }

    /// <summary>
    /// Validates only if the SubmittedBy is an existing User
    /// </summary>
    public RequirePermissionAttribute()
    {        
    }
   
    /// <summary>
    /// Validates if the SubmittedBy is an existing User AND if that user has specified permission
    /// </summary>
    /// <param name="p"></param>
    public RequirePermissionAttribute(string p)
    {
        Permission = p;
    }
}
That attribute could be now used to decorate commands present in our service layer like:
[RequirePermissionAttribute(Permissions.UpdateUser)]
public class UpdateUser : ContentCommandBase
{
    [Required]
    [StringLength(100)]
    public string Name { get; set; }
    // etc...
}

Associating permissions and Commands

The last step is to build the association between permissions and commands. The line below does exactly that. The code binds permission to its associated commands:
// load custom security permissions from command
var pa = cmd.GetType().GetCustomAttribute(typeof (RequirePermissionAttribute), true) as RequirePermissionAttribute;

Conclusion

On this post we reviewed how we can inject our custom security logic into a messaging framework like NServiceBus. Since most of these frameworks have extension points in their pipelines, it shouldn't be complicated to do a similar approach with MassTransit, for example. If want to read other posts about NServiceBus, please also consider:

References

    See Also

      About the Author

      Bruno Hildenbrand      
      Principal Architect, HildenCo Solutions.