@ -30,17 +30,18 @@ import org.springframework.web.util.UriComponentsBuilder;
import org.thingsboard.rule.engine.api.SmsService ;
import org.thingsboard.rule.engine.api.SmsService ;
import org.thingsboard.server.common.data.CacheConstants ;
import org.thingsboard.server.common.data.CacheConstants ;
import org.thingsboard.server.common.data.id.TenantId ;
import org.thingsboard.server.common.data.id.TenantId ;
import org.thingsboard.server.service.security.auth.mfa.config.TwoFactorAuthConfigManager ;
import org.thingsboard.server.service.security.auth.mfa.TwoFactorAuthService ;
import org.thingsboard.server.common.data.security.model.mfa.TwoFactorAuthSettings ;
import org.thingsboard.server.service.security.auth.mfa.config.TwoFaConfigManager ;
import org.thingsboard.server.common.data.security.model.mfa.account.SmsTwoFactorAuthAccountConfig ;
import org.thingsboard.server.common.data.security.model.mfa.PlatformTwoFaSettings ;
import org.thingsboard.server.common.data.security.model.mfa.account.TotpTwoFactorAuthAccountConfig ;
import org.thingsboard.server.common.data.security.model.mfa.account.SmsTwoFaAccountConfig ;
import org.thingsboard.server.common.data.security.model.mfa.account.TwoFactorAuthAccountConfig ;
import org.thingsboard.server.common.data.security.model.mfa.account.TotpTwoFaAccountConfig ;
import org.thingsboard.server.common.data.security.model.mfa.provider.SmsTwoFactorAuthProviderConfig ;
import org.thingsboard.server.common.data.security.model.mfa.account.TwoFaAccountConfig ;
import org.thingsboard.server.common.data.security.model.mfa.provider.TotpTwoFactorAuthProviderConfig ;
import org.thingsboard.server.common.data.security.model.mfa.provider.SmsTwoFaProviderConfig ;
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFactorAuthProviderConfig ;
import org.thingsboard.server.common.data.security.model.mfa.provider.TotpTwoFaProviderConfig ;
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFactorAuthProviderType ;
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderConfig ;
import org.thingsboard.server.service.security.auth.mfa.provider.impl.OtpBasedTwoFactorAuthProvider ;
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType ;
import org.thingsboard.server.service.security.auth.mfa.provider.impl.TotpTwoFactorAuthProvider ;
import org.thingsboard.server.service.security.auth.mfa.provider.impl.OtpBasedTwoFaProvider ;
import org.thingsboard.server.service.security.auth.mfa.provider.impl.TotpTwoFaProvider ;
import java.util.Arrays ;
import java.util.Arrays ;
import java.util.Collections ;
import java.util.Collections ;
@ -58,13 +59,15 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
@SpyBean
@SpyBean
private TotpTwoFactorAuth Provider totpTwoFactorAuthProvider ;
private TotpTwoFaProvider totpTwoFactorAuthProvider ;
@MockBean
@MockBean
private SmsService smsService ;
private SmsService smsService ;
@Autowired
@Autowired
private CacheManager cacheManager ;
private CacheManager cacheManager ;
@Autowired
@Autowired
private TwoFactorAuthConfigManager twoFactorAuthConfigManager ;
private TwoFaConfigManager twoFaConfigManager ;
@Autowired
private TwoFactorAuthService twoFactorAuthService ;
@Before
@Before
public void beforeEach ( ) throws Exception {
public void beforeEach ( ) throws Exception {
@ -73,8 +76,8 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
@After
@After
public void afterEach ( ) {
public void afterEach ( ) {
twoFactorAuth ConfigManager . deleteTwoFaSettings ( TenantId . SYS_TENANT_ID ) ;
twoFaConfigManager . deletePlatform TwoFaSettings ( TenantId . SYS_TENANT_ID ) ;
twoFactorAuth ConfigManager . deleteTwoFaSettings ( tenantId ) ;
twoFaConfigManager . deletePlatform TwoFaSettings ( tenantId ) ;
}
}
@ -88,13 +91,13 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
}
}
private void testSaveTestTwoFaSettings ( ) throws Exception {
private void testSaveTestTwoFaSettings ( ) throws Exception {
TotpTwoFactorAuth ProviderConfig totpTwoFaProviderConfig = new TotpTwoFactorAuth ProviderConfig ( ) ;
TotpTwoFaProviderConfig totpTwoFaProviderConfig = new TotpTwoFaProviderConfig ( ) ;
totpTwoFaProviderConfig . setIssuerName ( "tb" ) ;
totpTwoFaProviderConfig . setIssuerName ( "tb" ) ;
SmsTwoFactorAuth ProviderConfig smsTwoFaProviderConfig = new SmsTwoFactorAuth ProviderConfig ( ) ;
SmsTwoFaProviderConfig smsTwoFaProviderConfig = new SmsTwoFaProviderConfig ( ) ;
smsTwoFaProviderConfig . setSmsVerificationMessageTemplate ( "${verificationCode}" ) ;
smsTwoFaProviderConfig . setSmsVerificationMessageTemplate ( "${verificationCode}" ) ;
smsTwoFaProviderConfig . setVerificationCodeLifetime ( 60 ) ;
smsTwoFaProviderConfig . setVerificationCodeLifetime ( 60 ) ;
TwoFactorAuth Settings twoFaSettings = new TwoFactorAuth Settings ( ) ;
Platform TwoFaSettings twoFaSettings = new Platform TwoFaSettings( ) ;
twoFaSettings . setProviders ( List . of ( totpTwoFaProviderConfig , smsTwoFaProviderConfig ) ) ;
twoFaSettings . setProviders ( List . of ( totpTwoFaProviderConfig , smsTwoFaProviderConfig ) ) ;
twoFaSettings . setVerificationCodeSendRateLimit ( "1:60" ) ;
twoFaSettings . setVerificationCodeSendRateLimit ( "1:60" ) ;
twoFaSettings . setVerificationCodeCheckRateLimit ( "3:900" ) ;
twoFaSettings . setVerificationCodeCheckRateLimit ( "3:900" ) ;
@ -103,7 +106,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
doPost ( "/api/2fa/settings" , twoFaSettings ) . andExpect ( status ( ) . isOk ( ) ) ;
doPost ( "/api/2fa/settings" , twoFaSettings ) . andExpect ( status ( ) . isOk ( ) ) ;
TwoFactorAuth Settings savedTwoFaSettings = readResponse ( doGet ( "/api/2fa/settings" ) . andExpect ( status ( ) . isOk ( ) ) , TwoFactorAuth Settings . class ) ;
Platform TwoFaSettings savedTwoFaSettings = readResponse ( doGet ( "/api/2fa/settings" ) . andExpect ( status ( ) . isOk ( ) ) , Platform TwoFaSettings. class ) ;
assertThat ( savedTwoFaSettings . getProviders ( ) ) . hasSize ( 2 ) ;
assertThat ( savedTwoFaSettings . getProviders ( ) ) . hasSize ( 2 ) ;
assertThat ( savedTwoFaSettings . getProviders ( ) ) . contains ( totpTwoFaProviderConfig , smsTwoFaProviderConfig ) ;
assertThat ( savedTwoFaSettings . getProviders ( ) ) . contains ( totpTwoFaProviderConfig , smsTwoFaProviderConfig ) ;
@ -113,7 +116,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
public void testSaveTwoFaSettings_validationError ( ) throws Exception {
public void testSaveTwoFaSettings_validationError ( ) throws Exception {
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
TwoFactorAuth Settings twoFaSettings = new TwoFactorAuth Settings ( ) ;
Platform TwoFaSettings twoFaSettings = new Platform TwoFaSettings( ) ;
twoFaSettings . setProviders ( Collections . emptyList ( ) ) ;
twoFaSettings . setProviders ( Collections . emptyList ( ) ) ;
twoFaSettings . setVerificationCodeSendRateLimit ( "ab:aba" ) ;
twoFaSettings . setVerificationCodeSendRateLimit ( "ab:aba" ) ;
twoFaSettings . setVerificationCodeCheckRateLimit ( "0:12" ) ;
twoFaSettings . setVerificationCodeCheckRateLimit ( "0:12" ) ;
@ -146,19 +149,19 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
@Test
@Test
public void testGetTwoFaSettings_useSysadminSettingsAsDefault ( ) throws Exception {
public void testGetTwoFaSettings_useSysadminSettingsAsDefault ( ) throws Exception {
loginSysAdmin ( ) ;
loginSysAdmin ( ) ;
TwoFactorAuth Settings sysadminTwoFaSettings = new TwoFactorAuth Settings ( ) ;
Platform TwoFaSettings sysadminTwoFaSettings = new Platform TwoFaSettings( ) ;
TotpTwoFactorAuth ProviderConfig totpTwoFaProviderConfig = new TotpTwoFactorAuth ProviderConfig ( ) ;
TotpTwoFaProviderConfig totpTwoFaProviderConfig = new TotpTwoFaProviderConfig ( ) ;
totpTwoFaProviderConfig . setIssuerName ( "tb" ) ;
totpTwoFaProviderConfig . setIssuerName ( "tb" ) ;
sysadminTwoFaSettings . setProviders ( Collections . singletonList ( totpTwoFaProviderConfig ) ) ;
sysadminTwoFaSettings . setProviders ( Collections . singletonList ( totpTwoFaProviderConfig ) ) ;
sysadminTwoFaSettings . setMaxVerificationFailuresBeforeUserLockout ( 25 ) ;
sysadminTwoFaSettings . setMaxVerificationFailuresBeforeUserLockout ( 25 ) ;
doPost ( "/api/2fa/settings" , sysadminTwoFaSettings ) . andExpect ( status ( ) . isOk ( ) ) ;
doPost ( "/api/2fa/settings" , sysadminTwoFaSettings ) . andExpect ( status ( ) . isOk ( ) ) ;
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
TwoFactorAuth Settings tenantTwoFaSettings = new TwoFactorAuth Settings ( ) ;
Platform TwoFaSettings tenantTwoFaSettings = new Platform TwoFaSettings( ) ;
tenantTwoFaSettings . setUseSystemTwoFactorAuthSettings ( true ) ;
tenantTwoFaSettings . setUseSystemTwoFactorAuthSettings ( true ) ;
tenantTwoFaSettings . setProviders ( Collections . emptyList ( ) ) ;
tenantTwoFaSettings . setProviders ( Collections . emptyList ( ) ) ;
doPost ( "/api/2fa/settings" , tenantTwoFaSettings ) . andExpect ( status ( ) . isOk ( ) ) ;
doPost ( "/api/2fa/settings" , tenantTwoFaSettings ) . andExpect ( status ( ) . isOk ( ) ) ;
TwoFactorAuth Settings twoFaSettings = readResponse ( doGet ( "/api/2fa/settings" ) . andExpect ( status ( ) . isOk ( ) ) , TwoFactorAuth Settings . class ) ;
Platform TwoFaSettings twoFaSettings = readResponse ( doGet ( "/api/2fa/settings" ) . andExpect ( status ( ) . isOk ( ) ) , Platform TwoFaSettings. class ) ;
assertThat ( twoFaSettings ) . isEqualTo ( tenantTwoFaSettings ) ;
assertThat ( twoFaSettings ) . isEqualTo ( tenantTwoFaSettings ) ;
doPost ( "/api/2fa/account/config/generate?providerType=TOTP" )
doPost ( "/api/2fa/account/config/generate?providerType=TOTP" )
@ -168,7 +171,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
tenantTwoFaSettings . setProviders ( Collections . emptyList ( ) ) ;
tenantTwoFaSettings . setProviders ( Collections . emptyList ( ) ) ;
tenantTwoFaSettings . setMaxVerificationFailuresBeforeUserLockout ( 10 ) ;
tenantTwoFaSettings . setMaxVerificationFailuresBeforeUserLockout ( 10 ) ;
doPost ( "/api/2fa/settings" , tenantTwoFaSettings ) . andExpect ( status ( ) . isOk ( ) ) ;
doPost ( "/api/2fa/settings" , tenantTwoFaSettings ) . andExpect ( status ( ) . isOk ( ) ) ;
twoFaSettings = readResponse ( doGet ( "/api/2fa/settings" ) . andExpect ( status ( ) . isOk ( ) ) , TwoFactorAuth Settings . class ) ;
twoFaSettings = readResponse ( doGet ( "/api/2fa/settings" ) . andExpect ( status ( ) . isOk ( ) ) , Platform TwoFaSettings. class ) ;
assertThat ( twoFaSettings ) . isEqualTo ( tenantTwoFaSettings ) ;
assertThat ( twoFaSettings ) . isEqualTo ( tenantTwoFaSettings ) ;
assertThat ( getErrorMessage ( doPost ( "/api/2fa/account/config/generate?providerType=TOTP" )
assertThat ( getErrorMessage ( doPost ( "/api/2fa/account/config/generate?providerType=TOTP" )
@ -192,13 +195,13 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
. andExpect ( status ( ) . isOk ( ) ) ;
. andExpect ( status ( ) . isOk ( ) ) ;
loginSysAdmin ( ) ;
loginSysAdmin ( ) ;
twoFaSettings = readResponse ( doGet ( "/api/2fa/settings" ) . andExpect ( status ( ) . isOk ( ) ) , TwoFactorAuth Settings . class ) ;
twoFaSettings = readResponse ( doGet ( "/api/2fa/settings" ) . andExpect ( status ( ) . isOk ( ) ) , Platform TwoFaSettings. class ) ;
assertThat ( twoFaSettings ) . isEqualTo ( sysadminTwoFaSettings ) ;
assertThat ( twoFaSettings ) . isEqualTo ( sysadminTwoFaSettings ) ;
}
}
@Test
@Test
public void testSaveTotpTwoFaProviderConfig_validationError ( ) throws Exception {
public void testSaveTotpTwoFaProviderConfig_validationError ( ) throws Exception {
TotpTwoFactorAuth ProviderConfig invalidTotpTwoFaProviderConfig = new TotpTwoFactorAuth ProviderConfig ( ) ;
TotpTwoFaProviderConfig invalidTotpTwoFaProviderConfig = new TotpTwoFaProviderConfig ( ) ;
invalidTotpTwoFaProviderConfig . setIssuerName ( " " ) ;
invalidTotpTwoFaProviderConfig . setIssuerName ( " " ) ;
String errorResponse = saveTwoFaSettingsAndGetError ( invalidTotpTwoFaProviderConfig ) ;
String errorResponse = saveTwoFaSettingsAndGetError ( invalidTotpTwoFaProviderConfig ) ;
@ -207,7 +210,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
@Test
@Test
public void testSaveSmsTwoFaProviderConfig_validationError ( ) throws Exception {
public void testSaveSmsTwoFaProviderConfig_validationError ( ) throws Exception {
SmsTwoFactorAuth ProviderConfig invalidSmsTwoFaProviderConfig = new SmsTwoFactorAuth ProviderConfig ( ) ;
SmsTwoFaProviderConfig invalidSmsTwoFaProviderConfig = new SmsTwoFaProviderConfig ( ) ;
invalidSmsTwoFaProviderConfig . setSmsVerificationMessageTemplate ( "does not contain verification code" ) ;
invalidSmsTwoFaProviderConfig . setSmsVerificationMessageTemplate ( "does not contain verification code" ) ;
invalidSmsTwoFaProviderConfig . setVerificationCodeLifetime ( 60 ) ;
invalidSmsTwoFaProviderConfig . setVerificationCodeLifetime ( 60 ) ;
@ -221,8 +224,8 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
assertThat ( errorResponse ) . containsIgnoringCase ( "verification code lifetime is required" ) ;
assertThat ( errorResponse ) . containsIgnoringCase ( "verification code lifetime is required" ) ;
}
}
private String saveTwoFaSettingsAndGetError ( TwoFactorAuth ProviderConfig invalidTwoFaProviderConfig ) throws Exception {
private String saveTwoFaSettingsAndGetError ( TwoFaProviderConfig invalidTwoFaProviderConfig ) throws Exception {
TwoFactorAuth Settings twoFaSettings = new TwoFactorAuth Settings ( ) ;
Platform TwoFaSettings twoFaSettings = new Platform TwoFaSettings( ) ;
twoFaSettings . setProviders ( Collections . singletonList ( invalidTwoFaProviderConfig ) ) ;
twoFaSettings . setProviders ( Collections . singletonList ( invalidTwoFaProviderConfig ) ) ;
return getErrorMessage ( doPost ( "/api/2fa/settings" , twoFaSettings )
return getErrorMessage ( doPost ( "/api/2fa/settings" , twoFaSettings )
@ -235,12 +238,12 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
TwoFactorAuth ProviderType notConfiguredProviderType = TwoFactorAuth ProviderType . TOTP ;
TwoFaProviderType notConfiguredProviderType = TwoFaProviderType . TOTP ;
String errorMessage = getErrorMessage ( doPost ( "/api/2fa/account/config/generate?providerType=" + notConfiguredProviderType )
String errorMessage = getErrorMessage ( doPost ( "/api/2fa/account/config/generate?providerType=" + notConfiguredProviderType )
. andExpect ( status ( ) . isBadRequest ( ) ) ) ;
. andExpect ( status ( ) . isBadRequest ( ) ) ) ;
assertThat ( errorMessage ) . containsIgnoringCase ( "provider is not configured" ) ;
assertThat ( errorMessage ) . containsIgnoringCase ( "provider is not configured" ) ;
TotpTwoFactorAuth AccountConfig notConfiguredProviderAccountConfig = new TotpTwoFactorAuth AccountConfig ( ) ;
TotpTwoFaAccountConfig notConfiguredProviderAccountConfig = new TotpTwoFaAccountConfig ( ) ;
notConfiguredProviderAccountConfig . setAuthUrl ( "otpauth://totp/aba:aba?issuer=aba&secret=ABA" ) ;
notConfiguredProviderAccountConfig . setAuthUrl ( "otpauth://totp/aba:aba?issuer=aba&secret=ABA" ) ;
errorMessage = getErrorMessage ( doPost ( "/api/2fa/account/config/submit" , notConfiguredProviderAccountConfig ) ) ;
errorMessage = getErrorMessage ( doPost ( "/api/2fa/account/config/submit" , notConfiguredProviderAccountConfig ) ) ;
assertThat ( errorMessage ) . containsIgnoringCase ( "provider is not configured" ) ;
assertThat ( errorMessage ) . containsIgnoringCase ( "provider is not configured" ) ;
@ -248,7 +251,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
@Test
@Test
public void testGenerateTotpTwoFaAccountConfig ( ) throws Exception {
public void testGenerateTotpTwoFaAccountConfig ( ) throws Exception {
TotpTwoFactorAuth ProviderConfig totpTwoFaProviderConfig = configureTotpTwoFaProvider ( ) ;
TotpTwoFaProviderConfig totpTwoFaProviderConfig = configureTotpTwoFaProvider ( ) ;
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
@ -258,11 +261,11 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
@Test
@Test
public void testSubmitTotpTwoFaAccountConfig ( ) throws Exception {
public void testSubmitTotpTwoFaAccountConfig ( ) throws Exception {
TotpTwoFactorAuth ProviderConfig totpTwoFaProviderConfig = configureTotpTwoFaProvider ( ) ;
TotpTwoFaProviderConfig totpTwoFaProviderConfig = configureTotpTwoFaProvider ( ) ;
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
TotpTwoFactorAuth AccountConfig generatedTotpTwoFaAccountConfig = generateTotpTwoFaAccountConfig ( totpTwoFaProviderConfig ) ;
TotpTwoFaAccountConfig generatedTotpTwoFaAccountConfig = generateTotpTwoFaAccountConfig ( totpTwoFaProviderConfig ) ;
doPost ( "/api/2fa/account/config/submit" , generatedTotpTwoFaAccountConfig ) . andExpect ( status ( ) . isOk ( ) ) ;
doPost ( "/api/2fa/account/config/submit" , generatedTotpTwoFaAccountConfig ) . andExpect ( status ( ) . isOk ( ) ) ;
verify ( totpTwoFactorAuthProvider ) . prepareVerificationCode ( argThat ( user - > user . getEmail ( ) . equals ( TENANT_ADMIN_EMAIL ) ) ,
verify ( totpTwoFactorAuthProvider ) . prepareVerificationCode ( argThat ( user - > user . getEmail ( ) . equals ( TENANT_ADMIN_EMAIL ) ) ,
eq ( totpTwoFaProviderConfig ) , eq ( generatedTotpTwoFaAccountConfig ) ) ;
eq ( totpTwoFaProviderConfig ) , eq ( generatedTotpTwoFaAccountConfig ) ) ;
@ -274,7 +277,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
TotpTwoFactorAuth AccountConfig totpTwoFaAccountConfig = new TotpTwoFactorAuth AccountConfig ( ) ;
TotpTwoFaAccountConfig totpTwoFaAccountConfig = new TotpTwoFaAccountConfig ( ) ;
totpTwoFaAccountConfig . setAuthUrl ( null ) ;
totpTwoFaAccountConfig . setAuthUrl ( null ) ;
String errorMessage = getErrorMessage ( doPost ( "/api/2fa/account/config/submit" , totpTwoFaAccountConfig )
String errorMessage = getErrorMessage ( doPost ( "/api/2fa/account/config/submit" , totpTwoFaAccountConfig )
@ -293,11 +296,11 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
@Test
@Test
public void testVerifyAndSaveTotpTwoFaAccountConfig ( ) throws Exception {
public void testVerifyAndSaveTotpTwoFaAccountConfig ( ) throws Exception {
TotpTwoFactorAuth ProviderConfig totpTwoFaProviderConfig = configureTotpTwoFaProvider ( ) ;
TotpTwoFaProviderConfig totpTwoFaProviderConfig = configureTotpTwoFaProvider ( ) ;
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
TotpTwoFactorAuth AccountConfig generatedTotpTwoFaAccountConfig = generateTotpTwoFaAccountConfig ( totpTwoFaProviderConfig ) ;
TotpTwoFaAccountConfig generatedTotpTwoFaAccountConfig = generateTotpTwoFaAccountConfig ( totpTwoFaProviderConfig ) ;
String secret = UriComponentsBuilder . fromUriString ( generatedTotpTwoFaAccountConfig . getAuthUrl ( ) ) . build ( )
String secret = UriComponentsBuilder . fromUriString ( generatedTotpTwoFaAccountConfig . getAuthUrl ( ) ) . build ( )
. getQueryParams ( ) . getFirst ( "secret" ) ;
. getQueryParams ( ) . getFirst ( "secret" ) ;
@ -306,17 +309,17 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
doPost ( "/api/2fa/account/config?verificationCode=" + correctVerificationCode , generatedTotpTwoFaAccountConfig )
doPost ( "/api/2fa/account/config?verificationCode=" + correctVerificationCode , generatedTotpTwoFaAccountConfig )
. andExpect ( status ( ) . isOk ( ) ) ;
. andExpect ( status ( ) . isOk ( ) ) ;
TwoFactorAuth AccountConfig twoFaAccountConfig = readResponse ( doGet ( "/api/2fa/account/config" ) . andExpect ( status ( ) . isOk ( ) ) , TwoFactorAuth AccountConfig . class ) ;
TwoFaAccountConfig twoFaAccountConfig = readResponse ( doGet ( "/api/2fa/account/config" ) . andExpect ( status ( ) . isOk ( ) ) , TwoFaAccountConfig . class ) ;
assertThat ( twoFaAccountConfig ) . isEqualTo ( generatedTotpTwoFaAccountConfig ) ;
assertThat ( twoFaAccountConfig ) . isEqualTo ( generatedTotpTwoFaAccountConfig ) ;
}
}
@Test
@Test
public void testVerifyAndSaveTotpTwoFaAccountConfig_incorrectVerificationCode ( ) throws Exception {
public void testVerifyAndSaveTotpTwoFaAccountConfig_incorrectVerificationCode ( ) throws Exception {
TotpTwoFactorAuth ProviderConfig totpTwoFaProviderConfig = configureTotpTwoFaProvider ( ) ;
TotpTwoFaProviderConfig totpTwoFaProviderConfig = configureTotpTwoFaProvider ( ) ;
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
TotpTwoFactorAuth AccountConfig generatedTotpTwoFaAccountConfig = generateTotpTwoFaAccountConfig ( totpTwoFaProviderConfig ) ;
TotpTwoFaAccountConfig generatedTotpTwoFaAccountConfig = generateTotpTwoFaAccountConfig ( totpTwoFaProviderConfig ) ;
String incorrectVerificationCode = "100000" ;
String incorrectVerificationCode = "100000" ;
String errorMessage = getErrorMessage ( doPost ( "/api/2fa/account/config?verificationCode=" + incorrectVerificationCode , generatedTotpTwoFaAccountConfig )
String errorMessage = getErrorMessage ( doPost ( "/api/2fa/account/config?verificationCode=" + incorrectVerificationCode , generatedTotpTwoFaAccountConfig )
@ -325,12 +328,12 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
assertThat ( errorMessage ) . containsIgnoringCase ( "verification code is incorrect" ) ;
assertThat ( errorMessage ) . containsIgnoringCase ( "verification code is incorrect" ) ;
}
}
private TotpTwoFactorAuth AccountConfig generateTotpTwoFaAccountConfig ( TotpTwoFactorAuth ProviderConfig totpTwoFaProviderConfig ) throws Exception {
private TotpTwoFaAccountConfig generateTotpTwoFaAccountConfig ( TotpTwoFaProviderConfig totpTwoFaProviderConfig ) throws Exception {
TwoFactorAuth AccountConfig generatedTwoFaAccountConfig = readResponse ( doPost ( "/api/2fa/account/config/generate?providerType=TOTP" )
TwoFaAccountConfig generatedTwoFaAccountConfig = readResponse ( doPost ( "/api/2fa/account/config/generate?providerType=TOTP" )
. andExpect ( status ( ) . isOk ( ) ) , TwoFactorAuth AccountConfig . class ) ;
. andExpect ( status ( ) . isOk ( ) ) , TwoFaAccountConfig . class ) ;
assertThat ( generatedTwoFaAccountConfig ) . isInstanceOf ( TotpTwoFactorAuth AccountConfig . class ) ;
assertThat ( generatedTwoFaAccountConfig ) . isInstanceOf ( TotpTwoFaAccountConfig . class ) ;
assertThat ( ( ( TotpTwoFactorAuth AccountConfig ) generatedTwoFaAccountConfig ) ) . satisfies ( accountConfig - > {
assertThat ( ( ( TotpTwoFaAccountConfig ) generatedTwoFaAccountConfig ) ) . satisfies ( accountConfig - > {
UriComponents otpAuthUrl = UriComponentsBuilder . fromUriString ( accountConfig . getAuthUrl ( ) ) . build ( ) ;
UriComponents otpAuthUrl = UriComponentsBuilder . fromUriString ( accountConfig . getAuthUrl ( ) ) . build ( ) ;
assertThat ( otpAuthUrl . getScheme ( ) ) . isEqualTo ( "otpauth" ) ;
assertThat ( otpAuthUrl . getScheme ( ) ) . isEqualTo ( "otpauth" ) ;
assertThat ( otpAuthUrl . getHost ( ) ) . isEqualTo ( "totp" ) ;
assertThat ( otpAuthUrl . getHost ( ) ) . isEqualTo ( "totp" ) ;
@ -340,14 +343,14 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
assertDoesNotThrow ( ( ) - > Base32 . decode ( secretKey ) ) ;
assertDoesNotThrow ( ( ) - > Base32 . decode ( secretKey ) ) ;
} ) ;
} ) ;
} ) ;
} ) ;
return ( TotpTwoFactorAuth AccountConfig ) generatedTwoFaAccountConfig ;
return ( TotpTwoFaAccountConfig ) generatedTwoFaAccountConfig ;
}
}
@Test
@Test
public void testGetTwoFaAccountConfig_whenProviderNotConfigured ( ) throws Exception {
public void testGetTwoFaAccountConfig_whenProviderNotConfigured ( ) throws Exception {
testVerifyAndSaveTotpTwoFaAccountConfig ( ) ;
testVerifyAndSaveTotpTwoFaAccountConfig ( ) ;
assertThat ( readResponse ( doGet ( "/api/2fa/account/config" ) . andExpect ( status ( ) . isOk ( ) ) ,
assertThat ( readResponse ( doGet ( "/api/2fa/account/config" ) . andExpect ( status ( ) . isOk ( ) ) ,
TotpTwoFactorAuth AccountConfig . class ) ) . isNotNull ( ) ;
TotpTwoFaAccountConfig . class ) ) . isNotNull ( ) ;
loginSysAdmin ( ) ;
loginSysAdmin ( ) ;
@ -371,13 +374,13 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
SmsTwoFactorAuth AccountConfig smsTwoFaAccountConfig = new SmsTwoFactorAuth AccountConfig ( ) ;
SmsTwoFaAccountConfig smsTwoFaAccountConfig = new SmsTwoFaAccountConfig ( ) ;
smsTwoFaAccountConfig . setPhoneNumber ( "+38054159785" ) ;
smsTwoFaAccountConfig . setPhoneNumber ( "+38054159785" ) ;
doPost ( "/api/2fa/account/config/submit" , smsTwoFaAccountConfig ) . andExpect ( status ( ) . isOk ( ) ) ;
doPost ( "/api/2fa/account/config/submit" , smsTwoFaAccountConfig ) . andExpect ( status ( ) . isOk ( ) ) ;
String verificationCode = cacheManager . getCache ( CacheConstants . TWO_FA_VERIFICATION_CODES_CACHE )
String verificationCode = cacheManager . getCache ( CacheConstants . TWO_FA_VERIFICATION_CODES_CACHE )
. get ( tenantAdminUserId , OtpBasedTwoFactorAuth Provider . Otp . class ) . getValue ( ) ;
. get ( tenantAdminUserId , OtpBasedTwoFaProvider . Otp . class ) . getValue ( ) ;
verify ( smsService ) . sendSms ( eq ( tenantId ) , any ( ) , argThat ( phoneNumbers - > {
verify ( smsService ) . sendSms ( eq ( tenantId ) , any ( ) , argThat ( phoneNumbers - > {
return phoneNumbers [ 0 ] . equals ( smsTwoFaAccountConfig . getPhoneNumber ( ) ) ;
return phoneNumbers [ 0 ] . equals ( smsTwoFaAccountConfig . getPhoneNumber ( ) ) ;
@ -388,7 +391,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
public void testSubmitSmsTwoFaAccountConfig_validationError ( ) throws Exception {
public void testSubmitSmsTwoFaAccountConfig_validationError ( ) throws Exception {
configureSmsTwoFaProvider ( "${verificationCode}" ) ;
configureSmsTwoFaProvider ( "${verificationCode}" ) ;
SmsTwoFactorAuth AccountConfig smsTwoFaAccountConfig = new SmsTwoFactorAuth AccountConfig ( ) ;
SmsTwoFaAccountConfig smsTwoFaAccountConfig = new SmsTwoFaAccountConfig ( ) ;
String blankPhoneNumber = "" ;
String blankPhoneNumber = "" ;
smsTwoFaAccountConfig . setPhoneNumber ( blankPhoneNumber ) ;
smsTwoFaAccountConfig . setPhoneNumber ( blankPhoneNumber ) ;
@ -410,7 +413,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
SmsTwoFactorAuth AccountConfig smsTwoFaAccountConfig = new SmsTwoFactorAuth AccountConfig ( ) ;
SmsTwoFaAccountConfig smsTwoFaAccountConfig = new SmsTwoFaAccountConfig ( ) ;
smsTwoFaAccountConfig . setPhoneNumber ( "+38051889445" ) ;
smsTwoFaAccountConfig . setPhoneNumber ( "+38051889445" ) ;
ArgumentCaptor < String > verificationCodeCaptor = ArgumentCaptor . forClass ( String . class ) ;
ArgumentCaptor < String > verificationCodeCaptor = ArgumentCaptor . forClass ( String . class ) ;
@ -424,7 +427,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
doPost ( "/api/2fa/account/config?verificationCode=" + correctVerificationCode , smsTwoFaAccountConfig )
doPost ( "/api/2fa/account/config?verificationCode=" + correctVerificationCode , smsTwoFaAccountConfig )
. andExpect ( status ( ) . isOk ( ) ) ;
. andExpect ( status ( ) . isOk ( ) ) ;
TwoFactorAuth AccountConfig accountConfig = readResponse ( doGet ( "/api/2fa/account/config" ) . andExpect ( status ( ) . isOk ( ) ) , TwoFactorAuth AccountConfig . class ) ;
TwoFaAccountConfig accountConfig = readResponse ( doGet ( "/api/2fa/account/config" ) . andExpect ( status ( ) . isOk ( ) ) , TwoFaAccountConfig . class ) ;
assertThat ( accountConfig ) . isEqualTo ( smsTwoFaAccountConfig ) ;
assertThat ( accountConfig ) . isEqualTo ( smsTwoFaAccountConfig ) ;
}
}
@ -434,7 +437,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
SmsTwoFactorAuth AccountConfig smsTwoFaAccountConfig = new SmsTwoFactorAuth AccountConfig ( ) ;
SmsTwoFaAccountConfig smsTwoFaAccountConfig = new SmsTwoFaAccountConfig ( ) ;
smsTwoFaAccountConfig . setPhoneNumber ( "+38051889445" ) ;
smsTwoFaAccountConfig . setPhoneNumber ( "+38051889445" ) ;
String errorMessage = getErrorMessage ( doPost ( "/api/2fa/account/config?verificationCode=100000" , smsTwoFaAccountConfig )
String errorMessage = getErrorMessage ( doPost ( "/api/2fa/account/config?verificationCode=100000" , smsTwoFaAccountConfig )
@ -447,7 +450,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
configureSmsTwoFaProvider ( "${verificationCode}" ) ;
configureSmsTwoFaProvider ( "${verificationCode}" ) ;
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
SmsTwoFactorAuth AccountConfig initialSmsTwoFaAccountConfig = new SmsTwoFactorAuth AccountConfig ( ) ;
SmsTwoFaAccountConfig initialSmsTwoFaAccountConfig = new SmsTwoFaAccountConfig ( ) ;
initialSmsTwoFaAccountConfig . setPhoneNumber ( "+38051889445" ) ;
initialSmsTwoFaAccountConfig . setPhoneNumber ( "+38051889445" ) ;
ArgumentCaptor < String > verificationCodeCaptor = ArgumentCaptor . forClass ( String . class ) ;
ArgumentCaptor < String > verificationCodeCaptor = ArgumentCaptor . forClass ( String . class ) ;
@ -459,7 +462,7 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
String correctVerificationCode = verificationCodeCaptor . getValue ( ) ;
String correctVerificationCode = verificationCodeCaptor . getValue ( ) ;
SmsTwoFactorAuth AccountConfig anotherSmsTwoFaAccountConfig = new SmsTwoFactorAuth AccountConfig ( ) ;
SmsTwoFaAccountConfig anotherSmsTwoFaAccountConfig = new SmsTwoFaAccountConfig ( ) ;
anotherSmsTwoFaAccountConfig . setPhoneNumber ( "+38111111111" ) ;
anotherSmsTwoFaAccountConfig . setPhoneNumber ( "+38111111111" ) ;
String errorMessage = getErrorMessage ( doPost ( "/api/2fa/account/config?verificationCode=" + correctVerificationCode , anotherSmsTwoFaAccountConfig )
String errorMessage = getErrorMessage ( doPost ( "/api/2fa/account/config?verificationCode=" + correctVerificationCode , anotherSmsTwoFaAccountConfig )
. andExpect ( status ( ) . isBadRequest ( ) ) ) ;
. andExpect ( status ( ) . isBadRequest ( ) ) ) ;
@ -467,20 +470,20 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
doPost ( "/api/2fa/account/config?verificationCode=" + correctVerificationCode , initialSmsTwoFaAccountConfig )
doPost ( "/api/2fa/account/config?verificationCode=" + correctVerificationCode , initialSmsTwoFaAccountConfig )
. andExpect ( status ( ) . isOk ( ) ) ;
. andExpect ( status ( ) . isOk ( ) ) ;
TwoFactorAuth AccountConfig accountConfig = readResponse ( doGet ( "/api/2fa/account/config" ) . andExpect ( status ( ) . isOk ( ) ) , TwoFactorAuth AccountConfig . class ) ;
TwoFaAccountConfig accountConfig = readResponse ( doGet ( "/api/2fa/account/config" ) . andExpect ( status ( ) . isOk ( ) ) , TwoFaAccountConfig . class ) ;
assertThat ( accountConfig ) . isEqualTo ( initialSmsTwoFaAccountConfig ) ;
assertThat ( accountConfig ) . isEqualTo ( initialSmsTwoFaAccountConfig ) ;
}
}
private TotpTwoFactorAuth ProviderConfig configureTotpTwoFaProvider ( ) throws Exception {
private TotpTwoFaProviderConfig configureTotpTwoFaProvider ( ) throws Exception {
TotpTwoFactorAuth ProviderConfig totpTwoFaProviderConfig = new TotpTwoFactorAuth ProviderConfig ( ) ;
TotpTwoFaProviderConfig totpTwoFaProviderConfig = new TotpTwoFaProviderConfig ( ) ;
totpTwoFaProviderConfig . setIssuerName ( "tb" ) ;
totpTwoFaProviderConfig . setIssuerName ( "tb" ) ;
saveProvidersConfigs ( totpTwoFaProviderConfig ) ;
saveProvidersConfigs ( totpTwoFaProviderConfig ) ;
return totpTwoFaProviderConfig ;
return totpTwoFaProviderConfig ;
}
}
private SmsTwoFactorAuth ProviderConfig configureSmsTwoFaProvider ( String verificationMessageTemplate ) throws Exception {
private SmsTwoFaProviderConfig configureSmsTwoFaProvider ( String verificationMessageTemplate ) throws Exception {
SmsTwoFactorAuth ProviderConfig smsTwoFaProviderConfig = new SmsTwoFactorAuth ProviderConfig ( ) ;
SmsTwoFaProviderConfig smsTwoFaProviderConfig = new SmsTwoFaProviderConfig ( ) ;
smsTwoFaProviderConfig . setSmsVerificationMessageTemplate ( verificationMessageTemplate ) ;
smsTwoFaProviderConfig . setSmsVerificationMessageTemplate ( verificationMessageTemplate ) ;
smsTwoFaProviderConfig . setVerificationCodeLifetime ( 60 ) ;
smsTwoFaProviderConfig . setVerificationCodeLifetime ( 60 ) ;
@ -488,8 +491,8 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
return smsTwoFaProviderConfig ;
return smsTwoFaProviderConfig ;
}
}
private void saveProvidersConfigs ( TwoFactorAuth ProviderConfig . . . providerConfigs ) throws Exception {
private void saveProvidersConfigs ( TwoFaProviderConfig . . . providerConfigs ) throws Exception {
TwoFactorAuth Settings twoFaSettings = new TwoFactorAuth Settings ( ) ;
Platform TwoFaSettings twoFaSettings = new Platform TwoFaSettings( ) ;
twoFaSettings . setProviders ( Arrays . stream ( providerConfigs ) . collect ( Collectors . toList ( ) ) ) ;
twoFaSettings . setProviders ( Arrays . stream ( providerConfigs ) . collect ( Collectors . toList ( ) ) ) ;
doPost ( "/api/2fa/settings" , twoFaSettings ) . andExpect ( status ( ) . isOk ( ) ) ;
doPost ( "/api/2fa/settings" , twoFaSettings ) . andExpect ( status ( ) . isOk ( ) ) ;
@ -498,24 +501,24 @@ public abstract class TwoFactorAuthConfigTest extends AbstractControllerTest {
@Test
@Test
public void testIsTwoFaEnabled ( ) throws Exception {
public void testIsTwoFaEnabled ( ) throws Exception {
configureSmsTwoFaProvider ( "${verificationCode}" ) ;
configureSmsTwoFaProvider ( "${verificationCode}" ) ;
SmsTwoFactorAuth AccountConfig accountConfig = new SmsTwoFactorAuth AccountConfig ( ) ;
SmsTwoFaAccountConfig accountConfig = new SmsTwoFaAccountConfig ( ) ;
accountConfig . setPhoneNumber ( "+38050505050" ) ;
accountConfig . setPhoneNumber ( "+38050505050" ) ;
twoFactorAuth ConfigManager . saveTwoFaAccountConfig ( tenantId , tenantAdminUserId , accountConfig ) ;
twoFaConfigManager . saveTwoFaAccountConfig ( tenantId , tenantAdminUserId , accountConfig ) ;
assertThat ( twoFactorAuthConfigManager . isTwoFaEnabled ( tenantId , tenantAdminUserId ) ) . isTrue ( ) ;
assertThat ( twoFactorAuthService . isTwoFaEnabled ( tenantId , tenantAdminUserId ) ) . isTrue ( ) ;
}
}
@Test
@Test
public void testDeleteTwoFaAccountConfig ( ) throws Exception {
public void testDeleteTwoFaAccountConfig ( ) throws Exception {
configureSmsTwoFaProvider ( "${verificationCode}" ) ;
configureSmsTwoFaProvider ( "${verificationCode}" ) ;
SmsTwoFactorAuth AccountConfig accountConfig = new SmsTwoFactorAuth AccountConfig ( ) ;
SmsTwoFaAccountConfig accountConfig = new SmsTwoFaAccountConfig ( ) ;
accountConfig . setPhoneNumber ( "+38050505050" ) ;
accountConfig . setPhoneNumber ( "+38050505050" ) ;
loginTenantAdmin ( ) ;
loginTenantAdmin ( ) ;
twoFactorAuth ConfigManager . saveTwoFaAccountConfig ( tenantId , tenantAdminUserId , accountConfig ) ;
twoFaConfigManager . saveTwoFaAccountConfig ( tenantId , tenantAdminUserId , accountConfig ) ;
TwoFactorAuth AccountConfig savedAccountConfig = readResponse ( doGet ( "/api/2fa/account/config" ) . andExpect ( status ( ) . isOk ( ) ) , TwoFactorAuth AccountConfig . class ) ;
TwoFaAccountConfig savedAccountConfig = readResponse ( doGet ( "/api/2fa/account/config" ) . andExpect ( status ( ) . isOk ( ) ) , TwoFaAccountConfig . class ) ;
assertThat ( savedAccountConfig ) . isEqualTo ( accountConfig ) ;
assertThat ( savedAccountConfig ) . isEqualTo ( accountConfig ) ;
doDelete ( "/api/2fa/account/config" ) . andExpect ( status ( ) . isOk ( ) ) ;
doDelete ( "/api/2fa/account/config" ) . andExpect ( status ( ) . isOk ( ) ) ;