use of eu.bcvsolutions.idm.core.security.api.exception.TwoFactorAuthenticationRequiredException in project CzechIdMng by bcvsolutions.
the class DefaultTwoFactorAuthenticationManagerIntegrationTest method testAuthenticateMustChangePassword.
@Test(expected = MustChangePasswordException.class)
public void testAuthenticateMustChangePassword() {
// password is needed
IdmIdentityDto identity = getHelper().createIdentity();
IdmPasswordDto password = passwordService.findOneByIdentity(identity.getId());
password.setMustChange(true);
passwordService.save(password);
//
TwoFactorRegistrationResponseDto initResponse = manager.init(identity.getId(), TwoFactorAuthenticationType.NOTIFICATION);
Assert.assertNotNull(initResponse);
Assert.assertNotNull(initResponse.getVerificationSecret());
Assert.assertEquals(identity.getUsername(), initResponse.getUsername());
Assert.assertNull(initResponse.getQrcode());
//
// confirm
TwoFactorRegistrationConfirmDto confirm = new TwoFactorRegistrationConfirmDto();
confirm.setVerificationSecret(new GuardedString(initResponse.getVerificationSecret()));
confirm.setVerificationCode(manager.generateCode(new GuardedString(initResponse.getVerificationSecret())));
confirm.setTwoFactorAuthenticationType(TwoFactorAuthenticationType.NOTIFICATION);
Assert.assertTrue(manager.confirm(identity.getId(), confirm));
Assert.assertEquals(initResponse.getVerificationSecret(), getHelper().getPassword(identity).getVerificationSecret());
//
LoginDto loginDto = new LoginDto();
loginDto.setUsername(identity.getUsername());
loginDto.setPassword(identity.getPassword());
// creadentials are valid
Assert.assertTrue(authenticationManager.validate(loginDto));
// but two factor authentication is required
String token = null;
try {
authenticationManager.authenticate(loginDto);
} catch (TwoFactorAuthenticationRequiredException ex) {
token = ex.getToken();
}
Assert.assertNotNull(token);
//
loginDto.setToken(token);
loginDto.setPassword(manager.generateCode(identity.getId()));
manager.authenticate(loginDto);
}
use of eu.bcvsolutions.idm.core.security.api.exception.TwoFactorAuthenticationRequiredException in project CzechIdMng by bcvsolutions.
the class DefaultAuthenticationManager method authenticate.
@Override
public LoginDto authenticate(LoginDto loginDto) {
List<LoginDto> resultsList = new LinkedList<>();
RuntimeException firstFailure = null;
String logAction = siemLogger.buildAction(SiemLoggerManager.LOGIN_LEVEL_KEY, SiemLoggerManager.LOGIN_SUBLEVEL_KEY);
IdmIdentityDto identity = identityService.getByUsername(loginDto.getUsername());
if (identity == null) {
// just for logging purpose
identity = new IdmIdentityDto();
identity.setUsername(loginDto.getUsername());
}
// check if user can log in and hasn't administrator permission
try {
IdmPasswordDto passwordDto = passwordService.findOrCreateByIdentity(loginDto.getUsername());
if (passwordDto == null) {
throw new ResultCodeException(CoreResultCode.AUTH_FAILED, "Invalid login or password.");
}
if (passwordDto.getBlockLoginDate() != null && passwordDto.getBlockLoginDate().isAfter(ZonedDateTime.now())) {
LOG.info("Identity {} has blocked login to IdM.", loginDto.getUsername());
IdmIdentityDto identityDto = DtoUtils.getEmbedded(passwordDto, IdmPassword_.identity);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(configurationService.getDateTimeSecondsFormat());
ZonedDateTime blockLoginDate = passwordDto.getBlockLoginDate();
String dateAsString = blockLoginDate.format(formatter);
// Block login date can be set manually by password metadata,
// so block login date can be more than int amount.
long blockMillies = blockLoginDate.toInstant().toEpochMilli();
long nowMillis = ZonedDateTime.now().toInstant().toEpochMilli();
long different = blockMillies - nowMillis;
different = different / 1000;
throw new ResultCodeException(CoreResultCode.AUTH_BLOCKED, ImmutableMap.of("username", identityDto.getUsername(), "date", dateAsString, "seconds", different, "unsuccessfulAttempts", passwordDto.getUnsuccessfulAttempts()));
}
//
for (Authenticator authenticator : getEnabledAuthenticators()) {
LOG.debug("AuthenticationManager call authenticate by [{}].", authenticator.getName());
try {
LoginDto result = authenticator.authenticate(cloneLoginDto(loginDto));
if (result == null) {
// continue, authenticator is not implemented or etc.
continue;
}
if (authenticator.getExceptedResult() == AuthenticationResponseEnum.SUFFICIENT) {
checkAdditionalAuthenticationRequirements(passwordDto, result);
passwordDto = passwordService.setLastSuccessfulLogin(passwordDto);
siemLogger.log(logAction, SiemLoggerManager.SUCCESS_ACTION_STATUS, identity, null, null, null);
return result;
}
// if otherwise add result too list and continue
resultsList.add(result);
} catch (MustChangePasswordException | TwoFactorAuthenticationRequiredException ex) {
// publish additional authentication requirement
throw ex;
} catch (RuntimeException e) {
// if excepted response is REQUISITE exit immediately with error
if (authenticator.getExceptedResult() == AuthenticationResponseEnum.REQUISITE) {
blockLogin(passwordDto, loginDto);
//
throw e;
}
// if otherwise save first failure into exception
if (firstFailure == null) {
firstFailure = e;
}
}
}
// authenticator is sorted by implement ordered, return first success authenticate authenticator, if don't exist any otherwise throw first failure
if (resultsList.isEmpty()) {
blockLogin(passwordDto, loginDto);
throw firstFailure;
}
//
LoginDto result = resultsList.get(0);
checkAdditionalAuthenticationRequirements(passwordDto, result);
passwordDto = passwordService.setLastSuccessfulLogin(passwordDto);
//
siemLogger.log(logAction, SiemLoggerManager.SUCCESS_ACTION_STATUS, identity, null, null, null);
return result;
} catch (TwoFactorAuthenticationRequiredException tfaEx) {
// skip logging, 2FA is needed, result will be logged there
throw tfaEx;
} catch (Exception e) {
siemLogger.log(logAction, SiemLoggerManager.FAILED_ACTION_STATUS, identity, null, null, e.getMessage());
throw e;
}
}
use of eu.bcvsolutions.idm.core.security.api.exception.TwoFactorAuthenticationRequiredException in project CzechIdMng by bcvsolutions.
the class DefaultJwtAuthenticationService method createJwtAuthenticationAndAuthenticate.
@Override
public LoginDto createJwtAuthenticationAndAuthenticate(LoginDto loginDto, IdmIdentityDto identity, IdmTokenDto preparedToken) {
Assert.notNull(identity, "Identity is required.");
UUID identityId = identity.getId();
Assert.notNull(identityId, "Identity identifier is required.");
// check identity is valid
if (identity.isDisabled()) {
throw new IdentityDisabledException(MessageFormat.format("Check identity can login: The identity [{0}] is disabled.", identity.getUsername()));
}
// two factor authentication is not configured for given identity
if (tokenManager.isNew(preparedToken)) {
if (// public password change page => login is needed, before password is changed
loginDto.isSkipMustChange() || twoFactorAuthenticationManager.getTwoFactorAuthenticationType(identityId) == null) {
preparedToken.setSecretVerified(true);
} else {
// two factor needed
preparedToken.setSecretVerified(false);
}
}
// create token
IdmTokenDto token = jwtTokenMapper.createToken(identity, preparedToken);
// check two factor authentication is required
if (twoFactorAuthenticationManager.requireTwoFactorAuthentication(identityId, token.getId())) {
IdmJwtAuthenticationDto authenticationDto = jwtTokenMapper.toDto(token);
// token is needed in exception => sso login can be used and client doesn't have token
throw new TwoFactorAuthenticationRequiredException(jwtTokenMapper.writeToken(authenticationDto));
}
//
return login(loginDto, token);
}
use of eu.bcvsolutions.idm.core.security.api.exception.TwoFactorAuthenticationRequiredException in project CzechIdMng by bcvsolutions.
the class DefaultTwoFactorAuthenticationManagerIntegrationTest method testAuthenticatePasswordIsDeleted.
@Test(expected = EntityNotFoundException.class)
public void testAuthenticatePasswordIsDeleted() {
// password is needed
IdmIdentityDto identity = getHelper().createIdentity();
IdmPasswordDto password = passwordService.findOneByIdentity(identity.getId());
//
TwoFactorRegistrationResponseDto initResponse = manager.init(identity.getId(), TwoFactorAuthenticationType.NOTIFICATION);
Assert.assertNotNull(initResponse);
Assert.assertNotNull(initResponse.getVerificationSecret());
Assert.assertEquals(identity.getUsername(), initResponse.getUsername());
Assert.assertNull(initResponse.getQrcode());
//
// confirm
TwoFactorRegistrationConfirmDto confirm = new TwoFactorRegistrationConfirmDto();
confirm.setVerificationSecret(new GuardedString(initResponse.getVerificationSecret()));
confirm.setVerificationCode(manager.generateCode(new GuardedString(initResponse.getVerificationSecret())));
confirm.setTwoFactorAuthenticationType(TwoFactorAuthenticationType.NOTIFICATION);
Assert.assertTrue(manager.confirm(identity.getId(), confirm));
Assert.assertEquals(initResponse.getVerificationSecret(), getHelper().getPassword(identity).getVerificationSecret());
//
LoginDto loginDto = new LoginDto();
loginDto.setUsername(identity.getUsername());
loginDto.setPassword(identity.getPassword());
// creadentials are valid
Assert.assertTrue(authenticationManager.validate(loginDto));
// but two factor authentication is required
String token = null;
try {
authenticationManager.authenticate(loginDto);
} catch (TwoFactorAuthenticationRequiredException ex) {
token = ex.getToken();
}
Assert.assertNotNull(token);
//
loginDto.setToken(token);
loginDto.setPassword(manager.generateCode(identity.getId()));
//
// delete password
passwordService.delete(password);
//
manager.authenticate(loginDto);
}
use of eu.bcvsolutions.idm.core.security.api.exception.TwoFactorAuthenticationRequiredException in project CzechIdMng by bcvsolutions.
the class DefaultTwoFactorAuthenticationManagerIntegrationTest method testAuthenticateTokenExpired.
@Test(expected = ResultCodeException.class)
public void testAuthenticateTokenExpired() throws Exception {
// password is needed
IdmIdentityDto identity = getHelper().createIdentity();
//
TwoFactorRegistrationResponseDto initResponse = manager.init(identity.getId(), TwoFactorAuthenticationType.NOTIFICATION);
Assert.assertNotNull(initResponse);
Assert.assertNotNull(initResponse.getVerificationSecret());
Assert.assertEquals(identity.getUsername(), initResponse.getUsername());
Assert.assertNull(initResponse.getQrcode());
//
// confirm
TwoFactorRegistrationConfirmDto confirm = new TwoFactorRegistrationConfirmDto();
confirm.setVerificationSecret(new GuardedString(initResponse.getVerificationSecret()));
confirm.setVerificationCode(manager.generateCode(new GuardedString(initResponse.getVerificationSecret())));
confirm.setTwoFactorAuthenticationType(TwoFactorAuthenticationType.NOTIFICATION);
Assert.assertTrue(manager.confirm(identity.getId(), confirm));
Assert.assertEquals(initResponse.getVerificationSecret(), getHelper().getPassword(identity).getVerificationSecret());
//
LoginDto loginDto = new LoginDto();
loginDto.setUsername(identity.getUsername());
loginDto.setPassword(identity.getPassword());
// creadentials are valid
Assert.assertTrue(authenticationManager.validate(loginDto));
// but two factor authentication is required
String token = null;
try {
authenticationManager.authenticate(loginDto);
} catch (TwoFactorAuthenticationRequiredException ex) {
token = ex.getToken();
}
Assert.assertNotNull(token);
//
// set token expiration
IdmJwtAuthentication jwt = jwtAuthenticationMapper.readToken(token);
jwt.setExpiration(ZonedDateTime.now().minusDays(1));
token = jwtAuthenticationMapper.writeToken(jwt);
//
loginDto.setToken(token);
loginDto.setPassword(manager.generateCode(identity.getId()));
//
manager.authenticate(loginDto);
}
Aggregations