Search in sources :

Example 1 with EnrollmentAccount

use of io.gravitee.am.gateway.handler.account.model.EnrollmentAccount in project gravitee-access-management by gravitee-io.

the class AccountFactorsEndpointHandler method enrollFactor.

/**
 * Enroll a factor for the current user
 *
 * @param routingContext the routingContext holding the current user
 */
public void enrollFactor(RoutingContext routingContext) {
    try {
        if (routingContext.getBodyAsString() == null) {
            routingContext.fail(new InvalidRequestException("Unable to parse body message"));
            return;
        }
        final User user = routingContext.get(ConstantKeys.USER_CONTEXT_KEY);
        final io.gravitee.am.gateway.handler.account.model.Enrollment enrollment = Json.decodeValue(routingContext.getBodyAsString(), io.gravitee.am.gateway.handler.account.model.Enrollment.class);
        // factorId is required
        if (isEmpty(enrollment.getFactorId())) {
            routingContext.fail(new InvalidRequestException("Field [factorId] is required"));
            return;
        }
        final String factorId = enrollment.getFactorId();
        final EnrollmentAccount account = enrollment.getAccount();
        // find factor
        findFactor(factorId, h -> {
            if (h.failed()) {
                routingContext.fail(h.cause());
                return;
            }
            final Factor factor = h.result();
            final FactorProvider factorProvider = factorManager.get(factorId);
            if (factorProvider == null) {
                routingContext.fail(new FactorNotFoundException(factorId));
                return;
            }
            if (isRecoveryCodeFactor(factor)) {
                routingContext.fail(new InvalidRequestException("Recovery code does not support enrollment feature. Instead, use '/api/recovery_code' endpoint to generate recovery code."));
                return;
            }
            // check request body parameters
            switch(factor.getFactorType()) {
                case CALL:
                case SMS:
                    if (isNull(account) || isEmpty(account.getPhoneNumber())) {
                        routingContext.fail(new InvalidRequestException("Field [phoneNumber] is required"));
                        return;
                    }
                    break;
                case EMAIL:
                    if (isNull(account) || isEmpty(account.getEmail())) {
                        routingContext.fail(new InvalidRequestException("Field [email] is required"));
                        return;
                    }
                    break;
                default:
                    // Do nothing
                    break;
            }
            // check if the current factor is already enrolled
            if (user.getFactors() != null) {
                Optional<EnrolledFactor> optionalEnrolledFactor = user.getFactors().stream().filter(enrolledFactor -> factorId.equals(enrolledFactor.getFactorId())).findFirst();
                if (optionalEnrolledFactor.isPresent()) {
                    EnrolledFactor existingEnrolledFactor = optionalEnrolledFactor.get();
                    if (FactorStatus.ACTIVATED.equals(existingEnrolledFactor.getStatus())) {
                        AccountResponseHandler.handleDefaultResponse(routingContext, existingEnrolledFactor);
                        return;
                    }
                }
            }
            // enroll factor
            enrollFactor(factor, factorProvider, account, user, eh -> {
                if (eh.failed()) {
                    if (eh.cause() instanceof InvalidFactorAttributeException) {
                        routingContext.fail(400, eh.cause());
                    } else {
                        routingContext.fail(eh.cause());
                    }
                    return;
                }
                final EnrolledFactor enrolledFactor = eh.result();
                // send challenge
                sendChallenge(factorProvider, enrolledFactor, user, routingContext, sh -> {
                    // save enrolled factor
                    accountService.upsertFactor(user.getId(), enrolledFactor, new DefaultUser(user)).subscribe(__ -> AccountResponseHandler.handleDefaultResponse(routingContext, enrolledFactor), error -> routingContext.fail(error));
                });
            });
        });
    } catch (DecodeException ex) {
        routingContext.fail(new InvalidRequestException("Unable to parse body message"));
    }
}
Also used : SHARED_SECRET(io.gravitee.am.common.factor.FactorSecurityType.SHARED_SECRET) FactorType(io.gravitee.am.common.factor.FactorType) Factor(io.gravitee.am.model.Factor) Json(io.vertx.core.json.Json) java.util(java.util) Client(io.gravitee.am.model.oidc.Client) DecodeException(io.vertx.core.json.DecodeException) Completable(io.reactivex.Completable) ConstantKeys(io.gravitee.am.common.utils.ConstantKeys) DefaultUser(io.gravitee.am.identityprovider.api.DefaultUser) EnrolledFactorChannel(io.gravitee.am.model.factor.EnrolledFactorChannel) SecureRandom(java.security.SecureRandom) KEY_USER(io.gravitee.am.factor.api.FactorContext.KEY_USER) RECOVERY_CODE(io.gravitee.am.common.factor.FactorSecurityType.RECOVERY_CODE) InvalidRequestException(io.gravitee.am.common.exception.oauth2.InvalidRequestException) EnrolledFactor(io.gravitee.am.model.factor.EnrolledFactor) Type(io.gravitee.am.model.factor.EnrolledFactorChannel.Type) FactorStatus(io.gravitee.am.model.factor.FactorStatus) Observable(io.reactivex.Observable) Schedulers(io.reactivex.schedulers.Schedulers) JsonObject(io.vertx.core.json.JsonObject) Objects.isNull(java.util.Objects.isNull) AsyncResult(io.vertx.core.AsyncResult) User(io.gravitee.am.model.User) InvalidFactorAttributeException(io.gravitee.am.common.exception.mfa.InvalidFactorAttributeException) UpdateEnrolledFactor(io.gravitee.am.gateway.handler.account.model.UpdateEnrolledFactor) FactorNotFoundException(io.gravitee.am.service.exception.FactorNotFoundException) RoutingContextHelper.getEvaluableAttributes(io.gravitee.am.gateway.handler.common.utils.RoutingContextHelper.getEvaluableAttributes) FactorDataKeys(io.gravitee.am.common.factor.FactorDataKeys) VertxHttpServerRequest(io.gravitee.am.gateway.handler.common.vertx.core.http.VertxHttpServerRequest) Future(io.vertx.core.Future) RoutingContext(io.vertx.reactivex.ext.web.RoutingContext) ApplicationContext(org.springframework.context.ApplicationContext) Collectors(java.util.stream.Collectors) AccountService(io.gravitee.am.gateway.handler.account.services.AccountService) Maps(io.gravitee.common.util.Maps) StandardCharsets(java.nio.charset.StandardCharsets) EnrollmentAccount(io.gravitee.am.gateway.handler.account.model.EnrollmentAccount) EnrolledFactorSecurity(io.gravitee.am.model.factor.EnrolledFactorSecurity) EvaluableRequest(io.gravitee.gateway.api.el.EvaluableRequest) RecoveryFactor(io.gravitee.am.factor.api.RecoveryFactor) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) StringUtils.isEmpty(org.springframework.util.StringUtils.isEmpty) FactorContext(io.gravitee.am.factor.api.FactorContext) Enrollment(io.gravitee.am.factor.api.Enrollment) Handler(io.vertx.core.Handler) FactorProvider(io.gravitee.am.factor.api.FactorProvider) FactorManager(io.gravitee.am.gateway.handler.common.factor.FactorManager) DefaultUser(io.gravitee.am.identityprovider.api.DefaultUser) User(io.gravitee.am.model.User) EnrolledFactor(io.gravitee.am.model.factor.EnrolledFactor) UpdateEnrolledFactor(io.gravitee.am.gateway.handler.account.model.UpdateEnrolledFactor) FactorNotFoundException(io.gravitee.am.service.exception.FactorNotFoundException) EnrollmentAccount(io.gravitee.am.gateway.handler.account.model.EnrollmentAccount) DecodeException(io.vertx.core.json.DecodeException) FactorProvider(io.gravitee.am.factor.api.FactorProvider) InvalidFactorAttributeException(io.gravitee.am.common.exception.mfa.InvalidFactorAttributeException) DefaultUser(io.gravitee.am.identityprovider.api.DefaultUser) Factor(io.gravitee.am.model.Factor) EnrolledFactor(io.gravitee.am.model.factor.EnrolledFactor) UpdateEnrolledFactor(io.gravitee.am.gateway.handler.account.model.UpdateEnrolledFactor) RecoveryFactor(io.gravitee.am.factor.api.RecoveryFactor) InvalidRequestException(io.gravitee.am.common.exception.oauth2.InvalidRequestException)

Aggregations

InvalidFactorAttributeException (io.gravitee.am.common.exception.mfa.InvalidFactorAttributeException)1 InvalidRequestException (io.gravitee.am.common.exception.oauth2.InvalidRequestException)1 FactorDataKeys (io.gravitee.am.common.factor.FactorDataKeys)1 RECOVERY_CODE (io.gravitee.am.common.factor.FactorSecurityType.RECOVERY_CODE)1 SHARED_SECRET (io.gravitee.am.common.factor.FactorSecurityType.SHARED_SECRET)1 FactorType (io.gravitee.am.common.factor.FactorType)1 ConstantKeys (io.gravitee.am.common.utils.ConstantKeys)1 Enrollment (io.gravitee.am.factor.api.Enrollment)1 FactorContext (io.gravitee.am.factor.api.FactorContext)1 KEY_USER (io.gravitee.am.factor.api.FactorContext.KEY_USER)1 FactorProvider (io.gravitee.am.factor.api.FactorProvider)1 RecoveryFactor (io.gravitee.am.factor.api.RecoveryFactor)1 EnrollmentAccount (io.gravitee.am.gateway.handler.account.model.EnrollmentAccount)1 UpdateEnrolledFactor (io.gravitee.am.gateway.handler.account.model.UpdateEnrolledFactor)1 AccountService (io.gravitee.am.gateway.handler.account.services.AccountService)1 FactorManager (io.gravitee.am.gateway.handler.common.factor.FactorManager)1 RoutingContextHelper.getEvaluableAttributes (io.gravitee.am.gateway.handler.common.utils.RoutingContextHelper.getEvaluableAttributes)1 VertxHttpServerRequest (io.gravitee.am.gateway.handler.common.vertx.core.http.VertxHttpServerRequest)1 DefaultUser (io.gravitee.am.identityprovider.api.DefaultUser)1 Factor (io.gravitee.am.model.Factor)1