diff --git a/Controllers/AccountController.cs b/Controllers/AccountController.cs index db30a67..ea2f157 100644 --- a/Controllers/AccountController.cs +++ b/Controllers/AccountController.cs @@ -26,6 +26,7 @@ public class AccountController : ControllerBase private readonly ApplicationCache _applicationCache; private readonly AuthService _authService; private readonly MultiFactorApiClient _apiClient; + private readonly MultiFactorSelfServiceApiClient _selfServiceApiClient; private readonly IHttpClientFactory _httpFactory; private readonly ActiveDirectoryService _activeDirectoryService; private readonly DataProtectionService _dataProtectionService; @@ -35,6 +36,7 @@ public class AccountController : ControllerBase public AccountController(ApplicationCache applicationCache, AuthService authService, MultiFactorApiClient apiClient, + MultiFactorSelfServiceApiClient selfServiceApiClient, ActiveDirectoryService activeDirectoryService, DataProtectionService dataProtectionService, ILogger logger, IHttpClientFactory httpFactory) @@ -42,6 +44,7 @@ public AccountController(ApplicationCache applicationCache, _applicationCache = applicationCache ?? throw new ArgumentNullException(nameof(applicationCache)); _authService = authService ?? throw new ArgumentNullException(nameof(authService)); _apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient)); + _selfServiceApiClient = selfServiceApiClient ?? throw new ArgumentNullException(nameof(selfServiceApiClient)); _activeDirectoryService = activeDirectoryService ?? throw new ArgumentNullException(nameof(activeDirectoryService)); _dataProtectionService = @@ -224,9 +227,19 @@ public ActionResult Identity(IdentityModel model, SingleSignOnDto sso) // 2fa before authn var identity = model.UserName; + var authenticatorsResponse = _selfServiceApiClient.GetUserAuthenticators(identity); + if (!authenticatorsResponse.Success || !authenticatorsResponse.Model.GetAuthenticators().Any()) + { + return View("Login", new LoginModel() + { + UserName = identity + }); + } + // in common case if (!Configuration.Current.NeedPrebindInfo()) { + return RedirectToMfa( identity: identity, login: model.UserName, diff --git a/MultiFactor.SelfService.Windows.Portal.csproj b/MultiFactor.SelfService.Windows.Portal.csproj index 13a0456..fadfc6e 100644 --- a/MultiFactor.SelfService.Windows.Portal.csproj +++ b/MultiFactor.SelfService.Windows.Portal.csproj @@ -329,7 +329,7 @@ True True PasswordPolicy.ru.resx - + UserUnlock.resx True @@ -452,8 +452,8 @@ + - @@ -572,7 +572,7 @@ PublicResXFileCodeGenerator PasswordPolicy.ru.Designer.cs - + PublicResXFileCodeGenerator UserUnlock.Designer.cs diff --git a/Services/API/DTO/UserProfileAuthenticator.cs b/Services/API/DTO/UserProfileAuthenticator.cs deleted file mode 100644 index 9118e90..0000000 --- a/Services/API/DTO/UserProfileAuthenticator.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace MultiFactor.SelfService.Windows.Portal.Services.API.DTO -{ - /// - /// MFA authenticator - /// - public class UserProfileAuthenticator - { - public string Id { get; set; } - public string Label { get; set; } - } -} \ No newline at end of file diff --git a/Services/API/DTO/UserProfileAuthenticatorsDto.cs b/Services/API/DTO/UserProfileAuthenticatorsDto.cs new file mode 100644 index 0000000..5fea807 --- /dev/null +++ b/Services/API/DTO/UserProfileAuthenticatorsDto.cs @@ -0,0 +1,30 @@ +using System.Linq; + +namespace MultiFactor.SelfService.Windows.Portal.Services.API.DTO +{ + public class UserProfileAuthenticatorsDto + { + public UserProfileAuthenticatorDto[] TotpAuthenticators { get; set; } + public UserProfileAuthenticatorDto[] TelegramAuthenticators { get; set; } + public UserProfileAuthenticatorDto[] MobileAppAuthenticators { get; set; } + public UserProfileAuthenticatorDto[] PhoneAuthenticators { get; set; } + + public UserProfileAuthenticatorDto[] GetAuthenticators() + { + return TotpAuthenticators + .Concat(TelegramAuthenticators) + .Concat(MobileAppAuthenticators) + .Concat(PhoneAuthenticators) + .ToArray(); + } + } + + /// + /// MFA authenticator + /// + public class UserProfileAuthenticatorDto + { + public string Id { get; set; } + public string Label { get; set; } + } +} \ No newline at end of file diff --git a/Services/API/MultiFactorSelfServiceApiClient.cs b/Services/API/MultiFactorSelfServiceApiClient.cs index 35df9ab..16add9a 100644 --- a/Services/API/MultiFactorSelfServiceApiClient.cs +++ b/Services/API/MultiFactorSelfServiceApiClient.cs @@ -30,6 +30,19 @@ public UserProfile LoadUserProfile() return result.Model; } + public ApiResponse GetUserAuthenticators(string identity) + { + if (string.IsNullOrWhiteSpace(identity)) throw new ArgumentNullException(nameof(identity)); + + var payload = new + { + Identity = identity + }; + + var result = _apiClient.Post>("/self-service/user-authenticators", payload, x => x.Authorization = GetBasicAuth()); + return result; + } + public ApiResponse StartResetPassword(string twoFaIdentity, string ldapIdentity, string callbackUrl) { if (twoFaIdentity is null) throw new ArgumentNullException(nameof(twoFaIdentity));