Modify POST /user/:id/setupTotp to work with adjusted requirements
This commit is contained in:
parent
aa527fa567
commit
aaba9cb369
2
pom.xml
2
pom.xml
@ -109,7 +109,7 @@
|
|||||||
<version>2.7.0</version>
|
<version>2.7.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- TOTP -->
|
<!-- Totp -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.warrenstrange</groupId>
|
<groupId>com.warrenstrange</groupId>
|
||||||
<artifactId>googleauth</artifactId>
|
<artifactId>googleauth</artifactId>
|
||||||
|
@ -25,6 +25,7 @@ import io.vertx.core.http.HttpHeaders;
|
|||||||
import io.vertx.core.http.HttpMethod;
|
import io.vertx.core.http.HttpMethod;
|
||||||
import io.vertx.core.http.HttpServer;
|
import io.vertx.core.http.HttpServer;
|
||||||
import io.vertx.core.http.HttpServerOptions;
|
import io.vertx.core.http.HttpServerOptions;
|
||||||
|
import io.vertx.core.net.JksOptions;
|
||||||
import io.vertx.ext.web.Router;
|
import io.vertx.ext.web.Router;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import io.vertx.ext.web.handler.BodyHandler;
|
import io.vertx.ext.web.handler.BodyHandler;
|
||||||
@ -218,7 +219,8 @@ public final class APIv3 extends AbstractVerticle {
|
|||||||
private void setupHttpServer() {
|
private void setupHttpServer() {
|
||||||
HttpServer webServer = vertx.createHttpServer(
|
HttpServer webServer = vertx.createHttpServer(
|
||||||
new HttpServerOptions()
|
new HttpServerOptions()
|
||||||
//.setSsl(true) // TODO
|
//.setSsl(true)
|
||||||
|
//.setKeyStoreOptions(new JksOptions().setPath("c:\\Users\\cmcdonald\\Desktop\\apiv3.jks").setPassword("password"))
|
||||||
.setCompressionSupported(true)
|
.setCompressionSupported(true)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableMap;
|
|||||||
import com.mongodb.client.result.UpdateResult;
|
import com.mongodb.client.result.UpdateResult;
|
||||||
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
|
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
|
||||||
import io.vertx.core.Handler;
|
import io.vertx.core.Handler;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
import net.frozenorb.apiv3.model.User;
|
import net.frozenorb.apiv3.model.User;
|
||||||
@ -24,20 +25,27 @@ public final class POSTUserSetupTotp implements Handler<RoutingContext> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (user.getTotpSecret() != null) {
|
if (user.getTotpSecret() != null) {
|
||||||
ErrorUtils.respondInvalidInput(ctx, "User provided already has TOTP code set.");
|
ErrorUtils.respondInvalidInput(ctx, "User provided already has totp setup.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GoogleAuthenticatorKey generated = TotpUtils.generateTotpSecret();
|
JsonObject requestBody = ctx.getBodyAsJson();
|
||||||
|
String secret = requestBody.getString("secret");
|
||||||
|
int code = requestBody.getInteger("code");
|
||||||
|
|
||||||
user.setTotpSecret(generated.getKey());
|
if (TotpUtils.authorizeUser(secret, code)) {
|
||||||
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
user.setTotpSecret(secret);
|
||||||
user.save(callback);
|
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
||||||
callback.get();
|
user.save(callback);
|
||||||
|
callback.get();
|
||||||
|
|
||||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"qrCode", TotpUtils.getQrCodeUrl(user, generated)
|
"success", true,
|
||||||
));
|
"message", "Totp code set."
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
ErrorUtils.respondInvalidInput(ctx, "Confirmation code provided did not match.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -26,7 +26,7 @@ public final class POSTUserVerifyTotp implements Handler<RoutingContext> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (user.getTotpSecret() == null) {
|
if (user.getTotpSecret() == null) {
|
||||||
ErrorUtils.respondInvalidInput(ctx, "User provided does not have TOTP code set.");
|
ErrorUtils.respondInvalidInput(ctx, "User provided does not have totp code set.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ public final class POSTUserVerifyTotp implements Handler<RoutingContext> {
|
|||||||
if (recentlyUsedCallback.get()) {
|
if (recentlyUsedCallback.get()) {
|
||||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"authorized", false,
|
"authorized", false,
|
||||||
"message", "TOTP code was recently used."
|
"message", "Totp code was recently used."
|
||||||
));
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -63,12 +63,12 @@ public final class POSTUserVerifyTotp implements Handler<RoutingContext> {
|
|||||||
|
|
||||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"authorized", true,
|
"authorized", true,
|
||||||
"message", "Valid TOTP code provided."
|
"message", "Valid totp code provided."
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
APIv3.respondJson(ctx, ImmutableMap.of(
|
APIv3.respondJson(ctx, ImmutableMap.of(
|
||||||
"authorized", false,
|
"authorized", false,
|
||||||
"message", "TOTP code was not valid."
|
"message", "Totp code was not valid."
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,6 @@ package net.frozenorb.apiv3.util;
|
|||||||
import com.mongodb.async.SingleResultCallback;
|
import com.mongodb.async.SingleResultCallback;
|
||||||
import com.warrenstrange.googleauth.GoogleAuthenticator;
|
import com.warrenstrange.googleauth.GoogleAuthenticator;
|
||||||
import com.warrenstrange.googleauth.GoogleAuthenticatorConfig;
|
import com.warrenstrange.googleauth.GoogleAuthenticatorConfig;
|
||||||
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
|
|
||||||
import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator;
|
|
||||||
import io.vertx.redis.RedisClient;
|
import io.vertx.redis.RedisClient;
|
||||||
import io.vertx.redis.RedisOptions;
|
import io.vertx.redis.RedisOptions;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
@ -23,20 +21,8 @@ public class TotpUtils {
|
|||||||
.setPort(Integer.parseInt(APIv3.getConfig().getProperty("redis.port")))
|
.setPort(Integer.parseInt(APIv3.getConfig().getProperty("redis.port")))
|
||||||
);
|
);
|
||||||
|
|
||||||
public static GoogleAuthenticatorKey generateTotpSecret() {
|
public static boolean authorizeUser(String secret, int code) {
|
||||||
return googleAuthenticator.createCredentials();
|
return googleAuthenticator.authorize(secret, code);
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean authorizeUser(User user, int code) {
|
|
||||||
return googleAuthenticator.authorize(user.getTotpSecret(), code);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getQrCodeUrl(User user, GoogleAuthenticatorKey secret) {
|
|
||||||
return GoogleAuthenticatorQRGenerator.getOtpAuthURL(
|
|
||||||
"MineHQ Network",
|
|
||||||
user.getLastUsername(),
|
|
||||||
secret
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void isPreAuthorized(User user, String ip, SingleResultCallback<Boolean> callback) {
|
public static void isPreAuthorized(User user, String ip, SingleResultCallback<Boolean> callback) {
|
||||||
@ -68,7 +54,7 @@ public class TotpUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void wasRecentlyUsed(User user, int code, SingleResultCallback<Boolean> callback) {
|
public static void wasRecentlyUsed(User user, int code, SingleResultCallback<Boolean> callback) {
|
||||||
redisClient.exists(user.getId() + ":recentTOTPCodes:" + code, (result) -> {
|
redisClient.exists(user.getId() + ":recentTotpCodes:" + code, (result) -> {
|
||||||
if (result.succeeded()) {
|
if (result.succeeded()) {
|
||||||
callback.onResult(result.result() == 1 , null);
|
callback.onResult(result.result() == 1 , null);
|
||||||
} else {
|
} else {
|
||||||
@ -78,7 +64,7 @@ public class TotpUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void markRecentlyUsed(User user, int code, SingleResultCallback<Void> callback) {
|
public static void markRecentlyUsed(User user, int code, SingleResultCallback<Void> callback) {
|
||||||
String key = user.getId() + ":recentTOTPCodes:" + code;
|
String key = user.getId() + ":recentTotpCodes:" + code;
|
||||||
|
|
||||||
redisClient.set(key, "", (result) -> {
|
redisClient.set(key, "", (result) -> {
|
||||||
if (result.succeeded()) {
|
if (result.succeeded()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user