diff --git a/src/main/java/httpsServer/httpServer/src/annotations/Intercept.java b/src/main/java/httpsServer/httpServer/src/annotations/AllowedVerb.java similarity index 66% rename from src/main/java/httpsServer/httpServer/src/annotations/Intercept.java rename to src/main/java/httpsServer/httpServer/src/annotations/AllowedVerb.java index eecc256..3ce09a0 100644 --- a/src/main/java/httpsServer/httpServer/src/annotations/Intercept.java +++ b/src/main/java/httpsServer/httpServer/src/annotations/AllowedVerb.java @@ -4,6 +4,6 @@ import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -public @interface Intercept { - String allowedMethods() default "GET"; +public @interface AllowedVerb { + String name() default "GET"; } \ No newline at end of file diff --git a/src/main/java/httpsServer/httpServer/src/annotations/OnlyAuthorizedClients.java b/src/main/java/httpsServer/httpServer/src/annotations/OnlyAuthorizedClients.java new file mode 100644 index 0000000..9417e4a --- /dev/null +++ b/src/main/java/httpsServer/httpServer/src/annotations/OnlyAuthorizedClients.java @@ -0,0 +1,11 @@ +package httpsServer.httpServer.src.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface OnlyAuthorizedClients { +} diff --git a/src/main/java/httpsServer/httpServer/src/exceptions/ClientAuthorisationException.java b/src/main/java/httpsServer/httpServer/src/exceptions/ClientAuthorisationException.java new file mode 100644 index 0000000..aeb1b94 --- /dev/null +++ b/src/main/java/httpsServer/httpServer/src/exceptions/ClientAuthorisationException.java @@ -0,0 +1,9 @@ +package httpsServer.httpServer.src.exceptions; + +public class ClientAuthorisationException extends Exception { + + public ClientAuthorisationException(String message) { + super(message); + } + +} diff --git a/src/main/java/httpsServer/httpServer/src/exceptions/NoSuchVerbException.java b/src/main/java/httpsServer/httpServer/src/exceptions/NoSuchVerbException.java new file mode 100644 index 0000000..94d82b7 --- /dev/null +++ b/src/main/java/httpsServer/httpServer/src/exceptions/NoSuchVerbException.java @@ -0,0 +1,9 @@ +package httpsServer.httpServer.src.exceptions; + +public class NoSuchVerbException extends Exception { + + public NoSuchVerbException(String message) { + super(message); + } + +} diff --git a/src/main/java/httpsServer/httpServer/src/handlers/RequestHandler.java b/src/main/java/httpsServer/httpServer/src/handlers/RequestHandler.java index f6dc777..a3de7cc 100644 --- a/src/main/java/httpsServer/httpServer/src/handlers/RequestHandler.java +++ b/src/main/java/httpsServer/httpServer/src/handlers/RequestHandler.java @@ -4,7 +4,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.sun.net.httpserver.HttpExchange; import common.common.src.html.HtmlManager; import common.common.src.logger.Logger; -import httpsServer.httpServer.src.annotations.Intercept; +import httpsServer.httpServer.src.annotations.AllowedVerb; +import httpsServer.httpServer.src.annotations.OnlyAuthorizedClients; import httpsServer.httpServer.src.authorization.AuthorizedClients; import httpsServer.httpServer.src.authorization.Client; @@ -15,7 +16,7 @@ public class RequestHandler implements IRequestHandler { final AuthorizedClients authorizedClients = new AuthorizedClients(); - @Intercept(allowedMethods = "GET") + @AllowedVerb(name = "GET") public void handleRoot(HttpExchange exchange) { try{ respondToGet(exchange, "./assets/pages/index.html"); @@ -24,7 +25,8 @@ public class RequestHandler implements IRequestHandler { } } - @Intercept(allowedMethods = "GET") + @AllowedVerb(name = "GET") + @OnlyAuthorizedClients public void handlePayment(HttpExchange exchange) { Logger.displayReceived("/payment request"); try{ @@ -34,7 +36,7 @@ public class RequestHandler implements IRequestHandler { } } - @Intercept(allowedMethods = "POST") + @AllowedVerb(name = "POST") public void handleLogin(HttpExchange exchange) { try { InputStream is = exchange.getRequestBody(); @@ -58,6 +60,7 @@ public class RequestHandler implements IRequestHandler { e.printStackTrace(); } } + private void respondToGet(HttpExchange exchange, String pagePath) throws IOException { try{ diff --git a/src/main/java/httpsServer/httpServer/src/interceptors/RequestInterceptor.java b/src/main/java/httpsServer/httpServer/src/interceptors/RequestInterceptor.java index 1a872cc..1efe553 100644 --- a/src/main/java/httpsServer/httpServer/src/interceptors/RequestInterceptor.java +++ b/src/main/java/httpsServer/httpServer/src/interceptors/RequestInterceptor.java @@ -1,45 +1,82 @@ package httpsServer.httpServer.src.interceptors; +import com.fasterxml.jackson.databind.ObjectMapper; import com.sun.net.httpserver.HttpExchange; -import common.common.src.logger.Logger; -import httpsServer.httpServer.src.annotations.Intercept; +import httpsServer.httpServer.src.annotations.AllowedVerb; +import httpsServer.httpServer.src.annotations.OnlyAuthorizedClients; +import httpsServer.httpServer.src.authorization.AuthorizedClients; +import httpsServer.httpServer.src.authorization.Client; +import httpsServer.httpServer.src.exceptions.NoSuchVerbException; +import httpsServer.httpServer.src.exceptions.ClientAuthorisationException; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.lang.reflect.*; +import java.nio.Buffer; +import java.nio.charset.StandardCharsets; public class RequestInterceptor implements InvocationHandler { + private final AuthorizedClients authorizedClients; + private final ObjectMapper mapper; private final Object target; public RequestInterceptor(Object target) { + authorizedClients = new AuthorizedClients(); + mapper = new ObjectMapper(); this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + HttpExchange exchange = (HttpExchange) args[0]; + try{ + Method realMethod = target.getClass().getMethod(method.getName(), method.getParameterTypes()); - Method realMethod = target.getClass().getMethod(method.getName(), method.getParameterTypes()); - if (!realMethod.isAnnotationPresent(Intercept.class)) return null; + checkAuthorizedVerb(realMethod, exchange.getRequestMethod()); + //String a = exchange.getRequestHeaders().getFirst("Header-Name"); + checkAuthorizedClient(realMethod, exchange.getRequestBody()); - Logger.displayReceived("/ request"); - - HttpExchange exchange = (HttpExchange)args[0]; - - Intercept annotation = realMethod.getAnnotation(Intercept.class); - String allowedVerb = annotation.allowedMethods(); - String receivedVerb = exchange.getRequestMethod(); - - if(isAuthorizedVerb(allowedVerb, receivedVerb)) { return method.invoke(target, args); - } else { - exchange.sendResponseHeaders(405, -1); - exchange.getResponseBody().close(); + + } catch (NoSuchVerbException e) { + closeExchangeWithCode(exchange, 405); + return null; + } catch (ClientAuthorisationException e) { + closeExchangeWithCode(exchange, 401); return null; } - } - private boolean isAuthorizedVerb(String baseVerb, String receivedVerb) { - return baseVerb.equalsIgnoreCase(receivedVerb); + private void closeExchangeWithCode(HttpExchange exchange, int httpCode) throws IOException { + exchange.sendResponseHeaders(httpCode, -1); + exchange.getResponseBody().close(); } + private void checkAuthorizedVerb(Method method, String receivedVerb) throws NoSuchVerbException { + if (!method.isAnnotationPresent(AllowedVerb.class)) return; + + String allowedVerb = method.getAnnotation(AllowedVerb.class).name(); + if(!allowedVerb.equalsIgnoreCase(receivedVerb)){ + throw new NoSuchVerbException("HTTP verb not allowed"); + } + } + + private void checkAuthorizedClient(Method method, InputStream data) throws ClientAuthorisationException { + if (!method.isAnnotationPresent(OnlyAuthorizedClients.class)) return; + + Client client = null; + try(BufferedReader reader = new BufferedReader(new InputStreamReader(data, StandardCharsets.UTF_8))){ + String body = reader.lines().reduce("", (acc, line) -> acc + line + "\n"); + client = mapper.readValue(body, Client.class); + } catch (IOException e){ + throw new ClientAuthorisationException("Unable to read body"); + } + + if(!authorizedClients.isAuthorized(client)){ + throw new ClientAuthorisationException("Client not authorized"); + } + } }