Skip to content

Commit a751c4e

Browse files
committed
Don't lock the subscription owner of his tenants when TenantManager authorizations have been removed. (need to be checked further)
1 parent 186a98d commit a751c4e

File tree

13 files changed

+29
-23
lines changed

13 files changed

+29
-23
lines changed

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ User accounts for login in Security UI:
3434
| adminuser | admin | can manage system roles and authorizations |
3535
| user1| user | manage subscription and tenant |
3636

37-
Don't remove the "TenantManger" role on the user1, or detatch him from the subscription, or your will be locked out of your tenant.
38-
(implements your own better rules).
39-
4037
3. Play and deep dive in the code...
4138

4239
*If you want to run the integration test project, pls comment this line:

UbikLink.IntegrationTests/AspireFixture.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ private void ModifyResourcesForTesting()
140140
// port.Port = 8081;
141141
//}
142142

143-
144-
145143
var containerLifetimeAnnotation = keycloak.Annotations
146144
.OfType<ContainerLifetimeAnnotation>()
147145
.FirstOrDefault();

UbikLink.Proxy/Authorizations/UserTenantRolesOrAuthorizationsRequirement.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ public enum PermissionMode
1010
Authorization
1111
}
1212

13-
public class UserTenantRolesOrAuthorizationsRequirement(string[] values, PermissionMode mode) : IAuthorizationRequirement
13+
public class UserTenantRolesOrAuthorizationsRequirement(string[] values, PermissionMode mode, bool isSubscriptionOwnerAllowed) : IAuthorizationRequirement
1414
{
1515
public string[] Values { get; set; } = values;
1616
public PermissionMode Mode { get; set; } = mode;
17+
public bool IsSubscriptionOwnerAllowed { get; set; } = isSubscriptionOwnerAllowed;
1718
}
1819

1920
public class UserRolesAuthorizationOkHandler(UserService userService)
@@ -44,14 +45,12 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext
4445
return;
4546
}
4647

47-
//TODO: it's a security hole (need to check)
48-
// Certain tenant authorizations don't need to be deleted or you will be locked out of a tenant...
49-
//if (requirement.IsSubscriptionOwnerAllowed
50-
// && userInfo.OwnerOfSubscriptionsIds.Any())
51-
//{
52-
// context.Succeed(requirement);
53-
// return;
54-
//}
48+
//TODO: check that
49+
if (requirement.IsSubscriptionOwnerAllowed && userInfo.IsSubOwnerOfTheSelectetdTenant)
50+
{
51+
context.Succeed(requirement);
52+
return;
53+
}
5554

5655
switch (requirement.Mode)
5756
{

UbikLink.Proxy/Program.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,13 @@
9999
.AddPolicy("IsSubOwner", policy =>
100100
policy.Requirements.Add(new UserInfoOnlyRequirement(RoleRequirement.SubscriptionOwner)))
101101
.AddPolicy("CanReadTenant", policy =>
102-
policy.Requirements.Add(new UserTenantRolesOrAuthorizationsRequirement(["tenant:read"], PermissionMode.Authorization)))
102+
policy.Requirements.Add(new UserTenantRolesOrAuthorizationsRequirement(["tenant:read"], PermissionMode.Authorization, true)))
103103
.AddPolicy("CanReadTenantAndReadUser", policy =>
104-
policy.Requirements.Add(new UserTenantRolesOrAuthorizationsRequirement(["tenant:read", "user:read"], PermissionMode.Authorization)))
104+
policy.Requirements.Add(new UserTenantRolesOrAuthorizationsRequirement(["tenant:read", "user:read"], PermissionMode.Authorization, true)))
105105
.AddPolicy("CanReadTenantAndWriteUserRole", policy =>
106-
policy.Requirements.Add(new UserTenantRolesOrAuthorizationsRequirement(["tenant:read", "user:read", "tenant-user-role:write"], PermissionMode.Authorization)))
106+
policy.Requirements.Add(new UserTenantRolesOrAuthorizationsRequirement(["tenant:read", "user:read", "tenant-user-role:write"], PermissionMode.Authorization, true)))
107107
.AddPolicy("CanReadTenantAndReadTenantRoles", policy =>
108-
policy.Requirements.Add(new UserTenantRolesOrAuthorizationsRequirement(["tenant:read", "tenant-role:read"], PermissionMode.Authorization)));
108+
policy.Requirements.Add(new UserTenantRolesOrAuthorizationsRequirement(["tenant:read", "tenant-role:read"], PermissionMode.Authorization, true)));
109109

110110

111111
//Proxy

UbikLink.Security.Api/Features/Users/Services/Poco/UserWithSubscriptionInfo.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class UserWithSubscriptionInfo
1414
public required string Email { get; set; }
1515
public bool IsMegaAdmin { get; set; } = false;
1616
public Guid? SelectedTenantId { get; set; }
17+
public bool IsSubOwnerOfTheSelectetdTenant { get; init; } = false;
1718
public bool IsActiveInSelectedSubscription { get; set; }
1819
public List<Guid> OwnerOfSubscriptionsIds { get; set; } = [];
1920
public List<AuthorizationModel> SelectedTenantAuthorizations { get; set; } = [];

UbikLink.Security.Api/Features/Users/Services/UserQueryService.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public async Task<Either<IFeatureError, UserWithSubscriptionInfo>>
3030
{
3131
var con = _ctx.Database.GetDbConnection();
3232
var sql = $"""
33-
SELECT su.is_activated
33+
SELECT su.is_activated, su.is_owner
3434
FROM subscriptions_users su
3535
INNER JOIN users u ON su.user_id = u.id
3636
INNER JOIN tenants t ON t.id = u.selected_tenant_id
@@ -39,7 +39,7 @@ FROM subscriptions_users su
3939
AND su.subscription_id = t.subscription_id
4040
""";
4141

42-
var active = await con.QuerySingleOrDefaultAsync<bool?>(sql, new { userId = user.Id, user.SelectedTenantId }) ?? false;
42+
var activeAndOwner = await con.QuerySingleOrDefaultAsync<(bool? Active,bool? Owner)>(sql, new { userId = user.Id, user.SelectedTenantId });
4343

4444
if (con.State == System.Data.ConnectionState.Open)
4545
await con.CloseAsync();
@@ -48,7 +48,8 @@ FROM subscriptions_users su
4848
{
4949
AuthId = user.AuthId,
5050
Id = user.Id,
51-
IsActiveInSelectedSubscription = active,
51+
IsActiveInSelectedSubscription = activeAndOwner.Active == null ? false : (bool)activeAndOwner.Active,
52+
IsSubOwnerOfTheSelectetdTenant = activeAndOwner.Owner == null ? false : (bool)activeAndOwner.Owner,
5253
SelectedTenantId = user.SelectedTenantId,
5354
Email = user.Email,
5455
Firstname = user.Firstname,

UbikLink.Security.Api/Mappers/UserMappers.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public static UserProxyResult MapToUserProxyResult(this UserWithSubscriptionInfo
1919
Firstname = user.Firstname,
2020
Lastname = user.Lastname,
2121
Email = user.Email,
22+
IsSubOwnerOfTheSelectetdTenant = user.IsSubOwnerOfTheSelectetdTenant,
2223
IsActivatedInSelectedSubscription = user.IsActiveInSelectedSubscription,
2324
IsMegaAdmin = user.IsMegaAdmin,
2425
SelectedTenantId = user.SelectedTenantId,
@@ -38,6 +39,7 @@ public static UserMeResult MapToUserMeResult(this UserWithSubscriptionInfo user)
3839
Firstname = user.Firstname,
3940
Lastname = user.Lastname,
4041
Email = user.Email,
42+
IsSubOwnerOfTheSelectetdTenant = user.IsSubOwnerOfTheSelectetdTenant,
4143
IsActivatedInSelectedSubscription = user.IsActiveInSelectedSubscription,
4244
IsMegaAdmin = user.IsMegaAdmin,
4345
SelectedTenantId = user.SelectedTenantId,

UbikLink.Security.Contracts/Users/Results/UserMeResult.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public record UserMeResult
1919
public bool IsMegaAdmin { get; init; } = false;
2020
public IEnumerable<Guid> OwnerOfSubscriptionsIds { get; init; } = default!;
2121
public Guid? SelectedTenantId { get; init; }
22+
public bool IsSubOwnerOfTheSelectetdTenant { get; init; } = false;
2223
public List<AuthorizationLightResult> SelectedTenantAuthorizations { get; init; } = [];
2324
public List<RoleLightResult> SelectedTenantRoles { get; init; } = [];
2425
public Guid Version { get; init; }

UbikLink.Security.Contracts/Users/Results/UserProxyResult.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public record UserProxyResult
1414
public bool IsMegaAdmin { get; init; } = false;
1515
public IEnumerable<Guid> OwnerOfSubscriptionsIds { get; init; } = default!;
1616
public Guid? SelectedTenantId { get; init; }
17+
public bool IsSubOwnerOfTheSelectetdTenant { get; init; } = false;
1718
public List<AuthorizationLightResult> SelectedTenantAuthorizations { get; init; } = [];
1819
public List<RoleLightResult> SelectedTenantRoles { get; init; } = [];
1920
public Guid Version { get; init; }

UbikLink.Security.UI/Components/Tenant/TenantPage.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<UbikContentContainer>
1313
<UbikFluentBreadcrumb Items="BreadcrumbItems" WithClose="false" />
1414

15-
@if (_isTenantManager)
15+
@if (_isTenantManager || _isSubscriptionOwner)
1616
{
1717
<FluentStack Orientation="Orientation.Vertical" Class="tw-mb-2 tw-mt-3">
1818
<div>

0 commit comments

Comments
 (0)