diff --git a/src/main/java/org/tubes/db/Database.java b/src/main/java/org/tubes/db/Database.java index db1527bd7016da8c9a5cd4a366bd7e892118eba1..a062b08954aa99f191aa57f5268c5f00e41902e5 100644 --- a/src/main/java/org/tubes/db/Database.java +++ b/src/main/java/org/tubes/db/Database.java @@ -3,6 +3,7 @@ package org.tubes.db; import com.zaxxer.hikari.HikariDataSource; import lombok.NonNull; import lombok.var; +import org.tubes.models.Log; import org.tubes.utils.Config; import org.tubes.models.Subscription; @@ -29,6 +30,7 @@ public class Database { try (var con = getConnection(); var stmt = con.createStatement()) { System.out.println(Subscription.getDDL()); stmt.execute(Subscription.getDDL()); + stmt.execute(Log.getDDL()); } catch (SQLException e) { throw new RuntimeException(e); } diff --git a/src/main/java/org/tubes/middlewares/LoggingMiddleware.java b/src/main/java/org/tubes/middlewares/LoggingMiddleware.java new file mode 100644 index 0000000000000000000000000000000000000000..4b844b995846513f861c83aea4ab11e83ee6c66c --- /dev/null +++ b/src/main/java/org/tubes/middlewares/LoggingMiddleware.java @@ -0,0 +1,101 @@ +package org.tubes.middlewares; + +import com.sun.net.httpserver.HttpExchange; +import org.tubes.models.Log; +import org.tubes.repositories.LogRepo; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import javax.annotation.Resource; +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPBody; +import javax.xml.soap.SOAPEnvelope; +import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPPart; +import javax.xml.ws.WebServiceContext; +import javax.xml.ws.handler.MessageContext; +import javax.xml.ws.handler.soap.SOAPHandler; +import javax.xml.ws.handler.soap.SOAPMessageContext; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class LoggingMiddleware implements SOAPHandler<SOAPMessageContext> { + private final String httpExchangeKey = "com.sun.xml.internal.ws.http.exchange"; + + protected void recordClient(String endpoint, String description, String ipAddr) throws SQLException { + System.out.println("Client " + ipAddr + " called " + endpoint + " with description: " + description); + Timestamp ts = new Timestamp(System.currentTimeMillis()); + String s = ts.toString().split("\\.")[0]; + + Log model = new Log(description, ipAddr, endpoint, s); + LogRepo.getInstance().save(model); + } + + private String getRemoteAddr(SOAPMessageContext context) { + HttpExchange httpExchange = (HttpExchange) context.get(this.httpExchangeKey); + System.out.println("remote addr: " + httpExchange.getRemoteAddress()); + return httpExchange.getRemoteAddress().toString().replace("/", ""); + } + + protected String getClient(SOAPMessageContext context) { + return (String) context.get("client"); + } + + @Override + public Set<QName> getHeaders() { + return null; + } + + @Override + public boolean handleMessage(SOAPMessageContext context) { + String client = (String) context.get("authenticated-client"); + Boolean isOutbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); + HttpExchange httpExchange = (HttpExchange) context.get(this.httpExchangeKey); + + if (isOutbound) { + return true; + } + String remoteAddr = getRemoteAddr(context); + String endpoint = httpExchange.getRequestURI().toString(); + + + try { + SOAPPart soapPart = context.getMessage().getSOAPPart(); + SOAPEnvelope soapEnvelope = soapPart.getEnvelope(); + SOAPBody soapBody = soapEnvelope.getBody(); + + Node operation = soapBody.getChildNodes().item(1); + String description = String.format("called %s", operation.getLocalName()); + + NodeList parameters = operation.getChildNodes(); + + for (int i = 1; i < parameters.getLength(); i += 2){ + description = String.format("%s %s(%s)", description, parameters.item(i).getLocalName(), parameters.item(i).getTextContent()); + } + Timestamp ts = new Timestamp(System.currentTimeMillis()); + String s = ts.toString().split("\\.")[0]; + Log model = new Log(description, remoteAddr, endpoint, s); + LogRepo.getInstance().save(model); + + } catch (SOAPException e) { + return false; + } catch (SQLException e) { + throw new RuntimeException(e); + } + return true; + } + + @Override + public boolean handleFault(SOAPMessageContext context) { + return false; + } + + @Override + public void close(MessageContext context) { + + } +} diff --git a/src/main/java/org/tubes/models/Log.java b/src/main/java/org/tubes/models/Log.java new file mode 100644 index 0000000000000000000000000000000000000000..90063b4537b5dde09421856a24ed4ab78e6f1b32 --- /dev/null +++ b/src/main/java/org/tubes/models/Log.java @@ -0,0 +1,38 @@ +package org.tubes.models; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.tubes.models.annotation.Column; +import org.tubes.models.annotation.Table; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "logs") +public class Log extends BaseModel { + @Column("description") + private String description; + @Column("ip") + private String IP; + @Column("endpoint") + private String endpoint; + @Column("requested_at") + private String requested_at; + + + public static String getDDL() { + return String.join( + System.getProperty("line.separator"), + "CREATE TABLE IF NOT EXISTS logs (", + " id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,", + " description TEXT NOT NULL,", + " ip VARCHAR(50) NOT NULL,", + " endpoint VARCHAR(50) NOT NULL,", + " requested_at TIMESTAMP NOT NULL", + ");" + ); + } +} diff --git a/src/main/java/org/tubes/repositories/LogRepo.java b/src/main/java/org/tubes/repositories/LogRepo.java new file mode 100644 index 0000000000000000000000000000000000000000..83dca906034cc44b50ca59c632db23d9606a852f --- /dev/null +++ b/src/main/java/org/tubes/repositories/LogRepo.java @@ -0,0 +1,27 @@ +package org.tubes.repositories; + +import lombok.NonNull; +import lombok.var; +import org.tubes.models.Log; + +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collections; +import java.util.List; + +import org.tubes.db.Database; + +public class LogRepo extends Repository<Log> { + private static LogRepo instance = null; + @Override + public @NonNull Class<Log> getModelClass() { + return Log.class; + } + + public static @NonNull LogRepo getInstance() { + if (instance == null) { + instance = new LogRepo(); + } + return instance; + } +} diff --git a/src/main/java/org/tubes/services/SubscriptionServiceImpl.java b/src/main/java/org/tubes/services/SubscriptionServiceImpl.java index b0d085b345ac875827faf016579de9f48dc10445..cbb6535b9425c41bae17851b10e856a569b9257c 100644 --- a/src/main/java/org/tubes/services/SubscriptionServiceImpl.java +++ b/src/main/java/org/tubes/services/SubscriptionServiceImpl.java @@ -39,6 +39,7 @@ public class SubscriptionServiceImpl implements SubscriptionService { @Override public List<Subscription> getSubscriptions(String email) { + System.out.println("request"); if (email == null) return Collections.emptyList(); return SubscriptionRepo.getInstance().getByEmail(email); } diff --git a/src/main/resources/handler-chain.xml b/src/main/resources/handler-chain.xml index 2e0782fdcc6e613480163b1a343d42ab9f3c5d4b..35090ccc3ea930092e04f1fd150b877769f4b8b5 100644 --- a/src/main/resources/handler-chain.xml +++ b/src/main/resources/handler-chain.xml @@ -4,5 +4,8 @@ <handler> <handler-class>org.tubes.middlewares.ApiKeyMiddleware</handler-class> </handler> + <handler> + <handler-class>org.tubes.middlewares.LoggingMiddleware</handler-class> + </handler> </handler-chain> </handler-chains> \ No newline at end of file