diff --git a/src/Tgstation.Server.Host/Authority/AdministrationAuthority.cs b/src/Tgstation.Server.Host/Authority/AdministrationAuthority.cs
index 76c7fc937b..e8fa0d681b 100644
--- a/src/Tgstation.Server.Host/Authority/AdministrationAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/AdministrationAuthority.cs
@@ -90,154 +90,163 @@ namespace Tgstation.Server.Host.Authority
}
///
- public async ValueTask> GetUpdateInformation(bool forceFresh, CancellationToken cancellationToken)
- {
- try
- {
- async Task CacheFactory()
+ public RequirementsGated> GetUpdateInformation(bool forceFresh, CancellationToken cancellationToken)
+ => new(
+ () => Flag(AdministrationRights.ChangeVersion),
+ async () =>
{
- Version? greatestVersion = null;
- Uri? repoUrl = null;
- var scopeCancellationToken = CancellationToken.None; // DCT: None available
try
{
- var gitHubService = await gitHubServiceFactory.CreateService(scopeCancellationToken);
- var repositoryUrlTask = gitHubService.GetUpdatesRepositoryUrl(scopeCancellationToken);
- var releases = await gitHubService.GetTgsReleases(scopeCancellationToken);
-
- foreach (var kvp in releases)
+ async Task CacheFactory()
{
- var version = kvp.Key;
- var release = kvp.Value;
- if (version.Major > 3 // Forward/backward compatible but not before TGS4
- && (greatestVersion == null || version > greatestVersion))
- greatestVersion = version;
+ Version? greatestVersion = null;
+ Uri? repoUrl = null;
+ var scopeCancellationToken = CancellationToken.None; // DCT: None available
+ try
+ {
+ var gitHubService = await gitHubServiceFactory.CreateService(scopeCancellationToken);
+ var repositoryUrlTask = gitHubService.GetUpdatesRepositoryUrl(scopeCancellationToken);
+ var releases = await gitHubService.GetTgsReleases(scopeCancellationToken);
+
+ foreach (var kvp in releases)
+ {
+ var version = kvp.Key;
+ var release = kvp.Value;
+ if (version.Major > 3 // Forward/backward compatible but not before TGS4
+ && (greatestVersion == null || version > greatestVersion))
+ greatestVersion = version;
+ }
+
+ repoUrl = await repositoryUrlTask;
+ }
+ catch (NotFoundException e)
+ {
+ Logger.LogWarning(e, "Not found exception while retrieving upstream repository info!");
+ }
+
+ return new AdministrationResponse
+ {
+ LatestVersion = greatestVersion,
+ TrackedRepositoryUrl = repoUrl,
+ GeneratedAt = DateTimeOffset.UtcNow,
+ };
}
- repoUrl = await repositoryUrlTask;
+ var ttl = TimeSpan.FromMinutes(30);
+ Task task;
+ if (forceFresh || !cacheService.TryGetValue(ReadCacheKey, out var rawCacheObject))
+ {
+ using var entry = cacheService.CreateEntry(ReadCacheKey);
+ entry.AbsoluteExpirationRelativeToNow = ttl;
+ entry.Value = task = CacheFactory();
+ }
+ else
+ task = (Task)rawCacheObject!;
+
+ var result = await task.WaitAsync(cancellationToken);
+ return new AuthorityResponse(result);
}
- catch (NotFoundException e)
+ catch (RateLimitExceededException e)
{
- Logger.LogWarning(e, "Not found exception while retrieving upstream repository info!");
+ return RateLimit(e);
}
-
- return new AdministrationResponse
+ catch (ApiException e)
{
- LatestVersion = greatestVersion,
- TrackedRepositoryUrl = repoUrl,
- GeneratedAt = DateTimeOffset.UtcNow,
- };
- }
-
- var ttl = TimeSpan.FromMinutes(30);
- Task task;
- if (forceFresh || !cacheService.TryGetValue(ReadCacheKey, out var rawCacheObject))
- {
- using var entry = cacheService.CreateEntry(ReadCacheKey);
- entry.AbsoluteExpirationRelativeToNow = ttl;
- entry.Value = task = CacheFactory();
- }
- else
- task = (Task)rawCacheObject!;
-
- var result = await task.WaitAsync(cancellationToken);
- return new AuthorityResponse(result);
- }
- catch (RateLimitExceededException e)
- {
- return RateLimit(e);
- }
- catch (ApiException e)
- {
- Logger.LogWarning(e, OctokitException);
- return new AuthorityResponse(
- new ErrorMessageResponse(ErrorCode.RemoteApiError)
- {
- AdditionalData = e.Message,
- },
- HttpFailureResponse.FailedDependency);
- }
- }
+ Logger.LogWarning(e, OctokitException);
+ return new AuthorityResponse(
+ new ErrorMessageResponse(ErrorCode.RemoteApiError)
+ {
+ AdditionalData = e.Message,
+ },
+ HttpFailureResponse.FailedDependency);
+ }
+ });
///
- public async ValueTask> TriggerServerVersionChange(Version targetVersion, bool uploadZip, CancellationToken cancellationToken)
+ public RequirementsGated> TriggerServerVersionChange(Version targetVersion, bool uploadZip, CancellationToken cancellationToken)
{
var attemptingUpload = uploadZip == true;
- if (attemptingUpload)
- {
- if (!AuthenticationContext.PermissionSet.AdministrationRights!.Value.HasFlag(AdministrationRights.UploadVersion))
- return Forbid();
- }
- else if (!AuthenticationContext.PermissionSet.AdministrationRights!.Value.HasFlag(AdministrationRights.ChangeVersion))
- return Forbid();
-
- if (targetVersion.Major < 4)
- return BadRequest(ErrorCode.CannotChangeServerSuite);
-
- if (!serverControl.WatchdogPresent)
- return new AuthorityResponse(
- new ErrorMessageResponse(ErrorCode.MissingHostWatchdog),
- HttpFailureResponse.UnprocessableEntity);
-
- IFileUploadTicket? uploadTicket = attemptingUpload
- ? fileTransferService.CreateUpload(FileUploadStreamKind.None)
- : null;
-
- ServerUpdateResult updateResult;
- try
- {
- try
- {
- updateResult = await serverUpdateInitiator.InitiateUpdate(uploadTicket, targetVersion, cancellationToken);
- }
- catch
+ return new(
+ () =>
{
if (attemptingUpload)
- await uploadTicket!.DisposeAsync();
+ return Flag(AdministrationRights.UploadVersion);
- throw;
- }
- }
- catch (RateLimitExceededException ex)
- {
- return RateLimit(ex);
- }
- catch (ApiException e)
- {
- Logger.LogWarning(e, OctokitException);
- return new AuthorityResponse(
- new ErrorMessageResponse(ErrorCode.RemoteApiError)
+ return Flag(AdministrationRights.ChangeVersion);
+ },
+ async () =>
+ {
+ if (targetVersion.Major < 4)
+ return BadRequest(ErrorCode.CannotChangeServerSuite);
+
+ if (!serverControl.WatchdogPresent)
+ return new AuthorityResponse(
+ new ErrorMessageResponse(ErrorCode.MissingHostWatchdog),
+ HttpFailureResponse.UnprocessableEntity);
+
+ IFileUploadTicket? uploadTicket = attemptingUpload
+ ? fileTransferService.CreateUpload(FileUploadStreamKind.None)
+ : null;
+
+ ServerUpdateResult updateResult;
+ try
{
- AdditionalData = e.Message,
- },
- HttpFailureResponse.FailedDependency);
- }
+ try
+ {
+ updateResult = await serverUpdateInitiator.InitiateUpdate(uploadTicket, targetVersion, cancellationToken);
+ }
+ catch
+ {
+ if (attemptingUpload)
+ await uploadTicket!.DisposeAsync();
- return updateResult switch
- {
- ServerUpdateResult.Started => new AuthorityResponse(new ServerUpdateResponse(targetVersion, uploadTicket?.Ticket.FileTicket), HttpSuccessResponse.Accepted),
- ServerUpdateResult.ReleaseMissing => Gone(),
- ServerUpdateResult.UpdateInProgress => BadRequest(ErrorCode.ServerUpdateInProgress),
- ServerUpdateResult.SwarmIntegrityCheckFailed => new AuthorityResponse(
- new ErrorMessageResponse(ErrorCode.SwarmIntegrityCheckFailed),
- HttpFailureResponse.FailedDependency),
- _ => throw new InvalidOperationException($"Unexpected ServerUpdateResult: {updateResult}"),
- };
+ throw;
+ }
+ }
+ catch (RateLimitExceededException ex)
+ {
+ return RateLimit(ex);
+ }
+ catch (ApiException e)
+ {
+ Logger.LogWarning(e, OctokitException);
+ return new AuthorityResponse(
+ new ErrorMessageResponse(ErrorCode.RemoteApiError)
+ {
+ AdditionalData = e.Message,
+ },
+ HttpFailureResponse.FailedDependency);
+ }
+
+ return updateResult switch
+ {
+ ServerUpdateResult.Started => new AuthorityResponse(new ServerUpdateResponse(targetVersion, uploadTicket?.Ticket.FileTicket), HttpSuccessResponse.Accepted),
+ ServerUpdateResult.ReleaseMissing => Gone(),
+ ServerUpdateResult.UpdateInProgress => BadRequest(ErrorCode.ServerUpdateInProgress),
+ ServerUpdateResult.SwarmIntegrityCheckFailed => new AuthorityResponse(
+ new ErrorMessageResponse(ErrorCode.SwarmIntegrityCheckFailed),
+ HttpFailureResponse.FailedDependency),
+ _ => throw new InvalidOperationException($"Unexpected ServerUpdateResult: {updateResult}"),
+ };
+ });
}
///
- public async ValueTask TriggerServerRestart()
- {
- if (!serverControl.WatchdogPresent)
- {
- Logger.LogDebug("Restart request failed due to lack of host watchdog!");
- return new AuthorityResponse(
- new ErrorMessageResponse(ErrorCode.MissingHostWatchdog),
- HttpFailureResponse.UnprocessableEntity);
- }
+ public RequirementsGated TriggerServerRestart()
+ => new(
+ () => Flag(AdministrationRights.RestartHost),
+ async () =>
+ {
+ if (!serverControl.WatchdogPresent)
+ {
+ Logger.LogDebug("Restart request failed due to lack of host watchdog!");
+ return new AuthorityResponse(
+ new ErrorMessageResponse(ErrorCode.MissingHostWatchdog),
+ HttpFailureResponse.UnprocessableEntity);
+ }
- await serverControl.Restart();
- return new AuthorityResponse();
- }
+ await serverControl.Restart();
+ return new AuthorityResponse();
+ });
}
}
diff --git a/src/Tgstation.Server.Host/Authority/Core/AuthorityBase.cs b/src/Tgstation.Server.Host/Authority/Core/AuthorityBase.cs
index 0ea01a89da..a3468b7f5b 100644
--- a/src/Tgstation.Server.Host/Authority/Core/AuthorityBase.cs
+++ b/src/Tgstation.Server.Host/Authority/Core/AuthorityBase.cs
@@ -8,7 +8,7 @@ using Octokit;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Models.Response;
using Tgstation.Server.Host.Database;
-using Tgstation.Server.Host.Security;
+using Tgstation.Server.Host.Security.RightsEvaluation;
namespace Tgstation.Server.Host.Authority.Core
{
@@ -17,11 +17,6 @@ namespace Tgstation.Server.Host.Authority.Core
///
abstract class AuthorityBase : IAuthority
{
- ///
- /// Gets the for the .
- ///
- protected IAuthenticationContext AuthenticationContext { get; }
-
///
/// Gets the for the .
///
@@ -94,18 +89,47 @@ namespace Tgstation.Server.Host.Authority.Core
new ErrorMessageResponse(errorCode),
HttpFailureResponse.Conflict);
+ ///
+ /// Helper to quickly construct a .
+ ///
+ /// The to evaluate.
+ /// The single bit flag of the .
+ /// A new .
+ protected static FlagRightsConditional Flag(TRights flag)
+ where TRights : Enum
+ => new(flag);
+
+ ///
+ /// Helper to quickly construct an .
+ ///
+ /// The to evaluate.
+ /// The left hand side operand.
+ /// The right hand side operand.
+ /// A new .
+ protected static OrRightsConditional Or(RightsConditional lhs, RightsConditional rhs)
+ where TRights : Enum
+ => new(lhs, rhs);
+
+ ///
+ /// Helper to quickly construct an .
+ ///
+ /// The to evaluate.
+ /// The left hand side operand.
+ /// The right hand side operand.
+ /// A new .
+ protected static AndRightsConditional And(RightsConditional lhs, RightsConditional rhs)
+ where TRights : Enum
+ => new(lhs, rhs);
+
///
/// Initializes a new instance of the class.
///
- /// The value of .
/// The value of .
/// The value of .
protected AuthorityBase(
- IAuthenticationContext authenticationContext,
IDatabaseContext databaseContext,
ILogger logger)
{
- AuthenticationContext = authenticationContext ?? throw new ArgumentNullException(nameof(authenticationContext));
DatabaseContext = databaseContext ?? throw new ArgumentNullException(nameof(databaseContext));
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
diff --git a/src/Tgstation.Server.Host/Authority/Core/AuthorityInvokerBase{TAuthority}.cs b/src/Tgstation.Server.Host/Authority/Core/AuthorityInvokerBase{TAuthority}.cs
index f04293aecc..93f600c12d 100644
--- a/src/Tgstation.Server.Host/Authority/Core/AuthorityInvokerBase{TAuthority}.cs
+++ b/src/Tgstation.Server.Host/Authority/Core/AuthorityInvokerBase{TAuthority}.cs
@@ -1,7 +1,8 @@
using System;
using System.Linq;
+using System.Threading.Tasks;
-using Tgstation.Server.Api.Models;
+using Tgstation.Server.Host.Security;
namespace Tgstation.Server.Host.Authority.Core
{
@@ -14,35 +15,49 @@ namespace Tgstation.Server.Host.Authority.Core
///
protected TAuthority Authority { get; }
+ ///
+ /// The for the .
+ ///
+ readonly IAuthorizationService authorizationService;
+
///
/// Initializes a new instance of the class.
///
/// The value of .
- public AuthorityInvokerBase(TAuthority authority)
+ /// The value of .
+ public AuthorityInvokerBase(
+ TAuthority authority,
+ IAuthorizationService authorizationService)
{
Authority = authority ?? throw new ArgumentNullException(nameof(authority));
+ this.authorizationService = authorizationService ?? throw new ArgumentNullException(nameof(authorizationService));
}
///
- IQueryable IAuthorityInvoker.InvokeQueryable(Func> authorityInvoker)
+ async ValueTask?> IAuthorityInvoker.InvokeQueryable(Func>> authorityInvoker)
{
ArgumentNullException.ThrowIfNull(authorityInvoker);
- return authorityInvoker(Authority);
+
+ var requirementsGate = authorityInvoker(Authority);
+ return await ExecuteIfRequirementsSatisfied(requirementsGate);
}
- ///
- IQueryable IAuthorityInvoker.InvokeTransformableQueryable(Func> authorityInvoker)
+ ///
+ /// Unwrap a result, returning if the requirements weren't satisfied.
+ ///
+ /// The contained by the .
+ /// The result.
+ /// A resulting in the if the requirements were met, if the requirments weren't met.
+ protected async ValueTask ExecuteIfRequirementsSatisfied(RequirementsGated requirementsGate)
+ where TResult : class
{
- ArgumentNullException.ThrowIfNull(authorityInvoker);
+ var requirements = await requirementsGate.GetRequirements();
+ var authorizationResult = await authorizationService.AuthorizeAsync(requirements);
- var queryable = authorityInvoker(Authority);
+ if (!authorizationResult)
+ return null;
- if (typeof(EntityId).IsAssignableFrom(typeof(TResult)))
- queryable = queryable.OrderBy(item => ((EntityId)(object)item).Id!.Value); // order by ID to fix an EFCore warning
-
- var expression = new TTransformer().Expression;
- return queryable
- .Select(expression);
+ return await requirementsGate.Execute(authorizationService);
}
}
}
diff --git a/src/Tgstation.Server.Host/Authority/Core/GraphQLAuthorityInvoker{TAuthority}.cs b/src/Tgstation.Server.Host/Authority/Core/GraphQLAuthorityInvoker{TAuthority}.cs
index a25a04e278..f9f8b26863 100644
--- a/src/Tgstation.Server.Host/Authority/Core/GraphQLAuthorityInvoker{TAuthority}.cs
+++ b/src/Tgstation.Server.Host/Authority/Core/GraphQLAuthorityInvoker{TAuthority}.cs
@@ -1,7 +1,11 @@
using System;
+using System.Linq;
using System.Threading.Tasks;
+using Tgstation.Server.Api.Models;
+using Tgstation.Server.Api.Models.Response;
using Tgstation.Server.Host.GraphQL;
+using Tgstation.Server.Host.Security;
namespace Tgstation.Server.Host.Authority.Core
{
@@ -9,17 +13,30 @@ namespace Tgstation.Server.Host.Authority.Core
sealed class GraphQLAuthorityInvoker : AuthorityInvokerBase, IGraphQLAuthorityInvoker
where TAuthority : IAuthority
{
+ ///
+ /// Create a new to be thrown when a forbidden error occurs.
+ ///
+ /// A new .
+ static ErrorMessageException ForbiddenGraphQLError()
+ => new(new ErrorMessageResponse(), HttpFailureResponse.Forbidden.ToString());
+
///
/// Throws a for errored s.
///
- /// The potentially errored .
+ /// The being checked.
+ /// The potentially errored or if requirements evaluation failed.
/// If an error should be raised for and failures.
- static void ThrowGraphQLErrorIfNecessary(AuthorityResponse authorityResponse, bool errorOnMissing)
+ /// if an wasn't thrown.
+ static TAuthorityResponse ThrowGraphQLErrorIfNecessary(TAuthorityResponse? authorityResponse, bool errorOnMissing)
+ where TAuthorityResponse : AuthorityResponse
{
+ if (authorityResponse == null)
+ throw ForbiddenGraphQLError();
+
if (authorityResponse.Success
|| ((authorityResponse.FailureResponse.Value == HttpFailureResponse.NotFound
|| authorityResponse.FailureResponse.Value == HttpFailureResponse.Gone) && !errorOnMissing))
- return;
+ return authorityResponse;
var fallbackString = authorityResponse.FailureResponse.ToString()!;
throw new ErrorMessageException(authorityResponse.ErrorMessage, fallbackString);
@@ -29,40 +46,42 @@ namespace Tgstation.Server.Host.Authority.Core
/// Initializes a new instance of the class.
///
/// The .
- public GraphQLAuthorityInvoker(TAuthority authority)
- : base(authority)
+ /// the to use.
+ public GraphQLAuthorityInvoker(TAuthority authority, IAuthorizationService authorizationService)
+ : base(authority, authorizationService)
{
}
///
- async ValueTask IGraphQLAuthorityInvoker.Invoke(Func> authorityInvoker)
+ async ValueTask IGraphQLAuthorityInvoker.Invoke(Func> authorityInvoker)
{
ArgumentNullException.ThrowIfNull(authorityInvoker);
- var authorityResponse = await authorityInvoker(Authority);
+ var requirementsGate = authorityInvoker(Authority);
+ var authorityResponse = await ExecuteIfRequirementsSatisfied(requirementsGate);
ThrowGraphQLErrorIfNecessary(authorityResponse, true);
}
///
- async ValueTask IGraphQLAuthorityInvoker.InvokeAllowMissing(Func>> authorityInvoker)
+ async ValueTask IGraphQLAuthorityInvoker.InvokeAllowMissing(Func>> authorityInvoker)
where TApiModel : default
{
ArgumentNullException.ThrowIfNull(authorityInvoker);
- var authorityResponse = await authorityInvoker(Authority);
- ThrowGraphQLErrorIfNecessary(authorityResponse, false);
- return authorityResponse.Result;
+ var requirementsGate = authorityInvoker(Authority);
+ var authorityResponse = await ExecuteIfRequirementsSatisfied(requirementsGate);
+ return ThrowGraphQLErrorIfNecessary(authorityResponse, false).Result;
}
///
- async ValueTask IGraphQLAuthorityInvoker.InvokeTransformableAllowMissing(Func>> authorityInvoker)
+ async ValueTask IGraphQLAuthorityInvoker.InvokeTransformableAllowMissing(Func>> authorityInvoker)
where TApiModel : default
{
ArgumentNullException.ThrowIfNull(authorityInvoker);
- var authorityResponse = await authorityInvoker(Authority);
- ThrowGraphQLErrorIfNecessary(authorityResponse, false);
- var result = authorityResponse.Result;
+ var requirementsGate = authorityInvoker(Authority);
+ var authorityResponse = await ExecuteIfRequirementsSatisfied(requirementsGate);
+ var result = ThrowGraphQLErrorIfNecessary(authorityResponse, false).Result;
if (result == null)
return default;
@@ -70,11 +89,33 @@ namespace Tgstation.Server.Host.Authority.Core
}
///
- ValueTask IGraphQLAuthorityInvoker.Invoke(Func>> authorityInvoker)
+ async ValueTask> IGraphQLAuthorityInvoker.InvokeTransformableQueryable(
+ Func>> authorityInvoker,
+ Func, IQueryable>? preTransformer)
+ {
+ ArgumentNullException.ThrowIfNull(authorityInvoker);
+
+ var requirementsGate = authorityInvoker(Authority);
+ var queryable = await ExecuteIfRequirementsSatisfied(requirementsGate)
+ ?? throw ForbiddenGraphQLError();
+
+ if (preTransformer != null)
+ queryable = preTransformer(queryable);
+
+ if (typeof(EntityId).IsAssignableFrom(typeof(TResult)))
+ queryable = queryable.OrderBy(item => ((EntityId)(object)item).Id!.Value); // order by ID to fix an EFCore warning
+
+ var expression = new TTransformer().Expression;
+ return queryable
+ .Select(expression);
+ }
+
+ ///
+ ValueTask IGraphQLAuthorityInvoker.Invoke(Func>> authorityInvoker)
=> ((IGraphQLAuthorityInvoker)this).InvokeAllowMissing(authorityInvoker)!;
///
- ValueTask IGraphQLAuthorityInvoker.InvokeTransformable(Func>> authorityInvoker)
+ ValueTask IGraphQLAuthorityInvoker.InvokeTransformable(Func>> authorityInvoker)
=> ((IGraphQLAuthorityInvoker)this).InvokeTransformableAllowMissing(authorityInvoker)!;
}
}
diff --git a/src/Tgstation.Server.Host/Authority/Core/IAuthorityInvoker{TAuthority}.cs b/src/Tgstation.Server.Host/Authority/Core/IAuthorityInvoker{TAuthority}.cs
index 9b49bd9dda..98270fcc96 100644
--- a/src/Tgstation.Server.Host/Authority/Core/IAuthorityInvoker{TAuthority}.cs
+++ b/src/Tgstation.Server.Host/Authority/Core/IAuthorityInvoker{TAuthority}.cs
@@ -1,7 +1,6 @@
using System;
using System.Linq;
-
-using Tgstation.Server.Host.Models;
+using System.Threading.Tasks;
namespace Tgstation.Server.Host.Authority.Core
{
@@ -16,21 +15,8 @@ namespace Tgstation.Server.Host.Authority.Core
/// Invoke a method and get the result.
///
/// The returned .
- /// The returning a .
- /// A returned.
- IQueryable InvokeQueryable(Func> authorityInvoker);
-
- ///
- /// Invoke a method and get the transformed result.
- ///
- /// The returned by the .
- /// The returned .
- /// The for converting s to s.
- /// The returning a .
- /// A returned.
- IQueryable InvokeTransformableQueryable(Func> authorityInvoker)
- where TResult : IApiTransformable
- where TApiModel : notnull
- where TTransformer : ITransformer, new();
+ /// The authority invocation returning a .
+ /// A resulting in the returned on success or if the requirements weren't satisfied.
+ ValueTask?> InvokeQueryable(Func>> authorityInvoker);
}
}
diff --git a/src/Tgstation.Server.Host/Authority/Core/RequirementsGated{TResult}.cs b/src/Tgstation.Server.Host/Authority/Core/RequirementsGated{TResult}.cs
new file mode 100644
index 0000000000..7decf514d6
--- /dev/null
+++ b/src/Tgstation.Server.Host/Authority/Core/RequirementsGated{TResult}.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+using Microsoft.AspNetCore.Authorization;
+
+using Tgstation.Server.Host.Security;
+
+namespace Tgstation.Server.Host.Authority.Core
+{
+ ///
+ /// Evaluates a set of s to be checked before executing a response.
+ ///
+ /// The of object the response generates.
+ public sealed class RequirementsGated
+ {
+ ///
+ /// The retrieval function. is included automatically.
+ ///
+ readonly Func>> getRequirements;
+
+ ///
+ /// The response generation function.
+ ///
+ readonly Func> getResponse;
+
+ ///
+ /// Convert a given into a .
+ ///
+ /// The to convert.
+ /// A new based on .
+#pragma warning disable CA1000 // Do not declare static members on generic types
+ public static RequirementsGated FromResult(TResult result)
+#pragma warning restore CA1000 // Do not declare static members on generic types
+ => new(
+ () => (IAuthorizationRequirement?)null,
+ () => ValueTask.FromResult(result));
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value of . Resulting in a value is eqivalent to returning an empty of s.
+ /// The value of .
+ public RequirementsGated(
+ Func> getRequirement,
+ Func> getResponse)
+ {
+ ArgumentNullException.ThrowIfNull(getRequirement);
+ ArgumentNullException.ThrowIfNull(getResponse);
+ getRequirements = async () =>
+ {
+ var requirement = await getRequirement();
+ if (requirement == null)
+ return Enumerable.Empty();
+
+ return new List
+ {
+ requirement,
+ };
+ };
+ this.getResponse = _ => getResponse();
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value of .
+ /// The value of .
+ public RequirementsGated(
+ Func> getRequirements,
+ Func> getResponse)
+ {
+ ArgumentNullException.ThrowIfNull(getRequirements);
+ ArgumentNullException.ThrowIfNull(getResponse);
+ this.getRequirements = () => ValueTask.FromResult(getRequirements());
+ this.getResponse = _ => getResponse();
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value of . Resulting in a value is eqivalent to returning an empty of s.
+ /// The value of .
+ public RequirementsGated(
+ Func getRequirement,
+ Func> getResponse)
+ {
+ ArgumentNullException.ThrowIfNull(getRequirement);
+ ArgumentNullException.ThrowIfNull(getResponse);
+ getRequirements = () =>
+ {
+ var requirement = getRequirement();
+ if (requirement == null)
+ return ValueTask.FromResult(Enumerable.Empty());
+
+ return ValueTask.FromResult>(
+ new List
+ {
+ requirement,
+ });
+ };
+
+ this.getResponse = _ => getResponse();
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value of . Resulting in a value is eqivalent to returning an empty of s.
+ /// The value of .
+ public RequirementsGated(
+ Func getRequirement,
+ Func> getResponse)
+ {
+ ArgumentNullException.ThrowIfNull(getRequirement);
+ getRequirements = () =>
+ {
+ var requirement = getRequirement();
+ if (requirement == null)
+ return ValueTask.FromResult(Enumerable.Empty());
+
+ return ValueTask.FromResult>(
+ new List
+ {
+ requirement,
+ });
+ };
+
+ this.getResponse = getResponse ?? throw new ArgumentNullException(nameof(getResponse));
+ }
+
+ ///
+ /// Evaluates the s of the request.
+ ///
+ /// A resulting in the s for the request.
+ public async ValueTask> GetRequirements()
+ => (await getRequirements()).Concat([new UserSessionValidRequirement()]);
+
+ ///
+ /// Executes the request.
+ ///
+ /// The authorization service to use.
+ /// A resulting in the request .
+ public ValueTask Execute(Security.IAuthorizationService authorizationService)
+ => getResponse(authorizationService);
+ }
+}
diff --git a/src/Tgstation.Server.Host/Authority/Core/RestAuthorityInvoker{TAuthority}.cs b/src/Tgstation.Server.Host/Authority/Core/RestAuthorityInvoker{TAuthority}.cs
index 52532c2f0e..f0ac777801 100644
--- a/src/Tgstation.Server.Host/Authority/Core/RestAuthorityInvoker{TAuthority}.cs
+++ b/src/Tgstation.Server.Host/Authority/Core/RestAuthorityInvoker{TAuthority}.cs
@@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Mvc;
using Tgstation.Server.Host.Controllers;
using Tgstation.Server.Host.Extensions;
+using Tgstation.Server.Host.Security;
namespace Tgstation.Server.Host.Authority.Core
{
@@ -22,7 +23,10 @@ namespace Tgstation.Server.Host.Authority.Core
/// An for the .
/// The result returned in the .
/// The REST API result model built from .
- static IActionResult CreateSuccessfulActionResult(ApiController controller, Func resultTransformer, AuthorityResponse authorityResponse)
+ static IActionResult CreateSuccessfulActionResult(
+ ApiController controller,
+ Func resultTransformer,
+ AuthorityResponse authorityResponse)
where TApiModel : notnull
{
if (authorityResponse.IsNoContent!.Value)
@@ -44,9 +48,14 @@ namespace Tgstation.Server.Host.Authority.Core
///
/// The to use.
/// The .
- /// An if the is not successful, otherwise.
- static IActionResult? CreateErroredActionResult(ApiController controller, AuthorityResponse authorityResponse)
+ /// An if the is not successful, otherwise. If is returned, is not .
+ static IActionResult? CreateErroredActionResult(
+ ApiController controller,
+ AuthorityResponse? authorityResponse)
{
+ if (authorityResponse == null)
+ return controller.Forbid();
+
if (authorityResponse.Success)
return null;
@@ -74,47 +83,51 @@ namespace Tgstation.Server.Host.Authority.Core
/// Initializes a new instance of the class.
///
/// The .
- public RestAuthorityInvoker(TAuthority authority)
- : base(authority)
+ /// The to use.
+ public RestAuthorityInvoker(TAuthority authority, IAuthorizationService authorizationService)
+ : base(authority, authorizationService)
{
}
///
- async ValueTask IRestAuthorityInvoker.Invoke(ApiController controller, Func> authorityInvoker)
+ async ValueTask IRestAuthorityInvoker.Invoke(ApiController controller, Func> authorityInvoker)
{
ArgumentNullException.ThrowIfNull(controller);
ArgumentNullException.ThrowIfNull(authorityInvoker);
- var authorityResponse = await authorityInvoker(Authority);
+ var requirementsGate = authorityInvoker(Authority);
+ var authorityResponse = await ExecuteIfRequirementsSatisfied(requirementsGate);
return CreateErroredActionResult(controller, authorityResponse) ?? controller.NoContent();
}
///
- async ValueTask IRestAuthorityInvoker.Invoke(ApiController controller, Func>> authorityInvoker)
+ async ValueTask IRestAuthorityInvoker.Invoke(ApiController controller, Func>> authorityInvoker)
{
ArgumentNullException.ThrowIfNull(controller);
ArgumentNullException.ThrowIfNull(authorityInvoker);
- var authorityResponse = await authorityInvoker(Authority);
+ var requirementsGate = authorityInvoker(Authority);
+ var authorityResponse = await ExecuteIfRequirementsSatisfied(requirementsGate);
var erroredResult = CreateErroredActionResult(controller, authorityResponse);
if (erroredResult != null)
return erroredResult;
- return CreateSuccessfulActionResult(controller, result => result, authorityResponse);
+ return CreateSuccessfulActionResult(controller, result => result, authorityResponse!);
}
///
- async ValueTask IRestAuthorityInvoker.InvokeTransformable(ApiController controller, Func>> authorityInvoker)
+ async ValueTask IRestAuthorityInvoker.InvokeTransformable(ApiController controller, Func>> authorityInvoker)
{
ArgumentNullException.ThrowIfNull(controller);
ArgumentNullException.ThrowIfNull(authorityInvoker);
- var authorityResponse = await authorityInvoker(Authority);
+ var requirementsGate = authorityInvoker(Authority);
+ var authorityResponse = await ExecuteIfRequirementsSatisfied(requirementsGate);
var erroredResult = CreateErroredActionResult(controller, authorityResponse);
if (erroredResult != null)
return erroredResult;
- return CreateSuccessfulActionResult(controller, result => result.ToApi(), authorityResponse);
+ return CreateSuccessfulActionResult(controller, result => result.ToApi(), authorityResponse!);
}
}
}
diff --git a/src/Tgstation.Server.Host/Authority/IAdministrationAuthority.cs b/src/Tgstation.Server.Host/Authority/IAdministrationAuthority.cs
index 7fb28925b5..3381b8aa2c 100644
--- a/src/Tgstation.Server.Host/Authority/IAdministrationAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/IAdministrationAuthority.cs
@@ -1,6 +1,5 @@
using System;
using System.Threading;
-using System.Threading.Tasks;
using Tgstation.Server.Api.Models.Response;
using Tgstation.Server.Api.Rights;
@@ -19,9 +18,9 @@ namespace Tgstation.Server.Host.Authority
///
/// Bypass the caching that the authority performs for this request, forcing it to contact GitHub.
/// The for the operation.
- /// A resulting in the .
+ /// A .
[TgsAuthorize(AdministrationRights.ChangeVersion)]
- ValueTask> GetUpdateInformation(bool forceFresh, CancellationToken cancellationToken);
+ RequirementsGated> GetUpdateInformation(bool forceFresh, CancellationToken cancellationToken);
///
/// Triggers a restart of tgstation-server without terminating running game instances, setting its version to a given .
@@ -29,15 +28,15 @@ namespace Tgstation.Server.Host.Authority
/// The TGS will switch to upon reboot.
/// If a will be returned and the call must provide an uploaded zip file containing the update data to the file transfer service.
/// The for the operation.
- /// A resulting in the .
+ /// A .
[TgsAuthorize(AdministrationRights.ChangeVersion | AdministrationRights.UploadVersion)]
- ValueTask> TriggerServerVersionChange(Version targetVersion, bool uploadZip, CancellationToken cancellationToken);
+ RequirementsGated> TriggerServerVersionChange(Version targetVersion, bool uploadZip, CancellationToken cancellationToken);
///
/// Triggers a restart of tgstation-server without terminating running game instances.
///
- /// A resulting in the .
+ /// A .
[TgsAuthorize(AdministrationRights.RestartHost)]
- ValueTask TriggerServerRestart();
+ RequirementsGated TriggerServerRestart();
}
}
diff --git a/src/Tgstation.Server.Host/Authority/IGraphQLAuthorityInvoker{TAuthority}.cs b/src/Tgstation.Server.Host/Authority/IGraphQLAuthorityInvoker{TAuthority}.cs
index edface219a..341b78a6cd 100644
--- a/src/Tgstation.Server.Host/Authority/IGraphQLAuthorityInvoker{TAuthority}.cs
+++ b/src/Tgstation.Server.Host/Authority/IGraphQLAuthorityInvoker{TAuthority}.cs
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using System.Threading.Tasks;
using Tgstation.Server.Host.Authority.Core;
@@ -10,24 +11,25 @@ namespace Tgstation.Server.Host.Authority
/// Invokes s from GraphQL endpoints.
///
/// The invoked.
+ /// We take the approach that fields should be non-nullable if that is the case under ideal circumstances. Authorization issues should throw.
public interface IGraphQLAuthorityInvoker : IAuthorityInvoker
where TAuthority : IAuthority
{
///
/// Invoke a method with no success result.
///
- /// The returning a resulting in the .
+ /// The resulting in the .
/// A representing the running operation.
- ValueTask Invoke(Func> authorityInvoker);
+ ValueTask Invoke(Func> authorityInvoker);
///
/// Invoke a method and get the result.
///
/// The .
/// The resulting of the return value.
- /// The returning a resulting in the .
+ /// The resulting in the .
/// A resulting in the generated for the resulting .
- ValueTask InvokeAllowMissing(Func>> authorityInvoker)
+ ValueTask InvokeAllowMissing(Func>> authorityInvoker)
where TResult : TApiModel
where TApiModel : notnull;
@@ -37,9 +39,9 @@ namespace Tgstation.Server.Host.Authority
/// The .
/// The resulting of the return value.
/// The for converting s to s.
- /// The returning a resulting in the .
+ /// The resulting in the .
/// A resulting in the generated for the resulting .
- ValueTask InvokeTransformableAllowMissing(Func>> authorityInvoker)
+ ValueTask InvokeTransformableAllowMissing(Func>> authorityInvoker)
where TResult : notnull, IApiTransformable
where TApiModel : notnull
where TTransformer : ITransformer, new();
@@ -49,9 +51,9 @@ namespace Tgstation.Server.Host.Authority
///
/// The .
/// The resulting of the return value.
- /// The returning a resulting in the .
+ /// The resulting in the .
/// A resulting in the generated for the resulting .
- ValueTask Invoke(Func>> authorityInvoker)
+ ValueTask Invoke(Func>> authorityInvoker)
where TResult : TApiModel
where TApiModel : notnull;
@@ -61,11 +63,27 @@ namespace Tgstation.Server.Host.Authority
/// The .
/// The resulting of the return value.
/// The for converting s to s.
- /// The returning a resulting in the .
+ /// The resulting in the .
/// A resulting in the generated for the resulting .
- ValueTask InvokeTransformable(Func>> authorityInvoker)
+ ValueTask InvokeTransformable(Func>> authorityInvoker)
where TResult : notnull, IApiTransformable
where TApiModel : notnull
where TTransformer : ITransformer, new();
+
+ ///
+ /// Invoke a method and get the transformed result.
+ ///
+ /// The returned by the .
+ /// The returned .
+ /// The for converting s to s.
+ /// The returning a .
+ /// Optional transformer for the run once it has been acquired.
+ /// A resulting in the returned on success or if the requirements weren't satisfied.
+ ValueTask> InvokeTransformableQueryable(
+ Func>> authorityInvoker,
+ Func, IQueryable>? preTransformer = null)
+ where TResult : IApiTransformable
+ where TApiModel : notnull
+ where TTransformer : ITransformer, new();
}
}
diff --git a/src/Tgstation.Server.Host/Authority/ILoginAuthority.cs b/src/Tgstation.Server.Host/Authority/ILoginAuthority.cs
index 0558bbfaa0..111d83271f 100644
--- a/src/Tgstation.Server.Host/Authority/ILoginAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/ILoginAuthority.cs
@@ -16,13 +16,13 @@ namespace Tgstation.Server.Host.Authority
///
/// The for the operation.
/// A resulting in a .
- ValueTask> AttemptLogin(CancellationToken cancellationToken);
+ RequirementsGated> AttemptLogin(CancellationToken cancellationToken);
///
/// Attempt to login to an OAuth service with the current OAuth credentials.
///
/// The for the operation.
/// A resulting in an .
- ValueTask> AttemptOAuthGatewayLogin(CancellationToken cancellationToken);
+ RequirementsGated> AttemptOAuthGatewayLogin(CancellationToken cancellationToken);
}
}
diff --git a/src/Tgstation.Server.Host/Authority/IPermissionSetAuthority.cs b/src/Tgstation.Server.Host/Authority/IPermissionSetAuthority.cs
index bb10fed383..8e4a370087 100644
--- a/src/Tgstation.Server.Host/Authority/IPermissionSetAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/IPermissionSetAuthority.cs
@@ -1,10 +1,8 @@
using System.Threading;
using System.Threading.Tasks;
-using Tgstation.Server.Api.Rights;
using Tgstation.Server.Host.Authority.Core;
using Tgstation.Server.Host.Models;
-using Tgstation.Server.Host.Security;
namespace Tgstation.Server.Host.Authority
{
@@ -20,7 +18,6 @@ namespace Tgstation.Server.Host.Authority
/// The of .
/// The for the operation.
/// A resulting in a .
- [TgsAuthorize(AdministrationRights.ReadUsers)]
- ValueTask> GetId(long id, PermissionSetLookupType lookupType, CancellationToken cancellationToken);
+ RequirementsGated> GetId(long id, PermissionSetLookupType lookupType, CancellationToken cancellationToken);
}
}
diff --git a/src/Tgstation.Server.Host/Authority/IRestAuthorityInvoker{TAuthority}.cs b/src/Tgstation.Server.Host/Authority/IRestAuthorityInvoker{TAuthority}.cs
index 2cb05a2b9a..0e3b6f3b14 100644
--- a/src/Tgstation.Server.Host/Authority/IRestAuthorityInvoker{TAuthority}.cs
+++ b/src/Tgstation.Server.Host/Authority/IRestAuthorityInvoker{TAuthority}.cs
@@ -20,9 +20,9 @@ namespace Tgstation.Server.Host.Authority
/// Invoke a method with no success result.
///
/// The invoking the .
- /// The returning a resulting in the .
+ /// The resulting in the .
/// A resulting in the generated for the resulting .
- ValueTask Invoke(ApiController controller, Func> authorityInvoker);
+ ValueTask Invoke(ApiController controller, Func> authorityInvoker);
///
/// Invoke a method and get the result.
@@ -30,9 +30,9 @@ namespace Tgstation.Server.Host.Authority
/// The .
/// The resulting of the .
/// The invoking the .
- /// The returning a resulting in the .
+ /// The resulting in the .
/// A resulting in the generated for the resulting .
- ValueTask Invoke(ApiController controller, Func>> authorityInvoker)
+ ValueTask Invoke(ApiController controller, Func>> authorityInvoker)
where TResult : TApiModel
where TApiModel : notnull;
@@ -42,9 +42,9 @@ namespace Tgstation.Server.Host.Authority
/// The .
/// The returned REST .
/// The invoking the .
- /// The returning a resulting in the .
+ /// The resulting in the .
/// A resulting in the generated for the resulting .
- ValueTask InvokeTransformable(ApiController controller, Func>> authorityInvoker)
+ ValueTask InvokeTransformable(ApiController controller, Func>> authorityInvoker)
where TResult : notnull, ILegacyApiTransformable
where TApiModel : notnull;
}
diff --git a/src/Tgstation.Server.Host/Authority/IUserAuthority.cs b/src/Tgstation.Server.Host/Authority/IUserAuthority.cs
index f60275aceb..d2b39e45dc 100644
--- a/src/Tgstation.Server.Host/Authority/IUserAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/IUserAuthority.cs
@@ -1,6 +1,5 @@
using System.Linq;
using System.Threading;
-using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Models.Request;
@@ -20,9 +19,9 @@ namespace Tgstation.Server.Host.Authority
/// Gets the currently authenticated user.
///
/// The for the operation.
- /// A resulting in a .
+ /// A .
[TgsAuthorize]
- ValueTask> Read(CancellationToken cancellationToken);
+ RequirementsGated> Read(CancellationToken cancellationToken);
///
/// Gets the with a given .
@@ -31,33 +30,33 @@ namespace Tgstation.Server.Host.Authority
/// If related entities should be loaded.
/// If the may be returned.
/// The for the operation.
- /// A resulting in a .
+ /// A .
[TgsAuthorize(AdministrationRights.ReadUsers)]
- ValueTask> GetId(long id, bool includeJoins, bool allowSystemUser, CancellationToken cancellationToken);
+ RequirementsGated> GetId(long id, bool includeJoins, bool allowSystemUser, CancellationToken cancellationToken);
///
/// Gets the s for the with a given .
///
/// The of the .
/// The for the operation.
- /// A resulting in an of .
- ValueTask> OAuthConnections(long userId, CancellationToken cancellationToken);
+ /// A of .
+ RequirementsGated> OAuthConnections(long userId, CancellationToken cancellationToken);
///
/// Gets the s for the with a given .
///
/// The of the .
/// The for the operation.
- /// A resulting in an of .
- ValueTask> OidcConnections(long userId, CancellationToken cancellationToken);
+ /// A of .
+ RequirementsGated> OidcConnections(long userId, CancellationToken cancellationToken);
///
/// Gets all registered s.
///
/// If related entities should be loaded.
- /// A of s.
+ /// A of s.
[TgsAuthorize(AdministrationRights.ReadUsers)]
- IQueryable Queryable(bool includeJoins);
+ RequirementsGated> Queryable(bool includeJoins);
///
/// Creates a .
@@ -65,9 +64,9 @@ namespace Tgstation.Server.Host.Authority
/// The .
/// If a zero-length indicates and OAuth only user.
/// The for the operation.
- /// A resulting in am for the created .
+ /// A for the created .
[TgsAuthorize(AdministrationRights.WriteUsers)]
- ValueTask> Create(
+ RequirementsGated> Create(
UserCreateRequest createRequest,
bool? needZeroLengthPasswordWithOAuthConnections,
CancellationToken cancellationToken);
@@ -77,8 +76,8 @@ namespace Tgstation.Server.Host.Authority
///
/// The .
/// The for the operation.
- /// A resulting in am for the created .
+ /// A for the created .
[TgsAuthorize(AdministrationRights.WriteUsers | AdministrationRights.EditOwnPassword | AdministrationRights.EditOwnServiceConnections)]
- ValueTask> Update(UserUpdateRequest updateRequest, CancellationToken cancellationToken);
+ RequirementsGated> Update(UserUpdateRequest updateRequest, CancellationToken cancellationToken);
}
}
diff --git a/src/Tgstation.Server.Host/Authority/IUserGroupAuthority.cs b/src/Tgstation.Server.Host/Authority/IUserGroupAuthority.cs
index 28113b95f5..c63c417ab1 100644
--- a/src/Tgstation.Server.Host/Authority/IUserGroupAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/IUserGroupAuthority.cs
@@ -17,8 +17,9 @@ namespace Tgstation.Server.Host.Authority
///
/// Gets the current .
///
+ /// The for the operation.
/// A resulting in a .
- ValueTask> Read();
+ RequirementsGated> Read(CancellationToken cancellationToken);
///
/// Gets the with a given .
@@ -26,17 +27,17 @@ namespace Tgstation.Server.Host.Authority
/// The of the .
/// If related entities should be loaded.
/// The for the operation.
- /// A resulting in a .
+ /// A .
[TgsAuthorize(AdministrationRights.ReadUsers)]
- ValueTask> GetId(long id, bool includeJoins, CancellationToken cancellationToken);
+ RequirementsGated> GetId(long id, bool includeJoins, CancellationToken cancellationToken);
///
/// Gets all registered s.
///
/// If related entities should be loaded.
- /// A of s.
+ /// A of s.
[TgsAuthorize(AdministrationRights.ReadUsers)]
- IQueryable Queryable(bool includeJoins);
+ RequirementsGated> Queryable(bool includeJoins);
///
/// Create a .
@@ -44,9 +45,9 @@ namespace Tgstation.Server.Host.Authority
/// The created 's .
/// The created 's .
/// The for the operation.
- /// A resulting in a .
+ /// A .
[TgsAuthorize(AdministrationRights.WriteUsers)]
- ValueTask> Create(string name, PermissionSet? permissionSet, CancellationToken cancellationToken);
+ RequirementsGated> Create(string name, PermissionSet? permissionSet, CancellationToken cancellationToken);
///
/// Updates a .
@@ -55,17 +56,17 @@ namespace Tgstation.Server.Host.Authority
/// The optional new for the .
/// The optional new for the .
/// The for the operation.
- /// A resulting in a .
+ /// A resulting in a .
[TgsAuthorize(AdministrationRights.WriteUsers)]
- ValueTask> Update(long id, string? newName, PermissionSet? newPermissionSet, CancellationToken cancellationToken);
+ RequirementsGated> Update(long id, string? newName, PermissionSet? newPermissionSet, CancellationToken cancellationToken);
///
/// Deletes an empty .
///
/// The of the to delete.
/// The for the operation.
- /// A representing the running operation.
+ /// A representing the running operation.
[TgsAuthorize(AdministrationRights.WriteUsers)]
- ValueTask DeleteEmpty(long id, CancellationToken cancellationToken);
+ RequirementsGated DeleteEmpty(long id, CancellationToken cancellationToken);
}
}
diff --git a/src/Tgstation.Server.Host/Authority/LoginAuthority.cs b/src/Tgstation.Server.Host/Authority/LoginAuthority.cs
index ab8af50f91..12dcd4879d 100644
--- a/src/Tgstation.Server.Host/Authority/LoginAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/LoginAuthority.cs
@@ -3,6 +3,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -103,7 +104,6 @@ namespace Tgstation.Server.Host.Authority
///
/// Initializes a new instance of the class.
///
- /// The to use.
/// The to use.
/// The to use.
/// The value of .
@@ -115,7 +115,6 @@ namespace Tgstation.Server.Host.Authority
/// The value of .
/// The containing the value of .
public LoginAuthority(
- IAuthenticationContext authenticationContext,
IDatabaseContext databaseContext,
ILogger logger,
IApiHeadersProvider apiHeadersProvider,
@@ -127,7 +126,6 @@ namespace Tgstation.Server.Host.Authority
ISessionInvalidationTracker sessionInvalidationTracker,
IOptions securityConfigurationOptions)
: base(
- authenticationContext,
databaseContext,
logger)
{
@@ -142,7 +140,44 @@ namespace Tgstation.Server.Host.Authority
}
///