diff --git a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/InspectitAgentExtension.java b/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/InspectitAgentExtension.java index 857eadb..27f422d 100644 --- a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/InspectitAgentExtension.java +++ b/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/InspectitAgentExtension.java @@ -71,7 +71,6 @@ public AgentBuilder extend(AgentBuilder agentBuilder, ConfigProperties config) { // Notify configuration server about this agent NotificationManager notificationManager = NotificationManager.create(); - notificationManager.sendStartNotification(); // Set up shutdown notification to configuration server notificationManager.setUpShutdownNotification(); diff --git a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/configuration/http/HttpConfigurationCallback.java b/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/configuration/http/HttpConfigurationCallback.java index b0b453f..81c2555 100644 --- a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/configuration/http/HttpConfigurationCallback.java +++ b/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/configuration/http/HttpConfigurationCallback.java @@ -16,12 +16,10 @@ public class HttpConfigurationCallback implements FutureCallback headers = + Map.of( + X_GEPARD_SERVICE_NAME, agent.getServiceName(), + X_GEPARD_VM_ID, agent.getVmId(), + X_GEPARD_GEPARD_VERSION, agent.getGepardVersion(), + X_GEPARD_OTEL_VERSION, agent.getOtelVersion(), + X_GEPARD_JAVA_VERSION, agent.getJavaVersion(), + X_GEPARD_START_TIME, agent.getStartTime().toString()); + + headers.forEach(requestBuilder::addHeader); + agent + .getAttributes() + .forEach((key, value) -> requestBuilder.addHeader(X_GEPARD_ATTRIBUTE + key, value)); + + return requestBuilder; } } diff --git a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/internal/identity/IdentityManager.java b/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/internal/identity/IdentityManager.java index 638c8f9..51d5268 100644 --- a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/internal/identity/IdentityManager.java +++ b/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/internal/identity/IdentityManager.java @@ -6,6 +6,8 @@ import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Base64; import java.util.Objects; import rocks.inspectit.gepard.agent.internal.identity.model.IdentityInfo; @@ -38,13 +40,16 @@ public IdentityInfo getIdentityInfo() { * @return the SHA3-256 hashed String */ private static String hash(String input) { + String salt = generateSalt(); + String saltedInput = salt + input; + MessageDigest messageDigest; try { messageDigest = MessageDigest.getInstance("SHA3-256"); } catch (NoSuchAlgorithmException e) { throw new UnsupportedOperationException("SHA3-256 not supported", e); } - byte[] bytes = messageDigest.digest(input.getBytes(StandardCharsets.UTF_8)); + byte[] bytes = messageDigest.digest(saltedInput.getBytes(StandardCharsets.UTF_8)); StringBuilder hexString = new StringBuilder(2 * bytes.length); for (byte b : bytes) { String hex = Integer.toHexString(0xff & b); @@ -55,4 +60,12 @@ private static String hash(String input) { } return hexString.toString(); } + + /** Generates a secure random 128bit string/salt */ + private static String generateSalt() { + byte[] salt = new byte[16]; + SecureRandom secureRandom = new SecureRandom(); + secureRandom.nextBytes(salt); + return Base64.getEncoder().encodeToString(salt); + } } diff --git a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/NotificationManager.java b/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/NotificationManager.java index 3861ec4..52de7cd 100644 --- a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/NotificationManager.java +++ b/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/NotificationManager.java @@ -15,13 +15,10 @@ public class NotificationManager { private final String serverBaseUrl; - private final StartNotifier startNotifier; - private final ShutdownNotifier shutdownNotifier; private NotificationManager(String serverBaseUrl) { this.serverBaseUrl = serverBaseUrl; - this.startNotifier = new StartNotifier(); this.shutdownNotifier = new ShutdownNotifier(); } @@ -35,22 +32,6 @@ public static NotificationManager create() { return new NotificationManager(url); } - /** - * Sends a message to the configuration server, to notify it about this agent starting, if a - * configuration server url was provided. - * - * @return true, if the notification was executed successfully - */ - public boolean sendStartNotification() { - boolean successful = false; - if (serverBaseUrl.isEmpty()) log.info("No configuration server url was provided"); - else { - log.info("Sending start notification to configuration server with url: {}", serverBaseUrl); - successful = startNotifier.sendNotification(serverBaseUrl); - } - return successful; - } - /** * Sets up a shutdown notification to the configuration server, if a configuration server url was * provided. diff --git a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/StartNotifier.java b/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/StartNotifier.java deleted file mode 100644 index 3f1405b..0000000 --- a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/StartNotifier.java +++ /dev/null @@ -1,42 +0,0 @@ -/* (C) 2024 */ -package rocks.inspectit.gepard.agent.notification; - -import com.fasterxml.jackson.core.JsonProcessingException; -import java.net.URISyntaxException; -import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import rocks.inspectit.gepard.agent.internal.http.HttpRequestSender; -import rocks.inspectit.gepard.agent.notification.http.NotificationCallback; -import rocks.inspectit.gepard.agent.notification.http.NotificationFactory; - -/** Executes the start notification to the configuration server. */ -public class StartNotifier { - private static final Logger log = LoggerFactory.getLogger(StartNotifier.class); - - /** - * Sends a message to the configuration server, to notify it about this agent starting - * - * @return true, if the notification was executed successfully - */ - public boolean sendNotification(String serverBaseUrl) { - SimpleHttpRequest notification = createStartNotification(serverBaseUrl); - return HttpRequestSender.send(notification, new NotificationCallback()); - } - - /** - * @param serverUrl the url of the configuration server - * @return the created start notification request - */ - private SimpleHttpRequest createStartNotification(String serverUrl) { - SimpleHttpRequest notification = null; - try { - notification = NotificationFactory.createStartNotification(serverUrl); - } catch (URISyntaxException e) { - log.error("Error building HTTP URI for configuration server notification", e); - } catch (JsonProcessingException e) { - log.error("Could not process agent information for configuration server notification", e); - } - return notification; - } -} diff --git a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/http/NotificationCallback.java b/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/http/NotificationCallback.java deleted file mode 100644 index ebebefb..0000000 --- a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/http/NotificationCallback.java +++ /dev/null @@ -1,27 +0,0 @@ -/* (C) 2024 */ -package rocks.inspectit.gepard.agent.notification.http; - -import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; -import org.apache.hc.core5.concurrent.FutureCallback; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** Callback for notifications to the configuration server. Currently, only used for logging. */ -public class NotificationCallback implements FutureCallback { - private static final Logger log = LoggerFactory.getLogger(NotificationCallback.class); - - @Override - public void completed(SimpleHttpResponse result) { - log.info("Notified configuration server and received status code {}", result.getCode()); - } - - @Override - public void failed(Exception ex) { - log.error("Failed to notify configuration server", ex); - } - - @Override - public void cancelled() { - log.info("Cancelled notification to configuration server"); - } -} diff --git a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/http/NotificationFactory.java b/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/http/NotificationFactory.java index ddcc0c9..ad0f80a 100644 --- a/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/http/NotificationFactory.java +++ b/inspectit-gepard-agent/src/main/java/rocks/inspectit/gepard/agent/notification/http/NotificationFactory.java @@ -24,27 +24,6 @@ public class NotificationFactory { private NotificationFactory() {} - /** - * Create an HTTP post request to notify the configuration server about the starting agent and - * it's information. - * - * @param baseUrl the base url of the configuration server - * @return the HTTP post request, containing agent information - * @throws URISyntaxException invalid uri - * @throws JsonProcessingException corrupted agent information - */ - public static SimpleHttpRequest createStartNotification(String baseUrl) - throws URISyntaxException, JsonProcessingException { - String agentId = AgentInfo.INFO.getAgentId(); - URI uri = new URI(baseUrl + "/connections/" + agentId); - String agentInfoString = mapper.writeValueAsString(AgentInfo.INFO.getAgent()); - - return SimpleRequestBuilder.post(uri) - .setBody(agentInfoString, ContentType.APPLICATION_JSON) - .setHeader("content-type", "application/json") - .build(); - } - /** * Create an HTTP put request to notify the configuration server about the shutting down agent. * diff --git a/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/configuration/http/HttpConfigurationPollerTest.java b/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/configuration/http/HttpConfigurationPollerTest.java index 66b0524..a07942c 100644 --- a/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/configuration/http/HttpConfigurationPollerTest.java +++ b/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/configuration/http/HttpConfigurationPollerTest.java @@ -12,6 +12,7 @@ import org.mockserver.model.HttpError; import rocks.inspectit.gepard.agent.MockServerTestBase; import rocks.inspectit.gepard.agent.configuration.persistence.ConfigurationPersistence; +import rocks.inspectit.gepard.agent.internal.identity.model.AgentInfo; class HttpConfigurationPollerTest extends MockServerTestBase { @@ -19,6 +20,8 @@ class HttpConfigurationPollerTest extends MockServerTestBase { private static ConfigurationPersistence persistence; + private static String AGENT_ID = AgentInfo.INFO.getAgentId(); + @BeforeEach void beforeEach() { persistence = mock(ConfigurationPersistence.class); @@ -33,7 +36,7 @@ void afterEach() { @Test void runDoesntLoadLocalConfigurationWhenPollingIsSuccessful() { mockServer - .when(request().withMethod("GET").withPath("/api/v1/agent-configuration")) + .when(request().withMethod("GET").withPath("/api/v1/agent-configuration/" + AGENT_ID)) .respond(response().withStatusCode(200)); poller.run(); verify(persistence, never()).loadLocalConfiguration(); @@ -52,7 +55,7 @@ void runLoadsLocalConfigurationOnlyOnceWhenConnectionFailed() { @Test void configurationRequestIsSentSuccessfully() { mockServer - .when(request().withMethod("GET").withPath("/api/v1/agent-configuration")) + .when(request().withMethod("GET").withPath("/api/v1/agent-configuration/" + AGENT_ID)) .respond(response().withStatusCode(200)); boolean successful = poller.pollConfiguration(); diff --git a/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/integrationtest/ConfigurationServerMock.java b/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/integrationtest/ConfigurationServerMock.java index e0e55e4..735a596 100644 --- a/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/integrationtest/ConfigurationServerMock.java +++ b/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/integrationtest/ConfigurationServerMock.java @@ -8,8 +8,6 @@ import java.io.IOException; import org.apache.commons.io.FileUtils; import org.mockserver.client.MockServerClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.testcontainers.containers.MockServerContainer; import org.testcontainers.containers.Network; import org.testcontainers.utility.DockerImageName; @@ -22,8 +20,6 @@ */ public class ConfigurationServerMock { - private static final Logger logger = LoggerFactory.getLogger(ConfigurationServerMock.class); - private MockServerContainer server; private MockServerClient serverClient; @@ -56,7 +52,7 @@ public void configServerSetup(String config_path) throws IOException { String body = FileUtils.readFileToString(file, "UTF-8"); serverClient - .when(request().withMethod("GET").withPath("/api/v1/agent-configuration")) + .when(request().withMethod("GET").withPath("/api/v1/agent-configuration/.*")) .respond(response().withStatusCode(200).withBody(body)); serverClient diff --git a/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/internal/identity/IdentityManagerTest.java b/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/internal/identity/IdentityManagerTest.java index b7333cd..6900b81 100644 --- a/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/internal/identity/IdentityManagerTest.java +++ b/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/internal/identity/IdentityManagerTest.java @@ -7,16 +7,22 @@ import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; +import java.lang.reflect.Field; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.MockedStatic; import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; import rocks.inspectit.gepard.agent.internal.identity.model.IdentityInfo; -@ExtendWith(MockitoExtension.class) class IdentityManagerTest { + @BeforeEach + public void setup() throws NoSuchFieldException, IllegalAccessException { + Field instance = IdentityManager.class.getDeclaredField("instance"); + instance.setAccessible(true); + instance.set(null, null); + } + @Test void testCreateIdentityManagerSuccessfully() { RuntimeMXBean mockRuntimeMXBean = mock(RuntimeMXBean.class); @@ -33,9 +39,7 @@ void testCreateIdentityManagerSuccessfully() { assertNotNull(identityInfo); assertEquals("12345@mockedHostName", identityInfo.vmId()); - assertEquals( - "d29aca592fc2071bcef6577d649071d4d54a8ae6cd5c0be0e51f28af2867f207", - identityInfo.agentId()); + assertNotNull(identityInfo.agentId()); } } } diff --git a/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/notification/NotificationManagerTest.java b/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/notification/NotificationManagerTest.java index fddff65..18ddab2 100644 --- a/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/notification/NotificationManagerTest.java +++ b/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/notification/NotificationManagerTest.java @@ -3,15 +3,11 @@ import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable; import static org.junit.jupiter.api.Assertions.*; -import static org.mockserver.model.HttpRequest.request; -import static org.mockserver.model.HttpResponse.response; import static rocks.inspectit.gepard.agent.internal.properties.PropertiesResolver.SERVER_URL_ENV_PROPERTY; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockserver.model.HttpError; import rocks.inspectit.gepard.agent.MockServerTestBase; -import rocks.inspectit.gepard.agent.internal.identity.model.AgentInfo; import rocks.inspectit.gepard.agent.internal.shutdown.ShutdownHookManager; class NotificationManagerTest extends MockServerTestBase { @@ -20,60 +16,11 @@ class NotificationManagerTest extends MockServerTestBase { private final ShutdownHookManager shutdownHookManager = ShutdownHookManager.getInstance(); - private final String agentId = AgentInfo.INFO.getAgentId(); - @BeforeEach void beforeEach() { shutdownHookManager.reset(); } - @Test - void sendsStartNotificationIfServerUrlWasProvided() throws Exception { - mockServer - .when(request().withMethod("POST").withPath("/api/v1/connections/" + agentId)) - .respond(response().withStatusCode(201)); - - withEnvironmentVariable(SERVER_URL_ENV_PROPERTY, SERVER_URL) - .execute( - () -> { - manager = NotificationManager.create(); - }); - - boolean successful = manager.sendStartNotification(); - - assertTrue(successful); - } - - @Test - void startNotificationFailsWithServerError() throws Exception { - mockServer - .when(request().withMethod("POST").withPath("/api/v1/connections/" + agentId)) - .error(HttpError.error().withDropConnection(true)); - - withEnvironmentVariable(SERVER_URL_ENV_PROPERTY, SERVER_URL) - .execute( - () -> { - manager = NotificationManager.create(); - }); - - boolean successful = manager.sendStartNotification(); - - assertFalse(successful); - } - - @Test - void sendsNoStartNotificationWithoutProvidedServerUrl() { - mockServer - .when(request().withMethod("POST").withPath("/api/v1/connections/" + agentId)) - .respond(response().withStatusCode(201)); - - manager = NotificationManager.create(); - - boolean successful = manager.sendStartNotification(); - - assertFalse(successful); - } - @Test void shouldSetUpShutdownNotificationWithProvidedServerUrl() throws Exception { withEnvironmentVariable(SERVER_URL_ENV_PROPERTY, SERVER_URL) diff --git a/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/notification/StartNotifierTest.java b/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/notification/StartNotifierTest.java deleted file mode 100644 index 38c8974..0000000 --- a/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/notification/StartNotifierTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* (C) 2024 */ -package rocks.inspectit.gepard.agent.notification; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockserver.model.HttpRequest.request; -import static org.mockserver.model.HttpResponse.response; - -import org.junit.jupiter.api.Test; -import org.mockserver.model.HttpError; -import rocks.inspectit.gepard.agent.MockServerTestBase; -import rocks.inspectit.gepard.agent.internal.identity.model.AgentInfo; - -class StartNotifierTest extends MockServerTestBase { - - private final StartNotifier notifier = new StartNotifier(); - - private final String agentId = AgentInfo.INFO.getAgentId(); - - @Test - void notificationIsSentSuccessfully() { - mockServer - .when(request().withMethod("POST").withPath("/api/v1/connections/" + agentId)) - .respond(response().withStatusCode(201)); - - boolean successful = notifier.sendNotification(SERVER_URL); - - assertTrue(successful); - } - - @Test - void serverIsNotAvailable() { - mockServer - .when(request().withMethod("POST").withPath("/api/v1/connections/" + agentId)) - .respond(response().withStatusCode(503)); - - boolean successful = notifier.sendNotification(SERVER_URL); - - assertFalse(successful); - } - - @Test - void serverReturnsError() { - mockServer - .when(request().withMethod("POST").withPath("/api/v1/connections/" + agentId)) - .error(HttpError.error().withDropConnection(true)); - - boolean successful = notifier.sendNotification(SERVER_URL); - - assertFalse(successful); - } - - @Test - void serverIsNotFound() { - boolean successful = notifier.sendNotification(SERVER_URL); - - assertFalse(successful); - } -} diff --git a/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/notification/http/NotificationFactoryTest.java b/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/notification/http/NotificationFactoryTest.java index 46833e3..b2d0d14 100644 --- a/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/notification/http/NotificationFactoryTest.java +++ b/inspectit-gepard-agent/src/test/java/rocks/inspectit/gepard/agent/notification/http/NotificationFactoryTest.java @@ -22,27 +22,6 @@ class NotificationFactoryTest { private final String agentId = AgentInfo.INFO.getAgentId(); - @Test - void validUrlCreatesStartNotification() throws Exception { - String baseUrl = "http://localhost:8080"; - String url = "http://localhost:8080/connections/" + agentId; - String contentType = "application/json"; - String agent = mapper.writeValueAsString(AgentInfo.INFO.getAgent()); - - SimpleHttpRequest request = NotificationFactory.createStartNotification(baseUrl); - - assertEquals(url, request.getUri().toString()); - assertEquals(contentType, request.getHeader("content-type").getValue()); - assertEquals(agent, request.getBodyText()); - } - - @Test - void invalidStartNotificationUrlThrowsException() { - String url = "invalid url"; - - assertThrows(URISyntaxException.class, () -> NotificationFactory.createStartNotification(url)); - } - @Test void validUrlCreatesShutdownNotification() throws Exception { String baseUrl = "http://localhost:8080";