Search in sources :

Example 1 with ForgotPasswordParameters

use of io.gravitee.am.gateway.handler.root.service.user.model.ForgotPasswordParameters in project gravitee-access-management by gravitee-io.

the class ForgotPasswordSubmissionEndpoint method handle.

@Override
public void handle(RoutingContext context) {
    final String email = context.request().getParam(ConstantKeys.EMAIL_PARAM_KEY);
    final String username = context.request().getParam(ConstantKeys.USERNAME_PARAM_KEY);
    final Client client = context.get(ConstantKeys.CLIENT_CONTEXT_KEY);
    MultiMap queryParams = RequestUtils.getCleanedQueryParams(context.request());
    AccountSettings settings = AccountSettings.getInstance(domain, client);
    final ForgotPasswordParameters parameters = new ForgotPasswordParameters(email, username, settings != null && settings.isResetPasswordCustomForm(), settings != null && settings.isResetPasswordConfirmIdentity());
    userService.forgotPassword(parameters, client, getAuthenticatedUser(context)).subscribe(() -> {
        queryParams.set(ConstantKeys.SUCCESS_PARAM_KEY, "forgot_password_completed");
        redirectToPage(context, queryParams);
    }, error -> {
        // the actual error continue to be stored in the audit logs
        if (error instanceof UserNotFoundException || error instanceof AccountStatusException) {
            queryParams.set(ConstantKeys.SUCCESS_PARAM_KEY, "forgot_password_completed");
            redirectToPage(context, queryParams);
        } else if (error instanceof EnforceUserIdentityException) {
            if (settings.isResetPasswordConfirmIdentity()) {
                queryParams.set(ConstantKeys.WARNING_PARAM_KEY, FORGOT_PASSWORD_CONFIRM);
            } else {
                queryParams.set(ConstantKeys.SUCCESS_PARAM_KEY, "forgot_password_completed");
            }
            redirectToPage(context, queryParams);
        } else {
            queryParams.set(ConstantKeys.ERROR_PARAM_KEY, "forgot_password_failed");
            redirectToPage(context, queryParams, error);
        }
    });
}
Also used : AccountSettings(io.gravitee.am.model.account.AccountSettings) UserNotFoundException(io.gravitee.am.service.exception.UserNotFoundException) AccountStatusException(io.gravitee.am.common.exception.authentication.AccountStatusException) MultiMap(io.vertx.reactivex.core.MultiMap) EnforceUserIdentityException(io.gravitee.am.service.exception.EnforceUserIdentityException) Client(io.gravitee.am.model.oidc.Client) ForgotPasswordParameters(io.gravitee.am.gateway.handler.root.service.user.model.ForgotPasswordParameters)

Example 2 with ForgotPasswordParameters

use of io.gravitee.am.gateway.handler.root.service.user.model.ForgotPasswordParameters in project gravitee-access-management by gravitee-io.

the class UserServiceTest method shouldForgotPassword_MultipleMatch_NoMultiFieldForm.

@Test
public void shouldForgotPassword_MultipleMatch_NoMultiFieldForm() {
    Client client = mock(Client.class);
    when(client.getId()).thenReturn("client-id");
    User user = mock(User.class);
    when(user.getUsername()).thenReturn("username");
    when(user.isInactive()).thenReturn(false);
    when(user.getEmail()).thenReturn("test@test.com");
    UserProvider userProvider = mock(UserProvider.class);
    when(domain.getId()).thenReturn("domain-id");
    when(identityProviderManager.getUserProvider(user.getSource())).thenReturn(Maybe.just(userProvider));
    when(commonUserService.findByDomainAndCriteria(eq(domain.getId()), any(FilterCriteria.class))).thenReturn(Single.just(Arrays.asList(user, user)));
    when(commonUserService.update(any())).thenReturn(Single.just(user));
    when(userProvider.findByUsername("username")).thenReturn(Maybe.just(new DefaultUser("username")));
    TestObserver testObserver = userService.forgotPassword(new ForgotPasswordParameters(user.getEmail(), false, false), client, mock(io.gravitee.am.identityprovider.api.User.class)).test();
    testObserver.assertComplete();
    testObserver.assertNoErrors();
}
Also used : DefaultUser(io.gravitee.am.identityprovider.api.DefaultUser) DefaultUser(io.gravitee.am.identityprovider.api.DefaultUser) User(io.gravitee.am.model.User) UserProvider(io.gravitee.am.identityprovider.api.UserProvider) FilterCriteria(io.gravitee.am.repository.management.api.search.FilterCriteria) Client(io.gravitee.am.model.oidc.Client) ForgotPasswordParameters(io.gravitee.am.gateway.handler.root.service.user.model.ForgotPasswordParameters) TestObserver(io.reactivex.observers.TestObserver) Test(org.junit.Test)

Example 3 with ForgotPasswordParameters

use of io.gravitee.am.gateway.handler.root.service.user.model.ForgotPasswordParameters in project gravitee-access-management by gravitee-io.

the class UserServiceTest method shouldNotForgotPassword_MultipleMatch_ConfirmIdentityForm.

@Test
public void shouldNotForgotPassword_MultipleMatch_ConfirmIdentityForm() {
    Client client = mock(Client.class);
    when(client.getId()).thenReturn("client-id");
    User user = mock(User.class);
    when(user.getEmail()).thenReturn("test@test.com");
    when(domain.getId()).thenReturn("domain-id");
    when(commonUserService.findByDomainAndCriteria(eq(domain.getId()), any(FilterCriteria.class))).thenReturn(Single.just(Arrays.asList(user, user)));
    TestObserver testObserver = userService.forgotPassword(new ForgotPasswordParameters(user.getEmail(), true, true), client, mock(io.gravitee.am.identityprovider.api.User.class)).test();
    testObserver.assertNotComplete();
    testObserver.assertError(EnforceUserIdentityException.class);
}
Also used : DefaultUser(io.gravitee.am.identityprovider.api.DefaultUser) User(io.gravitee.am.model.User) FilterCriteria(io.gravitee.am.repository.management.api.search.FilterCriteria) Client(io.gravitee.am.model.oidc.Client) ForgotPasswordParameters(io.gravitee.am.gateway.handler.root.service.user.model.ForgotPasswordParameters) TestObserver(io.reactivex.observers.TestObserver) Test(org.junit.Test)

Example 4 with ForgotPasswordParameters

use of io.gravitee.am.gateway.handler.root.service.user.model.ForgotPasswordParameters 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();
}
Also used : java.util(java.util) Client(io.gravitee.am.model.oidc.Client) AccountInactiveException(io.gravitee.am.common.exception.authentication.AccountInactiveException) IdentityProviderManager(io.gravitee.am.gateway.handler.common.auth.idp.IdentityProviderManager) UserService(io.gravitee.am.gateway.handler.root.service.user.UserService) Autowired(org.springframework.beans.factory.annotation.Autowired) ConstantKeys(io.gravitee.am.common.utils.ConstantKeys) EmailService(io.gravitee.am.gateway.handler.common.email.EmailService) AuditService(io.gravitee.am.service.AuditService) DefaultUser(io.gravitee.am.identityprovider.api.DefaultUser) ForgotPasswordParameters(io.gravitee.am.gateway.handler.root.service.user.model.ForgotPasswordParameters) io.gravitee.am.service.exception(io.gravitee.am.service.exception) Strings(com.google.common.base.Strings) EnrolledFactor(io.gravitee.am.model.factor.EnrolledFactor) AuditBuilder(io.gravitee.am.service.reporter.builder.AuditBuilder) JWTService(io.gravitee.am.gateway.handler.common.jwt.JWTService) Qualifier(org.springframework.beans.factory.annotation.Qualifier) CredentialService(io.gravitee.am.service.CredentialService) Observable(io.reactivex.Observable) Objects.isNull(java.util.Objects.isNull) ClientSyncService(io.gravitee.am.gateway.handler.common.client.ClientSyncService) Map.entry(java.util.Map.entry) io.reactivex(io.reactivex) LoginAttemptService(io.gravitee.am.service.LoginAttemptService) FALSE(java.lang.Boolean.FALSE) JWTParser(io.gravitee.am.jwt.JWTParser) StandardClaims(io.gravitee.am.common.oidc.StandardClaims) Optional.ofNullable(java.util.Optional.ofNullable) ResetPasswordResponse(io.gravitee.am.gateway.handler.root.service.response.ResetPasswordResponse) EventType(io.gravitee.am.common.audit.EventType) Predicate(io.reactivex.functions.Predicate) RandomString(io.gravitee.am.common.utils.RandomString) io.gravitee.am.model(io.gravitee.am.model) TokenService(io.gravitee.am.service.TokenService) LoginAttemptCriteria(io.gravitee.am.repository.management.api.search.LoginAttemptCriteria) Collectors.toList(java.util.stream.Collectors.toList) UserToken(io.gravitee.am.gateway.handler.root.service.user.model.UserToken) UserAuditBuilder(io.gravitee.am.service.reporter.builder.management.UserAuditBuilder) EmailValidator(io.gravitee.am.service.validators.email.EmailValidator) ExpiredJWTException(io.gravitee.am.common.exception.jwt.ExpiredJWTException) UserValidator(io.gravitee.am.service.validators.user.UserValidator) Entry(java.util.Map.Entry) RegistrationResponse(io.gravitee.am.gateway.handler.root.service.response.RegistrationResponse) Objects.nonNull(java.util.Objects.nonNull) AccountSettings(io.gravitee.am.model.account.AccountSettings) StringUtils(org.springframework.util.StringUtils) DefaultUser(io.gravitee.am.identityprovider.api.DefaultUser) RandomString(io.gravitee.am.common.utils.RandomString) UserAuditBuilder(io.gravitee.am.service.reporter.builder.management.UserAuditBuilder) Predicate(io.reactivex.functions.Predicate) Entry(java.util.Map.Entry) AccountInactiveException(io.gravitee.am.common.exception.authentication.AccountInactiveException)

Aggregations

ForgotPasswordParameters (io.gravitee.am.gateway.handler.root.service.user.model.ForgotPasswordParameters)4 Client (io.gravitee.am.model.oidc.Client)4 DefaultUser (io.gravitee.am.identityprovider.api.DefaultUser)3 User (io.gravitee.am.model.User)2 AccountSettings (io.gravitee.am.model.account.AccountSettings)2 FilterCriteria (io.gravitee.am.repository.management.api.search.FilterCriteria)2 TestObserver (io.reactivex.observers.TestObserver)2 Test (org.junit.Test)2 Strings (com.google.common.base.Strings)1 EventType (io.gravitee.am.common.audit.EventType)1 AccountInactiveException (io.gravitee.am.common.exception.authentication.AccountInactiveException)1 AccountStatusException (io.gravitee.am.common.exception.authentication.AccountStatusException)1 ExpiredJWTException (io.gravitee.am.common.exception.jwt.ExpiredJWTException)1 StandardClaims (io.gravitee.am.common.oidc.StandardClaims)1 ConstantKeys (io.gravitee.am.common.utils.ConstantKeys)1 RandomString (io.gravitee.am.common.utils.RandomString)1 IdentityProviderManager (io.gravitee.am.gateway.handler.common.auth.idp.IdentityProviderManager)1 ClientSyncService (io.gravitee.am.gateway.handler.common.client.ClientSyncService)1 EmailService (io.gravitee.am.gateway.handler.common.email.EmailService)1 JWTService (io.gravitee.am.gateway.handler.common.jwt.JWTService)1