[Minor] Code cleanup, and close session on failed auth

This commit is contained in:
Robert von Burg 2022-05-02 15:19:32 +02:00
parent d60dfc5d3d
commit 9115cc47fe
Signed by: eitch
GPG Key ID: 75DB9C85C74331F7
2 changed files with 45 additions and 57 deletions

View File

@ -4,6 +4,7 @@ import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static li.strolch.plc.model.PlcConstants.*;
import static li.strolch.utils.helper.ExceptionHelper.getExceptionMessageWithCauses;
import static li.strolch.websocket.WebSocketRemoteIp.*;
import javax.websocket.CloseReason;
import javax.websocket.PongMessage;
@ -26,6 +27,7 @@ import li.strolch.model.log.LogMessage;
import li.strolch.model.log.LogMessageState;
import li.strolch.plc.model.*;
import li.strolch.privilege.base.NotAuthenticatedException;
import li.strolch.privilege.base.PrivilegeException;
import li.strolch.privilege.model.Certificate;
import li.strolch.privilege.model.Usage;
import li.strolch.privilege.model.UserRep;
@ -93,6 +95,7 @@ public class PlcGwServerHandler extends StrolchComponent {
this.plcAddressListenersByPlcId.put(plcId, plcListeners);
}
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (plcListeners) {
plcListeners.addElement(addressKey, listener);
}
@ -107,6 +110,7 @@ public class PlcGwServerHandler extends StrolchComponent {
if (plcListeners == null)
return;
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (plcListeners) {
plcListeners.removeElement(addressKey, listener);
}
@ -263,9 +267,8 @@ public class PlcGwServerHandler extends StrolchComponent {
StrolchSessionHandler sessionHandler = getContainer().getComponent(StrolchSessionHandler.class);
sessionHandler.validate(plcSession.certificate);
} catch (RuntimeException e) {
this.plcStateHandler
.handlePlcState(plcSession, ConnectionState.Failed, "Message received although not yet authed!",
null);
this.plcStateHandler.handlePlcState(plcSession, ConnectionState.Failed,
"Message received although not yet authed!", null);
throw new NotAuthenticatedException(sessionId + ": Certificate not valid!", e);
}
@ -281,7 +284,7 @@ public class PlcGwServerHandler extends StrolchComponent {
basic.sendText(data.substring(pos), true);
}
public void onWsMessage(String message, Session session) {
public void onWsMessage(String message, Session session) throws IOException {
JsonObject jsonObject = JsonParser.parseString(message).getAsJsonObject();
if (!jsonObject.has(PARAM_MESSAGE_TYPE))
@ -293,44 +296,19 @@ public class PlcGwServerHandler extends StrolchComponent {
String messageType = jsonObject.get(PARAM_MESSAGE_TYPE).getAsString();
switch (messageType) {
case MSG_TYPE_AUTHENTICATION: {
handleAuth(session.getId(), jsonObject);
break;
}
case MSG_TYPE_STATE_NOTIFICATION: {
PlcSession plcSession = assertPlcAuthed(plcId, session.getId());
handleStateMsg(plcSession, jsonObject);
break;
}
case MSG_TYPE_MESSAGE: {
case MSG_TYPE_AUTHENTICATION -> handleAuth(session, jsonObject);
case MSG_TYPE_PLC_NOTIFICATION -> handleNotification(assertPlcAuthed(plcId, session.getId()), jsonObject);
case MSG_TYPE_PLC_TELEGRAM -> handleTelegramResponse(assertPlcAuthed(plcId, session.getId()), jsonObject);
case MSG_TYPE_STATE_NOTIFICATION -> handleStateMsg(assertPlcAuthed(plcId, session.getId()), jsonObject);
case MSG_TYPE_MESSAGE -> {
assertPlcAuthed(plcId, session.getId());
handleMessage(jsonObject);
break;
}
case MSG_TYPE_DISABLE_MESSAGE: {
case MSG_TYPE_DISABLE_MESSAGE -> {
assertPlcAuthed(plcId, session.getId());
handleDisableMessage(jsonObject);
break;
}
case MSG_TYPE_PLC_NOTIFICATION: {
PlcSession plcSession = assertPlcAuthed(plcId, session.getId());
handleNotification(plcSession, jsonObject);
break;
}
case MSG_TYPE_PLC_TELEGRAM: {
PlcSession plcSession = assertPlcAuthed(plcId, session.getId());
handleTelegramResponse(plcSession, jsonObject);
break;
}
default:
logger.error(plcId + ": Unhandled message type " + messageType);
default -> logger.error(plcId + ": Unhandled message type " + messageType);
}
}
@ -352,8 +330,8 @@ public class PlcGwServerHandler extends StrolchComponent {
logger.info(plcSession.plcId + ": Received notification for " + addressKey.toKey() + ": " + value);
MapOfLists<PlcAddressKey, PlcNotificationListener> plcListeners = this.plcAddressListenersByPlcId
.get(plcSession.plcId);
MapOfLists<PlcAddressKey, PlcNotificationListener> plcListeners = this.plcAddressListenersByPlcId.get(
plcSession.plcId);
if (plcListeners == null) {
logger.warn(plcSession.plcId + ": No listeners for PLC " + plcSession.plcId);
return;
@ -415,11 +393,12 @@ public class PlcGwServerHandler extends StrolchComponent {
operationsLog.updateState(realm, locator, LogMessageState.Inactive);
}
private void handleAuth(String sessionId, JsonObject authJ) {
private void handleAuth(Session session, JsonObject authJ) throws IOException {
String sessionId = session.getId();
if (!authJ.has(PARAM_PLC_ID) || !authJ.has(PARAM_USERNAME) || !authJ.has(PARAM_PASSWORD))
throw new IllegalStateException(
sessionId + ": Auth Json is missing one of " + PARAM_PLC_ID + ", " + PARAM_USERNAME + ", "
+ PARAM_PASSWORD + ": " + authJ.toString());
+ PARAM_PASSWORD + ": " + authJ);
String plcId = authJ.get(PARAM_PLC_ID).getAsString();
String username = authJ.get(PARAM_USERNAME).getAsString();
@ -433,8 +412,16 @@ public class PlcGwServerHandler extends StrolchComponent {
sessionId + ": Auth PlcId " + plcId + " not same as Session's PlcID " + plcSession.plcId);
StrolchSessionHandler sessionHandler = getContainer().getComponent(StrolchSessionHandler.class);
Certificate certificate = sessionHandler
.authenticate(username, password.toCharArray(), WebSocketRemoteIp.get(), Usage.ANY, false);
Certificate certificate;
try {
char[] passwordChars = password.toCharArray();
certificate = sessionHandler.authenticate(username, passwordChars, get(), Usage.ANY, false);
} catch (PrivilegeException e) {
session.close(new CloseReason(CloseReason.CloseCodes.PROTOCOL_ERROR,
"Authentication failed for given credentials!"));
throw e;
}
plcSession.certificate = certificate;
JsonObject authResponseJ = new JsonObject();
@ -462,8 +449,8 @@ public class PlcGwServerHandler extends StrolchComponent {
} catch (Exception e) {
logger.error(plcSession.plcId + ": Failed to send data to PLC", e);
try {
plcSession.session.close(new CloseReason(CloseReason.CloseCodes.CLOSED_ABNORMALLY,
"Failed to send auth response"));
plcSession.session.close(
new CloseReason(CloseReason.CloseCodes.CLOSED_ABNORMALLY, "Failed to send auth response"));
} catch (IOException ex) {
logger.error(plcSession.plcId + ": Faild to close session to PLC");
}
@ -489,14 +476,14 @@ public class PlcGwServerHandler extends StrolchComponent {
PlcSession existingPlcSession = this.plcSessionsByPlcId.put(plcId, plcSession);
if (existingPlcSession != null) {
logger.error("Old PLC session found for plc " + plcId + " under SessionId " + existingPlcSession.session
.getId() + ". Closing that session.");
logger.error("Old PLC session found for plc " + plcId + " under SessionId "
+ existingPlcSession.session.getId() + ". Closing that session.");
this.plcSessionsBySessionId.remove(existingPlcSession.session.getId());
try {
synchronized (existingPlcSession.session) {
existingPlcSession.session
.close(new CloseReason(CloseReason.CloseCodes.NOT_CONSISTENT, "Stale session"));
existingPlcSession.session.close(
new CloseReason(CloseReason.CloseCodes.NOT_CONSISTENT, "Stale session"));
}
} catch (Exception e) {
logger.error("Failed to close session " + existingPlcSession.session.getId(), e);
@ -519,7 +506,7 @@ public class PlcGwServerHandler extends StrolchComponent {
// find all sessions which are timed out
List<PlcSession> expiredSessions = this.plcSessionsBySessionId.values().stream().filter(this::hasExpired)
.collect(toList());
.toList();
for (PlcSession plcSession : expiredSessions) {
logger.warn("Session " + plcSession.session.getId() + " has expired for PLC " + plcSession.plcId
@ -528,8 +515,8 @@ public class PlcGwServerHandler extends StrolchComponent {
// close the session
try {
synchronized (plcSession.session) {
plcSession.session
.close(new CloseReason(CloseReason.CloseCodes.CLOSED_ABNORMALLY, "Session expired!"));
plcSession.session.close(
new CloseReason(CloseReason.CloseCodes.CLOSED_ABNORMALLY, "Session expired!"));
}
} catch (IOException e) {
logger.error("Closing session lead to exception: " + getExceptionMessageWithCauses(e));
@ -552,9 +539,8 @@ public class PlcGwServerHandler extends StrolchComponent {
PlcSession plcSession = this.plcSessionsBySessionId.remove(session.getId());
if (plcSession == null) {
logger.warn(
session.getId() + ": Connection to session " + session.getId() + " is lost due to " + closeReason
.getCloseCode() + " " + closeReason.getReasonPhrase());
logger.warn(session.getId() + ": Connection to session " + session.getId() + " is lost due to "
+ closeReason.getCloseCode() + " " + closeReason.getReasonPhrase());
return;
}
@ -603,8 +589,8 @@ public class PlcGwServerHandler extends StrolchComponent {
}
// then notify any notification observers for disconnected PLCs
MapOfLists<PlcAddressKey, PlcNotificationListener> plcAddressListeners = this.plcAddressListenersByPlcId
.get(plcId);
MapOfLists<PlcAddressKey, PlcNotificationListener> plcAddressListeners = this.plcAddressListenersByPlcId.get(
plcId);
if (plcAddressListeners == null)
return;

View File

@ -3,6 +3,8 @@ package li.strolch.plc.gw.server;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import li.strolch.rest.RestfulStrolchComponent;
@ServerEndpoint("/websocket/strolch/plc")
@ -15,7 +17,7 @@ public class PlcServerWebSocketEndpoint {
}
@OnMessage
public void onMessage(String message, Session session) {
public void onMessage(String message, Session session) throws IOException {
this.serverHandler.onWsMessage(message, session);
}