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));