diff --git a/services/src/main/java/org/keycloak/authentication/otp/MicrosoftAuthenticatorOTPProvider.java b/services/src/main/java/org/keycloak/authentication/otp/MicrosoftAuthenticatorOTPProvider.java new file mode 100644 index 0000000000..486d69f731 --- /dev/null +++ b/services/src/main/java/org/keycloak/authentication/otp/MicrosoftAuthenticatorOTPProvider.java @@ -0,0 +1,40 @@ +package org.keycloak.authentication.otp; + +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.OTPPolicy; + +public class MicrosoftAuthenticatorOTPProvider implements OTPApplicationProviderFactory, OTPApplicationProvider { + + @Override + public OTPApplicationProvider create(KeycloakSession session) { + return this; + } + + @Override + public String getId() { + return "microsoft-authenticator"; + } + + @Override + public String getName() { + return "totpAppMicrosoftAuthenticatorName"; + } + + @Override + public boolean supports(OTPPolicy policy) { + if (policy.getDigits() != 6) { + return false; + } + + if (!policy.getAlgorithm().equals("HmacSHA1")) { + return false; + } + + return policy.getType().equals("totp") && policy.getPeriod() == 30; + } + + @Override + public void close() { + } + +} diff --git a/services/src/main/resources/META-INF/services/org.keycloak.authentication.otp.OTPApplicationProviderFactory b/services/src/main/resources/META-INF/services/org.keycloak.authentication.otp.OTPApplicationProviderFactory index 7a4a57b90c..e37c3f2bc9 100644 --- a/services/src/main/resources/META-INF/services/org.keycloak.authentication.otp.OTPApplicationProviderFactory +++ b/services/src/main/resources/META-INF/services/org.keycloak.authentication.otp.OTPApplicationProviderFactory @@ -1,2 +1,3 @@ org.keycloak.authentication.otp.GoogleAuthenticatorProvider -org.keycloak.authentication.otp.FreeOTPProvider \ No newline at end of file +org.keycloak.authentication.otp.FreeOTPProvider +org.keycloak.authentication.otp.MicrosoftAuthenticatorOTPProvider \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java index 4051c75838..e7a607bf3a 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java @@ -163,6 +163,7 @@ public class RequiredActionTotpSetupTest extends AbstractTestRealmKeycloakTest { assertTrue(pageSource.contains("Install one of the following applications on your mobile")); assertTrue(pageSource.contains("FreeOTP")); assertTrue(pageSource.contains("Google Authenticator")); + assertTrue(pageSource.contains("Microsoft Authenticator")); assertTrue(pageSource.contains("Open the application and scan the barcode")); assertFalse(pageSource.contains("Open the application and enter the key")); @@ -177,6 +178,7 @@ public class RequiredActionTotpSetupTest extends AbstractTestRealmKeycloakTest { assertTrue(pageSource.contains("Install one of the following applications on your mobile")); assertTrue(pageSource.contains("FreeOTP")); assertTrue(pageSource.contains("Google Authenticator")); + assertTrue(pageSource.contains("Microsoft Authenticator")); assertFalse(pageSource.contains("Open the application and scan the barcode")); assertTrue(pageSource.contains("Open the application and enter the key")); @@ -198,6 +200,7 @@ public class RequiredActionTotpSetupTest extends AbstractTestRealmKeycloakTest { assertTrue(pageSource.contains("Install one of the following applications on your mobile")); assertTrue(pageSource.contains("FreeOTP")); assertTrue(pageSource.contains("Google Authenticator")); + assertTrue(pageSource.contains("Microsoft Authenticator")); assertTrue(pageSource.contains("Open the application and scan the barcode")); assertFalse(pageSource.contains("Open the application and enter the key")); @@ -312,6 +315,7 @@ public class RequiredActionTotpSetupTest extends AbstractTestRealmKeycloakTest { assertTrue(pageSource.contains("FreeOTP")); assertFalse(pageSource.contains("Google Authenticator")); + assertFalse(pageSource.contains("Microsoft Authenticator")); totpPage.clickManual(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java index 5225b562a6..319aeb992e 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java @@ -889,8 +889,8 @@ public class RealmTest extends AbstractAdminTest { rep = realm.toRepresentation(); List supportedApplications = rep.getOtpSupportedApplications(); - assertThat(supportedApplications, hasSize(2)); - assertThat(supportedApplications, containsInAnyOrder("totpAppGoogleName", "totpAppFreeOTPName")); + assertThat(supportedApplications, hasSize(3)); + assertThat(supportedApplications, containsInAnyOrder("totpAppGoogleName", "totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName")); rep.setOtpPolicyDigits(8); realm.update(rep); diff --git a/themes/src/main/resources/theme/base/account/messages/messages_en.properties b/themes/src/main/resources/theme/base/account/messages/messages_en.properties index 5fbcc8d3a6..b639a9d2ac 100755 --- a/themes/src/main/resources/theme/base/account/messages/messages_en.properties +++ b/themes/src/main/resources/theme/base/account/messages/messages_en.properties @@ -165,6 +165,7 @@ totpDeviceName=Device Name totpAppFreeOTPName=FreeOTP totpAppGoogleName=Google Authenticator +totpAppMicrosoftAuthenticatorName=Microsoft Authenticator irreversibleAction=This action is irreversible deletingImplies=Deleting your account implies: diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties index 689d8910c0..61f83a153c 100644 --- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties +++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties @@ -1362,6 +1362,7 @@ time-based=Time Based counter-based=Counter Based totpAppFreeOTPName=FreeOTP totpAppGoogleName=Google Authenticator +totpAppMicrosoftAuthenticatorName=Microsoft Authenticator otp-type.tooltip=totp is Time-Based One Time Password. 'hotp' is a counter base one time password in which the server keeps a counter to hash against. otp-hash-algorithm=OTP Hash Algorithm otp-hash-algorithm.tooltip=What hashing algorithm should be used to generate the OTP. diff --git a/themes/src/main/resources/theme/base/login/messages/messages_en.properties b/themes/src/main/resources/theme/base/login/messages/messages_en.properties index 7a1d70a2a6..7a260a911a 100755 --- a/themes/src/main/resources/theme/base/login/messages/messages_en.properties +++ b/themes/src/main/resources/theme/base/login/messages/messages_en.properties @@ -137,6 +137,7 @@ loginTotp.hotp=Counter-based totpAppFreeOTPName=FreeOTP totpAppGoogleName=Google Authenticator +totpAppMicrosoftAuthenticatorName=Microsoft Authenticator loginChooseAuthenticator=Select login method