From 5a0b03a75f0315ad50c58299434d74603a5e3ce1 Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Fri, 5 Jan 2024 22:14:52 +0100 Subject: [PATCH] Improved token verification ~1h work --- .../mtcg/application/SessionHandler.java | 109 +++++++++++------- .../mtcg/application/TokenValidity.java | 8 ++ .../application/service/PackagesService.java | 21 ++-- .../mtcg/application/service/UserService.java | 8 +- 4 files changed, 91 insertions(+), 55 deletions(-) create mode 100644 src/at/nanopenguin/mtcg/application/TokenValidity.java diff --git a/src/at/nanopenguin/mtcg/application/SessionHandler.java b/src/at/nanopenguin/mtcg/application/SessionHandler.java index 7531ee7..bb0e0ee 100644 --- a/src/at/nanopenguin/mtcg/application/SessionHandler.java +++ b/src/at/nanopenguin/mtcg/application/SessionHandler.java @@ -12,63 +12,94 @@ import java.util.Map; import java.util.UUID; public final class SessionHandler { - private static SessionHandler INSTANCE; - private final Map Sessions = new HashMap<>(); + private static SessionHandler INSTANCE; + private final Map Sessions = new HashMap<>(); - private SessionHandler() { + private SessionHandler() { - } + } - public static SessionHandler getInstance() { + public static SessionHandler getInstance() { if (INSTANCE == null) { INSTANCE = new SessionHandler(); } return INSTANCE; - } + } - public UUID login(UserCredentials userCredentials) throws SQLException { - val result = DbQuery.builder() - .command(SqlCommand.SELECT) - .table(Table.USERS) - .column("uuid") - .column("password") - .column("admin") - .condition("username", userCredentials.username()) - .executeQuery(); - if (result.isEmpty()) { - // user not found - return null; - } + public UUID login(UserCredentials userCredentials) throws SQLException { + val result = DbQuery.builder() + .command(SqlCommand.SELECT) + .table(Table.USERS) + .column("uuid") + .column("password") + .column("admin") + .condition("username", userCredentials.username()) + .executeQuery(); + if (result.isEmpty()) { + // user not found + return null; + } - val row1 = result.get(0); - if (!row1.get("password").equals(userCredentials.password())) { - // wrong password - return null; - } + val row1 = result.get(0); + if (!row1.get("password").equals(userCredentials.password())) { + // wrong password + return null; + } - UUID uuid = UUID.randomUUID(); - this.Sessions.put(uuid, new UserInfo((UUID) row1.get("uuid"), userCredentials.username(), (boolean) row1.get("admin"))); - return uuid; - } + UUID uuid = UUID.randomUUID(); + this.Sessions.put(uuid, new UserInfo((UUID) row1.get("uuid"), userCredentials.username(), (boolean) row1.get("admin"))); + return uuid; + } - public static UUID uuidFromHttpHeader(String headerValue) { - return headerValue == null ? null : UUID.fromString(headerValue.replaceFirst("^Bearer ", "")); - } + public static UUID uuidFromHttpHeader(String headerValue) { + return headerValue == null ? null : UUID.fromString(headerValue.replaceFirst("^Bearer ", "")); + } - public boolean verifyUUID(UUID uuid) { + public TokenValidity verifyUUID(UUID uuid) { return verifyUUID(uuid, false); } - public boolean verifyUUID(UUID uuid, boolean requireAdmin) { - return uuid != null && Sessions.containsKey(uuid) && (!requireAdmin || Sessions.get(uuid).admin()); - } + public TokenValidity verifyUUID(UUID uuid, boolean requireAdmin) { + if (uuid == null) return TokenValidity.MISSING; + if (!Sessions.containsKey(uuid)) return TokenValidity.INVALID; + if (Sessions.get(uuid).admin() || !requireAdmin) return TokenValidity.VALID; + return TokenValidity.FORBIDDEN; + } - public boolean verifyUUID(UUID uuid, String username) { + public TokenValidity verifyUUID(UUID uuid, String username) { return verifyUUID(uuid, username, false); - } + } + + public TokenValidity verifyUUID(UUID uuid, String username, boolean allowAdmin) { + if (uuid == null) return TokenValidity.MISSING; + if (!Sessions.containsKey(uuid)) return TokenValidity.INVALID; + if (username.equals(Sessions.get(uuid).username())) return TokenValidity.VALID; + if (allowAdmin && Sessions.get(uuid).admin()) return TokenValidity.VALID; + return TokenValidity.FORBIDDEN; - public boolean verifyUUID(UUID uuid, String username, boolean allowAdmin) { - return uuid != null && Sessions.containsKey(uuid) && (username.equals(Sessions.get(uuid).username()) || (allowAdmin && Sessions.get(uuid).admin())); } } + +/* +* +* join() { +* lock() +* checks if someone waiting +* no -> { +* var waiting = true // sets self as waiting idk +* unlock() +* wait() +* response = battle log +* // process stuff +* unlock() +* } +* yes -> { +* start battle +* var battle log = battle log // no na ned +* // process stuff +* notifyAll() +* } +* } +* +* */ \ No newline at end of file diff --git a/src/at/nanopenguin/mtcg/application/TokenValidity.java b/src/at/nanopenguin/mtcg/application/TokenValidity.java new file mode 100644 index 0000000..0bd6280 --- /dev/null +++ b/src/at/nanopenguin/mtcg/application/TokenValidity.java @@ -0,0 +1,8 @@ +package at.nanopenguin.mtcg.application; + +public enum TokenValidity { + MISSING, + INVALID, + FORBIDDEN, + VALID +} diff --git a/src/at/nanopenguin/mtcg/application/service/PackagesService.java b/src/at/nanopenguin/mtcg/application/service/PackagesService.java index 042264e..b3b294c 100644 --- a/src/at/nanopenguin/mtcg/application/service/PackagesService.java +++ b/src/at/nanopenguin/mtcg/application/service/PackagesService.java @@ -2,6 +2,7 @@ package at.nanopenguin.mtcg.application.service; import at.nanopenguin.mtcg.application.Package; import at.nanopenguin.mtcg.application.SessionHandler; +import at.nanopenguin.mtcg.application.TokenValidity; import at.nanopenguin.mtcg.application.service.schemas.Card; import at.nanopenguin.mtcg.http.HttpMethod; import at.nanopenguin.mtcg.http.HttpRequest; @@ -10,10 +11,8 @@ import at.nanopenguin.mtcg.http.Response; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.val; import java.sql.SQLException; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; @@ -25,18 +24,18 @@ public class PackagesService implements Service { try { if (request.getPath().split("/")[1].equals("packages") && request.getMethod() == HttpMethod.POST) { UUID uuid; - if ((uuid = SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization"))) == null) - return new Response(HttpStatus.UNAUTHORIZED); // TODO: unauthorized for invalid token - if (!SessionHandler.getInstance().verifyUUID(uuid, true)) - return new Response(HttpStatus.FORBIDDEN); - - return new Response(Package.create(new ObjectMapper().readValue(request.getBody(), new TypeReference>() {})) ? - HttpStatus.CREATED : - HttpStatus.CONFLICT); + return switch (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), true)) { + case MISSING, INVALID -> new Response(HttpStatus.UNAUTHORIZED); + case FORBIDDEN -> new Response(HttpStatus.FORBIDDEN); + case VALID -> new Response( + Package.create(new ObjectMapper().readValue(request.getBody(), new TypeReference>() {})) ? + HttpStatus.CREATED : + HttpStatus.CONFLICT); + }; } if (String.join("/", Arrays.copyOfRange(request.getPath().split("/"), 1, 2)).equals("transactions/packages") && request.getMethod() == HttpMethod.POST) { - return new Response(!SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization"))) ? + return new Response(SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization"))) != TokenValidity.VALID ? HttpStatus.UNAUTHORIZED : HttpStatus.NOT_IMPLEMENTED); } diff --git a/src/at/nanopenguin/mtcg/application/service/UserService.java b/src/at/nanopenguin/mtcg/application/service/UserService.java index edc1278..452ad90 100644 --- a/src/at/nanopenguin/mtcg/application/service/UserService.java +++ b/src/at/nanopenguin/mtcg/application/service/UserService.java @@ -1,12 +1,10 @@ package at.nanopenguin.mtcg.application.service; import at.nanopenguin.mtcg.application.SessionHandler; +import at.nanopenguin.mtcg.application.TokenValidity; import at.nanopenguin.mtcg.application.User; import at.nanopenguin.mtcg.application.service.schemas.UserCredentials; import at.nanopenguin.mtcg.application.service.schemas.UserData; -import at.nanopenguin.mtcg.db.DbQuery; -import at.nanopenguin.mtcg.db.SqlCommand; -import at.nanopenguin.mtcg.db.Table; import at.nanopenguin.mtcg.http.HttpMethod; import at.nanopenguin.mtcg.http.HttpRequest; import at.nanopenguin.mtcg.http.HttpStatus; @@ -35,7 +33,7 @@ public class UserService implements Service { return switch (request.getMethod()) { case GET -> { String username = request.getPath().split("/")[2]; - if (!SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), username, true)) + if (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), username, true) != TokenValidity.VALID) yield new Response(HttpStatus.UNAUTHORIZED); val userData = User.retrieve(username); yield userData != null ? @@ -49,7 +47,7 @@ public class UserService implements Service { case PUT -> { String username = request.getPath().split("/")[2]; UserData userData = new ObjectMapper().readValue(request.getBody(), UserData.class); - if (!SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), username, true)) + if (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), username, true) != TokenValidity.FORBIDDEN) yield new Response(HttpStatus.UNAUTHORIZED); yield User.update(username, userData) ? new Response(HttpStatus.OK) : new Response(HttpStatus.NOT_FOUND); }