Skip to content

2.10 Security

Marjan Nikolovski edited this page Apr 9, 2021 · 1 revision

Purpose

Authorization is a security mechanism which is used to determine whether the user has access to a particular resource or not. Authorization can be achieved with several different techniques depending on the level of granularity that resources/features need to be restricted by.

Signals offers an implementation for the Security aspect out of the box:

  • Signals.Aspects.Security.Database

Only one implementation can be active at a time.

How to use

When we implement any type of process a permission provider is automatically injected in the process context.

public class MyProcess : BusinessProcess<VoidResult>
{
    /// <summary>
    /// Authenticate process
    /// </summary>
    /// <returns></returns>
    public override VoidResult Auth()
    {
        return Ok();
    }

    /// <summary>
    /// Validate process
    /// </summary>
    /// <returns></returns>
    public override VoidResult Validate()
    {
        return Ok();
    }

    /// <summary>
    /// Handle process
    /// </summary>
    /// <returns></returns>
    public override VoidResult Handle()
    {
        // Add permissions
        Context.PermissionManager.SetUserPermission("user_id_1", "my_feature", true);
        Context.PermissionManager.SetRolePermission("SystemAdmin", "my_feature", true);

        // Check permissions for current user
        var hasAccess = Context.PermissionManager.HasPermission("my_feature");

        // Check permissions for roles
        var hasAccess = Context.PermissionManager.HasPermission("my_feature", Entities.UserRoles.SystemAdmin);

        // Remove permissions
        Context.PermissionManager.RemoveUserPermission("user_id_1", "my_feature");
        Context.PermissionManager.RemoveRolePermission("SystemAdmin", "my_feature");

        return Ok();
    }
}

Other more manual way of using the permission manager is through the IPermissionManager instance.

public void CheckPermissions()
{
    Guid epicId = Guid.NewGuid();
    var permissionManager = SystemBootstrapper.GetInstance<IPermissionManager>();

    permissionManager.SetUserPermission("user_id_1", "my_feature", true);
    permissionManager.SetRolePermission("SystemAdmin", "my_feature", true);

    // Check permissions for current user
    var hasAccess = permissionManager.HasPermission("my_feature");

    // Check permissions for roles
    var hasAccess = permissionManager.HasPermission("my_feature", Entities.UserRoles.SystemAdmin);

    // Remove permissions
    permissionManager.RemoveUserPermission("user_id_1", "my_feature");
    permissionManager.RemoveRolePermission("SystemAdmin", "my_feature");
}

Configuration

We configure the security aspect by using an instance of Signals.Aspects.Security.Configurations.ISecurityConfiguration which we pass in the WebApplicationBootstrapConfiguration instance at startup.

Properties explanation

DatabaseSecurityConfiguration

  • ConnectionString: Database connection string
  • TableName: Benchmark checkpoints table name. Default Permission

Examples

Using Signals.Aspects.Security.Database

services
    .AddSignals(config =>
    {
        config.SecurityConfiguration = new DatabaseSecurityConfiguration
        {
            ConnectionString = myConnectionString,
            TableName = "Permission"
        }
    });

Extending security

  1. Install package Signals.Aspects.Security
  2. Create class with implementation of Signals.Aspects.Security.Configurations.ISecurityConfiguration
/// <summary>
/// Security configuration contract
/// </summary>
public class MySecurityConfiguration : ISecurityConfiguration
{
    /// <summary>
    /// Custom property
    /// </summary>
    public string MyProperty { get; set; }
}
  1. Create class with implementation of Signals.Aspects.Security.IPermissionProvider
/// <summary>
/// Storage contract
/// </summary>
public class MyStorageProvider : IStorageProvider
{
    private MySecurityConfiguration _configuraiton;

    /// <summary>
    /// Creates of updates permission in the system
    /// </summary>
    /// <param name="userIdentifier"></param>
    /// <param name="feature"></param>
    /// <param name="hasAccess"></param>
    void SetUserPermission(string userIdentifier, string feature, bool hasAccess);

    /// <summary>
    /// Creates of updates permission in the system
    /// </summary>
    /// <param name="role"></param>
    /// <param name="feature"></param>
    /// <param name="hasAccess"></param>
    void SetRolePermission(string role, string feature, bool hasAccess);

    /// <summary>
    /// Removes user permission from the system
    /// </summary>
    /// <param name="userName"></param>
    /// <param name="feature"></param>
    void RemoveUserPermission(string userName, string feature);

    /// <summary>
    /// Removes role permission from the system
    /// </summary>
    /// <param name="roleName"></param>
    /// <param name="feature"></param>
    void RemoveRolePermission(string roleName, string feature);

    /// <summary>
    /// Checks if the user has permission for the feature
    /// </summary>
    /// <param name="userName"></param>
    /// <param name="feature"></param>
    /// <param name="userRoles"></param>
    /// <returns></returns>
    bool HasPermission(string userName, string feature, string[] userRoles);
}
  1. Use our implementation of ISecurityConfiguration when configuring our application
public static IServiceProvider AddSignals(this IServiceCollection services)
{
    services
        .AddSignals(config =>
        {
            config.SecurityConfiguration = new MySecurityConfiguration
            {
                MyProperty = "my_value"
            };
        });
}
Clone this wiki locally