com.newrelic.agent.security.intcodeagent.controlcommand.ControlCommandProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of newrelic-security-agent Show documentation
Show all versions of newrelic-security-agent Show documentation
The New Relic Security Java agent module for full-stack security. To be used in newrelic-java-agent only.
The newest version!
package com.newrelic.agent.security.intcodeagent.controlcommand;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.newrelic.agent.security.AgentInfo;
import com.newrelic.agent.security.instrumentator.httpclient.IASTDataTransferRequestProcessor;
import com.newrelic.agent.security.instrumentator.httpclient.RestRequestProcessor;
import com.newrelic.agent.security.instrumentator.httpclient.RestRequestThreadPool;
import com.newrelic.agent.security.instrumentator.utils.AgentUtils;
import com.newrelic.agent.security.instrumentator.utils.InstrumentationUtils;
import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool;
import com.newrelic.api.agent.NewRelic;
import com.newrelic.api.agent.security.utils.logging.LogLevel;
import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants;
import com.newrelic.agent.security.intcodeagent.models.config.AgentPolicyParameters;
import com.newrelic.agent.security.intcodeagent.models.javaagent.EventResponse;
import com.newrelic.agent.security.intcodeagent.models.javaagent.IntCodeControlCommand;
import com.newrelic.agent.security.intcodeagent.websocket.EventSendPool;
import com.newrelic.agent.security.intcodeagent.websocket.JsonConverter;
import com.newrelic.agent.security.intcodeagent.websocket.WSClient;
import com.newrelic.agent.security.intcodeagent.websocket.WSUtils;
import com.newrelic.api.agent.security.NewRelicSecurity;
import com.newrelic.api.agent.security.instrumentation.helpers.GrpcClientRequestReplayHelper;
import com.newrelic.api.agent.security.schema.policy.AgentPolicy;
import org.apache.commons.lang3.StringUtils;
import org.java_websocket.framing.CloseFrame;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
public class ControlCommandProcessor implements Runnable {
private static final String COLLECTOR_IS_INITIALIZED_WITH_PROPERTIES = "Collector is initialized with properties : %s";
public static final JSONParser PARSER = new JSONParser();
public static final String EVENT_RESPONSE_ENTRY_NOT_FOUND_FOR_THIS_S = "Event response entry not found for this : %s";
public static final String EVENT_RESPONSE_TIME_TAKEN = "Event response time taken : ";
public static final String DOUBLE_COLON_SEPERATOR = " :: ";
public static final String FAILED_TO_CREATE_VULNERABLE_API_ENTRY = "Failed to create vulnerableAPI entry : ";
public static final String EVENT_RESPONSE = "Event response : ";
public static final String UNKNOWN_CONTROL_COMMAND_S = "Unknown control command : %s";
public static final String SETTING_NEW_IP_BLOCKING_TIMEOUT_TO_S_MS = "Setting new IP Blocking timeout to %s ms";
public static final String ATTACKED_API_BLOCKED_S = "Attacked API added to blocked list : %s";
public static final String ADDING_IP_ADDRESS_S_TO_BLOCKING_LIST_WITH_TIMEOUT_S = "Adding IP address %s to blocking list with timeout %s";
public static final String ERROR_IN_EVENT_RESPONSE = "Error in EVENT_RESPONSE : ";
public static final String FUZZ_REQUEST = "Fuzz request : ";
public static final String POLICY_PARAMETERS_ARE_UPDATED_TO_S = "Policy parameters are updated to : %s";
public static final String UPDATED_POLICY_FAILED_VALIDATION_REVERTING_TO_DEFAULT_POLICY_FOR_THE_MODE = "Updated policy failed validation. Reverting to default policy for the mode";
public static final String ERROR_WHILE_PROCESSING_RECONNECTION_CC_S_S = "Error while processing reconnection CC : %s : %s";
public static final String ERROR_WHILE_PROCESSING_RECONNECTION_CC = "Error while processing reconnection CC :";
public static final String ERROR_WHILE_PROCESSING_RECONNECTION_CC_ID = "Error while processing reconnection CC : %s";
public static final String UNABLE_TO_PARSE_RECEIVED_DEFAULT_POLICY = "Unable to parse received default policy : ";
public static final String ERROR_IN_CONTROL_COMMAND_PROCESSOR = "Error in controlCommandProcessor : ";
public static final String ARGUMENTS = "arguments";
public static final String DATA = "data";
public static final String CONTROL_COMMAND = "controlCommand";
public static final String REFLECTED_METADATA = "reflectedMetaData";
public static final String RECEIVED_WS_RECONNECT_COMMAND_FROM_SERVER_INITIATING_SEQUENCE = "Received WS 'reconnect' command from server. Initiating sequence.";
public static final String WS_RECONNECT_EVENT_SEND_POOL_DRAINED = "[WS RECONNECT] EventSend pool drained.";
public static final String WS_RECONNECT_IAST_REQUEST_REPLAY_POOL_DRAINED = "[WS RECONNECT] IAST request replay pool drained.";
public static final String ID = "id";
public static final String RECEIVED_IAST_COOLDOWN_WAITING_TILL_S = "Received IAST cooldown. Waiting for next : %s Seconds";
public static final String PURGING_CONFIRMED_IAST_PROCESSED_RECORDS_COUNT_S = "Purging confirmed IAST processed records count : %s";
public static final String PURGING_CONFIRMED_IAST_PROCESSED_RECORDS_S = "Purging confirmed IAST processed records : %s";
private String controlCommandMessage;
private long receiveTimestamp;
private static Instant iastReplayRequestMsgReceiveTime = Instant.now();
private static final FileLoggerThreadPool logger = FileLoggerThreadPool.getInstance();
public ControlCommandProcessor(String controlCommandMessage, long receiveTimestamp) {
this.controlCommandMessage = controlCommandMessage;
this.receiveTimestamp = receiveTimestamp;
}
@Override
public void run() {
if (StringUtils.isBlank(controlCommandMessage)) {
return;
}
IntCodeControlCommand controlCommand = null;
try {
JSONObject object = (JSONObject) PARSER.parse(controlCommandMessage);
controlCommand = new IntCodeControlCommand();
if(object.get(ID) != null) {
controlCommand.setId(object.get(ID).toString());
}
controlCommand.setArguments((List) object.get(ARGUMENTS));
controlCommand.setData(object.get(DATA));
controlCommand.setControlCommand(Integer.valueOf(object.get(CONTROL_COMMAND).toString()));
controlCommand.setReflectedMetaData((Map) object.get(REFLECTED_METADATA));
} catch (Throwable e) {
logger.log(LogLevel.SEVERE, ERROR_IN_CONTROL_COMMAND_PROCESSOR, e,
ControlCommandProcessor.class.getSimpleName());
logger.postLogMessageIfNecessary(LogLevel.WARNING,
ERROR_IN_CONTROL_COMMAND_PROCESSOR,
e, this.getClass().getName());
return;
}
switch (controlCommand.getControlCommand()) {
case IntCodeControlCommand.SHUTDOWN_LANGUAGE_AGENT:
InstrumentationUtils.shutdownLogic();
break;
case IntCodeControlCommand.UNSUPPORTED_AGENT:
logger.log(LogLevel.SEVERE, controlCommand.getArguments().get(0),
ControlCommandProcessor.class.getSimpleName());
NewRelic.noticeError("Incompatible New Relic Security Agent: " + controlCommand.getArguments().get(0), true);
System.err.println(controlCommand.getArguments().get(0));
NewRelic.getAgent().getLogger().log(Level.SEVERE, controlCommand.getArguments().get(0));
InstrumentationUtils.shutdownLogic();
break;
case IntCodeControlCommand.SEND_POLICY_PARAMETERS:
if (controlCommand.getData() == null) {
return;
}
try {
AgentPolicyParameters parameters = JsonConverter.getObjectMapper()
.readValue(controlCommand.getData().toString(), AgentPolicyParameters.class);
AgentUtils.getInstance().setAgentPolicyParameters(parameters);
logger.logInit(LogLevel.INFO,
String.format(IAgentConstants.AGENT_POLICY_PARAM_APPLIED_S, AgentUtils.getInstance().getAgentPolicyParameters()),
ControlCommandProcessor.class.getName());
} catch (JsonProcessingException e) {
logger.logInit(LogLevel.FINER, IAgentConstants.UNABLE_TO_SET_AGENT_POLICY_PARAM_DUE_TO_ERROR, e,
ControlCommandProcessor.class.getName());
}
break;
case IntCodeControlCommand.EVENT_RESPONSE:
boolean cleanUp = false;
try {
EventResponse receivedEventResponse = JsonConverter.getObjectMapper().readValue(controlCommand.getArguments().get(0),
EventResponse.class);
EventResponse eventResponse = AgentUtils.getInstance().getEventResponseSet()
.get(receivedEventResponse.getId());
if (eventResponse == null) {
logger.log(LogLevel.FINER,
String.format(EVENT_RESPONSE_ENTRY_NOT_FOUND_FOR_THIS_S, receivedEventResponse),
ControlCommandProcessor.class.getSimpleName());
cleanUp = true;
} else {
receivedEventResponse.setResponseSemaphore(eventResponse.getResponseSemaphore());
}
AgentUtils.getInstance().getEventResponseSet().put(receivedEventResponse.getId(),
receivedEventResponse);
logger.log(LogLevel.FINER, EVENT_RESPONSE + receivedEventResponse,
ControlCommandProcessor.class.getName());
receivedEventResponse.getResponseSemaphore().release();
if (cleanUp) {
AgentUtils.getInstance().getEventResponseSet().remove(receivedEventResponse.getId());
}
} catch (Exception e) {
logger.log(LogLevel.SEVERE, ERROR_IN_EVENT_RESPONSE, e, ControlCommandProcessor.class.getSimpleName());
}
break;
case IntCodeControlCommand.FUZZ_REQUEST:
AgentInfo.getInstance().getJaHealthCheck().getIastReplayRequest().incrementReceivedControlCommands();
logger.log(LogLevel.FINER, FUZZ_REQUEST + controlCommandMessage,
ControlCommandProcessor.class.getName());
iastReplayRequestMsgReceiveTime = Instant.now();
IASTDataTransferRequestProcessor.getInstance().setLastFuzzCCTimestamp(Instant.now().toEpochMilli());
RestRequestProcessor.processControlCommand(controlCommand);
if(ControlCommandProcessorThreadPool.getInstance().getScanStartTime() <= 0) {
ControlCommandProcessorThreadPool.getInstance().setScanStartTime(Instant.now().toEpochMilli());
AgentInfo.getInstance().getJaHealthCheck().setScanStartTime(ControlCommandProcessorThreadPool.getInstance().getScanStartTime());
}
break;
case IntCodeControlCommand.STARTUP_WELCOME_MSG:
if (controlCommand.getData() == null) {
return;
}
logger.log(LogLevel.INFO,
String.format(COLLECTOR_IS_INITIALIZED_WITH_PROPERTIES, controlCommand.getData()),
ControlCommandProcessor.class.getName());
break;
case IntCodeControlCommand.SEND_POLICY:
if (controlCommand.getData() == null) {
return;
}
try {
AgentPolicy policy = JsonConverter.getObjectMapper().convertValue(controlCommand.getData(), AgentPolicy.class);
logger.logInit(LogLevel.INFO,
String.format(IAgentConstants.RECEIVED_AGENT_POLICY, JsonConverter.toJSON(policy)),
AgentUtils.class.getName());
AgentUtils.getInstance().setDefaultAgentPolicy(policy);
if (AgentUtils.applyPolicy(policy)) {
AgentUtils.getInstance().applyPolicyOverrideIfApplicable();
}
} catch (IllegalArgumentException e) {
logger.log(LogLevel.SEVERE, UNABLE_TO_PARSE_RECEIVED_DEFAULT_POLICY, e,
ControlCommandProcessor.class.getName());
}
break;
case IntCodeControlCommand.POLICY_UPDATE_FAILED_DUE_TO_VALIDATION_ERROR:
logger.log(LogLevel.WARNING, UPDATED_POLICY_FAILED_VALIDATION_REVERTING_TO_DEFAULT_POLICY_FOR_THE_MODE,
ControlCommandProcessor.class.getName());
AgentUtils.instantiateDefaultPolicy();
break;
case IntCodeControlCommand.RECONNECT_AT_WILL:
/* This is only when we have IastScan enabled
* 1. Mark LC in reconnecting phase
* 2. Let IAST request processor ideal out.
* 3. Mark LC in inactive state by disconnecting WS connection.
* 4. Initiate WS reconnect
*
* Post reconnect: reset 'reconnecting phase' in WSClient.
*/
try {
AgentInfo.getInstance().getJaHealthCheck().getWebSocketConnectionStats().incrementReceivedReconnectAtWill();
WSUtils.getInstance().setReconnecting(true);
//TODO no need for draining IAST since last leg has complete ledger.
logger.log(LogLevel.INFO, RECEIVED_WS_RECONNECT_COMMAND_FROM_SERVER_INITIATING_SEQUENCE, this.getClass().getName());
WSClient.getInstance().close(CloseFrame.SERVICE_RESTART, "Reconnecting to service");
} catch (Throwable e) {
logger.log(LogLevel.SEVERE, String.format(ERROR_WHILE_PROCESSING_RECONNECTION_CC_S_S, e.getMessage(), e.getCause()), this.getClass().getName());
logger.log(LogLevel.SEVERE, ERROR_WHILE_PROCESSING_RECONNECTION_CC, e, this.getClass().getName());
logger.postLogMessageIfNecessary(LogLevel.SEVERE, String.format(ERROR_WHILE_PROCESSING_RECONNECTION_CC_ID, controlCommand.getId()), e,
this.getClass().getName());
}
break;
case IntCodeControlCommand.ENTER_IAST_COOLDOWN:
if(controlCommand.getData() instanceof Long) {
long sleepTill = Instant.now().plus((Long) controlCommand.getData(),
ChronoUnit.SECONDS).toEpochMilli();
IASTDataTransferRequestProcessor.getInstance().setCooldownTillTimestamp(sleepTill);
logger.log(LogLevel.INFO, String.format(RECEIVED_IAST_COOLDOWN_WAITING_TILL_S, controlCommand.getData()),
this.getClass().getName());
}
break;
case IntCodeControlCommand.IAST_RECORD_DELETE_CONFIRMATION:
logger.log(LogLevel.FINE, String.format(PURGING_CONFIRMED_IAST_PROCESSED_RECORDS_COUNT_S,
controlCommand.getArguments().size()), this.getClass().getName());
logger.log(LogLevel.FINEST, String.format(PURGING_CONFIRMED_IAST_PROCESSED_RECORDS_S,
controlCommand.getArguments()), this.getClass().getName());
controlCommand.getArguments().forEach(RestRequestThreadPool.getInstance().getProcessedIds()::remove);
controlCommand.getArguments().forEach(GrpcClientRequestReplayHelper.getInstance().getProcessedIds()::remove);
break;
default:
logger.log(LogLevel.WARNING, String.format(UNKNOWN_CONTROL_COMMAND_S, controlCommandMessage),
ControlCommandProcessor.class.getName());
break;
}
}
public static void processControlCommand(String controlCommandMessage, long receiveTimestamp) {
ControlCommandProcessorThreadPool.getInstance().executor
.submit(new ControlCommandProcessor(controlCommandMessage, receiveTimestamp));
}
public static Instant getIastReplayRequestMsgReceiveTime() {
return iastReplayRequestMsgReceiveTime;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy