Skip to content

Commit

Permalink
TenantTypes is now [Flags] and has AddSharding
Browse files Browse the repository at this point in the history
  • Loading branch information
JonPSmith committed Mar 16, 2022
1 parent d092a7b commit 3f0ed4b
Show file tree
Hide file tree
Showing 16 changed files with 201 additions and 27 deletions.
6 changes: 2 additions & 4 deletions AuthPermissions.AspNetCore/SetupExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ private static void RegisterCommonServices(this AuthSetupData setupData)
setupData.Services.AddScoped<IClaimsCalculator, ClaimsCalculator>();
setupData.Services.AddTransient<IUsersPermissionsService, UsersPermissionsService>();
setupData.Services.AddTransient<IEncryptDecryptService, EncryptDecryptService>();
if (setupData.Options.TenantType != TenantTypes.NotUsingTenants)
if (setupData.Options.TenantType.IsMultiTenant())
SetupMultiTenantServices(setupData);

//The factories for the optional services
Expand Down Expand Up @@ -231,15 +231,13 @@ private static void SetupMultiTenantServices(AuthSetupData setupData)
{
//This sets up the code to get the DataKey to the application's DbContext



if (setupData.Options.LinkToTenantType == LinkToTenantTypes.NotTurnedOn)
//This uses the efficient GetDataKey from user
setupData.Services.AddScoped<IGetDataKeyFromUser, GetDataKeyFromUserNormal>();
else
{
//Check the TenantType and LinkToTenantType for incorrect versions
if (setupData.Options.TenantType != TenantTypes.SingleLevel
if (!setupData.Options.TenantType.IsHierarchical()
&& setupData.Options.LinkToTenantType == LinkToTenantTypes.AppAndHierarchicalUsers)
throw new AuthPermissionsException(
$"You can't set the {nameof(AuthPermissionsOptions.LinkToTenantType)} to " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public AuthRolesAdminService(AuthPermissionsDbContext context, AuthPermissionsOp
{
_context = context;
_permissionType = options.InternalData.EnumPermissionsType;
_isMultiTenant = options.TenantType != TenantTypes.NotUsingTenants;
_isMultiTenant = options.TenantType.IsMultiTenant();
}

/// <summary>
Expand Down
13 changes: 7 additions & 6 deletions AuthPermissions/AdminCode/Services/AuthTenantAdminService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using AuthPermissions.AdminCode.Services.Internal;
using AuthPermissions.CommonCode;
using AuthPermissions.DataLayer;
using AuthPermissions.DataLayer.Classes;
Expand Down Expand Up @@ -71,7 +72,7 @@ public IQueryable<Tenant> QueryTenants()
/// <returns>query on the AuthP database</returns>
public IQueryable<Tenant> QueryEndLeafTenants()
{
return _tenantType == TenantTypes.SingleLevel
return _tenantType.IsSingleLevel()
? QueryTenants()
: _context.Tenants.Where(x => !x.Children.Any());
}
Expand Down Expand Up @@ -138,9 +139,9 @@ public async Task<IStatusGeneric> AddSingleTenantAsync(string tenantName, List<s
{
var status = new StatusGenericHandler { Message = $"Successfully added the new tenant {tenantName}." };

if (_tenantType != TenantTypes.SingleLevel)
if (!_tenantType.IsSingleLevel())
throw new AuthPermissionsException(
$"You cannot add a single tenant because the tenant configuration is {_tenantType}");
$"You cannot add a single tenant because the tenant configuration is {_tenantType}");

var tenantChangeService = _tenantChangeServiceFactory.GetService();

Expand Down Expand Up @@ -192,7 +193,7 @@ public async Task<IStatusGeneric> AddHierarchicalTenantAsync(string tenantName,
{
var status = new StatusGenericHandler();

if (_tenantType != TenantTypes.HierarchicalTenant)
if (!_tenantType.IsHierarchical())
throw new AuthPermissionsException(
$"You must set the {nameof(AuthPermissionsOptions.TenantType)} before you can use tenants");
if (tenantName.Contains('|'))
Expand Down Expand Up @@ -258,7 +259,7 @@ public async Task<IStatusGeneric> AddHierarchicalTenantAsync(string tenantName,
/// <returns></returns>
public async Task<IStatusGeneric> UpdateTenantRolesAsync(int tenantId, List<string> newTenantRoleNames)
{
if (_tenantType == TenantTypes.NotUsingTenants)
if (!_tenantType.IsMultiTenant())
throw new AuthPermissionsException(
$"You must set the {nameof(AuthPermissionsOptions.TenantType)} parameter in the AuthP's options");

Expand Down Expand Up @@ -377,7 +378,7 @@ public async Task<IStatusGeneric> MoveHierarchicalTenantToAnotherParentAsync(int
{
var status = new StatusGenericHandler { };

if (_tenantType != TenantTypes.HierarchicalTenant)
if (!_tenantType.IsHierarchical())
throw new AuthPermissionsException(
$"You cannot add a hierarchical tenant because the tenant configuration is {_tenantType}");

Expand Down
3 changes: 2 additions & 1 deletion AuthPermissions/AdminCode/Services/AuthUsersAdminService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AuthPermissions.AdminCode.Services.Internal;
using AuthPermissions.CommonCode;
using AuthPermissions.DataLayer.Classes;
using AuthPermissions.DataLayer.Classes.SupportTypes;
Expand Down Expand Up @@ -37,7 +38,7 @@ public AuthUsersAdminService(AuthPermissionsDbContext context,
{
_context = context ?? throw new ArgumentNullException(nameof(context));
_syncAuthenticationUsersFactory = syncAuthenticationUsersFactory;
_isMultiTenant = options.TenantType != TenantTypes.NotUsingTenants;
_isMultiTenant = options.TenantType.IsMultiTenant();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
// Copyright (c) 2022 Jon P Smith, GitHub: JonPSmith, web: http://www.thereformedprogrammer.net/
// Licensed under MIT license. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using AuthPermissions.CommonCode;
using AuthPermissions.DataLayer.Classes.SupportTypes;
Expand Down
44 changes: 44 additions & 0 deletions AuthPermissions/AdminCode/TenantTypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2022 Jon P Smith, GitHub: JonPSmith, web: http://www.thereformedprogrammer.net/
// Licensed under MIT license. See License.txt in the project root for license information.

using AuthPermissions.CommonCode;
using AuthPermissions.SetupCode;

namespace AuthPermissions.AdminCode;

public static class TenantTypeExtensions
{
public static void ThrowExceptionIfTenantTypeIsWrong(this TenantTypes tenantType)
{
if (tenantType.HasFlag(TenantTypes.SingleLevel) && tenantType.HasFlag(TenantTypes.HierarchicalTenant))
throw new AuthPermissionsException(
$"The {nameof(AuthPermissionsOptions.TenantType)} option can't have {nameof(TenantTypes.SingleLevel)} and "+
$"{nameof(TenantTypes.HierarchicalTenant)} at the same time.");

if (!tenantType.IsMultiTenant() && tenantType.HasFlag(TenantTypes.AddSharding))
throw new AuthPermissionsException(
$"You need to set the {nameof(AuthPermissionsOptions.TenantType)} option to either {nameof(TenantTypes.SingleLevel)} or " +
$"{nameof(TenantTypes.HierarchicalTenant)} when setting the {nameof(TenantTypes.AddSharding)} flag.");

}

public static bool IsMultiTenant(this TenantTypes tenantType)
{
return tenantType.HasFlag(TenantTypes.SingleLevel) || tenantType.HasFlag(TenantTypes.HierarchicalTenant);
}

public static bool IsSingleLevel(this TenantTypes tenantType)
{
return tenantType.HasFlag(TenantTypes.SingleLevel);
}

public static bool IsHierarchical(this TenantTypes tenantType)
{
return tenantType.HasFlag(TenantTypes.HierarchicalTenant);
}

public static bool UsingSharding(this TenantTypes tenantType)
{
return tenantType.HasFlag(TenantTypes.AddSharding);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AuthPermissions.AdminCode;
using AuthPermissions.AdminCode.Services.Internal;
using AuthPermissions.DataLayer.Classes;
using AuthPermissions.DataLayer.Classes.SupportTypes;
using AuthPermissions.DataLayer.EfCode;
Expand Down Expand Up @@ -52,14 +54,14 @@ public async Task<IStatusGeneric> AddTenantsToDatabaseAsync(List<BulkLoadTenantD
return status;

//Check the options are set
if (options.TenantType == TenantTypes.NotUsingTenants)
if (!options.TenantType.IsMultiTenant())
return status.AddError(
$"You must set the options {nameof(AuthPermissionsOptions.TenantType)} to allow tenants to be processed");

//This takes a COPY of the data because the code stores a tracked tenant in the database
var tenantsSetupCopy = tenantSetupData.ToList();

if (options.TenantType == TenantTypes.SingleLevel)
if (options.TenantType.IsSingleLevel())
{
var duplicateNames = tenantsSetupCopy.Select(x => x.TenantName)
.GroupBy(x => x).Where(x => x.Count() > 1).Select(x => x.Key).ToList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AuthPermissions.AdminCode;
using AuthPermissions.AdminCode.Services.Internal;
using AuthPermissions.BulkLoadServices.Concrete.Internal;
using AuthPermissions.CommonCode;
using AuthPermissions.DataLayer.Classes;
Expand Down Expand Up @@ -108,7 +110,7 @@ private async Task<IStatusGeneric> CreateUserTenantAndAddToDbAsync(BulkLoadUserW
(findUserInfoService == null ? " wasn't available." : " couldn't find it either.")));

Tenant userTenant = null;
if (_options.TenantType != TenantTypes.NotUsingTenants && !string.IsNullOrEmpty(userDefine.TenantNameForDataKey))
if (_options.TenantType.IsMultiTenant() && !string.IsNullOrEmpty(userDefine.TenantNameForDataKey))
{
userTenant = await _context.Tenants.SingleOrDefaultAsync(x => x.TenantFullName == userDefine.TenantNameForDataKey);
if (userTenant == null)
Expand Down
6 changes: 4 additions & 2 deletions AuthPermissions/ClaimsCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using AuthPermissions.AdminCode;
using AuthPermissions.AdminCode.Services.Internal;
using AuthPermissions.DataLayer.Classes.SupportTypes;
using AuthPermissions.DataLayer.EfCode;
using AuthPermissions.PermissionsCode;
Expand Down Expand Up @@ -82,7 +84,7 @@ private async Task<string> CalcPermissionsForUserAsync(string userId)
.Select(x => x.Role.PackedPermissionsInRole)
.ToListAsync();

if (_options.TenantType != TenantTypes.NotUsingTenants)
if (_options.TenantType.IsMultiTenant())
{
//We need to add any RoleTypes.TenantAdminAdd for a tenant user

Expand Down Expand Up @@ -113,7 +115,7 @@ private async Task<string> CalcPermissionsForUserAsync(string userId)
/// <returns>Returns the dataKey, or null if a) tenant isn't turned on, or b) the user doesn't have a tenant</returns>
private async Task<string> GetDataKeyAsync(string userid)
{
if (_options.TenantType == TenantTypes.NotUsingTenants)
if (!_options.TenantType.IsMultiTenant())
return null;

var userWithTenant = await _context.AuthUsers.Include(x => x.UserTenant)
Expand Down
4 changes: 3 additions & 1 deletion AuthPermissions/SetupCode/BulkLoadOnStartup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using AuthPermissions.AdminCode;
using AuthPermissions.AdminCode.Services.Internal;
using AuthPermissions.BulkLoadServices.Concrete;
using AuthPermissions.DataLayer.EfCode;
using AuthPermissions.SetupCode.Factories;
Expand Down Expand Up @@ -37,7 +39,7 @@ public static async Task<IStatusGeneric> SeedRolesTenantsUsersIfEmpty(this AuthP
status = await roleLoader.AddRolesToDatabaseAsync(options.InternalData.RolesPermissionsSetupData);
}

if (status is { IsValid: true } && options.TenantType != TenantTypes.NotUsingTenants && !context.Tenants.Any())
if (status is { IsValid: true } && options.TenantType.IsMultiTenant() && !context.Tenants.Any())
{
var tenantLoader = new BulkLoadTenantsService(context);
status = await tenantLoader.AddTenantsToDatabaseAsync(options.InternalData.TenantSetupData, options);
Expand Down
21 changes: 17 additions & 4 deletions AuthPermissions/SetupCode/TenantTypes.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,39 @@
// Copyright (c) 2021 Jon P Smith, GitHub: JonPSmith, web: http://www.thereformedprogrammer.net/
// Licensed under MIT license. See License.txt in the project root for license information.

using System;

namespace AuthPermissions.SetupCode
{
/// <summary>
/// This defines the types of tenant the AuthPermissions can handle
/// This defines the types of tenant the AuthPermissions can handle, with optional sharding
/// </summary>
[Flags]
public enum TenantTypes
{
/// <summary>
/// Usage of tenants are turned off
/// </summary>
NotUsingTenants,
NotUsingTenants = 0,
/// <summary>
/// Multi-tenant with one level only, e.g. a company has different departments: sales, finance, HR etc.
/// A User can only be in one of these levels
/// </summary>
SingleLevel,
SingleLevel = 1,
/// <summary>
/// Multi-tenant with one level only, e.g. a company has different departments: sales, finance, HR etc.
/// A tenant can be mixed in with
/// </summary>
/// <summary>
/// Multi-tenant many levels, e.g. Holding company -> USA branch -> East Coast -> New York
/// A User at the USA branch has read/write access to the USA branch data, read-only access to the East Coast and all its subsidiaries
/// </summary>
HierarchicalTenant
HierarchicalTenant = 2,
/// <summary>
/// This turns on the sharding. Sharding allows tenants to be split across many databases, including placing a tenant's data in its own database.
///
/// </summary>
AddSharding = 4

}
}
2 changes: 2 additions & 0 deletions AuthPermissions/SetupExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using AuthPermissions.AdminCode;
using AuthPermissions.CommonCode;
using AuthPermissions.DataLayer.Classes.SupportTypes;
using AuthPermissions.DataLayer.EfCode;
Expand Down Expand Up @@ -32,6 +33,7 @@ public static AuthSetupData RegisterAuthPermissions<TEnumPermissions>(this IServ
{
var authOptions = new AuthPermissionsOptions();
options?.Invoke(authOptions);
authOptions.TenantType.ThrowExceptionIfTenantTypeIsWrong();
authOptions.InternalData.EnumPermissionsType = typeof(TEnumPermissions);
authOptions.InternalData.EnumPermissionsType.ThrowExceptionIfEnumIsNotCorrect();
authOptions.InternalData.EnumPermissionsType.ThrowExceptionIfEnumHasMembersHaveDuplicateValues();
Expand Down
2 changes: 2 additions & 0 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

- BREAKING CHANGE: The ITenantChangeService has changed to allow multi-tenant sharding to be added - see #14
- BREAKING CHANGE: The option called AppConnectionString has been removed. Its longer needed because of ITenantChangeService change
- New Feature: Adding optional sharding to either a single-level or hierarchical multi-tenant applications - see documentation for an article explaining how to setup sharding



## 2.3.1
Expand Down
2 changes: 1 addition & 1 deletion Test/TestData/Test.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
82e9ba63-1e53-4c0b-9a78-c3704baf399c
8db6e054-0ea3-42f9-a143-4cba433737f7
Loading

0 comments on commit 3f0ed4b

Please sign in to comment.