use of io.gravitee.am.service.exception.FactorNotFoundException in project gravitee-access-management by gravitee-io.
the class MFAChallengeEndpoint method getEnrolledFactor.
private EnrolledFactor getEnrolledFactor(RoutingContext routingContext, Factor factor, User endUser) {
// enrolled factor can be either in session (if user come from mfa/enroll page)
// or from the user enrolled factor list
final String savedFactorId = routingContext.session().get(ConstantKeys.ENROLLED_FACTOR_ID_KEY);
if (factor.getId().equals(savedFactorId)) {
EnrolledFactor enrolledFactor = new EnrolledFactor();
enrolledFactor.setFactorId(factor.getId());
switch(factor.getFactorType()) {
case OTP:
enrolledFactor.setSecurity(new EnrolledFactorSecurity(SHARED_SECRET, routingContext.session().get(ConstantKeys.ENROLLED_FACTOR_SECURITY_VALUE_KEY)));
break;
case SMS:
enrolledFactor.setChannel(new EnrolledFactorChannel(Type.SMS, routingContext.session().get(ConstantKeys.ENROLLED_FACTOR_PHONE_NUMBER)));
break;
case CALL:
enrolledFactor.setChannel(new EnrolledFactorChannel(Type.CALL, routingContext.session().get(ConstantKeys.ENROLLED_FACTOR_PHONE_NUMBER)));
break;
case EMAIL:
Map<String, Object> additionalData = new Maps.MapBuilder(new HashMap()).put(FactorDataKeys.KEY_MOVING_FACTOR, generateInitialMovingFactor(endUser)).build();
// For email even if the endUser will contains all relevant information, we extract only the Expiration Date of the code.
// this is done only to enforce the other parameter (shared secret and initialMovingFactor)
getEnrolledFactor(factor, endUser).ifPresent(ef -> {
additionalData.put(FactorDataKeys.KEY_EXPIRE_AT, ef.getSecurity().getData(FactorDataKeys.KEY_EXPIRE_AT, Long.class));
});
enrolledFactor.setSecurity(new EnrolledFactorSecurity(SHARED_SECRET, routingContext.session().get(ConstantKeys.ENROLLED_FACTOR_SECURITY_VALUE_KEY), additionalData));
enrolledFactor.setChannel(new EnrolledFactorChannel(Type.EMAIL, routingContext.session().get(ConstantKeys.ENROLLED_FACTOR_EMAIL_ADDRESS)));
break;
case RECOVERY_CODE:
if (endUser.getFactors() != null) {
Optional<EnrolledFactorSecurity> factorSecurity = endUser.getFactors().stream().filter(ftr -> ftr.getSecurity().getType().equals(RECOVERY_CODE)).map(EnrolledFactor::getSecurity).findFirst();
factorSecurity.ifPresent(enrolledFactor::setSecurity);
}
break;
}
enrolledFactor.setCreatedAt(new Date());
enrolledFactor.setUpdatedAt(enrolledFactor.getCreatedAt());
return enrolledFactor;
}
return getEnrolledFactor(factor, endUser).orElseThrow(() -> new FactorNotFoundException("No enrolled factor found for the end user"));
}
use of io.gravitee.am.service.exception.FactorNotFoundException in project gravitee-access-management by gravitee-io.
the class AccountFactorsEndpointHandler method getEnrolledFactorQrCode.
/**
* Get QR code for the selected enrolled factor (TOTP only)
*
* @param routingContext the routingContext holding the current user
*/
public void getEnrolledFactorQrCode(RoutingContext routingContext) {
final User user = routingContext.get(ConstantKeys.USER_CONTEXT_KEY);
final String factorId = routingContext.request().getParam("factorId");
final FactorProvider factorProvider = factorManager.get(factorId);
if (factorProvider == null) {
routingContext.fail(new FactorNotFoundException(factorId));
return;
}
if (user.getFactors() == null) {
routingContext.fail(new FactorNotFoundException(factorId));
return;
}
Optional<EnrolledFactor> optionalEnrolledFactor = getEnrolledFactor(factorId, user);
if (optionalEnrolledFactor.isEmpty()) {
routingContext.fail(new FactorNotFoundException(factorId));
return;
}
EnrolledFactor enrolledFactor = optionalEnrolledFactor.get();
factorProvider.generateQrCode(user, enrolledFactor).subscribe(barCode -> AccountResponseHandler.handleDefaultResponse(routingContext, new JsonObject().put("qrCode", barCode)), error -> routingContext.fail(error), () -> routingContext.fail(404));
}
use of io.gravitee.am.service.exception.FactorNotFoundException in project gravitee-access-management by gravitee-io.
the class AccountFactorsEndpointHandler method verifyFactor.
/**
* Verify a factor for the current user
*
* @param routingContext the routingContext holding the current user
*/
public void verifyFactor(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 String factorId = routingContext.request().getParam("factorId");
final String code = routingContext.getBodyAsJson().getString("code");
// code is required
if (isEmpty(code)) {
routingContext.fail(new InvalidRequestException("Field [code] is required"));
return;
}
// find factor
findFactor(factorId, h -> {
if (h.failed()) {
routingContext.fail(h.cause());
return;
}
final FactorProvider factorProvider = factorManager.get(factorId);
if (factorProvider == null) {
routingContext.fail(new FactorNotFoundException(factorId));
return;
}
// get enrolled factor for the current user
Optional<EnrolledFactor> optionalEnrolledFactor = user.getFactors().stream().filter(enrolledFactor -> factorId.equals(enrolledFactor.getFactorId())).findFirst();
if (!optionalEnrolledFactor.isPresent()) {
routingContext.fail(new FactorNotFoundException(factorId));
return;
}
// if factor is already activated, continue
final EnrolledFactor enrolledFactor = optionalEnrolledFactor.get();
if (FactorStatus.ACTIVATED.equals(enrolledFactor.getStatus())) {
AccountResponseHandler.handleDefaultResponse(routingContext, enrolledFactor);
return;
}
// verify factor
verifyFactor(code, enrolledFactor, factorProvider, vh -> {
if (vh.failed()) {
routingContext.fail(vh.cause());
return;
}
// verify successful, change the EnrolledFactor Status
enrolledFactor.setStatus(FactorStatus.ACTIVATED);
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.service.exception.FactorNotFoundException in project gravitee-access-management by gravitee-io.
the class AccountFactorsEndpointHandler method getEnrolledFactor.
/**
* Get enrolled factor detail for the current user
*
* @param routingContext the routingContext holding the current user
*/
public void getEnrolledFactor(RoutingContext routingContext) {
final User user = routingContext.get(ConstantKeys.USER_CONTEXT_KEY);
final String factorId = routingContext.request().getParam("factorId");
if (user.getFactors() == null) {
routingContext.fail(new FactorNotFoundException(factorId));
return;
}
final Optional<EnrolledFactor> optionalEnrolledFactor = getEnrolledFactor(factorId, user);
if (optionalEnrolledFactor.isEmpty()) {
routingContext.fail(new FactorNotFoundException(factorId));
return;
}
// Remove recovery code from enrolled factor
EnrolledFactor enrolledFactor = optionalEnrolledFactor.get();
if (RECOVERY_CODE.equals(enrolledFactor.getSecurity())) {
routingContext.fail(new FactorNotFoundException(factorId));
return;
}
AccountResponseHandler.handleDefaultResponse(routingContext, enrolledFactor);
}
use of io.gravitee.am.service.exception.FactorNotFoundException 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"));
}
}
Aggregations