diff --git a/.idea/workspace.xml b/.idea/workspace.xml index d8d2e07ce9a3a1c62f00c4e62e3cab8955029503..3d8eb8dd50765ff490ea0a49d6b841d552aa82c6 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -6,10 +6,16 @@ <component name="ChangeListManager"> <list default="true" id="8522785e-cde9-49a6-ad14-9d935d110316" name="Changes" comment=""> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/Dockerfile" beforeDir="false" /> - <change beforePath="$PROJECT_DIR$/src/main/java/com/example/jaxw/HelloServlet.java" beforeDir="false" /> - <change beforePath="$PROJECT_DIR$/src/main/java/com/example/jaxw/Main.java" beforeDir="false" /> - <change beforePath="$PROJECT_DIR$/src/main/java/com/example/jaxw/TestingService.java" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/docker-compose.yml" beforeDir="false" afterPath="$PROJECT_DIR$/docker-compose.yml" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/pom.xml" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/src/main/java/com/gymtracker/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/gymtracker/Main.java" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/src/main/java/com/gymtracker/controllers/GenerateAPIKeyController.java" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/main/java/com/gymtracker/example/TestingService.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/gymtracker/example/TestingService.java" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/src/main/java/com/gymtracker/middleware/APIKeyValidator.java" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/main/resources/META-INF/beans.xml" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/main/resources/META-INF/persistence.xml" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/main/webapp/WEB-INF/web.xml" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/main/webapp/index.jsp" beforeDir="false" /> </list> <option name="SHOW_DIALOG" value="false" /> <option name="HIGHLIGHT_CONFLICTS" value="true" /> @@ -19,6 +25,7 @@ <component name="FileTemplateManagerImpl"> <option name="RECENT_TEMPLATES"> <list> + <option value="FxmlFile" /> <option value="Class" /> </list> </option> @@ -29,6 +36,14 @@ <component name="MarkdownSettingsMigration"> <option name="stateVersion" value="1" /> </component> + <component name="MavenImportPreferences"> + <option name="generalSettings"> + <MavenGeneralSettings> + <option name="mavenHome" value="Use Maven wrapper" /> + <option name="useMavenConfig" value="true" /> + </MavenGeneralSettings> + </option> + </component> <component name="ProjectColorInfo">{ "associatedIndex": 4 }</component> diff --git a/src/main/java/com/gymtracker/Main.java b/src/main/java/com/gymtracker/Main.java index 6e026629bb51f82c1ccb1835406626aeaeb02f2f..58ea50e5f17539cb1ced33fe97c1e0affb695bda 100644 --- a/src/main/java/com/gymtracker/Main.java +++ b/src/main/java/com/gymtracker/Main.java @@ -1,15 +1,13 @@ -package src.main.java.com.gymtracker; +package com.gymtracker; -import src.main.java.com.gymtracker.example.TestingService; -import src.main.java.com.gymtracker.controllers.GenerateAPIKeyController; +import com.gymtracker.example.TestingService; import javax.xml.ws.Endpoint; public class Main { public static void main(String[] args) { try { - Endpoint.publish("http://localhost:3001/ws/testing", new TestingService()); - Endpoint.publish("http://localhost:3001/ws/generate-api-key", new GenerateAPIKeyController()); + Endpoint.publish("http://0.0.0.0:3001/ws/testing", new TestingService()); System.out.println("Server started"); } catch (Exception e) { System.out.println("Something's wrong"); diff --git a/src/main/java/com/gymtracker/database/Database.java b/src/main/java/com/gymtracker/database/Database.java new file mode 100644 index 0000000000000000000000000000000000000000..728efac1f37cd213cb44f8347d3b37f7dcbb51fd --- /dev/null +++ b/src/main/java/com/gymtracker/database/Database.java @@ -0,0 +1,48 @@ +package com.gymtracker.database; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; +import java.sql.SQLException; + +import io.github.cdimascio.dotenv.Dotenv; + +public class Database { + private static Connection connection = null; + + public static Connection getConnection() throws SQLException { + if(connection == null) { + try { + Dotenv dotenv = Dotenv.configure().directory("/").load(); + + String name = dotenv.get("MYSQL_DATABASE"); + String port = dotenv.get("MYSQL_TCP_PORT"); + String username = dotenv.get("MYSQL_USER"); + String password = dotenv.get("MYSQL_ROOT_PASSWORD"); + + String url = "jdbc:mysql://db-java:" + port + "/" + name; + connection = DriverManager.getConnection(url, username, password); + } catch(SQLException e) { + throw new SQLException("Error establishing database connection", e); + } + } + return connection; + } + + public static ResultSet executeQuery(String query) throws SQLException { + try (Statement statement = getConnection().createStatement()) { + return statement.executeQuery(query); + } catch(SQLException e) { + throw new SQLException("Error executing query: " + query, e); + } + } + + public static int executeUpdate(String query) throws SQLException { + try (Statement statement = getConnection().createStatement()) { + return statement.executeUpdate(query); + } catch(SQLException e) { + throw new SQLException("Error executing update: " + query, e); + } + } +} diff --git a/src/main/java/com/gymtracker/example/TestingService.java b/src/main/java/com/gymtracker/example/TestingService.java index b7f483db714c32156647c4e1e7c738eb0679d001..49b0076280889dfcea22f9ebc8f6520440a64b71 100644 --- a/src/main/java/com/gymtracker/example/TestingService.java +++ b/src/main/java/com/gymtracker/example/TestingService.java @@ -1,23 +1,21 @@ -package src.main.java.com.gymtracker.example; +package com.gymtracker.example; -import src.main.java.com.gymtracker.middleware.APIKeyValidator; +import com.gymtracker.database.Database; +import javax.jws.HandlerChain; import javax.jws.WebMethod; import javax.jws.WebService; import javax.xml.ws.WebServiceContext; import javax.annotation.Resource; +import java.sql.SQLException; @WebService -public class TestingService extends APIKeyValidator { +@HandlerChain(file = "log_and_auth.xml") +public class TestingService { @Resource WebServiceContext wsContext; @WebMethod - public String HelloWorld(String name) { - if(verifyAPIKey(wsContext)) { - return "Hello " + name; - } - else { - return "Your key is wrong!"; - } + public String Test() { + return "Test successful"; } } diff --git a/src/main/java/com/gymtracker/handler/LogAuthHandler.java b/src/main/java/com/gymtracker/handler/LogAuthHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..6743135c5bc7fe62c60b5f40e6b8a181904b494a --- /dev/null +++ b/src/main/java/com/gymtracker/handler/LogAuthHandler.java @@ -0,0 +1,103 @@ +package com.gymtracker.handler; + +import com.gymtracker.util.Util; +import com.gymtracker.model.Logging; +import io.github.cdimascio.dotenv.Dotenv; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPBody; +import javax.xml.soap.SOAPMessage; +import javax.xml.ws.handler.MessageContext; +import javax.xml.ws.handler.soap.SOAPHandler; +import javax.xml.ws.handler.soap.SOAPMessageContext; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class LogAuthHandler implements SOAPHandler<SOAPMessageContext> { + @Override + public Set<QName> getHeaders() { + return null; + } + + @Override + public void close(MessageContext mc) { + } + + public boolean handleFault(SOAPMessageContext smc) { + return true; + } + + public boolean handleMessage(SOAPMessageContext smc) { + Boolean outbound = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); + if (!outbound) { + boolean authorized = authorize(smc); + log(smc, authorized); + } + return true; + } + + private boolean authorize(SOAPMessageContext smc) { + try { + @SuppressWarnings("unchecked") + Map<String, List<?>> httpHeaders = (Map<String, List<?>>) smc.get(MessageContext.HTTP_REQUEST_HEADERS); + Dotenv dotenv = Dotenv.configure().directory("/").load(); + + if (httpHeaders.containsKey("Authorization")) { + String token = (String) httpHeaders.get("Authorization").get(0); + + String phpKey = dotenv.get("PHP_KEY"); + String nodeKey = dotenv.get("NODE_KEY"); + + return token.equals(phpKey) || token.equals(nodeKey); + } + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + private void log(SOAPMessageContext smc, boolean authorized) { + try { + StringBuilder description = new StringBuilder(); + + if(authorized) { + @SuppressWarnings("unchecked") + Map<String, List<?>> httpHeaders = (Map<String, List<?>>) smc.get(MessageContext.HTTP_REQUEST_HEADERS); + Dotenv dotenv = Dotenv.configure().directory("/").load(); + String token = (String) httpHeaders.get("Authorization").get(0); + String phpKey = dotenv.get("PHP_KEY"); + + description.append("Authorized access: "); + String caller = token.equals(phpKey) ? "PHP" : "Node"; + description.append(caller).append(" call to "); + + QName operation = (QName) smc.get(MessageContext.WSDL_OPERATION); + description.append(operation.getLocalPart()); + + SOAPMessage soapMessage = smc.getMessage(); + SOAPBody soapBody = soapMessage.getSOAPBody(); + String bodyContent = soapBody.getTextContent(); + + description.append(" with body: "); + description.append(bodyContent); + + } else { + description.append("Unauthorized access: Tried to call "); + QName operation = (QName) smc.get(MessageContext.WSDL_OPERATION); + description.append(operation.getLocalPart()); + + SOAPMessage soapMessage = smc.getMessage(); + SOAPBody soapBody = soapMessage.getSOAPBody(); + String bodyContent = soapBody.getTextContent(); + + description.append(" with body: "); + description.append(bodyContent); + } + Logging log = new Logging(Util.getIP(smc), Util.getURL(smc), description.toString()); + log.insert(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/gymtracker/model/Application.java b/src/main/java/com/gymtracker/model/Application.java new file mode 100644 index 0000000000000000000000000000000000000000..95ac3772819a461720ac14c720fded0ae2eeb8df --- /dev/null +++ b/src/main/java/com/gymtracker/model/Application.java @@ -0,0 +1,91 @@ +package com.gymtracker.model; + +import com.gymtracker.database.Database; + +import java.lang.reflect.Field; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.List; + +public class Application { + private String username; + private Integer gym_id; + private Boolean acceptance; + private String trainer_name; + private String trainer_description; + private String application_description; + + public Application() { + this.username = ""; + this.gym_id = 0; + this.acceptance = Boolean.FALSE; + this.trainer_name = ""; + this.trainer_description = ""; + this.application_description = ""; + } + + public Application(String username, Integer gym_id, Boolean acceptance, String trainer_name, String trainer_description, String application_description) { + this.username = username; + this.gym_id = gym_id; + this.acceptance = acceptance; + this.trainer_name = trainer_name; + this.trainer_description = trainer_description; + this.application_description = application_description; + } + + private static List<Application> toList(ResultSet resultSet) { + try { + Class<Application> clazz = Application.class; + + List<Application> list = new ArrayList<Application>(); + while (resultSet.next()) { + Application instance = clazz.newInstance(); + for (Field field : clazz.getDeclaredFields()) { + field.setAccessible(true); + field.set(instance, resultSet.getObject(field.getName())); + } + list.add(instance); + } + + return list; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + public static List<Application> getAll() { + try { + String query = "SELECT * FROM application"; + ResultSet resultSet = Database.executeQuery(query); + return toList(resultSet); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static Application findByUsername(String username) { + try { + String query = "SELECT * FROM application WHERE `username` = " + username; + ResultSet resultSet = Database.executeQuery(query); + return (Application) toList(resultSet).get(0); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static Application findByGymID(Integer gym_id) { + try { + String query = "SELECT * FROM application WHERE `gym_id` = " + gym_id; + ResultSet resultSet = Database.executeQuery(query); + return (Application) toList(resultSet).get(0); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + +} diff --git a/src/main/java/com/gymtracker/model/Logging.java b/src/main/java/com/gymtracker/model/Logging.java new file mode 100644 index 0000000000000000000000000000000000000000..f061d1aa6319d5e0de6aa088d9f2b7abd5bd3ebf --- /dev/null +++ b/src/main/java/com/gymtracker/model/Logging.java @@ -0,0 +1,36 @@ +package com.gymtracker.model; + +import com.gymtracker.database.Database; + +import java.sql.SQLException; +import java.sql.Timestamp; + +public class Logging { + private String ip; + private Timestamp timestamp; + private String endpoint; + private String description; + + public Logging(String ip, String endpoint, String description) { + this.ip = ip; + this.timestamp = new Timestamp(System.currentTimeMillis()); + this.endpoint = endpoint; + this.description = description; + } + + public int insert() { + try { + StringBuilder query = new StringBuilder("INSERT INTO logging "); + query.append("(ip_address,timestamp,endpoint,request_description) VALUES("); + query.append("'").append(this.ip).append("',"); + query.append("'").append(this.timestamp).append("',"); + query.append("'").append(this.endpoint).append("',"); + query.append("'").append(this.description).append("');"); + + return Database.executeUpdate(query.toString()); + } catch (SQLException e) { + e.printStackTrace(); + } + return 0; + } +} diff --git a/src/main/java/com/gymtracker/util/Util.java b/src/main/java/com/gymtracker/util/Util.java new file mode 100644 index 0000000000000000000000000000000000000000..a764a59bf2b89b430bb29d044cd2656dba727c9c --- /dev/null +++ b/src/main/java/com/gymtracker/util/Util.java @@ -0,0 +1,38 @@ +package com.gymtracker.util; + +import javax.xml.ws.handler.MessageContext; +import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import java.net.URI; + +public class Util { + public static String getIP(MessageContext mc) { + try { + Class<?> clazz = mc.get("com.sun.xml.internal.ws.http.exchange").getClass(); + Method method = clazz.getDeclaredMethod("getRemoteAddress"); + method.setAccessible(true); + + InetSocketAddress address = (InetSocketAddress) method + .invoke(mc.get("com.sun.xml.internal.ws.http.exchange")); + return address.getAddress().getHostAddress(); + } + catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + public static String getURL(MessageContext mc) { + try { + Class<?> clazz = mc.get("com.sun.xml.internal.ws.http.exchange").getClass(); + Method method = clazz.getDeclaredMethod("getRequestURI"); + method.setAccessible(true); + + URI uri = (URI) method.invoke(mc.get("com.sun.xml.internal.ws.http.exchange")); + return uri.toString(); + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } +} diff --git a/src/main/resources/log_and_auth.xml b/src/main/resources/log_and_auth.xml new file mode 100644 index 0000000000000000000000000000000000000000..7558c3d9f3491d38fdd1ffbe1ea7a00b4c8ad6c8 --- /dev/null +++ b/src/main/resources/log_and_auth.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<handler-chains xmlns="http://java.sun.com/xml/ns/javaee"> + <handler-chain> + <handler> + <handler-class>com.gymtracker.handler.LogAuthHandler</handler-class> + </handler> + </handler-chain> +</handler-chains> \ No newline at end of file