1 /**
2 * Copyright © DiamondMVC 2019
3 * License: MIT (https://github.com/DiamondMVC/Diamond/blob/master/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 */
6 module diamond.authentication.permissions;
7 
8 import diamond.core.apptype;
9 
10 static if (isWeb)
11 {
12   import diamond.http;
13   import diamond.http.method; // Bug: Cannot get acess to members from this module through "diamond.http"
14   import diamond.authentication.roles;
15 
16   /// Enumeration of permission types.
17   enum PermissionType
18   {
19     readAccess,
20     writeAccess,
21     updateAccess,
22     deleteAccess
23   }
24 
25   /// Wrapper around permissions.
26   final class Permission
27   {
28     private:
29     /// The resource.
30     string _resource;
31 
32     /// Boolean determining the read-access.
33     bool _readAccess;
34 
35     /// Boolean determining the write-access.
36     bool _writeAccess;
37 
38     /// Boolean determining the update-access.
39     bool _updateAccess;
40 
41     /// Boolean determining the delete-access.
42     bool _deleteAccess;
43 
44     public:
45     final:
46     /**
47     * Creates a new permission.
48     * Params:
49     *   resource =      The resource.
50     *   readAccess =    Boolean determining the read-access.
51     *   writeAccess =   Boolean determining the write-access.
52     *   updateAccess =  Boolean determining the update-access.
53     *   deleteAccess =  Boolean determining the delete-access.
54     */
55     this(string resource, bool readAccess, bool writeAccess, bool updateAccess, bool deleteAccess)
56     {
57       _resource = resource;
58       _readAccess = readAccess;
59       _writeAccess = writeAccess;
60       _updateAccess = updateAccess;
61       _deleteAccess = deleteAccess;
62     }
63 
64     @property
65     {
66       /// Gets the resource.
67       string resource() { return _resource; }
68 
69       /// Gets a boolean determining the read-access.
70       bool readAccess() { return _readAccess; }
71 
72       /// Gets a boolean determining the write-access.
73       bool writeAccess() { return _writeAccess; }
74 
75       /// Gets a boolean determining the update-access.
76       bool updateAccess() { return _updateAccess; }
77 
78       /// Gets a boolean determining the delete-access.
79       bool deleteAccess() { return _deleteAccess; }
80     }
81   }
82 
83   /// The permissions for http methods.
84   private static __gshared PermissionType[][HttpMethod] permissions;
85 
86   /// Boolean for the default permission access.
87   public static __gshared bool defaultPermission;
88 
89   /// The default permissions for http methods.
90   private static __gshared PermissionType[] defaultPermissions = [];
91 
92   /**
93   * Unrequires a permission for a http method.
94   * Params:
95   *   method =     The method.
96   *   permission = The permission.
97   */
98   void unrequirePermissionMethod(HttpMethod method, PermissionType permission)
99   {
100     import std.algorithm : filter;
101     import std.array : array;
102 
103     permissions[method] = permissions[method].filter!(p => p != permission).array;
104   }
105 
106   /**
107   * Requires a permission for a http method.
108   * Params:
109   *   method =     The method.
110   *   permission = The permission.
111   */
112   void requirePermissionMethod(HttpMethod method, PermissionType permission)
113   {
114     permissions[method] ~= permission;
115   }
116 
117   /**
118   * Checks whether a specific role has access with a specific method's permissions on a resource.
119   * Params:
120   *   role =      The role.
121   *   method =    The method.
122   *   resourcce = The resource.
123   * Returns:
124   *   Returns true if the role has access, false otherwise.
125   */
126   bool hasAccess(Role role, HttpMethod method, string resource)
127   {
128     bool access = true;
129     auto accessPermissions = permissions.get(method, defaultPermissions);
130 
131     foreach (permission; accessPermissions)
132     {
133       if (!role.hasPermission(resource, permission))
134       {
135         access = false;
136         break;
137       }
138     }
139 
140     return access;
141   }
142 }