mirror of
https://github.com/bitwarden/server.git
synced 2025-04-17 11:08:16 -05:00
PM-2128 Enforce one time use of TOTP (#3152)
* enforcing one time MFA token use * Updated cache TTL * renamed the cache * removed IP limit, added comment, updated cache Key * fixed build errors
This commit is contained in:
parent
4b482f0a34
commit
917c657439
@ -26,6 +26,7 @@ using Bit.Core.Utilities;
|
|||||||
using Bit.Identity.Utilities;
|
using Bit.Identity.Utilities;
|
||||||
using IdentityServer4.Validation;
|
using IdentityServer4.Validation;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
|
||||||
namespace Bit.Identity.IdentityServer;
|
namespace Bit.Identity.IdentityServer;
|
||||||
|
|
||||||
@ -45,6 +46,8 @@ public abstract class BaseRequestValidator<T> where T : class
|
|||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
private readonly IUserRepository _userRepository;
|
private readonly IUserRepository _userRepository;
|
||||||
private readonly IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> _tokenDataFactory;
|
private readonly IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> _tokenDataFactory;
|
||||||
|
private readonly IDistributedCache _distributedCache;
|
||||||
|
private readonly DistributedCacheEntryOptions _cacheEntryOptions;
|
||||||
|
|
||||||
protected ICurrentContext CurrentContext { get; }
|
protected ICurrentContext CurrentContext { get; }
|
||||||
protected IPolicyService PolicyService { get; }
|
protected IPolicyService PolicyService { get; }
|
||||||
@ -69,7 +72,8 @@ public abstract class BaseRequestValidator<T> where T : class
|
|||||||
IPolicyService policyService,
|
IPolicyService policyService,
|
||||||
IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> tokenDataFactory,
|
IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> tokenDataFactory,
|
||||||
IFeatureService featureService,
|
IFeatureService featureService,
|
||||||
ISsoConfigRepository ssoConfigRepository)
|
ISsoConfigRepository ssoConfigRepository,
|
||||||
|
IDistributedCache distributedCache)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_deviceRepository = deviceRepository;
|
_deviceRepository = deviceRepository;
|
||||||
@ -89,6 +93,14 @@ public abstract class BaseRequestValidator<T> where T : class
|
|||||||
_tokenDataFactory = tokenDataFactory;
|
_tokenDataFactory = tokenDataFactory;
|
||||||
FeatureService = featureService;
|
FeatureService = featureService;
|
||||||
SsoConfigRepository = ssoConfigRepository;
|
SsoConfigRepository = ssoConfigRepository;
|
||||||
|
_distributedCache = distributedCache;
|
||||||
|
_cacheEntryOptions = new DistributedCacheEntryOptions
|
||||||
|
{
|
||||||
|
// This sets the time an item is cached to 15 minutes. This value is hard coded
|
||||||
|
// to 15 because to it covers all time-out windows for both Authenticators and
|
||||||
|
// Email TOTP.
|
||||||
|
AbsoluteExpirationRelativeToNow = new TimeSpan(0, 15, 0)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task ValidateAsync(T context, ValidatedTokenRequest request,
|
protected async Task ValidateAsync(T context, ValidatedTokenRequest request,
|
||||||
@ -135,6 +147,15 @@ public abstract class BaseRequestValidator<T> where T : class
|
|||||||
var verified = await VerifyTwoFactor(user, twoFactorOrganization,
|
var verified = await VerifyTwoFactor(user, twoFactorOrganization,
|
||||||
twoFactorProviderType, twoFactorToken);
|
twoFactorProviderType, twoFactorToken);
|
||||||
|
|
||||||
|
var cacheKey = "TOTP_" + user.Email;
|
||||||
|
|
||||||
|
var isOtpCached = Core.Utilities.DistributedCacheExtensions.TryGetValue(_distributedCache, cacheKey, out string _);
|
||||||
|
if (isOtpCached)
|
||||||
|
{
|
||||||
|
await BuildErrorResultAsync("Two-step token is invalid. Try again.", true, context, user);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((!verified || isBot) && twoFactorProviderType != TwoFactorProviderType.Remember)
|
if ((!verified || isBot) && twoFactorProviderType != TwoFactorProviderType.Remember)
|
||||||
{
|
{
|
||||||
await UpdateFailedAuthDetailsAsync(user, true, !validatorContext.KnownDevice);
|
await UpdateFailedAuthDetailsAsync(user, true, !validatorContext.KnownDevice);
|
||||||
@ -148,6 +169,7 @@ public abstract class BaseRequestValidator<T> where T : class
|
|||||||
await BuildTwoFactorResultAsync(user, twoFactorOrganization, context);
|
await BuildTwoFactorResultAsync(user, twoFactorOrganization, context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
await Core.Utilities.DistributedCacheExtensions.SetAsync(_distributedCache, cacheKey, twoFactorToken, _cacheEntryOptions);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,7 @@ using IdentityModel;
|
|||||||
using IdentityServer4.Extensions;
|
using IdentityServer4.Extensions;
|
||||||
using IdentityServer4.Validation;
|
using IdentityServer4.Validation;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
@ -42,11 +43,13 @@ public class CustomTokenRequestValidator : BaseRequestValidator<CustomTokenReque
|
|||||||
IUserRepository userRepository,
|
IUserRepository userRepository,
|
||||||
IPolicyService policyService,
|
IPolicyService policyService,
|
||||||
IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> tokenDataFactory,
|
IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> tokenDataFactory,
|
||||||
IFeatureService featureService)
|
IFeatureService featureService,
|
||||||
|
IDistributedCache distributedCache)
|
||||||
: base(userManager, deviceRepository, deviceService, userService, eventService,
|
: base(userManager, deviceRepository, deviceService, userService, eventService,
|
||||||
organizationDuoWebTokenProvider, organizationRepository, organizationUserRepository,
|
organizationDuoWebTokenProvider, organizationRepository, organizationUserRepository,
|
||||||
applicationCacheService, mailService, logger, currentContext, globalSettings,
|
applicationCacheService, mailService, logger, currentContext, globalSettings,
|
||||||
userRepository, policyService, tokenDataFactory, featureService, ssoConfigRepository)
|
userRepository, policyService, tokenDataFactory, featureService, ssoConfigRepository,
|
||||||
|
distributedCache)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ using Bit.Core.Utilities;
|
|||||||
using IdentityServer4.Models;
|
using IdentityServer4.Models;
|
||||||
using IdentityServer4.Validation;
|
using IdentityServer4.Validation;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
|
||||||
namespace Bit.Identity.IdentityServer;
|
namespace Bit.Identity.IdentityServer;
|
||||||
|
|
||||||
@ -44,11 +45,12 @@ public class ResourceOwnerPasswordValidator : BaseRequestValidator<ResourceOwner
|
|||||||
IPolicyService policyService,
|
IPolicyService policyService,
|
||||||
IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> tokenDataFactory,
|
IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> tokenDataFactory,
|
||||||
IFeatureService featureService,
|
IFeatureService featureService,
|
||||||
ISsoConfigRepository ssoConfigRepository)
|
ISsoConfigRepository ssoConfigRepository,
|
||||||
|
IDistributedCache distributedCache)
|
||||||
: base(userManager, deviceRepository, deviceService, userService, eventService,
|
: base(userManager, deviceRepository, deviceService, userService, eventService,
|
||||||
organizationDuoWebTokenProvider, organizationRepository, organizationUserRepository,
|
organizationDuoWebTokenProvider, organizationRepository, organizationUserRepository,
|
||||||
applicationCacheService, mailService, logger, currentContext, globalSettings, userRepository, policyService,
|
applicationCacheService, mailService, logger, currentContext, globalSettings, userRepository, policyService,
|
||||||
tokenDataFactory, featureService, ssoConfigRepository)
|
tokenDataFactory, featureService, ssoConfigRepository, distributedCache)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user