Improved token verification

~1h work
This commit is contained in:
Benedikt Galbavy 2024-01-05 22:14:52 +01:00
parent 86d43f04ce
commit 5a0b03a75f
4 changed files with 91 additions and 55 deletions

View File

@ -56,19 +56,50 @@ public final class SessionHandler {
return headerValue == null ? null : UUID.fromString(headerValue.replaceFirst("^Bearer ", "")); return headerValue == null ? null : UUID.fromString(headerValue.replaceFirst("^Bearer ", ""));
} }
public boolean verifyUUID(UUID uuid) { public TokenValidity verifyUUID(UUID uuid) {
return verifyUUID(uuid, false); return verifyUUID(uuid, false);
} }
public boolean verifyUUID(UUID uuid, boolean requireAdmin) { public TokenValidity verifyUUID(UUID uuid, boolean requireAdmin) {
return uuid != null && Sessions.containsKey(uuid) && (!requireAdmin || Sessions.get(uuid).admin()); 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); return verifyUUID(uuid, username, false);
} }
public boolean verifyUUID(UUID uuid, String username, boolean allowAdmin) { public TokenValidity verifyUUID(UUID uuid, String username, boolean allowAdmin) {
return uuid != null && Sessions.containsKey(uuid) && (username.equals(Sessions.get(uuid).username()) || (allowAdmin && Sessions.get(uuid).admin())); 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;
} }
} }
/*
*
* 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()
* }
* }
*
* */

View File

@ -0,0 +1,8 @@
package at.nanopenguin.mtcg.application;
public enum TokenValidity {
MISSING,
INVALID,
FORBIDDEN,
VALID
}

View File

@ -2,6 +2,7 @@ package at.nanopenguin.mtcg.application.service;
import at.nanopenguin.mtcg.application.Package; import at.nanopenguin.mtcg.application.Package;
import at.nanopenguin.mtcg.application.SessionHandler; import at.nanopenguin.mtcg.application.SessionHandler;
import at.nanopenguin.mtcg.application.TokenValidity;
import at.nanopenguin.mtcg.application.service.schemas.Card; import at.nanopenguin.mtcg.application.service.schemas.Card;
import at.nanopenguin.mtcg.http.HttpMethod; import at.nanopenguin.mtcg.http.HttpMethod;
import at.nanopenguin.mtcg.http.HttpRequest; 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.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.val;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -25,18 +24,18 @@ public class PackagesService implements Service {
try { try {
if (request.getPath().split("/")[1].equals("packages") && request.getMethod() == HttpMethod.POST) { if (request.getPath().split("/")[1].equals("packages") && request.getMethod() == HttpMethod.POST) {
UUID uuid; UUID uuid;
if ((uuid = SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization"))) == null) return switch (SessionHandler.getInstance().verifyUUID(SessionHandler.uuidFromHttpHeader(request.getHttpHeader("Authorization")), true)) {
return new Response(HttpStatus.UNAUTHORIZED); // TODO: unauthorized for invalid token case MISSING, INVALID -> new Response(HttpStatus.UNAUTHORIZED);
if (!SessionHandler.getInstance().verifyUUID(uuid, true)) case FORBIDDEN -> new Response(HttpStatus.FORBIDDEN);
return new Response(HttpStatus.FORBIDDEN); case VALID -> new Response(
Package.create(new ObjectMapper().readValue(request.getBody(), new TypeReference<List<Card>>() {})) ?
return new Response(Package.create(new ObjectMapper().readValue(request.getBody(), new TypeReference<List<Card>>() {})) ?
HttpStatus.CREATED : HttpStatus.CREATED :
HttpStatus.CONFLICT); HttpStatus.CONFLICT);
};
} }
if (String.join("/", Arrays.copyOfRange(request.getPath().split("/"), 1, 2)).equals("transactions/packages") && request.getMethod() == HttpMethod.POST) { 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.UNAUTHORIZED :
HttpStatus.NOT_IMPLEMENTED); HttpStatus.NOT_IMPLEMENTED);
} }

View File

@ -1,12 +1,10 @@
package at.nanopenguin.mtcg.application.service; package at.nanopenguin.mtcg.application.service;
import at.nanopenguin.mtcg.application.SessionHandler; import at.nanopenguin.mtcg.application.SessionHandler;
import at.nanopenguin.mtcg.application.TokenValidity;
import at.nanopenguin.mtcg.application.User; import at.nanopenguin.mtcg.application.User;
import at.nanopenguin.mtcg.application.service.schemas.UserCredentials; import at.nanopenguin.mtcg.application.service.schemas.UserCredentials;
import at.nanopenguin.mtcg.application.service.schemas.UserData; 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.HttpMethod;
import at.nanopenguin.mtcg.http.HttpRequest; import at.nanopenguin.mtcg.http.HttpRequest;
import at.nanopenguin.mtcg.http.HttpStatus; import at.nanopenguin.mtcg.http.HttpStatus;
@ -35,7 +33,7 @@ public class UserService implements Service {
return switch (request.getMethod()) { return switch (request.getMethod()) {
case GET -> { case GET -> {
String username = request.getPath().split("/")[2]; 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); yield new Response(HttpStatus.UNAUTHORIZED);
val userData = User.retrieve(username); val userData = User.retrieve(username);
yield userData != null ? yield userData != null ?
@ -49,7 +47,7 @@ public class UserService implements Service {
case PUT -> { case PUT -> {
String username = request.getPath().split("/")[2]; String username = request.getPath().split("/")[2];
UserData userData = new ObjectMapper().readValue(request.getBody(), UserData.class); 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 new Response(HttpStatus.UNAUTHORIZED);
yield User.update(username, userData) ? new Response(HttpStatus.OK) : new Response(HttpStatus.NOT_FOUND); yield User.update(username, userData) ? new Response(HttpStatus.OK) : new Response(HttpStatus.NOT_FOUND);
} }