Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions src/Idmt.Plugin/Configuration/IdmtOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,10 @@ public static class IdmtMultiTenantStrategy
public const string Route = "route";
public const string BasePath = "basepath";

// Strategy options keys

public const string HeaderKeyOption = "HeaderKey";
public const string ClaimOption = "ClaimType";
public const string RouteParameterOption = "RouteParameter";

// Strategy options defaults

public const string DefaultHeaderName = "__tenant__";
public const string DefaultClaimType = "tenant";
public const string DefaultHeader = "__tenant__";
public const string DefaultClaim = "tenant";
public const string DefaultRouteParameter = "__tenant__";
}

Expand Down
6 changes: 3 additions & 3 deletions src/Idmt.Plugin/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,18 +185,18 @@ private static void ConfigureMultiTenant(IServiceCollection services, IdmtOption
{
case IdmtMultiTenantStrategy.Header:
builder.WithHeaderStrategy(
idmtOptions.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.HeaderKeyOption, IdmtMultiTenantStrategy.DefaultHeaderName));
idmtOptions.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.Header, IdmtMultiTenantStrategy.DefaultHeader));
break;

case IdmtMultiTenantStrategy.Route:
builder.WithRouteStrategy(
idmtOptions.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.RouteParameterOption, IdmtMultiTenantStrategy.DefaultRouteParameter),
idmtOptions.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.Route, IdmtMultiTenantStrategy.DefaultRouteParameter),
useTenantAmbientRouteValue: true);
break;

case IdmtMultiTenantStrategy.Claim:
builder.WithClaimStrategy(
idmtOptions.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.ClaimOption, IdmtMultiTenantStrategy.DefaultClaimType));
idmtOptions.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.Claim, IdmtMultiTenantStrategy.DefaultClaim));
break;

case IdmtMultiTenantStrategy.BasePath:
Expand Down
1 change: 1 addition & 0 deletions src/Idmt.Plugin/Features/Auth/Login.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Finbuckle.MultiTenant.Abstractions;
using Idmt.Plugin.Configuration;
using Idmt.Plugin.Models;
using Idmt.Plugin.Validation;
using Microsoft.AspNetCore.Authentication;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ private bool ValidateTokenTenant(

// Get the tenant claim type from configuration
var tenantClaimType = idmtOptions.Value.MultiTenant.StrategyOptions.GetValueOrDefault(
IdmtMultiTenantStrategy.ClaimOption,
IdmtMultiTenantStrategy.DefaultClaimType);
IdmtMultiTenantStrategy.Claim,
IdmtMultiTenantStrategy.DefaultClaim);

// Extract tenant claim from token
var tokenTenantClaim = context.User.FindFirst(tenantClaimType)?.Value;
Expand Down
4 changes: 2 additions & 2 deletions src/Idmt.Plugin/Services/CurrentUserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ internal sealed class CurrentUserService(
multiTenantContextAccessor.MultiTenantContext?.TenantInfo?.Id;

public string? TenantIdentifier =>
User?.FindFirstValue(idmtOptions.Value.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.ClaimOption, IdmtMultiTenantStrategy.DefaultClaimType)) ??
User?.FindFirstValue(idmtOptions.Value.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.Claim, IdmtMultiTenantStrategy.DefaultClaim)) ??
multiTenantContextAccessor.MultiTenantContext?.TenantInfo?.Identifier;

public bool IsActive => User?.FindFirstValue("is_active") == "true";
public bool IsActive => string.Equals(User?.FindFirstValue("is_active"), "true", StringComparison.OrdinalIgnoreCase);

public bool IsInRole(string role) => User?.IsInRole(role) ?? false;

Expand Down
2 changes: 1 addition & 1 deletion src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ protected override async Task<ClaimsIdentity> GenerateClaimsAsync(IdmtUser user)

// Add tenant claim for multi-tenant strategies (header, claim, route)
// This ensures token validation includes tenant context
var claimKey = idmtOptions.Value.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.ClaimOption, IdmtMultiTenantStrategy.DefaultClaimType);
var claimKey = idmtOptions.Value.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.Claim, IdmtMultiTenantStrategy.DefaultClaim);

// Try to get tenant info from store using user's TenantId
var tenantInfo = await tenantStore.GetAsync(user.TenantId) ?? throw new InvalidOperationException($"Tenant information not found for tenant ID: {user.TenantId}. User ID: {user.Id}");
Expand Down
8 changes: 6 additions & 2 deletions src/samples/Idmt.BasicSample/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
"Idmt": {
"MultiTenant": {
"DefaultTenantId": "system-tenant",
"Strategies": ["header", "claim"]
"Strategies": ["header", "claim"],
"StrategyOptions": {
"header": "__tenant-identifier__",
"claim": "tenant-identifier"
}
}
}
}
}
8 changes: 6 additions & 2 deletions src/samples/Idmt.BasicSample/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
"Idmt": {
"MultiTenant": {
"DefaultTenantId": "system-tenant",
"Strategies": ["header", "claim"]
"Strategies": ["header", "claim"],
"StrategyOptions": {
"header": "__tenant-identifier__",
"claim": "tenant-identifier"
}
}
}
}
}
11 changes: 8 additions & 3 deletions src/tests/Idmt.BasicSample.Tests/IdmtApiFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Moq;

namespace Idmt.BasicSample.Tests;
Expand Down Expand Up @@ -92,13 +93,17 @@ public HttpClient CreateClientWithTenant(string? tenantId = null, bool allowAuto
AllowAutoRedirect = allowAutoRedirect,
});

if (_strategies.Contains(IdmtMultiTenantStrategy.Route))
var idmtOptions = Services.GetRequiredService<IOptions<IdmtOptions>>().Value;

var strategies = idmtOptions.MultiTenant.Strategies;

if (strategies.Contains(IdmtMultiTenantStrategy.Route))
{
client.BaseAddress = new Uri($"http://localhost/{tenantId}/");
}
if (_strategies.Contains(IdmtMultiTenantStrategy.Header))
if (strategies.Contains(IdmtMultiTenantStrategy.Header))
{
client.DefaultRequestHeaders.TryAddWithoutValidation(IdmtMultiTenantStrategy.DefaultHeaderName, tenantId);
client.DefaultRequestHeaders.TryAddWithoutValidation(idmtOptions.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.Header, IdmtMultiTenantStrategy.DefaultHeader), tenantId);
}
return client;
}
Expand Down
4 changes: 2 additions & 2 deletions src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public void TenantIdentifier_ReturnsTenantIdentifier_WhenClaimExists()
var user = new System.Security.Claims.ClaimsPrincipal(
new System.Security.Claims.ClaimsIdentity(
[
new System.Security.Claims.Claim(IdmtMultiTenantStrategy.DefaultClaimType, tenantId)
new System.Security.Claims.Claim(IdmtMultiTenantStrategy.DefaultClaim, tenantId)
]));

_service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0");
Expand Down Expand Up @@ -165,7 +165,7 @@ public void TenantIdentifier_ReturnsTenantIdentifier_WhenCustomClaimTypeIsConfig
{
StrategyOptions = new Dictionary<string, string>
{
{ IdmtMultiTenantStrategy.ClaimOption, customClaimType }
{ IdmtMultiTenantStrategy.Claim, customClaimType }
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ public async Task CreateAsync_AddsTenantClaim_WithDefaultClaimType()

var identity = await CallGenerateClaimsAsync(user);

var tenantClaim = identity.FindFirst(IdmtMultiTenantStrategy.DefaultClaimType);
var tenantClaim = identity.FindFirst(IdmtMultiTenantStrategy.DefaultClaim);
Assert.NotNull(tenantClaim);
// The factory adds tenantInfo.Identifier, not tenantId
Assert.Equal(tenantIdentifier, tenantClaim.Value);
Expand All @@ -196,7 +196,7 @@ public async Task CreateAsync_AddsTenantClaim_WithCustomClaimType()
{
StrategyOptions = new Dictionary<string, string>
{
{ IdmtMultiTenantStrategy.ClaimOption, customClaimType }
{ IdmtMultiTenantStrategy.Claim, customClaimType }
}
}
};
Expand Down Expand Up @@ -236,7 +236,7 @@ public async Task CreateAsync_AddsTenantClaim_WithCustomClaimType()
Assert.Equal(tenantIdentifier, tenantClaim.Value);

// Verify default claim type is not present
var defaultTenantClaim = identity.FindFirst(IdmtMultiTenantStrategy.DefaultClaimType);
var defaultTenantClaim = identity.FindFirst(IdmtMultiTenantStrategy.DefaultClaim);
Assert.Null(defaultTenantClaim);
}

Expand Down Expand Up @@ -302,7 +302,7 @@ public async Task CreateAsync_AddsAllCustomClaims()
Assert.NotNull(isActiveClaim);
Assert.Equal("True", isActiveClaim.Value);

var tenantClaim = identity.FindFirst(IdmtMultiTenantStrategy.DefaultClaimType);
var tenantClaim = identity.FindFirst(IdmtMultiTenantStrategy.DefaultClaim);
Assert.NotNull(tenantClaim);
// The factory adds tenantInfo.Identifier, not tenantId
Assert.Equal(tenantIdentifier, tenantClaim.Value);
Expand Down