Skip to content

Commit fddfa22

Browse files
committed
Use Claims more for User and Device
1 parent 9cee0c5 commit fddfa22

File tree

12 files changed

+93
-142
lines changed

12 files changed

+93
-142
lines changed

API/Controller/Device/GetSelf.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using Microsoft.EntityFrameworkCore;
55
using OpenShock.API.Controller.Users;
66
using OpenShock.API.Models.Response;
7+
using OpenShock.Common.Authentication;
8+
using OpenShock.Common.Extensions;
79
using OpenShock.Common.Models;
810

911
namespace OpenShock.API.Controller.Device;
@@ -19,7 +21,11 @@ public sealed partial class DeviceController
1921
[ProducesResponseType<LegacyDataResponse<DeviceSelfResponse>>(StatusCodes.Status200OK, MediaTypeNames.Application.Json)]
2022
public async Task<IActionResult> GetSelf()
2123
{
22-
var shockers = await _db.Shockers.Where(x => x.DeviceId == CurrentDevice.Id).Select(x => new MinimalShocker
24+
var identity = User.GetOpenShockUserIdentity();
25+
var currentHubId = identity.GetClaimValueAsGuid(OpenShockAuthClaims.HubId);
26+
var currentHubName = identity.GetClaimValue(OpenShockAuthClaims.HubName);
27+
28+
var shockers = await _db.Shockers.Where(x => x.DeviceId == currentHubId).Select(x => new MinimalShocker
2329
{
2430
Id = x.Id,
2531
RfId = x.RfId,
@@ -28,8 +34,8 @@ public async Task<IActionResult> GetSelf()
2834

2935
return LegacyDataOk(new DeviceSelfResponse
3036
{
31-
Id = CurrentDevice.Id,
32-
Name = CurrentDevice.Name,
37+
Id = currentHubId,
38+
Name = currentHubName,
3339
Shockers = shockers
3440
}
3541
);

API/Controller/Device/_ApiController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
using Asp.Versioning;
22
using Microsoft.AspNetCore.Authorization;
33
using Microsoft.AspNetCore.Mvc;
4+
using OpenShock.Common;
45
using OpenShock.Common.Authentication;
5-
using OpenShock.Common.Authentication.ControllerBase;
66
using OpenShock.Common.OpenShockDb;
77
using Redis.OM.Contracts;
88

@@ -17,7 +17,7 @@ namespace OpenShock.API.Controller.Device;
1717
[Tags("Hub Endpoints")]
1818
[Route("/{version:apiVersion}/device")]
1919
[Authorize(AuthenticationSchemes = OpenShockAuthSchemes.HubToken)]
20-
public sealed partial class DeviceController : AuthenticatedHubControllerBase
20+
public sealed partial class DeviceController : OpenShockControllerBase
2121
{
2222
private readonly OpenShockContext _db;
2323
private readonly IRedisConnectionProvider _redis;

API/Controller/OAuth/HandOff.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.AspNetCore.Authentication;
1+
using System.Security.Claims;
2+
using Microsoft.AspNetCore.Authentication;
23
using Microsoft.AspNetCore.Mvc;
34
using Microsoft.AspNetCore.RateLimiting;
45
using OpenShock.API.Services.OAuthConnection;
@@ -81,12 +82,15 @@ public async Task<IActionResult> OAuthHandOff(
8182

8283
case OAuthFlow.Link:
8384
{
84-
if (!User.TryGetAuthenticatedOpenShockUserId(out var userId))
85+
var identity = User.TryGetOpenShockUserIdentity();
86+
if (identity is null)
8587
{
8688
await HttpContext.SignOutAsync(OAuthConstants.FlowScheme);
8789
return RedirectFrontendError("mustBeAuthenticated");
8890
}
8991

92+
var userId = identity.GetClaimValueAsGuid(ClaimTypes.NameIdentifier);
93+
9094
if (connection is not null)
9195
{
9296
await HttpContext.SignOutAsync(OAuthConstants.FlowScheme);

Common/Authentication/AuthenticationHandlers/HubAuthentication.cs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ namespace OpenShock.Common.Authentication.AuthenticationHandlers;
1616
/// </summary>
1717
public sealed class HubAuthentication : AuthenticationHandler<AuthenticationSchemeOptions>
1818
{
19-
private readonly IClientAuthService<Device> _authService;
2019
private readonly OpenShockContext _db;
2120

2221
private OpenShockProblem? _authResultError = null;
@@ -26,38 +25,44 @@ public HubAuthentication(
2625
IOptionsMonitor<AuthenticationSchemeOptions> options,
2726
ILoggerFactory logger,
2827
UrlEncoder encoder,
29-
IClientAuthService<Device> clientAuth,
3028
OpenShockContext db
3129
)
3230
: base(options, logger, encoder)
3331
{
34-
_authService = clientAuth;
3532
_db = db;
3633
}
3734

3835
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
3936
{
40-
if (!Context.TryGetDeviceTokenFromHeader(out var sessionKey))
37+
if (!Context.TryGetHubTokenFromHeader(out var hubToken))
4138
{
4239
return Fail(AuthResultError.HeaderMissingOrInvalid);
4340
}
4441

45-
var device = await _db.Devices.Include(d => d.Owner.UserDeactivation).FirstOrDefaultAsync(x => x.Token == sessionKey);
46-
if (device is null)
42+
var hub = await _db.Devices
43+
.Where(x => x.Token == hubToken)
44+
.Select(x => new
45+
{
46+
x.Id,
47+
x.Name,
48+
x.OwnerId,
49+
IsDeactivated = x.Owner.UserDeactivation != null
50+
})
51+
.FirstOrDefaultAsync();
52+
if (hub is null)
4753
{
4854
return Fail(AuthResultError.TokenInvalid);
4955
}
50-
if (device.Owner.UserDeactivation is not null)
56+
if (hub.IsDeactivated)
5157
{
5258
return Fail(AuthResultError.AccountDeactivated);
5359
}
5460

55-
_authService.CurrentClient = device;
56-
5761
Claim[] claims = [
5862
new(ClaimTypes.AuthenticationMethod, OpenShockAuthSchemes.HubToken),
59-
new(ClaimTypes.NameIdentifier, device.OwnerId.ToString()),
60-
new(OpenShockAuthClaims.HubId, _authService.CurrentClient.Id.ToString()),
63+
new(ClaimTypes.NameIdentifier, hub.OwnerId.ToString()),
64+
new(OpenShockAuthClaims.HubId, hub.Id.ToString()),
65+
new(OpenShockAuthClaims.HubName, hub.Name),
6166
];
6267

6368
var ident = new ClaimsIdentity(claims, OpenShockAuthSchemes.HubToken);

Common/Authentication/ControllerBase/AuthenticatedHubControllerBase.cs

Lines changed: 0 additions & 25 deletions
This file was deleted.

Common/Authentication/OpenShockAuthClaims.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ public class OpenShockAuthClaims
55
public const string ApiTokenId = "openshock.apiTokenId";
66
public const string ApiTokenPermission = "openshock.ApiTokenPermission";
77
public const string HubId = "openshock.hubId";
8+
public const string HubName = "openshock.hubName";
89
}

Common/Extensions/ClaimsPrincipalExtensions.cs

Lines changed: 7 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,55 +6,12 @@ namespace OpenShock.Common.Extensions;
66

77
public static class ClaimsPrincipalExtensions
88
{
9-
public static bool HasOpenShockUserIdentity(this ClaimsPrincipal principal)
10-
{
11-
ArgumentNullException.ThrowIfNull(principal);
12-
13-
foreach (var ident in principal.Identities)
14-
{
15-
if (ident is { IsAuthenticated: true, AuthenticationType: OpenShockAuthSchemes.UserSessionCookie })
16-
{
17-
return true;
18-
}
19-
}
20-
21-
return false;
22-
}
9+
private static readonly Func<ClaimsIdentity, bool> UserClaimPredicate = x => x is
10+
{ IsAuthenticated: true, AuthenticationType: OpenShockAuthSchemes.UserSessionCookie };
2311

24-
public static bool TryGetOpenShockUserIdentity(this ClaimsPrincipal principal, [NotNullWhen(true)] out ClaimsIdentity? identity)
25-
{
26-
ArgumentNullException.ThrowIfNull(principal);
27-
28-
foreach (var ident in principal.Identities)
29-
{
30-
if (ident is { IsAuthenticated: true, AuthenticationType: OpenShockAuthSchemes.UserSessionCookie })
31-
{
32-
identity = ident;
33-
return true;
34-
}
35-
}
36-
37-
identity = null;
38-
return false;
39-
}
40-
41-
public static bool TryGetAuthenticatedOpenShockUserId(this ClaimsPrincipal principal, out Guid userId)
42-
{
43-
ArgumentNullException.ThrowIfNull(principal);
44-
45-
if (!principal.TryGetOpenShockUserIdentity(out var identity))
46-
{
47-
userId = Guid.Empty;
48-
return false;
49-
}
50-
51-
var idStr = identity.Claims.SingleOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value;
52-
if (string.IsNullOrEmpty(idStr))
53-
{
54-
userId = Guid.Empty;
55-
return false;
56-
}
57-
58-
return Guid.TryParse(idStr, out userId);
59-
}
12+
public static bool HasOpenShockUserIdentity(this ClaimsPrincipal principal) => principal.Identities.Any(UserClaimPredicate);
13+
public static ClaimsIdentity GetOpenShockUserIdentity(this ClaimsPrincipal principal) => principal.Identities.Single(UserClaimPredicate);
14+
public static ClaimsIdentity? TryGetOpenShockUserIdentity(this ClaimsPrincipal principal) => principal.Identities.SingleOrDefault(UserClaimPredicate);
15+
public static string GetClaimValue(this ClaimsIdentity identity, string claimType) => identity.Claims.Single(x => x.Type == claimType).Value;
16+
public static Guid GetClaimValueAsGuid(this ClaimsIdentity identity, string claimType) => Guid.Parse(GetClaimValue(identity, claimType));
6017
}

Common/Extensions/HttpContextExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public static bool TryGetApiTokenFromHeader(this HttpContext context, [NotNullWh
5555
return false;
5656
}
5757

58-
public static bool TryGetDeviceTokenFromHeader(this HttpContext context, [NotNullWhen(true)] out string? token)
58+
public static bool TryGetHubTokenFromHeader(this HttpContext context, [NotNullWhen(true)] out string? token)
5959
{
6060
ArgumentNullException.ThrowIfNull(context);
6161

Common/OpenShockServiceHelper.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ public static IServiceCollection AddOpenShockServices(this IServiceCollection se
109109
});
110110

111111
services.AddScoped<IClientAuthService<User>, ClientAuthService<User>>();
112-
services.AddScoped<IClientAuthService<Device>, ClientAuthService<Device>>();
113112
services.AddScoped<IUserReferenceService, UserReferenceService>();
114113

115114
var authBuilder = services

LiveControlGateway/Controllers/HubControllerBase.cs

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
using FlatSharp;
22
using Microsoft.AspNetCore.Mvc;
33
using Microsoft.AspNetCore.Mvc.Filters;
4-
using Microsoft.Extensions.Options;
54
using OneOf;
65
using OneOf.Types;
7-
using OpenShock.Common.Authentication.Services;
86
using OpenShock.Common.Constants;
97
using OpenShock.Common.Errors;
10-
using OpenShock.Common.OpenShockDb;
118
using OpenShock.Common.Problems;
129
using OpenShock.Common.Utils;
1310
using OpenShock.LiveControlGateway.LifetimeManager;
1411
using OpenShock.LiveControlGateway.Options;
1512
using OpenShock.LiveControlGateway.Websocket;
1613
using OpenShock.Serialization.Gateway;
1714
using System.Net.WebSockets;
15+
using System.Security.Claims;
16+
using OpenShock.Common.Authentication;
17+
using OpenShock.Common.Extensions;
1818
using SemVersion = OpenShock.Common.Models.SemVersion;
1919
using Timer = System.Timers.Timer;
2020

@@ -30,7 +30,8 @@ public abstract class HubControllerBase<TIn, TOut> : FlatbuffersWebsocketBaseCon
3030
/// <summary>
3131
/// The current hub
3232
/// </summary>
33-
protected Device CurrentHub = null!;
33+
protected Guid CurrentHubId = Guid.Empty;
34+
protected Guid CurrentHubOwnerId = Guid.Empty;
3435

3536
/// <summary>
3637
/// Service provider
@@ -43,7 +44,12 @@ public abstract class HubControllerBase<TIn, TOut> : FlatbuffersWebsocketBaseCon
4344
/// Hub lifetime
4445
/// </summary>
4546
/// <exception cref="InvalidOperationException"></exception>
46-
protected HubLifetime HubLifetime => _hubLifetime ?? throw new InvalidOperationException("Hub lifetime is null but was tried to access");
47+
protected HubLifetime HubLifetime
48+
{
49+
get => _hubLifetime ?? throw new InvalidOperationException("Hub lifetime is null but was tried to access");
50+
private set => _hubLifetime = value;
51+
}
52+
4753
private readonly LcgOptions _options;
4854

4955
private readonly HubLifetimeManager _hubLifetimeManager;
@@ -53,7 +59,7 @@ public abstract class HubControllerBase<TIn, TOut> : FlatbuffersWebsocketBaseCon
5359
private string? _userAgent;
5460

5561
/// <inheritdoc cref="IHubController.Id" />
56-
public override Guid Id => CurrentHub.Id;
62+
public override Guid Id => CurrentHubId;
5763

5864
/// <summary>
5965
/// Authentication context
@@ -62,9 +68,9 @@ public abstract class HubControllerBase<TIn, TOut> : FlatbuffersWebsocketBaseCon
6268
[NonAction]
6369
public void OnActionExecuting(ActionExecutingContext context)
6470
{
65-
CurrentHub = ControllerContext.HttpContext.RequestServices
66-
.GetRequiredService<IClientAuthService<Device>>()
67-
.CurrentClient;
71+
var identity = User.GetOpenShockUserIdentity();
72+
CurrentHubId = identity.GetClaimValueAsGuid(OpenShockAuthClaims.HubId);
73+
CurrentHubOwnerId = identity.GetClaimValueAsGuid(ClaimTypes.NameIdentifier);
6874
}
6975

7076
/// <summary>
@@ -147,7 +153,7 @@ protected override async Task<OneOf<Success, Error<OpenShockProblem>>> Connectio
147153
return new Error<OpenShockProblem>(ExceptionError.Exception);
148154
}
149155

150-
_hubLifetime = hubLifetimeResult.AsT0;
156+
HubLifetime = hubLifetimeResult.AsT0;
151157

152158
return new Success();
153159
}
@@ -212,18 +218,18 @@ protected async Task<bool> SelfOnline(ulong uptimeMs, ushort? latency = null, in
212218
var bootedAt = GetBootedAtFromUptimeMs(uptimeMs);
213219
if (!bootedAt.HasValue)
214220
{
215-
Logger.LogDebug("Client attempted to abuse reported boot time, uptime indicated that hub [{HubId}] booted prior to 2024", CurrentHub.Id);
221+
Logger.LogDebug("Client attempted to abuse reported boot time, uptime indicated that hub [{HubId}] booted prior to 2024", CurrentHubId);
216222
return false;
217223
}
218224

219-
Logger.LogDebug("Received keep alive from hub [{HubId}]", CurrentHub.Id);
225+
Logger.LogDebug("Received keep alive from hub [{HubId}]", CurrentHubId);
220226

221227
// Reset the keep alive timeout
222228
_keepAliveTimeoutTimer.Interval = Duration.DeviceKeepAliveTimeout.TotalMilliseconds;
223229

224-
await HubLifetime.Online(CurrentHub.Id, new SelfOnlineData()
230+
await HubLifetime.Online(CurrentHubId, new SelfOnlineData()
225231
{
226-
Owner = CurrentHub.OwnerId,
232+
Owner = CurrentHubOwnerId,
227233
Gateway = _options.Fqdn,
228234
FirmwareVersion = _firmwareVersion!,
229235
ConnectedAt = _connected,

0 commit comments

Comments
 (0)