public async Task <ActionResult <ApiResult <SessionPreview> > > LoginMfa([FromBody] MfaLoginModel data, CancellationToken cancellationToken = default) { if (data.ActionToken == null || data.MfaCode == null) { return(this.StatusCode(403, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.Unauthorized, "MFA state validation failed.")))); } var(stateId, clientTk) = this.UnpackState(data.ActionToken); var serverTk = await this.MfaStateRepository.ValidateStateAsync(this.HttpContext.Connection.RemoteIpAddress.ToString(), stateId, cancellationToken); var tokenPair = new ActionTokenPair(clientTk, serverTk); if (!this.ActionTokenPairHandler.ValidateTokenPair(tokenPair, TokenActionMFA)) { return(this.StatusCode(403, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.Unauthorized, "MFA state validation failed.")))); } var userId = BinaryPrimitives.ReadInt64BigEndian(clientTk.State); var mfa = await this.MfaRepository.GetMfaSettingsAsync(userId, cancellationToken); if (mfa == null || !mfa.IsConfirmed) { return(this.StatusCode(400, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.InvalidCredentials, "MFA not configured.")))); } if (data.MfaCode.Length == 6) { if (!this.MfaValidator.ValidateCode(data.MfaCode, mfa)) { return(this.StatusCode(403, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.InvalidCredentials, "Invalid MFA code provided.")))); } } else if (data.MfaCode.Length == 8) { if (!this.MfaValidator.ValidateRecoveryCode(data.MfaCode, mfa)) { return(this.StatusCode(403, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.InvalidCredentials, "Invalid MFA code provided.")))); } await this.MfaRepository.TripRecoveryCodeAsync(userId, cancellationToken); } else { return(this.StatusCode(403, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.InvalidCredentials, "Invalid MFA code provided.")))); } var user = await this.UserRepository.GetUserAsync(userId, cancellationToken); var ruser = this.UserPreviewRepository.GetUser(user); var token = this.Jwt.IssueToken(ruser); return(this.Ok(ApiResult.FromResult(this.UserPreviewRepository.GetSession(ruser, token.Token, token.ExpiresAt, user.RequiresMfa)))); }
public async Task <ActionResult <ApiResult <SessionPreview> > > MfaEnable([FromBody] MfaLoginModel data, CancellationToken cancellationToken = default) { var(stateId, clientTk) = this.UnpackState(data.ActionToken); var serverTk = await this.MfaStateRepository.ValidateStateAsync(this.HttpContext.Connection.RemoteIpAddress.ToString(), stateId, cancellationToken); var tokenPair = new ActionTokenPair(clientTk, serverTk); if (!this.ActionTokenPairHandler.ValidateTokenPair(tokenPair, TokenActionMFAConfigure)) { return(this.StatusCode(403, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.Unauthorized, "MFA state validation failed.")))); } var user = this.RosettaUser; var pwd = await this.UserRepository.GetUserPasswordAsync(user.Id, cancellationToken); if (pwd == null) { return(this.StatusCode(401, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.InvalidCredentials, "Specified credentials were invalid.")))); } var mfa = await this.MfaRepository.GetMfaSettingsAsync(user.Id, cancellationToken); if (mfa == null) { return(this.StatusCode(401, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.InvalidCredentials, "MFA not configured.")))); } if (mfa.IsConfirmed) { return(this.StatusCode(401, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.AlreadyConfigured, "MFA is already configured.")))); } if (!this.MfaValidator.ValidateCode(data.MfaCode, mfa)) { await this.MfaRepository.RemoveMfaAsync(user.Id, cancellationToken); return(this.StatusCode(403, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.InvalidCredentials, "Invalid MFA code provided.")))); } await this.MfaRepository.ConfirmMfaAsync(user.Id, cancellationToken); var ruser = this.UserPreviewRepository.GetUser(user); var token = this.Jwt.IssueToken(ruser); return(this.Ok(ApiResult.FromResult(this.UserPreviewRepository.GetSession(ruser, token.Token, token.ExpiresAt, user.RequiresMfa)))); }
public async Task <ActionResult <ApiResult <SessionPreview> > > Login([FromBody] OAuthAuthenticationModel data, CancellationToken cancellationToken = default) { if (data.State == null) { return(this.StatusCode(403, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.Unauthorized, "OAuth state validation failed.")))); } var(stateId, clientTk) = this.UnpackState(data.State); var serverTk = await this.OAuthStateRepository.ValidateStateAsync(this.HttpContext.Connection.RemoteIpAddress.ToString(), stateId, cancellationToken); var tokenPair = new ActionTokenPair(clientTk, serverTk); if (!this.ActionTokenPairHandler.ValidateTokenPair(tokenPair, TokenActionOAuth)) { return(this.StatusCode(403, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.Unauthorized, "OAuth state validation failed.")))); } var provider = this.OAuthSelector.IdFromReferrer(new Uri(data.Referrer)); var oauth = this.OAuthSelector.GetById(provider); if (oauth == null) { return(this.NotFound(ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.InvalidProvider, "Specified provider does not exist.")))); } var ctx = this.CreateContext(provider, data.State); var tokens = await oauth.CompleteLoginAsync(ctx, data.Code, cancellationToken); if (tokens == null) { return(this.StatusCode(403, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.ExternalAuthenticationError, "Failed to authenticate with the OAuth provider.")))); } var expires = DateTimeOffset.UtcNow.AddSeconds(tokens.ExpiresIn - 20); var ouser = await oauth.GetUserAsync(ctx, tokens.AccessToken, cancellationToken); if (ouser == null || !ouser.IsAuthorized) { return(this.StatusCode(403, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.Unauthorized, "You are not authorized to participate.")))); } var oid = ouser.Id; var euser = await this.UserRepository.GetExternalAccountAsync(oid, provider, cancellationToken); var user = euser?.User; if (euser == null) { if (!AbstractionUtilities.NameRegex.IsMatch(ouser.Username)) { return(this.StatusCode(403, ApiResult.FromError <SessionPreview>(new ApiError(ApiErrorCode.InvalidName, "Specified username contained invalid characters.")))); } var uid = this.GetUserId(); if (uid == null) { user = await this.UserRepository.CreateUserAsync(ouser.Username, ouser.IsAuthorized, cancellationToken); } else { user = await this.UserRepository.GetUserAsync(uid.Value, cancellationToken); } euser = await this.UserRepository.ConnectExternalAccountAsync(user.Id, ouser.Id, ouser.Username, provider, cancellationToken); } await this.UserRepository.UpdateTokensAsync(user.Id, euser.ProviderId, tokens.AccessToken, tokens.RefreshToken, expires, cancellationToken); var ruser = this.UserPreviewRepository.GetUser(user); var token = this.Jwt.IssueToken(ruser); return(this.Ok(ApiResult.FromResult(this.UserPreviewRepository.GetSession(ruser, token.Token, token.ExpiresAt, user.RequiresMfa)))); }