use of io.gravitee.am.common.exception.authentication.AccountInactiveException in project gravitee-access-management by gravitee-io.
the class UserServiceImpl method forgotPassword.
@Override
public Completable forgotPassword(ForgotPasswordParameters params, Client client, io.gravitee.am.identityprovider.api.User principal) {
final String email = params.getEmail();
if (email != null && !emailValidator.validate(email)) {
return Completable.error(new EmailFormatInvalidException(email));
}
return userService.findByDomainAndCriteria(domain.getId(), params.buildCriteria()).flatMap(users -> {
List<User> foundUsers = new ArrayList<>(users);
// narrow users
if (users.size() > 1) {
// filter by identity provider
if (client.getIdentityProviders() != null && !client.getIdentityProviders().isEmpty()) {
foundUsers = users.stream().flatMap(u -> client.getIdentityProviders().stream().map(appIdp -> entry(u, appIdp.getIdentity()))).filter(entry -> {
var user = entry.getKey();
var identity = entry.getValue();
return Objects.equals(user.getSource(), identity);
}).map(Entry::getKey).collect(toList());
}
if (foundUsers.size() > 1) {
// try to filter by latest application used
List<User> filteredSourceUsers = users.stream().filter(u -> u.getClient() == null || client.getId().equals(u.getClient())).collect(toList());
if (!filteredSourceUsers.isEmpty()) {
foundUsers = new ArrayList<>(filteredSourceUsers);
}
}
}
// If multiple results, check if ConfirmIdentity isn't required before returning the first User.
if (foundUsers.size() == 1 || (foundUsers.size() > 1 && !params.isConfirmIdentityEnabled())) {
User user = foundUsers.get(0);
// check if user can update its password according to its identity provider type
return identityProviderManager.getUserProvider(user.getSource()).switchIfEmpty(Single.error(new UserInvalidException("User [ " + user.getUsername() + " ] cannot be updated because its identity provider does not support user provisioning"))).flatMap(userProvider -> {
// if user registration is not completed and force registration option is disabled throw invalid account exception
if (user.isInactive() && !forceUserRegistration(domain, client)) {
return Single.error(new AccountInactiveException("User [ " + user.getUsername() + " ] needs to complete the activation process"));
}
// fetch latest information from the identity provider and return the user
return userProvider.findByUsername(user.getUsername()).map(Optional::ofNullable).defaultIfEmpty(Optional.empty()).flatMapSingle(optUser -> {
if (optUser.isEmpty()) {
return Single.just(user);
}
return userService.update(enhanceUser(user, optUser.get()));
});
});
}
if (foundUsers.size() > 1) {
throw new EnforceUserIdentityException();
}
// fallback to registered user providers if user has never been authenticated
if (client.getIdentityProviders() == null || client.getIdentityProviders().isEmpty()) {
return Single.error(new UserNotFoundException(email));
}
if (Strings.isNullOrEmpty(params.getEmail()) & StringUtils.isEmpty(params.getUsername())) {
// no user found using criteria. email & username are missing, unable to search the user through UserProvider
return Single.error(new UserNotFoundException(email));
}
// email used in priority for backward compatibility
return Observable.fromIterable(client.getIdentityProviders()).flatMapMaybe(authProvider -> identityProviderManager.getUserProvider(authProvider.getIdentity()).flatMap(userProvider -> {
final String username = params.getUsername();
final Maybe<io.gravitee.am.identityprovider.api.User> findQuery = Strings.isNullOrEmpty(email) ? userProvider.findByUsername(username) : userProvider.findByEmail(email);
return findQuery.map(user -> Optional.of(new UserAuthentication(user, authProvider.getIdentity()))).defaultIfEmpty(Optional.empty()).onErrorReturnItem(Optional.empty());
}).defaultIfEmpty(Optional.empty())).takeUntil((Predicate<? super Optional<UserAuthentication>>) Optional::isPresent).lastOrError().flatMap(optional -> {
// be sure to not duplicate an existing user
if (optional.isEmpty()) {
return Single.error(new UserNotFoundException());
}
final UserAuthentication idpUser = optional.get();
return userService.findByDomainAndUsernameAndSource(domain.getId(), idpUser.getUser().getUsername(), idpUser.getSource()).switchIfEmpty(Maybe.defer(() -> userService.findByDomainAndExternalIdAndSource(domain.getId(), idpUser.getUser().getId(), idpUser.getSource()))).map(Optional::ofNullable).defaultIfEmpty(Optional.empty()).flatMapSingle(optEndUser -> {
if (optEndUser.isEmpty()) {
return userService.create(convert(idpUser.getUser(), idpUser.getSource()));
}
return userService.update(enhanceUser(optEndUser.get(), idpUser.getUser()));
});
}).onErrorResumeNext(Single.error(new UserNotFoundException(email != null ? email : params.getUsername())));
}).doOnSuccess(user -> new Thread(() -> emailService.send(Template.RESET_PASSWORD, user, client)).start()).doOnSuccess(user1 -> {
// reload principal
io.gravitee.am.identityprovider.api.User principal1 = reloadPrincipal(principal, user1);
auditService.report(AuditBuilder.builder(UserAuditBuilder.class).domain(domain.getId()).client(client).principal(principal1).type(EventType.FORGOT_PASSWORD_REQUESTED));
}).doOnError(throwable -> auditService.report(AuditBuilder.builder(UserAuditBuilder.class).domain(domain.getId()).client(client).principal(principal).type(EventType.FORGOT_PASSWORD_REQUESTED).throwable(throwable))).ignoreElement();
}
use of io.gravitee.am.common.exception.authentication.AccountInactiveException in project gravitee-access-management by gravitee-io.
the class UserServiceImpl method resetPassword.
@Override
public Single<ResetPasswordResponse> resetPassword(Client client, User user, io.gravitee.am.identityprovider.api.User principal) {
// get account settings
final AccountSettings accountSettings = AccountSettings.getInstance(domain, client);
// if user registration is not completed and force registration option is disabled throw invalid account exception
if (user.isInactive() && !forceUserRegistration(domain, client)) {
return Single.error(new AccountInactiveException("User needs to complete the activation process"));
}
// only idp manage password, find user idp and update its password
return identityProviderManager.getUserProvider(user.getSource()).switchIfEmpty(Maybe.error(new UserProviderNotFoundException(user.getSource()))).flatMapSingle(userProvider -> userProvider.findByUsername(user.getUsername()).switchIfEmpty(Maybe.error(new UserNotFoundException(user.getUsername()))).flatMapSingle(idpUser -> {
// set password
((DefaultUser) idpUser).setCredentials(user.getPassword());
return userProvider.update(idpUser.getId(), idpUser);
}).onErrorResumeNext(ex -> {
if (ex instanceof UserNotFoundException) {
// idp user not found, create its account
return userProvider.create(convert(user));
}
return Single.error(ex);
})).flatMap(idpUser -> {
// if user was in pre-registration mode, end the registration process
if (user.isPreRegistration()) {
user.setRegistrationCompleted(true);
user.setEnabled(true);
}
user.setAccountNonLocked(true);
user.setAccountLockedAt(null);
user.setAccountLockedUntil(null);
user.setPassword(null);
user.setExternalId(idpUser.getId());
user.setLastPasswordReset(new Date());
user.setUpdatedAt(new Date());
// additional information
extractAdditionalInformation(user, idpUser.getAdditionalInformation());
// set login information
if (accountSettings != null && accountSettings.isAutoLoginAfterResetPassword()) {
user.setLoggedAt(new Date());
user.setLoginsCount(user.getLoginsCount() + 1);
}
return userService.update(user);
}).flatMap(user1 -> {
LoginAttemptCriteria criteria = new LoginAttemptCriteria.Builder().domain(user1.getReferenceId()).client(user1.getClient()).username(user1.getUsername()).build();
return loginAttemptService.reset(criteria).andThen(Single.just(user1));
}).flatMap(user1 -> {
if (accountSettings != null && accountSettings.isDeletePasswordlessDevicesAfterResetPassword()) {
return credentialService.deleteByUserId(user1.getReferenceType(), user1.getReferenceId(), user1.getId()).andThen(Single.just(user1));
}
return Single.just(user1);
}).flatMap(userService::enhance).map(user1 -> new ResetPasswordResponse(user1, accountSettings != null ? accountSettings.getRedirectUriAfterResetPassword() : null, accountSettings != null ? accountSettings.isAutoLoginAfterResetPassword() : false)).doOnSuccess(response -> auditService.report(AuditBuilder.builder(UserAuditBuilder.class).domain(domain.getId()).client(client).principal(principal).type(EventType.USER_PASSWORD_RESET).user(user))).doOnError(throwable -> auditService.report(AuditBuilder.builder(UserAuditBuilder.class).domain(domain.getId()).client(client).principal(principal).type(EventType.USER_PASSWORD_RESET).user(user).throwable(throwable)));
}
Aggregations