From c6eb1c813cb0b1af1e18085d8e69be0023a49797 Mon Sep 17 00:00:00 2001 From: Benjamin Gamard Date: Fri, 1 Feb 2019 14:47:18 +0100 Subject: [PATCH] #268: endpoint to test TOTP code --- .../docs/rest/resource/UserResource.java | 41 +++++++++++++++++++ .../sismics/docs/rest/TestUserResource.java | 11 ++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java index 6a2ed09a..a851da2c 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java @@ -919,6 +919,47 @@ public class UserResource extends BaseResource { .add("secret", key.getKey()); return Response.ok().entity(response.build()).build(); } + + /** + * Test time-based one-time password. + * + * @api {post} /user/test_totp Test TOTP authentication + * @apiDescription Test a TOTP validation code. + * @apiName PostUserTestTotp + * @apiParam {String} code TOTP validation code + * @apiGroup User + * @apiSuccess {String} status Status OK + * @apiError (client) ForbiddenError The validation code is not valid or access denied + * @apiPermission user + * @apiVersion 1.6.0 + * + * @return Response + */ + @POST + @Path("test_totp") + public Response testTotp(@FormParam("code") String validationCodeStr) { + if (!authenticate() || principal.isGuest()) { + throw new ForbiddenClientException(); + } + + // Get the user + UserDao userDao = new UserDao(); + User user = userDao.getActiveByUsername(principal.getName()); + + // Test the validation code + if (user.getTotpKey() != null) { + int validationCode = ValidationUtil.validateInteger(validationCodeStr, "code"); + GoogleAuthenticator googleAuthenticator = new GoogleAuthenticator(); + if (!googleAuthenticator.authorize(user.getTotpKey(), validationCode)) { + throw new ForbiddenClientException(); + } + } + + // Always return OK + JsonObjectBuilder response = Json.createObjectBuilder() + .add("status", "ok"); + return Response.ok().entity(response.build()).build(); + } /** * Disable time-based one-time password for the current user. diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestUserResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestUserResource.java index 74ee47dd..a727ff91 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestUserResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestUserResource.java @@ -370,7 +370,16 @@ public class TestUserResource extends BaseJerseyTest { .cookie(TokenBasedSecurityFilter.COOKIE_NAME, totp1Token) .get(JsonObject.class); Assert.assertTrue(json.getBoolean("totp_enabled")); - + + // Generate a OTP + validationCode = googleAuthenticator.calculateCode(secret, new Date().getTime() / 30000); + + // Test a validation code + target().path("/user/test_totp").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, totp1Token) + .post(Entity.form(new Form() + .param("code", Integer.toString(validationCode))), JsonObject.class); + // Disable TOTP for totp1 target().path("/user/disable_totp").request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, totp1Token)