in extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/UserVerificationService.java [288:369]
public void verifyIdentity(UserContext context,
AuthenticatedUser authenticatedUser) throws GuacamoleException {
// Ignore anonymous users
String username = authenticatedUser.getIdentifier();
if (username.equals(AuthenticatedUser.ANONYMOUS_IDENTIFIER))
return;
// Check if TOTP has been disabled for this user
if (totpDisabled(context, authenticatedUser))
return;
// Ignore users which do not have an associated key
UserTOTPKey key = getKey(context, username);
if (key == null)
return;
// Pull the original HTTP request used to authenticate
Credentials credentials = authenticatedUser.getCredentials();
HttpServletRequest request = credentials.getRequest();
// Retrieve TOTP from request
String code = request.getParameter(AuthenticationCodeField.PARAMETER_NAME);
// If no TOTP provided, request one
if (code == null) {
AuthenticationCodeField field = codeFieldProvider.get();
// If the user hasn't completed enrollment, request that they do
if (!key.isConfirmed()) {
field.exposeKey(key);
throw new TranslatableGuacamoleInsufficientCredentialsException(
"TOTP enrollment must be completed before "
+ "authentication can continue",
"TOTP.INFO_ENROLL_REQUIRED", new CredentialsInfo(
Collections.<Field>singletonList(field)
));
}
// Otherwise simply request the user's authentication code
throw new TranslatableGuacamoleInsufficientCredentialsException(
"A TOTP authentication code is required before login can "
+ "continue", "TOTP.INFO_CODE_REQUIRED", new CredentialsInfo(
Collections.<Field>singletonList(field)
));
}
try {
// Get generator based on user's key and provided configuration
TOTPGenerator totp = new TOTPGenerator(key.getSecret(),
confService.getMode(), confService.getDigits(),
TOTPGenerator.DEFAULT_START_TIME, confService.getPeriod());
// Verify provided TOTP against value produced by generator
if ((code.equals(totp.generate()) || code.equals(totp.previous()))
&& codeService.useCode(username, code)) {
// Record key as confirmed, if it hasn't already been so recorded
if (!key.isConfirmed()) {
key.setConfirmed(true);
setKey(context, key);
}
// User has been verified
return;
}
}
catch (InvalidKeyException e) {
logger.warn("User \"{}\" is associated with an invalid TOTP key.", username);
logger.debug("TOTP key is not valid.", e);
}
// Provided code is not valid
throw new TranslatableGuacamoleClientException("Provided TOTP code "
+ "is not valid.", "TOTP.INFO_VERIFICATION_FAILED");
}