Skip to content

Commit

Permalink
#194 simple password protection on ipc socket communication
Browse files Browse the repository at this point in the history
  • Loading branch information
Thorsten Marx committed May 16, 2024
1 parent 262bd82 commit f254c59
Show file tree
Hide file tree
Showing 11 changed files with 204 additions and 18 deletions.
46 changes: 46 additions & 0 deletions cms-api/src/main/java/com/github/thmarx/cms/api/IPCProperties.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.github.thmarx.cms.api;

/*-
* #%L
* cms-api
* %%
* Copyright (C) 2023 - 2024 Marx-Software
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/

import java.util.Map;
import java.util.Optional;
import lombok.RequiredArgsConstructor;

/**
* Application Performance Management Properties
*
* @author t.marx
*/
@RequiredArgsConstructor
public class IPCProperties {
private final Map<String, Object> properties;

public int port () {
return (int) properties.getOrDefault("port", 6868);
}

public Optional<String> password () {
return Optional.ofNullable((String)properties.get("password"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public APMProperties apm () {
return new APMProperties(getSubMap("apm"));
}

public int ipc_port () {
return MapUtil.getValue(properties, "ipc.port", 6868);
public IPCProperties ipc () {
return new IPCProperties(getSubMap("ipc"));
}
}
3 changes: 3 additions & 0 deletions cms-server/server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ server:
port: 1010
ip: "127.0.0.1"
env: dev
ipc:
port: 6868
password: test_pwd
apm:
enabled: true
max_requests: 100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public void run() {

var server = new JettyServer(properties);

var ipcServer = new IPCServer(properties.ipc_port(), server::fireServerEvent);
var ipcServer = new IPCServer(properties.ipc(), server::fireServerEvent);
ipcServer.start();

server.startup();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@
import com.github.thmarx.cms.api.Constants;
import com.github.thmarx.cms.api.PropertiesLoader;
import com.github.thmarx.cms.api.ServerProperties;
import com.github.thmarx.cms.ipc.Command;
import com.github.thmarx.cms.ipc.IPCClient;
import com.sun.jdi.Bootstrap;
import com.sun.jdi.VirtualMachine;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
Expand All @@ -52,9 +51,9 @@ public void run() {
System.out.println("can not find cms process");
} else {
ServerProperties properties = PropertiesLoader.serverProperties(Path.of("server.yaml"));
IPCClient ipcClient = new IPCClient(properties.ipc_port());
IPCClient ipcClient = new IPCClient(properties.ipc());

ipcClient.send("shutdown");
ipcClient.send(new Command("shutdown"));

Files.deleteIfExists(Path.of(Constants.PID_FILE));
}
Expand Down
50 changes: 50 additions & 0 deletions cms-server/src/main/java/com/github/thmarx/cms/ipc/Command.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.github.thmarx.cms.ipc;

/*-
* #%L
* cms-server
* %%
* Copyright (C) 2023 - 2024 Marx-Software
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

/**
*
* @author t.marx
*/
@RequiredArgsConstructor
public class Command {

private Map<String, Object> headers = new HashMap<>();

@Getter
public final String command;

public Optional<Object> getHeader (String name) {
return Optional.ofNullable(headers.get(name));
}

public void setHeader (String name, Object value) {
headers.put(name, value);
}
}
22 changes: 17 additions & 5 deletions cms-server/src/main/java/com/github/thmarx/cms/ipc/IPCClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
* #L%
*/

import com.github.thmarx.cms.api.IPCProperties;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Map;
import lombok.RequiredArgsConstructor;

/**
Expand All @@ -33,15 +35,25 @@
@RequiredArgsConstructor
public class IPCClient {

private final int port;
private final IPCProperties properties;

private final IPCCommands IPCCOMMANDS = new IPCCommands();

public void send(String command) throws Exception {
try (Socket kkSocket = new Socket("localhost", port); PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), true);) {
out.write(command);
public void send(Command command) throws Exception {
try (Socket kkSocket = new Socket("localhost", properties.port());
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), true);) {

if (properties.password().isPresent()) {
command.setHeader("ipc.auth", properties.password().get());
}

out.write(IPCCOMMANDS.toJsonString(command));
}
}

public static void main (String...args) throws Exception {
new IPCClient(6868).send("shutdown");
new IPCClient(new IPCProperties(
Map.of("port", 6868, "password", "test_pwd")
)).send(new Command("shutdown"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.github.thmarx.cms.ipc;

/*-
* #%L
* cms-server
* %%
* Copyright (C) 2023 - 2024 Marx-Software
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/

import com.google.gson.Gson;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;

/**
*
* @author t.marx
*/
@Slf4j
public class IPCCommands {

public static final Gson GSON = new Gson();

public Optional<Command> parse (String commandJson) {
try {
return Optional.of(GSON.fromJson(commandJson, Command.class));
} catch (Exception e) {
log.error("", e);
}
return Optional.empty();
}

public String toJsonString (Command command) {
return GSON.toJson(command);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,43 @@
* #L%
*/

import com.github.thmarx.cms.api.IPCProperties;
import com.github.thmarx.cms.api.eventbus.Event;
import com.github.thmarx.cms.api.eventbus.events.lifecycle.ServerShutdownInitiated;
import java.util.function.Consumer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;


@Slf4j
@RequiredArgsConstructor
public class IPCProtocol {

private final Consumer<Event> eventConsumer;

private final IPCProperties properties;

private final IPCCommands ipcCommands = new IPCCommands();

public void processInput(final String theInput) {
if ("shutdown".equals(theInput)) {

var commandOpt = ipcCommands.parse(theInput);
if (commandOpt.isEmpty()) {
return;
}
var command = commandOpt.get();
if (properties.password().isPresent()) {
if (command.getHeader("ipc.auth").isEmpty()) {
log.warn("no ipc.auth header set");
return;
} else if (!command.getHeader("ipc.auth").get().equals(properties.password().get())) {
log.warn("unauthorized ipc call");
return;
}
}


if ("shutdown".equals(command.getCommand())) {
eventConsumer.accept(new ServerShutdownInitiated());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* #L%
*/

import com.github.thmarx.cms.api.IPCProperties;
import com.github.thmarx.cms.api.eventbus.Event;
import java.io.IOException;
import java.net.ServerSocket;
Expand All @@ -35,16 +36,16 @@
@RequiredArgsConstructor
public class IPCServer extends Thread {

private final int port;
private final IPCProperties properties;
private final Consumer<Event> eventConsumer;
boolean listening = true;

@Override
public void run() {

try (ServerSocket serverSocket = new ServerSocket(port)) {
try (ServerSocket serverSocket = new ServerSocket(properties.port())) {
while (listening) {
new IPCServerThread(serverSocket.accept(), eventConsumer).start();
new IPCServerThread(serverSocket.accept(), eventConsumer, properties).start();
}
} catch (IOException e) {
System.exit(-1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* #L%
*/

import com.github.thmarx.cms.api.IPCProperties;
import com.github.thmarx.cms.api.eventbus.Event;
import java.io.BufferedReader;
import java.io.IOException;
Expand All @@ -42,11 +43,11 @@ public class IPCServerThread extends Thread {
private Consumer<Event> eventConsumer;
private IPCProtocol protocol;

public IPCServerThread(Socket socket, Consumer<Event> eventConsumer) {
public IPCServerThread(Socket socket, Consumer<Event> eventConsumer, IPCProperties properties) {
super("IPCServerThread");
this.socket = socket;
this.eventConsumer = eventConsumer;
protocol = new IPCProtocol(eventConsumer);
protocol = new IPCProtocol(eventConsumer, properties);
}

public void run() {
Expand Down

0 comments on commit f254c59

Please sign in to comment.