4using System.Threading.Tasks;
6using Microsoft.AspNetCore.Authorization;
7using Microsoft.EntityFrameworkCore;
8using Microsoft.Extensions.Logging;
9using Microsoft.Extensions.Options;
79 AdditionalData = headersException.
Message,
82 ? HttpFailureResponse.NotAcceptable
93 var users = await query
94 .ToListAsync(cancellationToken);
98 .OrderByDescending(dbUser => dbUser.SystemIdentifier ==
null)
119 ILogger<LoginAuthority> logger,
127 IOptions<SecurityConfiguration> securityConfigurationOptions)
139 securityConfiguration = securityConfigurationOptions?.Value ??
throw new ArgumentNullException(nameof(securityConfigurationOptions));
159 var oAuthProvider = headers.OAuthProvider;
160 if (!oAuthProvider.HasValue)
161 return BadRequest<OAuthGatewayLoginResult>(
ErrorCode.BadHeaders);
163 var (errorResponse, oAuthResult) = await TryOAuthenticate<OAuthGatewayLoginResult>(headers, oAuthProvider.Value,
false, cancellationToken);
164 if (errorResponse !=
null)
165 return errorResponse;
167 Logger.LogDebug(
"Generated {provider} OAuth AccessCode", oAuthProvider.Value);
181 private async ValueTask<AuthorityResponse<LoginResult>>
AttemptLoginImpl(CancellationToken cancellationToken)
185 return Unauthorized<LoginResult>();
191 if (headers.IsTokenAuthentication)
192 return BadRequest<LoginResult>(
ErrorCode.TokenWithToken);
194 var oAuthLogin = headers.OAuthProvider.HasValue;
203 catch (NotImplementedException)
208 using (systemIdentity)
214 var oAuthProvider = headers.OAuthProvider!.Value;
215 var (errorResponse, oauthResult) = await TryOAuthenticate<LoginResult>(headers, oAuthProvider,
true, cancellationToken);
216 if (errorResponse !=
null)
217 return errorResponse;
220 x => x.OAuthConnections!.Any(
221 y => y.Provider == oAuthProvider
222 && y.ExternalUserId == oauthResult!.Value.UserID));
228 return Unauthorized<LoginResult>();
230 if (systemIdentity ==
null)
231 query = query.Where(x => x.CanonicalName == canonicalUserName);
233 query = query.Where(x => x.CanonicalName == canonicalUserName || x.SystemIdentifier == systemIdentity.
Uid);
240 return Unauthorized<LoginResult>();
247 var originalHash = user.PasswordHash;
248 var isLikelyDbUser = originalHash !=
null;
249 var usingSystemIdentity = systemIdentity !=
null && !isLikelyDbUser;
251 if (!usingSystemIdentity)
255 return Unauthorized<LoginResult>();
256 if (user.PasswordHash != originalHash)
258 Logger.LogDebug(
"User ID {userId}'s password hash needs a refresh, updating database.", user.Id);
259 var updatedUser =
new User
264 updatedUser.PasswordHash = user.PasswordHash;
270 var usernameMismatch = systemIdentity!.
Username != user.Name;
271 if (isLikelyDbUser || usernameMismatch)
274 if (usernameMismatch)
277 Logger.LogDebug(
"User ID {userId}'s system identity needs a refresh, updating database.", user.Id);
278 user.Name = systemIdentity.
Username;
285 Logger.LogDebug(
"System user ID {userId}'s PasswordHash is polluted, updating database.", user.Id);
286 user.PasswordHash =
null;
295 if (!user.Enabled!.Value)
297 Logger.LogTrace(
"Not logging in disabled user {userId}.", user.Id);
298 return Forbid<LoginResult>();
308 if (usingSystemIdentity)
311 Logger.LogDebug(
"Successfully logged in user {userId}!", user.Id);
329 identExpiry += TimeSpan.FromSeconds(15);
344 (
string? UserID,
string AccessCode)? oauthResult;
348#pragma warning disable CS0618
350#pragma warning restore CS0618
356 if (validator ==
null)
358 oauthResult = await validator
361 Logger.LogTrace(
"External {oAuthProvider} UID: {externalUserId}", oAuthProvider, oauthResult);
363 catch (Octokit.RateLimitExceededException ex)
368 if (!oauthResult.HasValue)
371 return (
null, OAuthResult: oauthResult);
virtual ? long Id
The ID of the entity.
Represents an error message returned by the server.
string? Message
A human-readable description of the error.
JsonWebToken ParseJwt()
Parses the Bearer as a JsonWebToken.
Base implementation of IAuthority.
static AuthorityResponse< TResult > Unauthorized< TResult >()
Generates a HttpFailureResponse.Unauthorized type AuthorityResponse<TResult>.
AuthorityResponse< TResult > RateLimit< TResult >(RateLimitExceededException rateLimitException)
Generates a HttpFailureResponse.RateLimited type AuthorityResponse.
ILogger< AuthorityBase > Logger
Gets the ILogger for the AuthorityBase.
static AuthorityResponse< TResult > BadRequest< TResult >(ErrorCode errorCode)
Generates a HttpFailureResponse.BadRequest type AuthorityResponse<TResult>.
Represents a response from an authority.
Evaluates a set of IAuthorizationRequirements to be checked before executing a response.
async ValueTask< AuthorityResponse< LoginResult > > AttemptLoginImpl(CancellationToken cancellationToken)
Login process.
LoginAuthority(IDatabaseContext databaseContext, ILogger< LoginAuthority > logger, IApiHeadersProvider apiHeadersProvider, ISystemIdentityFactory systemIdentityFactory, IOAuthProviders oAuthProviders, ITokenFactory tokenFactory, ICryptographySuite cryptographySuite, IIdentityCache identityCache, ISessionInvalidationTracker sessionInvalidationTracker, IOptions< SecurityConfiguration > securityConfigurationOptions)
Initializes a new instance of the LoginAuthority class.
readonly IApiHeadersProvider apiHeadersProvider
The IApiHeadersProvider for the LoginAuthority.
RequirementsGated< AuthorityResponse< LoginResult > > AttemptLogin(CancellationToken cancellationToken)
Attempt to login to the server with the current Basic or OAuth credentials.A ValueTask<TResult> resul...
readonly IOAuthProviders oAuthProviders
The IOAuthProviders for the LoginAuthority.
async ValueTask CacheSystemIdentity(ISystemIdentity systemIdentity, User user, LoginResult loginPayload)
Add a given systemIdentity to the identityCache.
readonly IIdentityCache identityCache
The IIdentityCache for the LoginAuthority.
RequirementsGated< AuthorityResponse< OAuthGatewayLoginResult > > AttemptOAuthGatewayLogin(CancellationToken cancellationToken)
Attempt to login to an OAuth service with the current OAuth credentials.A ValueTask<TResult> resultin...
async ValueTask<(AuthorityResponse< TResult >? ErrorResponse,(string? UserID, string AccessCode)? OAuthResult)> TryOAuthenticate< TResult >(ApiHeaders headers, OAuthProvider oAuthProvider, bool forLogin, CancellationToken cancellationToken)
Attempt OAuth authentication.
readonly ISystemIdentityFactory systemIdentityFactory
The ISystemIdentityFactory for the LoginAuthority.
static async ValueTask< User?> SelectUserInfoFromQuery(IQueryable< User > query, CancellationToken cancellationToken)
Select the details needed to generate a TokenResponse from a given query .
readonly SecurityConfiguration securityConfiguration
The SecurityConfiguration for the LoginAuthority.
static AuthorityResponse< TResult > GenerateHeadersExceptionResponse< TResult >(HeadersException headersException)
Generate an AuthorityResponse<TResult> for a given headersException .
readonly ICryptographySuite cryptographySuite
The ICryptographySuite for the LoginAuthority.
readonly ISessionInvalidationTracker sessionInvalidationTracker
The ISessionInvalidationTracker for the LoginAuthority.
readonly ITokenFactory tokenFactory
The ITokenFactory for the LoginAuthority.
Configuration options pertaining to user security.
bool OidcStrictMode
If OIDC strict mode should be enabled. This mode enforces the existence of at least one OpenIDConnect...
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.
Success response for a login attempt.
Success result for an OAuth gateway login attempt.
required string AccessCode
The user's access token for the requested OAuth service.
const string TgsSystemUserName
Username used when creating jobs automatically.
static string CanonicalizeName(string name)
Change a UserName.Name into a CanonicalName.
IAuthority for authenticating with the server.
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.
Handles invalidating user sessions.
void UserModifiedInvalidateSessions(User user)
Invalidate all sessions for a given user .
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.
string CreateToken(Models.User user, bool serviceLogin)
Create a TokenResponse for a given user .
TokenValidationParameters ValidationParameters
The TokenValidationParameters for the ITokenFactory.
Contains IOAuthValidators.
IOAuthValidator? GetValidator(OAuthProvider oAuthProvider, bool forLogin)
Gets the IOAuthValidator for a given oAuthProvider .
ValueTask<(string? UserID, string AccessCode)?> ValidateResponseCode(string code, bool requireUserID, CancellationToken cancellationToken)
Validate a given OAuth response code .
ErrorCode
Types of Response.ErrorMessageResponses that the API may return.
OAuthProvider
List of OAuth2.0 providers supported by TGS that do not support OIDC.
HeaderErrorTypes
Types of individual ApiHeaders errors.
HttpFailureResponse
Indicates the type of HTTP status code an failing AuthorityResponse should generate.
@ Id
Lookup the Api.Models.EntityId.Id of the Models.PermissionSet.