Browse Source

began Auth

tags/v0.6.0
Robin Thoni 7 years ago
parent
commit
bd2d2f596e
55 changed files with 1108 additions and 116 deletions
  1. 6
    0
      .idea/.idea.luticate2/riderModule.iml
  2. 34
    0
      Luticate2.Auth/Attributes/EntityAccessors/LuAttrArgumentAccessor.cs
  3. 21
    0
      Luticate2.Auth/Attributes/EntityAccessors/LuAttrLoggedUserAccessor.cs
  4. 10
    0
      Luticate2.Auth/Attributes/LuPermissionArgAttribute.cs
  5. 43
    0
      Luticate2.Auth/Attributes/LuPermissionAttribute.cs
  6. 6
    0
      Luticate2.Auth/Business/LuBusinessExtensions.cs
  7. 6
    10
      Luticate2.Auth/Business/LuGroupsBusiness.cs
  8. 21
    0
      Luticate2.Auth/Business/LuPermissionsBusiness.cs
  9. 39
    0
      Luticate2.Auth/Business/LuUsersBusiness.cs
  10. 16
    0
      Luticate2.Auth/Controllers/LuAuthController.cs
  11. 54
    0
      Luticate2.Auth/Controllers/LuAuthCrudController.cs
  12. 48
    9
      Luticate2.Auth/Controllers/LuAuthExtensions.cs
  13. 41
    9
      Luticate2.Auth/Controllers/LuGroupsController.cs
  14. 21
    0
      Luticate2.Auth/Controllers/LuLoggedUserAccessor.cs
  15. 1
    6
      Luticate2.Auth/Controllers/LuUsersController.cs
  16. 4
    4
      Luticate2.Auth/DataAccess/LuAuthDatabaseContext.cs
  17. 38
    24
      Luticate2.Auth/DataAccess/LuGroupsDataAccess.cs
  18. 21
    0
      Luticate2.Auth/DataAccess/Models/ModelsToDbo.cs
  19. 1
    1
      Luticate2.Auth/DataAccess/Models/lu_authentication_sources.cs
  20. 1
    1
      Luticate2.Auth/DataAccess/Models/lu_groups.cs
  21. 3
    1
      Luticate2.Auth/DataAccess/Models/lu_users.cs
  22. 4
    4
      Luticate2.Auth/DataAccess/code-from-ds/DataSource.twig
  23. 5
    1
      Luticate2.Auth/DataAccess/code-from-ds/code-from-ds.json
  24. 2
    2
      Luticate2.Auth/Dbo/Groups/LuGroupsAddDbo.cs
  25. 1
    4
      Luticate2.Auth/Dbo/Groups/LuGroupsDbo.cs
  26. 9
    0
      Luticate2.Auth/Dbo/Permissions/LuEntityTypes.cs
  27. 9
    0
      Luticate2.Auth/Dbo/Permissions/LuPermissions.cs
  28. 3
    4
      Luticate2.Auth/Dbo/Users/UsersDbo.cs
  29. 15
    0
      Luticate2.Auth/Dbo/Users/UsersToken.cs
  30. 10
    0
      Luticate2.Auth/Interfaces/Groups/ILuGroupsBusiness.cs
  31. 9
    0
      Luticate2.Auth/Interfaces/Permissions/ILuAttrEntityAccessor.cs
  32. 13
    0
      Luticate2.Auth/Interfaces/Permissions/ILuPermissionsBusiness.cs
  33. 13
    0
      Luticate2.Auth/Interfaces/Permissions/ILuPermissionsProvider.cs
  34. 9
    0
      Luticate2.Auth/Interfaces/Users/ILuLoggedUserAccessor.cs
  35. 16
    0
      Luticate2.Auth/Interfaces/Users/ILuUsersBusiness.cs
  36. 0
    34
      Luticate2.Auth/Middlewares/LuAuthMiddleware.cs
  37. 54
    0
      Luticate2.Auth/Middlewares/LuLoggedUserMiddleware.cs
  38. 57
    0
      Luticate2.Auth/Middlewares/LuPermissionMiddleware.cs
  39. 1
    1
      Luticate2.Auth/project.json
  40. 6
    1
      Luticate2.Utils/Controllers/LuUtilsExtensions.cs
  41. 24
    0
      TestAuth/Business/LuGroupsBusinessTest.cs
  42. 26
    0
      TestAuth/Properties/AssemblyInfo.cs
  43. 22
    0
      TestAuth/TestAuth.xproj
  44. 51
    0
      TestAuth/Tests.cs
  45. 28
    0
      TestAuth/project.json
  46. 44
    0
      WebApiAuth/Controllers/ValuesController.cs
  47. 25
    0
      WebApiAuth/Program.cs
  48. 26
    0
      WebApiAuth/Properties/AssemblyInfo.cs
  49. 59
    0
      WebApiAuth/Startup.cs
  50. 22
    0
      WebApiAuth/WebApiAuth.xproj
  51. 14
    0
      WebApiAuth/appsettings.Development.json
  52. 15
    0
      WebApiAuth/appsettings.json
  53. 55
    0
      WebApiAuth/project.json
  54. 14
    0
      WebApiAuth/web.config
  55. 12
    0
      luticate2.sln

+ 6
- 0
.idea/.idea.luticate2/riderModule.iml View File

@@ -4,14 +4,20 @@
4 4
     <content url="file://$MODULE_DIR$/../..">
5 5
       <sourceFolder url="file://$MODULE_DIR$/../../Luticate2.Auth" isTestSource="false" />
6 6
       <sourceFolder url="file://$MODULE_DIR$/../../Luticate2.Utils" isTestSource="false" />
7
+      <sourceFolder url="file://$MODULE_DIR$/../../TestAuth" isTestSource="false" />
7 8
       <sourceFolder url="file://$MODULE_DIR$/../../TestUtils" isTestSource="false" />
9
+      <sourceFolder url="file://$MODULE_DIR$/../../WebApiAuth" isTestSource="false" />
8 10
       <sourceFolder url="file://$MODULE_DIR$/../../WebApiUtils" isTestSource="false" />
9 11
       <excludeFolder url="file://$MODULE_DIR$/../../Luticate2.Auth/bin" />
10 12
       <excludeFolder url="file://$MODULE_DIR$/../../Luticate2.Auth/obj" />
11 13
       <excludeFolder url="file://$MODULE_DIR$/../../Luticate2.Utils/bin" />
12 14
       <excludeFolder url="file://$MODULE_DIR$/../../Luticate2.Utils/obj" />
15
+      <excludeFolder url="file://$MODULE_DIR$/../../TestAuth/bin" />
16
+      <excludeFolder url="file://$MODULE_DIR$/../../TestAuth/obj" />
13 17
       <excludeFolder url="file://$MODULE_DIR$/../../TestUtils/bin" />
14 18
       <excludeFolder url="file://$MODULE_DIR$/../../TestUtils/obj" />
19
+      <excludeFolder url="file://$MODULE_DIR$/../../WebApiAuth/bin" />
20
+      <excludeFolder url="file://$MODULE_DIR$/../../WebApiAuth/obj" />
15 21
       <excludeFolder url="file://$MODULE_DIR$/../../WebApiUtils/bin" />
16 22
       <excludeFolder url="file://$MODULE_DIR$/../../WebApiUtils/obj" />
17 23
       <excludeFolder url="file://$MODULE_DIR$/../../packages" />

+ 34
- 0
Luticate2.Auth/Attributes/EntityAccessors/LuAttrArgumentAccessor.cs View File

@@ -0,0 +1,34 @@
1
+using System.Reflection;
2
+using Luticate2.Auth.Interfaces.Permissions;
3
+using Microsoft.AspNetCore.Mvc.Controllers;
4
+using Microsoft.AspNetCore.Mvc.Filters;
5
+
6
+namespace Luticate2.Auth.Attributes.EntityAccessors
7
+{
8
+    public class LuAttrArgumentAccessor : ILuAttrEntityAccessor
9
+    {
10
+        public object GetEntity(ActionExecutingContext context, object id)
11
+        {
12
+            var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
13
+            if (actionDescriptor != null)
14
+            {
15
+                var parameters = actionDescriptor.MethodInfo.GetParameters();
16
+                foreach (var parameter in parameters)
17
+                {
18
+                    var attributes = parameter.GetCustomAttributes<LuPermissionArgAttribute>();
19
+                    foreach (var attribute in attributes)
20
+                    {
21
+                        if (attribute.Id == id)
22
+                        {
23
+                            if (context.ActionArguments.ContainsKey(parameter.Name))
24
+                            {
25
+                                return context.ActionArguments[parameter.Name];
26
+                            }
27
+                        }
28
+                    }
29
+                }
30
+            }
31
+            return null;
32
+        }
33
+    }
34
+}

+ 21
- 0
Luticate2.Auth/Attributes/EntityAccessors/LuAttrLoggedUserAccessor.cs View File

@@ -0,0 +1,21 @@
1
+using Luticate2.Auth.Interfaces.Permissions;
2
+using Luticate2.Auth.Interfaces.Users;
3
+using Microsoft.AspNetCore.Mvc.Filters;
4
+
5
+namespace Luticate2.Auth.Attributes.EntityAccessors
6
+{
7
+    public class LuAttrLoggedUserAccessor : ILuAttrEntityAccessor
8
+    {
9
+        private readonly ILuLoggedUserAccessor _loggedUserAccessor;
10
+
11
+        public LuAttrLoggedUserAccessor(ILuLoggedUserAccessor loggedUserAccessor)
12
+        {
13
+            _loggedUserAccessor = loggedUserAccessor;
14
+        }
15
+
16
+        public object GetEntity(ActionExecutingContext context, object id)
17
+        {
18
+            return _loggedUserAccessor.GetLoggedUser();
19
+        }
20
+    }
21
+}

+ 10
- 0
Luticate2.Auth/Attributes/LuPermissionArgAttribute.cs View File

@@ -0,0 +1,10 @@
1
+using System;
2
+
3
+namespace Luticate2.Auth.Attributes
4
+{
5
+    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)]
6
+    public class LuPermissionArgAttribute : Attribute
7
+    {
8
+        public object Id { get; set; }
9
+    }
10
+}

+ 43
- 0
Luticate2.Auth/Attributes/LuPermissionAttribute.cs View File

@@ -0,0 +1,43 @@
1
+using System;
2
+using Luticate2.Auth.Attributes.EntityAccessors;
3
+using Luticate2.Auth.Dbo.Permissions;
4
+
5
+namespace Luticate2.Auth.Attributes
6
+{
7
+    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
8
+    public class LuPermissionAttribute : Attribute
9
+    {
10
+        public string PermissionName { get; protected set; }
11
+
12
+        public string SrcEntityType { get; protected set; }
13
+
14
+        public Type SrcEntityAccessor { get; protected set; }
15
+
16
+        public string DstEntityType { get; protected set; }
17
+
18
+        public Type DstEntityAccessor { get; protected set; }
19
+
20
+        public object Id { get; protected set; }
21
+
22
+        public LuPermissionAttribute(string permissionName, string srcEntityType, Type srcEntityAccessor,
23
+            string dstEntityType, Type dstEntityAccessor, object id = null)
24
+        {
25
+            PermissionName = permissionName;
26
+            SrcEntityType = srcEntityType;
27
+            SrcEntityAccessor = srcEntityAccessor;
28
+            DstEntityType = dstEntityType;
29
+            DstEntityAccessor = dstEntityAccessor;
30
+            Id = id;
31
+        }
32
+
33
+        public LuPermissionAttribute(string permissionName, string dstEntityType, Type dstEntityAccessor, object id = null)
34
+            : this(permissionName, LuEntityTypes.LuUsers, typeof(LuAttrLoggedUserAccessor), dstEntityType, dstEntityAccessor, id)
35
+        {
36
+        }
37
+
38
+        public LuPermissionAttribute(string permissionName, string dstEntityType, object id = null)
39
+            : this(permissionName, dstEntityType, typeof(LuAttrArgumentAccessor), id)
40
+        {
41
+        }
42
+    }
43
+}

+ 6
- 0
Luticate2.Auth/Business/LuBusinessExtensions.cs View File

@@ -0,0 +1,6 @@
1
+namespace Luticate2.Auth.Business
2
+{
3
+    public static class LuBusinessExtensions
4
+    {
5
+    }
6
+}

+ 6
- 10
Luticate2.Auth/Business/LuGroupsBusiness.cs View File

@@ -1,20 +1,16 @@
1 1
 using Luticate2.Auth.DataAccess;
2
+using Luticate2.Auth.Dbo.Groups;
3
+using Luticate2.Auth.Interfaces.Groups;
2 4
 using Luticate2.Utils.Business;
5
+using Luticate2.Utils.Interfaces;
3 6
 
4 7
 namespace Luticate2.Auth.Business
5 8
 {
6
-    public class LuGroupsBusiness : LuBusiness
9
+    public class LuGroupsBusiness : LuCrudBusiness<LuGroupsDataAccess, LuGroupsAddDbo, LuGroupsDbo, LuGroupsAddDbo, string>,
10
+        ILuGroupsBusiness
7 11
     {
8
-        private readonly LuGroupsDataAccess _luGroupsDataAccess;
9
-
10
-        public LuGroupsBusiness(LuGroupsDataAccess dataAccess)
11
-        {
12
-            _luGroupsDataAccess = dataAccess;
13
-        }
14
-
15
-        public string Get()
12
+        public LuGroupsBusiness(LuGroupsDataAccess dataAccess, ILuNotificationsBusiness notificationsBusiness) : base(dataAccess, notificationsBusiness)
16 13
         {
17
-            return _luGroupsDataAccess.Get();
18 14
         }
19 15
     }
20 16
 }

+ 21
- 0
Luticate2.Auth/Business/LuPermissionsBusiness.cs View File

@@ -0,0 +1,21 @@
1
+using System;
2
+using Luticate2.Auth.Interfaces.Permissions;
3
+using Luticate2.Utils.Dbo.Result;
4
+
5
+namespace Luticate2.Auth.Business
6
+{
7
+    public class LuPermissionsBusiness : ILuPermissionsBusiness
8
+    {
9
+        public LuResult<bool> GetPermissionValue(string permissionName, string srcEntityType, object srcEntity,
10
+            string dstEntityType, object dstEntity)
11
+        {
12
+            return LuResult<bool>.Ok(true);
13
+        }
14
+
15
+        public LuResult<bool> GetPermissionEffectiveValue(string permissionName, string srcEntityType, object srcEntity,
16
+            string dstEntityType, object dstEntity)
17
+        {
18
+            return LuResult<bool>.Ok(true);
19
+        }
20
+    }
21
+}

+ 39
- 0
Luticate2.Auth/Business/LuUsersBusiness.cs View File

@@ -0,0 +1,39 @@
1
+using System;
2
+using Luticate2.Auth.Dbo.Users;
3
+using Luticate2.Auth.Interfaces.Users;
4
+using Luticate2.Utils.Dbo.Result;
5
+using Luticate2.Utils.Utils;
6
+
7
+namespace Luticate2.Auth.Business
8
+{
9
+    public class LuUsersBusiness : ILuUsersBusiness
10
+    {
11
+        public LuResult<UsersToken> GetToken(string token)
12
+        {
13
+            var id = Guid.NewGuid().ToDbo();
14
+            return LuResult<UsersToken>.Ok(new UsersToken
15
+            {
16
+                UserId = id
17
+            });//TODO
18
+        }
19
+
20
+        public LuResult<string> RegisterToken(UsersToken token)
21
+        {
22
+            return LuResult<string>.Ok("token");//TODO
23
+        }
24
+
25
+        public LuResult<UsersToken> UnRegisterToken(string token)
26
+        {
27
+            return LuResult<UsersToken>.Ok(new UsersToken());//TODO
28
+        }
29
+
30
+        public LuResult<UsersDbo> GetSingleById(string id)
31
+        {
32
+            return LuResult<UsersDbo>.Ok(new UsersDbo
33
+            {
34
+                Id = id,
35
+                Username = "user-" + id.Split('-')[0]
36
+            });//TODO
37
+        }
38
+    }
39
+}

+ 16
- 0
Luticate2.Auth/Controllers/LuAuthController.cs View File

@@ -0,0 +1,16 @@
1
+using Luticate2.Auth.Dbo.Users;
2
+using Luticate2.Utils.Controllers;
3
+using Luticate2.Utils.Dbo.Basic;
4
+using Microsoft.Extensions.Options;
5
+
6
+namespace Luticate2.Auth.Controllers
7
+{
8
+    public class LuAuthController : LuController
9
+    {
10
+//        protected UsersDbo LoggedUser => LuItems["loggedUser"] as UsersDbo;
11
+
12
+        public LuAuthController(IOptions<LuUtilsOptionsDbo> luUtilsOptionsDbo) : base(luUtilsOptionsDbo)
13
+        {
14
+        }
15
+    }
16
+}

+ 54
- 0
Luticate2.Auth/Controllers/LuAuthCrudController.cs View File

@@ -0,0 +1,54 @@
1
+using System.ComponentModel.DataAnnotations;
2
+using Luticate2.Utils.Dbo.Basic;
3
+using Luticate2.Utils.Dbo.PaginatedRequest;
4
+using Luticate2.Utils.Interfaces;
5
+using Luticate2.Utils.Utils;
6
+using Microsoft.AspNetCore.Mvc;
7
+using Microsoft.Extensions.Options;
8
+
9
+namespace Luticate2.Auth.Controllers
10
+{
11
+    public abstract class LuAuthCrudController<TBusiness, TDboCreate, TDboRead, TDboUpdate, TId> : LuAuthController
12
+        where TDboCreate : class
13
+        where TDboRead : class
14
+        where TDboUpdate : class
15
+        where TBusiness : ILuCrudInterface<TDboCreate, TDboRead, TDboUpdate, TId>
16
+    {
17
+        protected readonly TBusiness Busines;
18
+
19
+        protected LuAuthCrudController(TBusiness busines, IOptions<LuUtilsOptionsDbo> luUtilsOptionsDbo) : base(luUtilsOptionsDbo)
20
+        {
21
+            Busines = busines;
22
+        }
23
+
24
+        [HttpGet("[controller]/{id}")]
25
+        public virtual LuApiWrapperDbo<TDboRead> GetSingleById([Required]TId id)
26
+        {
27
+            return Handle(Busines.GetSingleById(id));
28
+        }
29
+
30
+        [HttpGet("[controller]")]
31
+        public virtual LuApiWrapperDbo<LuPaginatedDbo<TDboRead>> GetMultiple([Required]LuPaginatedRequestDbo request)
32
+        {
33
+            return Handle(Busines.GetMultiple(request));
34
+        }
35
+
36
+        [HttpPost("[controller]")]
37
+        public virtual LuApiWrapperDbo<TDboRead> AddDbo([FromBody][Required]TDboCreate data)
38
+        {
39
+            return Handle(Busines.AddDbo(data));
40
+        }
41
+
42
+        [HttpPost("[controller]/{id}")]
43
+        public virtual LuApiWrapperDbo<TDboRead> EditSingleByIdDbo([Required]TId id, [FromBody][Required]TDboUpdate data)
44
+        {
45
+            return Handle(Busines.EditSingleByIdDbo(id, data));
46
+        }
47
+
48
+        [HttpDelete("[controller]/{id}")]
49
+        public virtual LuApiWrapperDbo<TDboRead> Delete([Required]TId id)
50
+        {
51
+            return Handle(Busines.DeleteSingleByIdDbo(id));
52
+        }
53
+    }
54
+}

+ 48
- 9
Luticate2.Auth/Controllers/LuAuthExtensions.cs View File

@@ -1,28 +1,56 @@
1 1
 using System;
2
+using Luticate2.Auth.Attributes.EntityAccessors;
2 3
 using Luticate2.Auth.Business;
3 4
 using Luticate2.Auth.DataAccess;
5
+using Luticate2.Auth.Dbo.Users;
6
+using Luticate2.Auth.Interfaces.Groups;
7
+using Luticate2.Auth.Interfaces.Permissions;
8
+using Luticate2.Auth.Interfaces.Users;
4 9
 using Luticate2.Auth.Middlewares;
5 10
 using Luticate2.Utils.Controllers;
6 11
 using Luticate2.Utils.Dbo.Basic;
7 12
 using Microsoft.AspNetCore.Builder;
8 13
 using Microsoft.AspNetCore.Http;
14
+using Microsoft.AspNetCore.Mvc;
15
+using Microsoft.EntityFrameworkCore;
9 16
 using Microsoft.Extensions.DependencyInjection;
10 17
 
11 18
 namespace Luticate2.Auth.Controllers
12 19
 {
13 20
     public static class LuAuthExtensions
14 21
     {
15
-        public static IServiceCollection AddLuticateAuth(this IServiceCollection services, Action<LuUtilsOptionsDbo> optionsDelegate)
22
+        public const string RoutePrefix = "luticate";
23
+
24
+        public const string LuticateItemsLoggedUser = "loggedUser";
25
+
26
+        public static IServiceCollection AddLuticateAuth(this IServiceCollection services,
27
+            Action<LuUtilsOptionsDbo> optionsDelegate, Action<DbContextOptionsBuilder> optionsAction)
16 28
         {
17 29
             services.AddLuticateUtils(optionsDelegate);
18 30
 
19
-            services.AddSingleton<LuGroupsController>();
20
-            services.AddSingleton<LuGroupsBusiness>();
21
-            services.AddSingleton<LuGroupsDataAccess>();
31
+            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
32
+
33
+            services.AddScoped<ILuLoggedUserAccessor, LuLoggedUserAccessor>();
34
+            services.AddScoped<LuAttrLoggedUserAccessor>();
35
+            services.AddScoped<LuAttrArgumentAccessor>();
36
+
37
+            services.AddTransient<LuGroupsController>();
38
+            services.AddTransient<ILuGroupsBusiness, LuGroupsBusiness>();
39
+            services.AddTransient<LuGroupsDataAccess>();
22 40
 
23
-            services.AddSingleton<LuUsersController>();
41
+            services.AddTransient<LuUsersController>();
42
+            services.AddTransient<ILuUsersBusiness, LuUsersBusiness>();
24 43
 
25
-            services.AddDbContext<LuDatabaseContext>();
44
+            services.AddTransient<ILuPermissionsBusiness, LuPermissionsBusiness>();
45
+
46
+            services.AddDbContext<LuAuthDatabaseContext>(options =>
47
+            {
48
+                options.UseInternalServiceProvider(new ServiceCollection()
49
+                    .AddEntityFrameworkNpgsqlLuticate()
50
+                    .AddEntityFrameworkNpgsql()
51
+                    .BuildServiceProvider());
52
+                optionsAction.Invoke(options);
53
+            }, ServiceLifetime.Transient);
26 54
 
27 55
             return services;
28 56
         }
@@ -30,19 +58,30 @@ namespace Luticate2.Auth.Controllers
30 58
         public static IMvcBuilder AddLuticateAuth(this IMvcBuilder builder)
31 59
         {
32 60
             builder.AddLuticateUtils();
61
+            builder.Services.Configure<MvcOptions>(
62
+                options =>
63
+                {
64
+                    options.Filters.Add(typeof(LuLoggedUserMiddleware));
65
+                    options.Filters.Add(typeof(LuPermissionMiddleware));
66
+                });
33 67
             return builder;
34 68
         }
35 69
 
36 70
         public static IApplicationBuilder UseLuticateAuth(this IApplicationBuilder app)
37 71
         {
38 72
             app.UseLuticateUtils();
39
-            app.UseMiddleware<LuAuthMiddleware>();
40 73
             return app;
41 74
         }
42 75
 
43
-        public static object GetLuCurrentUser(this HttpContext context)
76
+        public static UsersDbo GetLuLoggedUser(this HttpContext context)
77
+        {
78
+            return context.GetLuItems()[LuticateItemsLoggedUser] as UsersDbo;
79
+        }
80
+
81
+        public static void SetLuLoggedUser(this HttpContext context, UsersDbo user)
44 82
         {
45
-            return context.GetLuItems()["currentUser"];//TODO
83
+            throw new Exception($"{user.Id} {user.Username}");
84
+            context.GetLuItems()[LuticateItemsLoggedUser] = user;
46 85
         }
47 86
     }
48 87
 }

+ 41
- 9
Luticate2.Auth/Controllers/LuGroupsController.cs View File

@@ -1,24 +1,56 @@
1
-using Luticate2.Auth.Business;
2
-using Luticate2.Utils.Controllers;
1
+using System.ComponentModel.DataAnnotations;
2
+using Luticate2.Auth.Attributes;
3
+using Luticate2.Auth.Dbo.Groups;
4
+using Luticate2.Auth.Dbo.Permissions;
5
+using Luticate2.Auth.Interfaces.Groups;
3 6
 using Luticate2.Utils.Dbo.Basic;
7
+using Luticate2.Utils.Dbo.PaginatedRequest;
4 8
 using Microsoft.AspNetCore.Mvc;
5 9
 using Microsoft.Extensions.Options;
6 10
 
7 11
 namespace Luticate2.Auth.Controllers
8 12
 {
9
-    [Route("luticate/groups")]
10
-    public class LuGroupsController : LuController
13
+    [Route(LuAuthExtensions.RoutePrefix)]
14
+    public class LuGroupsController : LuAuthCrudController<ILuGroupsBusiness, LuGroupsAddDbo, LuGroupsDbo, LuGroupsAddDbo, string>
11 15
     {
12
-        private readonly LuGroupsBusiness _luGroupsBusiness;
16
+        private const string EntityType = LuEntityTypes.LuGroups;
13 17
 
14
-        public LuGroupsController(LuGroupsBusiness luGroupsBusiness, IOptions<LuUtilsOptionsDbo> luUtilsOptionsDbo) : base(luUtilsOptionsDbo)
18
+        private const string ReadPermission = LuPermissions.LuGroupsRead;
19
+
20
+        private const string WritePermission = LuPermissions.LuGroupsWrite;
21
+
22
+        public LuGroupsController(ILuGroupsBusiness busines, IOptions<LuUtilsOptionsDbo> luUtilsOptionsDbo) : base(busines, luUtilsOptionsDbo)
23
+        {
24
+        }
25
+
26
+        [LuPermission(ReadPermission, EntityType)]
27
+        public override LuApiWrapperDbo<LuGroupsDbo> GetSingleById([LuPermissionArg][Required]string id)
28
+        {
29
+            return base.GetSingleById(id);
30
+        }
31
+
32
+        [LuPermission(ReadPermission, EntityType)]
33
+        public override LuApiWrapperDbo<LuPaginatedDbo<LuGroupsDbo>> GetMultiple([Required]LuPaginatedRequestDbo request)
34
+        {
35
+            return base.GetMultiple(request);
36
+        }
37
+
38
+        [LuPermission(WritePermission, EntityType)]
39
+        public override LuApiWrapperDbo<LuGroupsDbo> AddDbo([Required]LuGroupsAddDbo data)
40
+        {
41
+            return base.AddDbo(data);
42
+        }
43
+
44
+        [LuPermission(WritePermission, EntityType)]
45
+        public override LuApiWrapperDbo<LuGroupsDbo> EditSingleByIdDbo([LuPermissionArg][Required]string id, [Required]LuGroupsAddDbo data)
15 46
         {
16
-            _luGroupsBusiness = luGroupsBusiness;
47
+            return base.EditSingleByIdDbo(id, data);
17 48
         }
18 49
 
19
-        public string Get()
50
+        [LuPermission(WritePermission, EntityType)]
51
+        public override LuApiWrapperDbo<LuGroupsDbo> Delete([LuPermissionArg][Required]string id)
20 52
         {
21
-            return _luGroupsBusiness.Get();
53
+            return base.Delete(id);
22 54
         }
23 55
     }
24 56
 }

+ 21
- 0
Luticate2.Auth/Controllers/LuLoggedUserAccessor.cs View File

@@ -0,0 +1,21 @@
1
+using Luticate2.Auth.Dbo.Users;
2
+using Luticate2.Auth.Interfaces.Users;
3
+using Microsoft.AspNetCore.Http;
4
+
5
+namespace Luticate2.Auth.Controllers
6
+{
7
+    public class LuLoggedUserAccessor : ILuLoggedUserAccessor
8
+    {
9
+        private readonly IHttpContextAccessor _httpContextAccessor;
10
+
11
+        public LuLoggedUserAccessor(IHttpContextAccessor httpContextAccessor)
12
+        {
13
+            _httpContextAccessor = httpContextAccessor;
14
+        }
15
+
16
+        public UsersDbo GetLoggedUser()
17
+        {
18
+            return _httpContextAccessor.HttpContext.GetLuLoggedUser();
19
+        }
20
+    }
21
+}

+ 1
- 6
Luticate2.Auth/Controllers/LuUsersController.cs View File

@@ -5,16 +5,11 @@ using Microsoft.Extensions.Options;
5 5
 
6 6
 namespace Luticate2.Auth.Controllers
7 7
 {
8
-    [Route("luticate/users")]
8
+    [Route(LuAuthExtensions.RoutePrefix)]
9 9
     public class LuUsersController : LuController
10 10
     {
11 11
         public LuUsersController(IOptions<LuUtilsOptionsDbo> luUtilsOptionsDbo) : base(luUtilsOptionsDbo)
12 12
         {
13 13
         }
14
-
15
-        public string Get()
16
-        {
17
-            return "users";
18
-        }
19 14
     }
20 15
 }

Luticate2.Auth/DataAccess/LuDatabaseContext.cs → Luticate2.Auth/DataAccess/LuAuthDatabaseContext.cs View File

@@ -3,20 +3,20 @@ using Luticate2.Auth.DataAccess.Models;
3 3
 
4 4
 namespace Luticate2.Auth.DataAccess
5 5
 {
6
-    public partial class LuDatabaseContext : DbContext
6
+    public partial class LuAuthDatabaseContext : DbContext
7 7
     {
8 8
         private readonly string _connectionString;
9 9
 
10
-        public LuDatabaseContext()
10
+        public LuAuthDatabaseContext()
11 11
         {
12 12
         }
13 13
 
14
-        public LuDatabaseContext(string connectionString)
14
+        public LuAuthDatabaseContext(string connectionString)
15 15
         {
16 16
             _connectionString = connectionString;
17 17
         }
18 18
 
19
-        public LuDatabaseContext(DbContextOptions options) :base(options)
19
+        public LuAuthDatabaseContext(DbContextOptions options) :base(options)
20 20
         {
21 21
         }
22 22
 

+ 38
- 24
Luticate2.Auth/DataAccess/LuGroupsDataAccess.cs View File

@@ -1,36 +1,50 @@
1
-using Luticate2.Auth.DataAccess.Models;
1
+using System;
2
+using Luticate2.Auth.DataAccess.Models;
2 3
 using Luticate2.Auth.Dbo.Groups;
3 4
 using Luticate2.Utils.DataAccess;
5
+using Luticate2.Utils.Dbo.Result;
6
+using Microsoft.EntityFrameworkCore;
7
+using Npgsql;
4 8
 
5 9
 namespace Luticate2.Auth.DataAccess
6 10
 {
7
-    public class LuGroupsDataAccess //: LuEfCrudDataAccess<lu_groups, LuGroupsAddDbo, LuGroupsDbo, LuDatabaseContext>
11
+    public class LuGroupsDataAccess : LuEfCrudDataAccess<lu_groups, LuGroupsAddDbo, LuGroupsDbo, LuGroupsAddDbo, LuAuthDatabaseContext, string>
8 12
     {
9
-//        public LuGroupsDataAccess(LuDatabaseContext db)
10
-//            : base(db, db.lu_groups)
11
-//        {
12
-//        }
13
+        public LuGroupsDataAccess(IServiceProvider serviceProvider) : base(serviceProvider)
14
+        {
15
+        }
13 16
 
14
-        public string Get()
17
+        protected override LuResult<T> HandleError<T>(Exception e)
15 18
         {
16
-            return "groups";
19
+            if (e is DbUpdateException && e.InnerException is PostgresException)
20
+            {
21
+                var pge = (PostgresException) e.InnerException;
22
+                if (pge.ConstraintName == "lu_groups_name_key")
23
+                {
24
+                    return LuResult<T>.Error(LuStatus.InputError, e, "Group name already exists");
25
+                }
26
+            }
27
+            return null;
17 28
         }
18 29
 
19
-//        protected override lu_groups GetModelFromTCreate(LuGroupsAddDbo obj)
20
-//        {
21
-//            return new lu_groups
22
-//            {
23
-//                name = obj.Name
24
-//            };
25
-//        }
26
-//
27
-//        protected override LuGroupsDbo GetDboFromModel(lu_groups model)
28
-//        {
29
-//            return new LuGroupsDbo
30
-//            {
31
-//                Id = model.id.ToString(),
32
-//                Name = model.name
33
-//            };
34
-//        }
30
+        protected override DbSet<lu_groups> GetTable(LuAuthDatabaseContext db)
31
+        {
32
+            return db.lu_groups;
33
+        }
34
+
35
+        protected override lu_groups GetModelFromTCreate(LuGroupsAddDbo obj)
36
+        {
37
+            return GetModelFromTUpdate(obj, new lu_groups());
38
+        }
39
+
40
+        protected override void EditModelFromTUpdate(LuGroupsAddDbo obj, lu_groups model)
41
+        {
42
+            model.name = obj.Name;
43
+        }
44
+
45
+        protected override LuGroupsDbo GetDboFromModel(lu_groups model)
46
+        {
47
+            return model.ToDbo();
48
+        }
35 49
     }
36 50
 }

+ 21
- 0
Luticate2.Auth/DataAccess/Models/ModelsToDbo.cs View File

@@ -0,0 +1,21 @@
1
+using Luticate2.Auth.Dbo.Groups;
2
+using Luticate2.Utils.Utils;
3
+
4
+namespace Luticate2.Auth.DataAccess.Models
5
+{
6
+    public static class ModelsToDbo
7
+    {
8
+        public static LuGroupsDbo ToDbo(this lu_groups model)
9
+        {
10
+            if (model == null)
11
+            {
12
+                return null;
13
+            }
14
+            return new LuGroupsDbo
15
+            {
16
+                Id = model.id.ToDbo(),
17
+                Name = model.name
18
+            };
19
+        }
20
+    }
21
+}

+ 1
- 1
Luticate2.Auth/DataAccess/Models/lu_authentication_sources.cs View File

@@ -18,7 +18,7 @@ namespace Luticate2.Auth.DataAccess.Models
18 18
         
19 19
         
20 20
         
21
-        public virtual ICollection<lu_users> lu_users_fk { get; set; }
21
+        public virtual IList<lu_users> lu_users_fk { get; set; }
22 22
         
23 23
     }
24 24
 }

+ 1
- 1
Luticate2.Auth/DataAccess/Models/lu_groups.cs View File

@@ -14,7 +14,7 @@ namespace Luticate2.Auth.DataAccess.Models
14 14
         
15 15
         
16 16
         
17
-        public virtual ICollection<lu_verb_users_groups> lu_verb_users_groups_fk { get; set; }
17
+        public virtual IList<lu_verb_users_groups> lu_verb_users_groups_fk { get; set; }
18 18
         
19 19
     }
20 20
 }

+ 3
- 1
Luticate2.Auth/DataAccess/Models/lu_users.cs View File

@@ -18,11 +18,13 @@ namespace Luticate2.Auth.DataAccess.Models
18 18
         
19 19
         public string salt { get; set; }
20 20
         
21
+        public string data { get; set; }
22
+        
21 23
         
22 24
         public virtual lu_authentication_sources fk_lu_authentication_sources { get; set; }
23 25
         
24 26
         
25
-        public virtual ICollection<lu_verb_users_groups> lu_verb_users_groups_fk { get; set; }
27
+        public virtual IList<lu_verb_users_groups> lu_verb_users_groups_fk { get; set; }
26 28
         
27 29
     }
28 30
 }

+ 4
- 4
Luticate2.Auth/DataAccess/code-from-ds/DataSource.twig View File

@@ -3,20 +3,20 @@ using Luticate2.Auth.DataAccess.Models;
3 3
 
4 4
 namespace Luticate2.Auth.DataAccess
5 5
 {
6
-    public partial class LuDatabaseContext : DbContext
6
+    public partial class LuAuthDatabaseContext : DbContext
7 7
     {
8 8
         private readonly string _connectionString;
9 9
 
10
-        public LuDatabaseContext()
10
+        public LuAuthDatabaseContext()
11 11
         {
12 12
         }
13 13
 
14
-        public LuDatabaseContext(string connectionString)
14
+        public LuAuthDatabaseContext(string connectionString)
15 15
         {
16 16
             _connectionString = connectionString;
17 17
         }
18 18
 
19
-        public LuDatabaseContext(DbContextOptions options) :base(options)
19
+        public LuAuthDatabaseContext(DbContextOptions options) :base(options)
20 20
         {
21 21
         }
22 22
 

+ 5
- 1
Luticate2.Auth/DataAccess/code-from-ds/code-from-ds.json View File

@@ -1,6 +1,6 @@
1 1
 {
2 2
     "castFileRelativePath": "Luticate2.Auth/DataAccess/code-from-ds/types-cast.json",
3
-    "dataSourceRelativePath": "Luticate2.Auth/DataAccess/LuDatabaseContext.cs",
3
+    "dataSourceRelativePath": "Luticate2.Auth/DataAccess/LuAuthDatabaseContext.cs",
4 4
     "modelsRelativePath": "Luticate2.Auth/DataAccess/Models",
5 5
     "selection": {
6 6
         "tables": [
@@ -59,6 +59,10 @@
59 59
                     {
60 60
                         "column": "salt",
61 61
                         "selected": true
62
+                    },
63
+                    {
64
+                        "column": "data",
65
+                        "selected": true
62 66
                     }
63 67
                 ],
64 68
                 "table": "lu_users"

+ 2
- 2
Luticate2.Auth/Dbo/Groups/LuGroupsAddDbo.cs View File

@@ -1,10 +1,10 @@
1
-using Luticate2.Utils.Dbo;
2
-using Luticate2.Utils.Dbo.Basic;
1
+using System.ComponentModel.DataAnnotations;
3 2
 
4 3
 namespace Luticate2.Auth.Dbo.Groups
5 4
 {
6 5
     public class LuGroupsAddDbo
7 6
     {
7
+        [Required(AllowEmptyStrings = false)]
8 8
         public string Name { get; set; }
9 9
     }
10 10
 }

+ 1
- 4
Luticate2.Auth/Dbo/Groups/LuGroupsDbo.cs View File

@@ -1,7 +1,4 @@
1
-using Luticate2.Utils.Dbo;
2
-using Luticate2.Utils.Dbo.Basic;
3
-
4
-namespace Luticate2.Auth.Dbo.Groups
1
+namespace Luticate2.Auth.Dbo.Groups
5 2
 {
6 3
     public class LuGroupsDbo
7 4
     {

+ 9
- 0
Luticate2.Auth/Dbo/Permissions/LuEntityTypes.cs View File

@@ -0,0 +1,9 @@
1
+namespace Luticate2.Auth.Dbo.Permissions
2
+{
3
+    public static class LuEntityTypes
4
+    {
5
+        public const string LuUsers = "LuUsers";
6
+
7
+        public const string LuGroups = "LuGroups";
8
+    }
9
+}

+ 9
- 0
Luticate2.Auth/Dbo/Permissions/LuPermissions.cs View File

@@ -0,0 +1,9 @@
1
+namespace Luticate2.Auth.Dbo.Permissions
2
+{
3
+    public static class LuPermissions
4
+    {
5
+        public const string LuGroupsRead = "LU_GROUPS_READ";
6
+
7
+        public const string LuGroupsWrite = "LU_GROUPS_WRITE";
8
+    }
9
+}

+ 3
- 4
Luticate2.Auth/Dbo/Users/UsersDbo.cs View File

@@ -1,10 +1,9 @@
1
-using Luticate2.Utils.Dbo;
2
-using Luticate2.Utils.Dbo.Basic;
3
-
4
-namespace Luticate2.Auth.Dbo.Users
1
+namespace Luticate2.Auth.Dbo.Users
5 2
 {
6 3
     public class UsersDbo
7 4
     {
5
+        public string Id { get; set; }
8 6
 
7
+        public string Username { get; set; }
9 8
     }
10 9
 }

+ 15
- 0
Luticate2.Auth/Dbo/Users/UsersToken.cs View File

@@ -0,0 +1,15 @@
1
+using System;
2
+
3
+namespace Luticate2.Auth.Dbo.Users
4
+{
5
+    public class UsersToken
6
+    {
7
+        public string UserId { get; set; }
8
+
9
+        public DateTime? NotBefore { get; set; }
10
+
11
+        public DateTime? NotAfter { get; set; }
12
+
13
+        public object Data { get; set; }
14
+    }
15
+}

+ 10
- 0
Luticate2.Auth/Interfaces/Groups/ILuGroupsBusiness.cs View File

@@ -0,0 +1,10 @@
1
+using Luticate2.Auth.Dbo.Groups;
2
+using Luticate2.Utils.Interfaces;
3
+
4
+namespace Luticate2.Auth.Interfaces.Groups
5
+{
6
+    public interface ILuGroupsBusiness : ILuCrudInterface<LuGroupsAddDbo, LuGroupsDbo, LuGroupsAddDbo, string>
7
+    {
8
+
9
+    }
10
+}

+ 9
- 0
Luticate2.Auth/Interfaces/Permissions/ILuAttrEntityAccessor.cs View File

@@ -0,0 +1,9 @@
1
+using Microsoft.AspNetCore.Mvc.Filters;
2
+
3
+namespace Luticate2.Auth.Interfaces.Permissions
4
+{
5
+    public interface ILuAttrEntityAccessor
6
+    {
7
+        object GetEntity(ActionExecutingContext context, object id);
8
+    }
9
+}

+ 13
- 0
Luticate2.Auth/Interfaces/Permissions/ILuPermissionsBusiness.cs View File

@@ -0,0 +1,13 @@
1
+using Luticate2.Utils.Dbo.Result;
2
+
3
+namespace Luticate2.Auth.Interfaces.Permissions
4
+{
5
+    public interface ILuPermissionsBusiness
6
+    {
7
+        LuResult<bool> GetPermissionValue(string permissionName, string srcEntityType, object srcEntity,
8
+            string dstEntityType, object dstEntity);
9
+
10
+        LuResult<bool> GetPermissionEffectiveValue(string permissionName, string srcEntityType, object srcEntity,
11
+            string dstEntityType, object dstEntity);
12
+    }
13
+}

+ 13
- 0
Luticate2.Auth/Interfaces/Permissions/ILuPermissionsProvider.cs View File

@@ -0,0 +1,13 @@
1
+using Luticate2.Utils.Dbo.Result;
2
+
3
+namespace Luticate2.Auth.Interfaces.Permissions
4
+{
5
+    public interface ILuPermissionsProvider
6
+    {
7
+        LuResult<bool?> GetPermissionValue(string permissionName, string srcEntityType, object srcEntity,
8
+            string dstEntityType, object dstEntity);
9
+
10
+        LuResult<bool?> GetPermissionEffectiveValue(string permissionName, string srcEntityType, object srcEntity,
11
+            string dstEntityType, object dstEntity);
12
+    }
13
+}

+ 9
- 0
Luticate2.Auth/Interfaces/Users/ILuLoggedUserAccessor.cs View File

@@ -0,0 +1,9 @@
1
+using Luticate2.Auth.Dbo.Users;
2
+
3
+namespace Luticate2.Auth.Interfaces.Users
4
+{
5
+    public interface ILuLoggedUserAccessor
6
+    {
7
+        UsersDbo GetLoggedUser();
8
+    }
9
+}

+ 16
- 0
Luticate2.Auth/Interfaces/Users/ILuUsersBusiness.cs View File

@@ -0,0 +1,16 @@
1
+using Luticate2.Auth.Dbo.Users;
2
+using Luticate2.Utils.Dbo.Result;
3
+
4
+namespace Luticate2.Auth.Interfaces.Users
5
+{
6
+    public interface ILuUsersBusiness
7
+    {
8
+        LuResult<UsersToken> GetToken(string token);
9
+
10
+        LuResult<string> RegisterToken(UsersToken token);
11
+
12
+        LuResult<UsersToken> UnRegisterToken(string token);
13
+
14
+        LuResult<UsersDbo> GetSingleById(string id);
15
+    }
16
+}

+ 0
- 34
Luticate2.Auth/Middlewares/LuAuthMiddleware.cs View File

@@ -1,34 +0,0 @@
1
-using System;
2
-using System.Linq;
3
-using System.Reflection;
4
-using System.Threading.Tasks;
5
-using Microsoft.AspNetCore.Http;
6
-using Microsoft.AspNetCore.Mvc.Controllers;
7
-using Microsoft.AspNetCore.Mvc.Infrastructure;
8
-
9
-namespace Luticate2.Auth.Middlewares
10
-{
11
-    public class LuAuthMiddleware
12
-    {
13
-        private readonly RequestDelegate _next;
14
-        private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;
15
-
16
-        public LuAuthMiddleware(RequestDelegate next, IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
17
-        {
18
-            _next = next;
19
-            _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
20
-        }
21
-
22
-        public async Task Invoke(HttpContext context)
23
-        {
24
-//            var items = _actionDescriptorCollectionProvider.ActionDescriptors.Items;
25
-//            var item = items.FirstOrDefault();
26
-//            var actionDescriptor = item as ControllerActionDescriptor;
27
-//            if (actionDescriptor != null)
28
-//            {
29
-////                actionDescriptor.MethodInfo.GetCustomAttributes()
30
-//            }
31
-            await _next.Invoke(context);
32
-        }
33
-    }
34
-}

+ 54
- 0
Luticate2.Auth/Middlewares/LuLoggedUserMiddleware.cs View File

@@ -0,0 +1,54 @@
1
+using System;
2
+using Luticate2.Auth.Controllers;
3
+using Luticate2.Auth.Dbo.Users;
4
+using Luticate2.Auth.Interfaces.Users;
5
+using Luticate2.Utils.Controllers;
6
+using Luticate2.Utils.Dbo.Result;
7
+using Luticate2.Utils.Utils;
8
+using Microsoft.AspNetCore.Mvc.Filters;
9
+
10
+namespace Luticate2.Auth.Middlewares
11
+{
12
+    public class LuLoggedUserMiddleware : IActionFilter
13
+    {
14
+        public const string TokenCookieName = "luticate2-token";
15
+
16
+        private readonly ILuUsersBusiness _luUsersBusiness;
17
+
18
+        public LuLoggedUserMiddleware(ILuUsersBusiness luUsersBusiness)
19
+        {
20
+            _luUsersBusiness = luUsersBusiness;
21
+        }
22
+
23
+        public void OnActionExecuting(ActionExecutingContext context)
24
+        {
25
+            var token = context.HttpContext.Request.Cookies[TokenCookieName];
26
+            var userId = Guid.Empty.ToDbo();
27
+            if (!string.IsNullOrWhiteSpace(token))
28
+            {
29
+                var tokenRes = _luUsersBusiness.GetToken(token);
30
+                if (tokenRes.Status == LuStatus.NotFound)
31
+                {
32
+                    throw new LuResultException(LuResult<object>.Error(LuStatus.LoginError, $"{token}", "Invalid session"));
33
+                }
34
+                if (!tokenRes)
35
+                {
36
+                    throw new LuResultException(tokenRes.To<object>());
37
+                }
38
+                userId = tokenRes.Data.UserId;
39
+            }
40
+
41
+            var userRes = _luUsersBusiness.GetSingleById(userId);
42
+            if (!userRes)
43
+            {
44
+                throw new LuResultException(userRes.To<object>());
45
+            }
46
+
47
+            context.HttpContext.SetLuLoggedUser(userRes.Data);
48
+        }
49
+
50
+        public void OnActionExecuted(ActionExecutedContext context)
51
+        {
52
+        }
53
+    }
54
+}

+ 57
- 0
Luticate2.Auth/Middlewares/LuPermissionMiddleware.cs View File

@@ -0,0 +1,57 @@
1
+using System;
2
+using System.Reflection;
3
+using Luticate2.Auth.Attributes;
4
+using Luticate2.Auth.Interfaces.Permissions;
5
+using Luticate2.Auth.Interfaces.Users;
6
+using Luticate2.Utils.Controllers;
7
+using Luticate2.Utils.Dbo.Result;
8
+using Microsoft.AspNetCore.Mvc.Controllers;
9
+using Microsoft.AspNetCore.Mvc.Filters;
10
+using Microsoft.Extensions.DependencyInjection;
11
+
12
+namespace Luticate2.Auth.Middlewares
13
+{
14
+    public class LuPermissionMiddleware : IActionFilter
15
+    {
16
+        private readonly IServiceProvider _serviceProvider;
17
+        private readonly ILuPermissionsBusiness _luPermissionsBusiness;
18
+
19
+        public LuPermissionMiddleware(IServiceProvider serviceProvider, ILuPermissionsBusiness luPermissionsBusiness)
20
+        {
21
+            _serviceProvider = serviceProvider;
22
+            _luPermissionsBusiness = luPermissionsBusiness;
23
+        }
24
+
25
+        public void OnActionExecuting(ActionExecutingContext context)
26
+        {
27
+            var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
28
+            if (actionDescriptor != null)
29
+            {
30
+                var attributes = actionDescriptor.MethodInfo.GetCustomAttributes<LuPermissionAttribute>();
31
+                foreach (var attribute in attributes)
32
+                {
33
+                    var srcAccessor = _serviceProvider.GetService(attribute.SrcEntityAccessor) as ILuAttrEntityAccessor;
34
+                    var dstAccessor = _serviceProvider.GetService(attribute.DstEntityAccessor) as ILuAttrEntityAccessor;
35
+                    var srcEntity = srcAccessor?.GetEntity(context, attribute.Id);
36
+                    var dstEntity = dstAccessor?.GetEntity(context, attribute.Id);
37
+                    var permissionValue = _luPermissionsBusiness.GetPermissionEffectiveValue(attribute.PermissionName,
38
+                        attribute.SrcEntityType, srcEntity, attribute.DstEntityType, dstEntity);
39
+                    if (!permissionValue)
40
+                    {
41
+                        throw new LuResultException(permissionValue.To<object>());
42
+                    }
43
+                    if (!permissionValue.Data)
44
+                    {
45
+                        var user = _serviceProvider.GetService<ILuLoggedUserAccessor>().GetLoggedUser();
46
+                        throw new LuResultException(LuResult<object>.Error(LuStatus.PermissionError,
47
+                            $"user: {user?.Id} {user?.Username}", "Permission denied"));
48
+                    }
49
+                }
50
+            }
51
+        }
52
+
53
+        public void OnActionExecuted(ActionExecutedContext context)
54
+        {
55
+        }
56
+    }
57
+}

+ 1
- 1
Luticate2.Auth/project.json View File

@@ -1,5 +1,5 @@
1 1
 {
2
-    "version": "0.1.0",
2
+    "version": "0.5.0",
3 3
     "buildOptions": {
4 4
         "debugType": "portable"
5 5
     },

+ 6
- 1
Luticate2.Utils/Controllers/LuUtilsExtensions.cs View File

@@ -159,7 +159,12 @@ namespace Luticate2.Utils.Controllers
159 159
 
160 160
         public static IDictionary<object, object> GetLuItems(this HttpContext context)
161 161
         {
162
-            return (IDictionary<object, object>) context.Items["luticateItems"];
162
+            const string key = "luticateItems";
163
+            if (!context.Items.ContainsKey(key))
164
+            {
165
+                context.Items.Add(key, new Dictionary<object, object>());
166
+            }
167
+            return (IDictionary<object, object>) context.Items[key];
163 168
         }
164 169
     }
165 170
 }

+ 24
- 0
TestAuth/Business/LuGroupsBusinessTest.cs View File

@@ -0,0 +1,24 @@
1
+using Luticate2.Auth.Dbo.Groups;
2
+using Luticate2.Auth.Interfaces.Groups;
3
+using Luticate2.Utils.Dbo.Result;
4
+using Luticate2.Utils.Utils;
5
+using Xunit;
6
+
7
+namespace TestAuth.Business
8
+{
9
+    public class LuGroupsBusinessTest
10
+    {
11
+        [Fact]
12
+        public void Test1()
13
+        {
14
+            Tests.TestRealDb<ILuGroupsBusiness>(business =>
15
+            {
16
+                var res = business.AddDbo(new LuGroupsAddDbo
17
+                {
18
+                    Name = "Test."
19
+                });
20
+                Assert.Equal(LuStatus.Success, res.Status);
21
+            });
22
+        }
23
+    }
24
+}

+ 26
- 0
TestAuth/Properties/AssemblyInfo.cs View File

@@ -0,0 +1,26 @@
1
+using System.Reflection;
2
+using System.Runtime.CompilerServices;
3
+using System.Runtime.InteropServices;
4
+
5
+// General Information about an assembly is controlled through the following
6
+// set of attributes. Change these attribute values to modify the information
7
+// associated with an assembly.
8
+
9
+[assembly: AssemblyTitle("TestAuth")]
10
+[assembly: AssemblyDescription("")]
11
+[assembly: AssemblyConfiguration("")]
12
+[assembly: AssemblyCompany("")]
13
+[assembly: AssemblyProduct("TestAuth")]
14
+[assembly: AssemblyCopyright("Copyright ©  2017")]
15
+[assembly: AssemblyTrademark("")]
16
+[assembly: AssemblyCulture("")]
17
+
18
+// Setting ComVisible to false makes the types in this assembly not visible
19
+// to COM components.  If you need to access a type in this assembly from
20
+// COM, set the ComVisible attribute to true on that type.
21
+
22
+[assembly: ComVisible(false)]
23
+
24
+// The following GUID is for the ID of the typelib if this project is exposed to COM
25
+
26
+[assembly: Guid("5064E1F4-DAAF-440E-81C7-6C0BDCF5BCC7")]

+ 22
- 0
TestAuth/TestAuth.xproj View File

@@ -0,0 +1,22 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+  <PropertyGroup>
4
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
5
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
6
+  </PropertyGroup>
7
+
8
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
9
+  <PropertyGroup Label="Globals">
10
+    <ProjectGuid>{5064E1F4-DAAF-440E-81C7-6C0BDCF5BCC7}</ProjectGuid>
11
+    <ProjectTypeGuids>{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}</ProjectTypeGuids>
12
+    <RootNamespace>TestAuth</RootNamespace>
13
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
14
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
15
+    <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
16
+  </PropertyGroup>
17
+
18
+  <PropertyGroup>
19
+    <SchemaVersion>2.0</SchemaVersion>
20
+  </PropertyGroup>
21
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
22
+</Project>

+ 51
- 0
TestAuth/Tests.cs View File

@@ -0,0 +1,51 @@
1
+using System;
2
+using Luticate2.Auth.Controllers;
3
+using Luticate2.Auth.DataAccess;
4
+using Luticate2.Utils.DataAccess;
5
+using Microsoft.EntityFrameworkCore;
6
+using Microsoft.Extensions.DependencyInjection;
7
+
8
+namespace TestAuth
9
+{
10
+    public class Tests
11
+    {
12
+        public const string RealDbConnectionString =
13
+            "User ID=dev;Password=dev;Host=localhost;Port=5432;Database=luticate2;Pooling=true;";
14
+
15
+        public static IServiceProvider BuildRealDbServiceProvider()
16
+        {
17
+            IServiceCollection serviceCollection = new ServiceCollection();
18
+            serviceCollection.AddLuticateAuth(dbo =>
19
+            {
20
+                dbo.Version = "tests";
21
+            }, builder =>
22
+            {
23
+                builder.UseNpgsql(RealDbConnectionString);
24
+            });
25
+            return serviceCollection.BuildServiceProvider();
26
+        }
27
+
28
+        protected static void _TestRealDb(Action<IServiceProvider> func)
29
+        {
30
+            var serviceProvider = BuildRealDbServiceProvider();
31
+            var transactionScope = serviceProvider.GetService<LuEfTransactionScope>();
32
+            transactionScope.BeginTransaction<LuAuthDatabaseContext>(null);
33
+            try
34
+            {
35
+                func(serviceProvider);
36
+            }
37
+            finally
38
+            {
39
+                transactionScope.RollbackTransaction<LuAuthDatabaseContext>();
40
+            }
41
+        }
42
+
43
+        public static void TestRealDb<TService>(Action<TService> func)
44
+        {
45
+            _TestRealDb(provider =>
46
+            {
47
+                func(provider.GetService<TService>());
48
+            });
49
+        }
50
+    }
51
+}

+ 28
- 0
TestAuth/project.json View File

@@ -0,0 +1,28 @@
1
+{
2
+    "version": "0.1.0",
3
+    "buildOptions": {
4
+        "debugType": "portable"
5
+    },
6
+    "dependencies": {
7
+        "dotnet-test-xunit": "1.0.0-rc2-*",
8
+        "Luticate2.Auth": "0.5.*",
9
+        "Moq": "4.6.38-alpha",
10
+        "System.Runtime.Serialization.Primitives": "4.1.1",
11
+        "xunit": "2.1.0"
12
+    },
13
+    "testRunner": "xunit",
14
+    "frameworks": {
15
+        "netcoreapp1.0": {
16
+            "dependencies": {
17
+                "Microsoft.NETCore.App": {
18
+                    "type": "platform",
19
+                    "version": "1.0.1"
20
+                }
21
+            },
22
+            "imports": [
23
+                "dotnet5.4",
24
+                "portable-net451+win8"
25
+            ]
26
+        }
27
+    }
28
+}

+ 44
- 0
WebApiAuth/Controllers/ValuesController.cs View File

@@ -0,0 +1,44 @@
1
+using System;
2
+using System.Collections.Generic;
3
+using System.Linq;
4
+using System.Threading.Tasks;
5
+using Microsoft.AspNetCore.Mvc;
6
+
7
+namespace WebApiAuth.Controllers
8
+{
9
+    [Route("api/[controller]")]
10
+    public class ValuesController : Controller
11
+    {
12
+        // GET api/values
13
+        [HttpGet]
14
+        public IEnumerable<string> Get()
15
+        {
16
+            return new string[] {"value1", "value2"};
17
+        }
18
+
19
+        // GET api/values/5
20
+        [HttpGet("{id}")]
21
+        public string Get(int id)
22
+        {
23
+            return "value";
24
+        }
25
+
26
+        // POST api/values
27
+        [HttpPost]
28
+        public void Post([FromBody] string value)
29
+        {
30
+        }
31
+
32
+        // PUT api/values/5
33
+        [HttpPut("{id}")]
34
+        public void Put(int id, [FromBody] string value)
35
+        {
36
+        }
37
+
38
+        // DELETE api/values/5
39
+        [HttpDelete("{id}")]
40
+        public void Delete(int id)
41
+        {
42
+        }
43
+    }
44
+}

+ 25
- 0
WebApiAuth/Program.cs View File

@@ -0,0 +1,25 @@
1
+using System;
2
+using System.Collections.Generic;
3
+using System.IO;
4
+using System.Linq;
5
+using System.Threading.Tasks;
6
+using Microsoft.AspNetCore.Hosting;
7
+
8
+namespace WebApiAuth
9
+{
10
+    public class Program
11
+    {
12
+        public static void Main(string[] args)
13
+        {
14
+            var host = new WebHostBuilder()
15
+                .UseKestrel()
16
+                .UseContentRoot(Directory.GetCurrentDirectory())
17
+                .UseUrls("http://0.0.0.0:8080")
18
+                .UseIISIntegration()
19
+                .UseStartup<Startup>()
20
+                .Build();
21
+
22
+            host.Run();
23
+        }
24
+    }
25
+}

+ 26
- 0
WebApiAuth/Properties/AssemblyInfo.cs View File

@@ -0,0 +1,26 @@
1
+using System.Reflection;
2
+using System.Runtime.CompilerServices;
3
+using System.Runtime.InteropServices;
4
+
5
+// General Information about an assembly is controlled through the following
6
+// set of attributes. Change these attribute values to modify the information
7
+// associated with an assembly.
8
+
9
+[assembly: AssemblyTitle("WebApiAuth")]
10
+[assembly: AssemblyDescription("")]
11
+[assembly: AssemblyConfiguration("")]
12
+[assembly: AssemblyCompany("")]
13
+[assembly: AssemblyProduct("WebApiAuth")]
14
+[assembly: AssemblyCopyright("Copyright ©  2017")]
15
+[assembly: AssemblyTrademark("")]
16
+[assembly: AssemblyCulture("")]
17
+
18
+// Setting ComVisible to false makes the types in this assembly not visible
19
+// to COM components.  If you need to access a type in this assembly from
20
+// COM, set the ComVisible attribute to true on that type.
21
+
22
+[assembly: ComVisible(false)]
23
+
24
+// The following GUID is for the ID of the typelib if this project is exposed to COM
25
+
26
+[assembly: Guid("D71E5DEE-6122-45D0-8A09-C05F79B1A17E")]

+ 59
- 0
WebApiAuth/Startup.cs View File

@@ -0,0 +1,59 @@
1
+using System;
2
+using System.Collections.Generic;
3
+using System.Linq;
4
+using System.Threading.Tasks;
5
+using Luticate2.Auth.Controllers;
6
+using Microsoft.AspNetCore.Builder;
7
+using Microsoft.AspNetCore.Hosting;
8
+using Microsoft.EntityFrameworkCore;
9
+using Microsoft.Extensions.Configuration;
10
+using Microsoft.Extensions.DependencyInjection;
11
+using Microsoft.Extensions.Logging;
12
+
13
+namespace WebApiAuth
14
+{
15
+    public class Startup
16
+    {
17
+        public Startup(IHostingEnvironment env)
18
+        {
19
+            var builder = new ConfigurationBuilder()
20
+                .SetBasePath(env.ContentRootPath)
21
+                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
22
+                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
23
+
24
+            if (env.IsEnvironment("Development"))
25
+            {
26
+                // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
27
+                builder.AddApplicationInsightsSettings(developerMode: true);
28
+            }
29
+
30
+            builder.AddEnvironmentVariables();
31
+            Configuration = builder.Build();
32
+        }
33
+
34
+        public IConfigurationRoot Configuration { get; }
35
+
36
+        // This method gets called by the runtime. Use this method to add services to the container
37
+        public void ConfigureServices(IServiceCollection services)
38
+        {
39
+            services.AddLuticateAuth(options => options.Version = "dev", options =>
40
+            {
41
+                options.UseNpgsql(Configuration.GetConnectionString("default"));
42
+            });
43
+
44
+            services.AddMvc()
45
+                .AddLuticateAuth();
46
+        }
47
+
48
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline
49
+        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
50
+        {
51
+            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
52
+            loggerFactory.AddDebug();
53
+
54
+            app.UseLuticateAuth();
55
+
56
+            app.UseMvc();
57
+        }
58
+    }
59
+}

+ 22
- 0
WebApiAuth/WebApiAuth.xproj View File

@@ -0,0 +1,22 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+  <PropertyGroup>
4
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
5
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
6
+  </PropertyGroup>
7
+
8
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
9
+  <PropertyGroup Label="Globals">
10
+    <ProjectGuid>{D71E5DEE-6122-45D0-8A09-C05F79B1A17E}</ProjectGuid>
11
+    <ProjectTypeGuids>{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}</ProjectTypeGuids>
12
+    <RootNamespace>WebApiAuth</RootNamespace>
13
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
14
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
15
+    <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
16
+  </PropertyGroup>
17
+
18
+  <PropertyGroup>
19
+    <SchemaVersion>2.0</SchemaVersion>
20
+  </PropertyGroup>
21
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
22
+</Project>

+ 14
- 0
WebApiAuth/appsettings.Development.json View File

@@ -0,0 +1,14 @@
1
+{
2
+    "Logging": {
3
+        "IncludeScopes": false,
4
+        "LogLevel": {
5
+            "Default": "Debug",
6
+            "System": "Information",
7
+            "Microsoft": "Information",
8
+            "Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory": "Information"
9
+        }
10
+    },
11
+    "ConnectionStrings": {
12
+        "default":  "User ID=dev;Password=dev;Host=localhost;Port=5432;Database=luticate2;Pooling=true;ApplicationName=WebApiAuthDev"
13
+    }
14
+}

+ 15
- 0
WebApiAuth/appsettings.json View File

@@ -0,0 +1,15 @@
1
+{
2
+    "Logging": {
3
+        "IncludeScopes": false,
4
+        "LogLevel": {
5
+            "Default": "Information",
6
+            "System": "Information",
7
+            "Microsoft": "Information",
8
+            "Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory": "Error",
9
+            "Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor": "Error"
10
+        }
11
+    },
12
+    "ConnectionStrings": {
13
+        "default":  "User ID=POSTGRES_USER;Password=POSTGRES_PASSWORD;Host=POSTGRES_HOST;Port=5432;Database=POSTGRES_DB;Pooling=true;ApplicationName=WebApiUtils"
14
+    }
15
+}

+ 55
- 0
WebApiAuth/project.json View File

@@ -0,0 +1,55 @@
1
+{
2
+    "dependencies": {
3
+        "TestAuth": "0.1.*",
4
+        "Microsoft.ApplicationInsights.AspNetCore": "1.0.2",
5
+        "Microsoft.AspNetCore.Mvc": "1.1.0",
6
+        "Microsoft.AspNetCore.Routing": "1.1.0",
7
+        "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
8
+        "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
9
+        "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
10
+        "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0",
11
+        "Microsoft.Extensions.Configuration.Json": "1.1.0",
12
+        "Microsoft.Extensions.Logging": "1.1.0",
13
+        "Microsoft.Extensions.Logging.Console": "1.1.0",
14
+        "Microsoft.Extensions.Logging.Debug": "1.1.0",
15
+        "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
16
+        "Microsoft.NETCore.App": {
17
+            "version": "1.0.1",
18
+            "type": "platform"
19
+        }
20
+    },
21
+    "tools": {
22
+        "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
23
+    },
24
+    "frameworks": {
25
+        "netcoreapp1.0": {
26
+            "imports": [
27
+                "dotnet5.6",
28
+                "portable-net45+win8"
29
+            ]
30
+        }
31
+    },
32
+    "buildOptions": {
33
+        "emitEntryPoint": true,
34
+        "debugType": "portable",
35
+        "preserveCompilationContext": true
36
+    },
37
+    "runtimeOptions": {
38
+        "configProperties": {
39
+            "System.GC.Server": true
40
+        }
41
+    },
42
+    "publishOptions": {
43
+        "include": [
44
+            "wwwroot",
45
+            "**/*.cshtml",
46
+            "appsettings.json",
47
+            "web.config"
48
+        ]
49
+    },
50
+    "scripts": {
51
+        "postpublish": [
52
+            "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%"
53
+        ]
54
+    }
55
+}

+ 14
- 0
WebApiAuth/web.config View File

@@ -0,0 +1,14 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<configuration>
3
+
4
+  <!--
5
+    Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
6
+  -->
7
+
8
+  <system.webServer>
9
+    <handlers>
10
+      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
11
+    </handlers>
12
+    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
13
+  </system.webServer>
14
+</configuration>

+ 12
- 0
luticate2.sln View File

@@ -11,6 +11,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestUtils", "TestUtils\Test
11 11
 EndProject
12 12
 Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "WebApiUtils", "WebApiUtils\WebApiUtils.xproj", "{8380B793-B696-4979-A892-1BCAFA66A64E}"
13 13
 EndProject
14
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "WebApiAuth", "WebApiAuth\WebApiAuth.xproj", "{D71E5DEE-6122-45D0-8A09-C05F79B1A17E}"
15
+EndProject
16
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestAuth", "TestAuth\TestAuth.xproj", "{5064E1F4-DAAF-440E-81C7-6C0BDCF5BCC7}"
17
+EndProject
14 18
 Global
15 19
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 20
 		Debug|Any CPU = Debug|Any CPU
@@ -33,6 +37,14 @@ Global
33 37
 		{8380B793-B696-4979-A892-1BCAFA66A64E}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 38
 		{8380B793-B696-4979-A892-1BCAFA66A64E}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 39
 		{8380B793-B696-4979-A892-1BCAFA66A64E}.Release|Any CPU.Build.0 = Release|Any CPU
40
+		{D71E5DEE-6122-45D0-8A09-C05F79B1A17E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41
+		{D71E5DEE-6122-45D0-8A09-C05F79B1A17E}.Debug|Any CPU.Build.0 = Debug|Any CPU
42
+		{D71E5DEE-6122-45D0-8A09-C05F79B1A17E}.Release|Any CPU.ActiveCfg = Release|Any CPU
43
+		{D71E5DEE-6122-45D0-8A09-C05F79B1A17E}.Release|Any CPU.Build.0 = Release|Any CPU
44
+		{5064E1F4-DAAF-440E-81C7-6C0BDCF5BCC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45
+		{5064E1F4-DAAF-440E-81C7-6C0BDCF5BCC7}.Debug|Any CPU.Build.0 = Debug|Any CPU
46
+		{5064E1F4-DAAF-440E-81C7-6C0BDCF5BCC7}.Release|Any CPU.ActiveCfg = Release|Any CPU
47
+		{5064E1F4-DAAF-440E-81C7-6C0BDCF5BCC7}.Release|Any CPU.Build.0 = Release|Any CPU
36 48
 	EndGlobalSection
37 49
 	GlobalSection(SolutionProperties) = preSolution
38 50
 		HideSolutionNode = FALSE

Loading…
Cancel
Save