use of io.gravitee.am.factor.api.Enrollment 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"));
}
}
use of io.gravitee.am.factor.api.Enrollment in project gravitee-access-management by gravitee-io.
the class MFAEnrollEndpoint method saveEnrollment.
private void saveEnrollment(RoutingContext routingContext) {
MultiMap params = routingContext.request().formAttributes();
final Boolean acceptEnrollment = Boolean.valueOf(params.get(ConstantKeys.USER_MFA_ENROLLMENT));
final String factorId = params.get(ConstantKeys.MFA_ENROLLMENT_FACTOR_ID);
final String sharedSecret = params.get(ConstantKeys.MFA_ENROLLMENT_SHARED_SECRET);
final String phoneNumber = params.get(ConstantKeys.MFA_ENROLLMENT_PHONE);
final String emailAddress = params.get(ConstantKeys.MFA_ENROLLMENT_EMAIL);
if (factorId == null) {
logger.warn("No factor id in form - did you forget to include factor id value ?");
routingContext.fail(400);
return;
}
final Client client = routingContext.get(ConstantKeys.CLIENT_CONTEXT_KEY);
final Map<io.gravitee.am.model.Factor, FactorProvider> factors = getFactors(client);
Optional<Map.Entry<io.gravitee.am.model.Factor, FactorProvider>> optFactor = factors.entrySet().stream().filter(factor -> factorId.equals(factor.getKey().getId())).findFirst();
if (optFactor.isEmpty()) {
logger.warn("Factor not found - did you send a valid factor id ?");
routingContext.fail(400);
return;
}
// if user has skipped the enrollment process, continue
if (!acceptEnrollment) {
final User endUser = ((io.gravitee.am.gateway.handler.common.vertx.web.auth.user.User) routingContext.user().getDelegate()).getUser();
userService.setMfaEnrollmentSkippedTime(client, endUser).doFinally(() -> redirectToAuthorize(routingContext)).subscribe();
} else {
FactorProvider provider = optFactor.get().getValue();
if (provider.checkSecurityFactor(getSecurityFactor(params, optFactor.get().getKey()))) {
// save enrolled factor for the current user and continue
routingContext.session().put(ConstantKeys.ENROLLED_FACTOR_ID_KEY, factorId);
if (sharedSecret != null) {
routingContext.session().put(ConstantKeys.ENROLLED_FACTOR_SECURITY_VALUE_KEY, sharedSecret);
}
if (phoneNumber != null) {
routingContext.session().put(ConstantKeys.ENROLLED_FACTOR_PHONE_NUMBER, phoneNumber);
}
if (emailAddress != null) {
routingContext.session().put(ConstantKeys.ENROLLED_FACTOR_EMAIL_ADDRESS, emailAddress);
}
redirectToAuthorize(routingContext);
} else {
// parameters are invalid
routingContext.fail(400);
}
}
}
Aggregations