4using System.Threading.Tasks;
6using Microsoft.AspNetCore.Authorization;
7using Microsoft.AspNetCore.Mvc;
8using Microsoft.EntityFrameworkCore;
9using Microsoft.Extensions.Logging;
10using Microsoft.Extensions.Options;
11using Microsoft.Extensions.Primitives;
12using Microsoft.Net.Http.Headers;
117 IOptions<GeneralConfiguration> generalConfigurationOptions,
118 ILogger<ApiRootController> logger,
122 authenticationContext,
136 generalConfiguration = generalConfigurationOptions?.Value ??
throw new ArgumentNullException(nameof(generalConfigurationOptions));
165 failIfUnauthed = Request.Headers.Authorization.Count > 0;
168 failIfUnauthed = ApiHeaders.Token !=
null;
202#pragma warning disable CA1506
203 public async ValueTask<IActionResult>
CreateToken(CancellationToken cancellationToken)
207 Response.Headers.Add(HeaderNames.WWWAuthenticate,
new StringValues($
"basic realm=\"Create TGS {ApiHeaders.BearerAuthenticationScheme} token\""));
223 catch (NotImplementedException)
228 using (systemIdentity)
235 string? externalUserId;
241 if (validator ==
null)
244 externalUserId = await validator
247 Logger.LogTrace(
"External {oAuthProvider} UID: {externalUserId}", oAuthProvider, externalUserId);
249 catch (RateLimitExceededException ex)
254 if (externalUserId ==
null)
258 x => x.OAuthConnections!.Any(
259 y => y.Provider == oAuthProvider
260 && y.ExternalUserId == externalUserId));
265 if (canonicalUserName == Models.User.CanonicalizeName(Models.User.TgsSystemUserName))
268 if (systemIdentity ==
null)
269 query = query.Where(x => x.CanonicalName == canonicalUserName);
271 query = query.Where(x => x.CanonicalName == canonicalUserName || x.SystemIdentifier == systemIdentity.
Uid);
274 var users = await query
275 .Select(x =>
new Models.User
278 PasswordHash = x.PasswordHash,
281 SystemIdentifier = x.SystemIdentifier,
283 .ToListAsync(cancellationToken);
287 .OrderByDescending(dbUser => dbUser.SystemIdentifier ==
null)
299 var originalHash = user.PasswordHash;
300 var isLikelyDbUser = originalHash !=
null;
301 bool usingSystemIdentity = systemIdentity !=
null && !isLikelyDbUser;
303 if (!usingSystemIdentity)
308 if (user.PasswordHash != originalHash)
310 Logger.LogDebug(
"User ID {userId}'s password hash needs a refresh, updating database.", user.Id);
316 updatedUser.PasswordHash = user.PasswordHash;
322 var usernameMismatch = systemIdentity!.
Username != user.Name;
323 if (isLikelyDbUser || usernameMismatch)
329 Logger.LogDebug(
"System user ID {userId}'s PasswordHash is polluted, updating database.", user.Id);
330 user.PasswordHash =
null;
331 user.LastPasswordUpdate = DateTimeOffset.UtcNow;
334 if (usernameMismatch)
337 Logger.LogDebug(
"User ID {userId}'s system identity needs a refresh, updating database.", user.Id);
338 user.Name = systemIdentity.
Username;
339 user.CanonicalName = Models.User.CanonicalizeName(user.Name);
347 if (!user.Enabled!.Value)
349 Logger.LogTrace(
"Not logging in disabled user {userId}.", user.Id);
354 if (usingSystemIdentity)
357 var identExpiry = token.
ParseJwt().ValidTo;
359 identExpiry += TimeSpan.FromSeconds(15);
363 Logger.LogDebug(
"Successfully logged in user {userId}!", user.Id);
368#pragma warning restore CA1506
virtual ? long Id
The ID of the entity.
Represents an error message returned by the server.
Represents a JWT returned by the API.
JsonWebToken ParseJwt()
Parses the Bearer as a JsonWebToken.
Routes to a server actions.
const string ApiRoot
The root of API methods.
Constants used for communication with the DMAPI.
static readonly Version InteropVersion
The DMAPI InteropVersion being used.
General configuration options.
Base Controller for API functions.
IActionResult HeadersIssue(HeadersException headersException)
Response for missing/Invalid headers.
new ObjectResult Unauthorized()
Generic 401 response.
ObjectResult RateLimit(RateLimitExceededException rateLimitException)
429 response for a given rateLimitException .
ILogger< ApiController > Logger
The ILogger for the ApiController.
Root ApiController for the Application.
ApiRootController(IDatabaseContext databaseContext, IAuthenticationContext authenticationContext, ITokenFactory tokenFactory, ISystemIdentityFactory systemIdentityFactory, ICryptographySuite cryptographySuite, IAssemblyInformationProvider assemblyInformationProvider, IIdentityCache identityCache, IOAuthProviders oAuthProviders, IPlatformIdentifier platformIdentifier, ISwarmService swarmService, IServerControl serverControl, IOptions< GeneralConfiguration > generalConfigurationOptions, ILogger< ApiRootController > logger, IApiHeadersProvider apiHeadersProvider)
Initializes a new instance of the ApiRootController class.
readonly ITokenFactory tokenFactory
The ITokenFactory for the ApiRootController.
readonly ISystemIdentityFactory systemIdentityFactory
The ISystemIdentityFactory for the ApiRootController.
readonly IServerControl serverControl
The IServerControl for the ApiRootController.
readonly IIdentityCache identityCache
The IIdentityCache for the ApiRootController.
readonly ICryptographySuite cryptographySuite
The ICryptographySuite for the ApiRootController.
async ValueTask< IActionResult > CreateToken(CancellationToken cancellationToken)
Attempt to authenticate a User using ApiController.ApiHeaders.
readonly IPlatformIdentifier platformIdentifier
The IPlatformIdentifier for the ApiRootController.
readonly GeneralConfiguration generalConfiguration
The GeneralConfiguration for the ApiRootController.
IActionResult ServerInfo()
Main page of the Application.
readonly IAssemblyInformationProvider assemblyInformationProvider
The IAssemblyInformationProvider for the ApiRootController.
readonly IOAuthProviders oAuthProviders
The IOAuthProviders for the ApiRootController.
readonly ISwarmService swarmService
The ISwarmService for the ApiRootController.
Backend abstract implementation of IDatabaseContext.
Task Save(CancellationToken cancellationToken)
Saves changes made to the IDatabaseContext. A Task representing the running operation.
DbSet< User > Users
The Users in the DatabaseContext.
bool Valid
If the IAuthenticationContext is for a valid login.
Represents a service that may take an updated Host assembly and run it, stopping the current assembly...
bool UpdateInProgress
Whether or not the server is currently updating.
Represents the currently authenticated Models.User.
Contains various cryptographic functions.
bool CheckUserPassword(User user, string password)
Checks a given password matches a given user 's User.PasswordHash. This may result in User....
For caching ISystemIdentitys.
ValueTask CacheSystemIdentity(User user, ISystemIdentity systemIdentity, DateTimeOffset expiry)
Keep a user 's systemIdentity alive until an expiry time.
Factory for ISystemIdentitys.
Task< ISystemIdentity?> CreateSystemIdentity(User user, CancellationToken cancellationToken)
Create a ISystemIdentity for a given user .
Represents a user on the current global::System.Runtime.InteropServices.OSPlatform.
string Uid
A unique identifier for the user.
string Username
The user's name.
For creating TokenResponses.
TokenResponse CreateToken(Models.User user, bool oAuth)
Create a TokenResponse for a given user .
TokenValidationParameters ValidationParameters
The TokenValidationParameters for the ITokenFactory.
Contains IOAuthValidators.
IOAuthValidator? GetValidator(OAuthProvider oAuthProvider)
Gets the IOAuthValidator for a given oAuthProvider .
Dictionary< OAuthProvider, OAuthProviderInfo > ProviderInfos()
Gets a Dictionary<TKey, TValue> of the provider client IDs.
Used for swarm operations. Functions may be no-op based on configuration.
List< SwarmServerResponse >? GetSwarmServers()
Gets the list of SwarmServerResponses in the swarm, including the current one.
ErrorCode
Types of Response.ErrorMessageResponses that the API may return.