GranularPermissions 1.0.5

dotnet add package GranularPermissions --version 1.0.5                
NuGet\Install-Package GranularPermissions -Version 1.0.5                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GranularPermissions" Version="1.0.5" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add GranularPermissions --version 1.0.5                
#r "nuget: GranularPermissions, 1.0.5"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install GranularPermissions as a Cake Addin
#addin nuget:?package=GranularPermissions&version=1.0.5

// Install GranularPermissions as a Cake Tool
#tool nuget:?package=GranularPermissions&version=1.0.5                

GranularPermissions

The world's most over-engineered permissions system.

Supports net5.0.

Features

  • Generic nodes (not tied to a resource)
  • Resource-bound nodes, evaluated with respect to a particular resource marked IPermissionManaged
  • Simple chains allow/deny grants with respect to an identifier (e.g. user ID)
    • Evaluated one after each other in order of provided Index to come up with a final pass/fail answer
  • Default disallow policy if no matching grants
  • Complex resource-bound grants using a DSL which is compiled into AST transformation at startup and then evaluated at runtime
  • AspNetMvc (Core) extensions for registering services, logging permissions for debugging etc

Terminology

  • Node: A permission entry. Something that can be done that needs its access controlled.
    • These have a key which by convention is represented as EntityName.[SubGroup].Action.
  • Grants: Allow/deny rules that cover a single permission node. Can be typed as Generic or ResourceBound.
  • ResourceBound grant: Evaluation of the grant must be performed in the context pf a resource.
    • For example, Product.Edit probably requires the product in question to be considered when checking to see if the user should have the permission or not.
  • Generic grant: Does not require a resource when evaluating. E.g. Product.Create.
  • Chain: grants are organised into chains and have identifiers within a chain. When nodes are checked, all grants that match the identifier in the specified chain are considered.
    • Example chains: Groups or Users
    • Example identifiers: Group ID or User ID
  • Condition: An additional requirement on top of a ResourceBound grant. Written in a DSL for this permissions system.

DSL examples

new Cat
{
    Breed = CatBreed.Bengal,
    Age = 10,
    Name = "Felix"
}

You could write some conditions for a resource bound grant on node Cat.Adopt:

resource.Name == "Felix" || resource.Age < 10

resource.Age != 5

Supported operators: <=, >=, <, >, &&, ||, ., ==, !=, !, ~= (regex)

Usage

From an ASP.NET MVC Core project, in ConfigureServices in Startup.cs:

services.AddScoped<IPermissionGrantProvider, SomePermissionGrantProvider>();
services.AddGranularPermissions(typeof(Permissions));

SomePermissionGrantProvider must implement IPermissionGrantProvider. Its role is to return all grants (which implement IPermissionGrantSerialized) persisted in the system. You may wish to retrieve them from a database, for instance.

The Permissions class must define all permission nodes you wish to exist in your project:

public static class Permissions
{
    public static class Product
    {
        public static readonly ResourceNode<ProductModel> View =
            new ResourceNode<ProductModel>("Product.View", "View an individual product");
        
        public static readonly GenericNode Create =
            new GenericNode("Product.Create", "Create a product");
        
        public static readonly ResourceNode<ProductModel> Buy =
            new ResourceNode<ProductModel>("Product.Purchase", "Purchase an individual product");
    }
    
    public static class Cat
    {
        public static readonly ResourceNode<ProductModel> Pet =
            new ResourceNode<ProductModel>("Cat.Pet", "Pet the cat without being bitten/scratched");
        
        public static readonly GenericNode Adopt =
            new GenericNode("Cat.Adopt", "Be adopted by a cat");
    }
}

To check a permission within a specified chain, call GetResultUsingChain on the IPermissionsService instance which will return a PermissionResult (Unset, Allow or Deny).

It is possible to reload the grants at runtime by calling ReplaceAllGrants with a new IEnumerable<IPermissionGrantSerialized>.

Example use-case

A web application has two groups which have different levels of access. Group 1 is for "Everyone" and includes a basic level of permission grants. Group 2, "Administrators" includes a higher level of access for a subset of application users who are in this group.

Within GranularPermissions, you'd have:

  • One chain, "Groups"
  • A set of IPermissionGrantSerialized for the "Groups" chain with Identifier=1. These will apply to all users in the Everyone group.
  • A set of IPermissionGrantSerialized for the "Groups" chain with Identifier=2. These will apply to all users in the Administrators group.
  • Some IPermissionGrantProvider which returns the aforementioned IPermissionGrantSerialized instances from DB

A simple permissions checker would call GetResultUsingChain("Groups", Permissions.Node.ToCheck, groupId) for each of the user's groups and then aggregate the results to come up with a final allowed/denied result. For example, the administrators group may be considered a higher priority than the everyone group.

For resource bound nodes, it's simply a case of passing an additional argument GetResultUsingChain("Groups", Permissions.Node.ToCheckWithResource, groupId, resourceToCheckAgainst).

TODO

  • Add ability to register DSL functions/identifiers
Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on GranularPermissions:

Package Downloads
GranularPermissions.Mvc

ASP.NET Core MVC integration for GranularPermissions.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.5 1,334 5/16/2021
1.0.3 2,265 6/14/2019
1.0.2-beta 1,227 8/23/2018
1.0.1-beta 719 8/14/2018
1.0.0-beta 993 4/16/2018
0.0.5-alpha 903 4/16/2018
0.0.4-alpha 946 3/21/2018
0.0.3-alpha 939 3/20/2018
0.0.2-alpha 926 3/20/2018
0.0.1-alpha 1,012 3/19/2018