Round #484
09 May 2026, 19:40· csharp· qwen2.5-coder-7b-instruct· r13-clean-hints
- Complexity
- band 1
- ZP / UO / OBS
- 5 / 5 / 1
- Journey weight
- 742
- Lightshift ΔL
- +0.80
Prompt
Implement tenant-scoped authorization that prevents cross-tenant access
Zero-point index (what the engine surfaced)
ZPI-ZPI-0008 | 2026-05-09T19:40:41Z
Implement tenant-scoped authorization that prevents cross-tenant access
ZERO POINT — 5 entries (structural invariants)
● hsl(178.91, 100%, 27%) IAuthorizationHandler [contract]
● hsl(14.32, 100%, 27%) IAuthorizationRequirement [contract]
● hsl(349.17, 100%, 27%) AuthorizationHandler<TRequirement> [contract]
● hsl(83.28, 100%, 18%) ITenantInfo [contract]
● hsl(281.88, 100%, 18%) IMultiTenantStore<TTenantInfo> [contract]
UNOBSERVED — 5 entries (implied truths)
○ hsl(27.69, 100%, 50%) async [feature]
○ hsl(49.23, 100%, 50%) try [feature]
○ hsl(112.62, 100%, 30%) Token validation parameters [function]
○ hsl(31.38, 100%, 42%) Scoped registration [function]
○ hsl(44.31, 100%, 42%) IOptions of T binding [function]
OBSERVED — 1 entries (explicit in request)
◉ hsl(102.56, 100%, 28%) scoped [feature]
COMPLEXITY │ 11 entries │ spread: 85° │ band: MEDIUM
Baseline response (no ZPI)
To implement tenant-scoped authorization in a C# application, you can use ASP.NET Core's built-in support for authorization policies along with custom claims to identify the tenant. Below is a step-by-step guide on how to achieve this:
### Step 1: Define Tenant Claims
First, ensure that your authentication system includes a claim that identifies the tenant. This could be done during user login or token issuance.
```csharp
public class CustomClaimsIdentity : ClaimsIdentity
{
public CustomClaimsIdentity(IEnumerable<Claim> claims, string authenticationType)
: base(claims, authenticationType)
{
}
public static CustomClaimsIdentity CreateFromUser(User user, string tenantId)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim("TenantId", tenantId)
};
return new CustomClaimsIdentity(claims, "Custom");
}
}
```
### Step 2: Configure Authentication and Authorization
In your `Startup.cs` or `Program.cs`, configure authentication and authorization to use the custom claims.
```csharp
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("TenantScoped", policy =>
{
policy.RequireClaim("TenantId");
});
});
services.AddControllers();
}
```
### Step 3: Apply Authorization Policies
Apply the `TenantScoped` policy to your controllers or actions where you want to enforce tenant isolation.
```csharp
[ApiController]
[Route("[controller]")]
public class DataController : ControllerBase
{
[HttpGet("{id}")]
[Authorize(Policy = "TenantScoped")]
public IActionResult GetData(int id)
{
var tenantId = User.FindFirst("TenantId")?.Value;
// Ensure the data belongs to the current tenant
if (IsDataForCurrentTenant(id, tenantId))
{
return Ok(data);
}
else
{
return Forbid();
}
}
private bool IsDataForCurrentTenant(int id, string tenantId)
{
// Implement logic to check if data belongs to the current tenant
return true; // Placeholder
}
}
```
### Step 4: Ensure Data Isolation
In your business logic, ensure that any operations on data respect the tenant boundary. This might involve checking the `TenantId` claim before performing database queries or other operations.
```csharp
public class DataService
{
private readonly ApplicationDbContext _context;
public DataService(ApplicationDbContext context)
{
_context = context;
}
public async Task<List<DataItem>> GetDataForCurrentTenant()
{
var tenantId = User.FindFirst("TenantId")?.Value;
return await _context.DataItems
.Where(item => item.TenantId == tenantId)
.ToListAsync();
}
}
```
### Step 5: Handle Cross-Tenant Access
If a user tries to access data from another tenant, the `Forbid` method will be called, which returns a 403 Forbidden response.
```csharp
[HttpGet("{id}")]
[Authorize(Policy = "TenantScoped")]
public IActionResult GetData(int id)
{
var tenantId = User.FindFirst("TenantId")?.Value;
if (IsDataForCurrentTenant(id, tenantId))
{
return Ok(data);
}
else
{
return Forbid();
}
}
```
By following these steps, you can implement tenant-scoped authorization in your C# application to prevent cross-tenant access.
Enhanced response (with ZPI)
To implement tenant-scoped authorization that prevents cross-tenant access, we'll create a custom authorization handler and requirement. We'll also use dependency injection to manage the tenant information.
Here's the implementation:
1. **Create the `ITenantInfo` interface:**
```csharp
public interface ITenantInfo
{
string TenantId { get; }
}
```
2. **Create the `IMultiTenantStore<TTenantInfo>` interface:**
```csharp
public interface IMultiTenantStore<TTenantInfo>
{
Task<TTenantInfo> GetTenantInfoAsync(string tenantId);
}
```
3. **Create the custom authorization requirement:**
```csharp
public class TenantAuthorizationRequirement : IAuthorizationRequirement
{
public string ExpectedTenantId { get; }
public TenantAuthorizationRequirement(string expectedTenantId)
{
ExpectedTenantId = expectedTenantId;
}
}
```
4. **Create the custom authorization handler:**
```csharp
public class TenantAuthorizationHandler : AuthorizationHandler<TenantAuthorizationRequirement>
{
private readonly ITenantInfo _tenantInfo;
public TenantAuthorizationHandler(ITenantInfo tenantInfo)
{
_tenantInfo = tenantInfo;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TenantAuthorizationRequirement requirement)
{
if (context.User == null || !context.User.Identity.IsAuthenticated)
{
context.Fail();
return Task.CompletedTask;
}
var userTenantId = context.User.FindFirst("tenant_id")?.Value;
if (userTenantId != requirement.ExpectedTenantId)
{
context.Fail();
}
else
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
```
5. **Register the services in the dependency injection container:**
```csharp
public void ConfigureServices(IServiceCollection services)
{
// Register ITenantInfo and IMultiTenantStore<TTenantInfo>
services.AddScoped<ITenantInfo, TenantInfo>();
services.AddScoped<IMultiTenantStore<TenantInfo>, MultiTenantStore>();
// Register the authorization handler
services.AddAuthorization(options =>
{
options.AddPolicy("TenantAccess", policy =>
policy.Requirements.Add(new TenantAuthorizationRequirement("your-expected-tenant-id")));
});
// Add other services and middleware
}
```
6. **Create a concrete implementation of `ITenantInfo`:**
```csharp
public class TenantInfo : ITenantInfo
{
public string TenantId { get; }
public TenantInfo(string tenantId)
{
TenantId = tenantId;
}
}
```
7. **Create a concrete implementation of `IMultiTenantStore<TTenantInfo>`:**
```csharp
public class MultiTenantStore : IMultiTenantStore<TenantInfo>
{
private readonly Dictionary<string, TenantInfo> _tenants;
public MultiTenantStore()
{
_tenants = new Dictionary<string, TenantInfo>
{
{ "tenant1", new TenantInfo("tenant1") },
{ "tenant2", new TenantInfo("tenant2") }
};
}
public Task<TenantInfo> GetTenantInfoAsync(string tenantId)
{
if (_tenants.TryGetValue(tenantId, out var tenant))
{
return Task.FromResult(tenant);
}
throw new ArgumentException("Invalid tenant ID");
}
}
```
8. **Use the authorization policy in your controller or action:**
```csharp
[Authorize(Policy = "TenantAccess")]
public class TenantController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("This is a tenant-scoped resource.");
}
}
```
### Explanation:
1. **ITenantInfo and IMultiTenantStore<TTenantInfo>:** These interfaces define the contract for retrieving tenant information.
2. **TenantAuthorizationRequirement:** This class represents the requirement that must be met for authorization to proceed.
3. **TenantAuthorizationHandler:** This handler checks if the user's tenant ID matches the expected tenant ID.
4. **Dependency Injection Registration:** The services are registered in the DI container, including the custom authorization policy.
5. **Concrete Implementations:** `TenantInfo` and `MultiTenantStore` provide concrete implementations of the interfaces.
6. **Authorization Policy Usage:** The `[Authorize]` attribute is used to apply the tenant access policy to a controller or action.
This implementation ensures that only requests from users with the correct tenant ID are allowed, preventing cross-tenant access.
Grader chain
Each grader reads the same baseline + enhanced pair and casts an independent verdict. Disagreement is the framework's own signal — not noise to be averaged away.
V1samba/Meta-Llama-3.3-70B-Instruct
BetterV4qwen2.5-coder-3b-instruct
BetterV5cerebras/qwen-3-235b-a22b-instruct-2507
BetterV7qwen2.5-coder-7b-instruct
BetterV8openai/gpt-4.1
BetterV9anthropic/claude-opus-4-7
WorseV12openai/gpt-4o
BetterComments
Our grader said what it said. What do you say? Comment as a guest below.
No comments yet. Be the first to say what you make of this round.