Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Ning async http client 1.0.x #116

Merged
merged 5 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions instrumentation-security/ning-async-http-client-1.0.0/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
dependencies {
implementation(project(":newrelic-security-api"))
implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}")
implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}")
implementation("com.ning:async-http-client:1.0.0")
}

jar {
manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.ning-async-http-client-1.0.0' }
}

verifyInstrumentation {
passesOnly 'com.ning:async-http-client:[1.0,1.1)'
}

site {
title 'Ning AsyncHttpClient'
type 'Messaging'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.newrelic.agent.security.instrumentation.ning.http_1_0;

import com.newrelic.api.agent.security.NewRelicSecurity;
import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper;
import com.newrelic.api.agent.security.instrumentation.helpers.ServletHelper;
import com.newrelic.api.agent.security.schema.AbstractOperation;
import com.newrelic.api.agent.security.schema.SecurityMetaData;
import com.newrelic.api.agent.security.schema.StringUtils;
import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException;
import com.newrelic.api.agent.security.schema.operation.SSRFOperation;
import com.newrelic.api.agent.security.utils.SSRFUtils;
import com.ning.http.client.Request;

import java.net.URI;
import java.net.URISyntaxException;

public class NingHelper {
public static final String METHOD_NAME_EXECUTE = "execute";
public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "SSRF_OPERATION_LOCK_NING-";

public static void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) {
try {
if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty()
) {
return;
}
NewRelicSecurity.getAgent().registerExitEvent(operation);
} catch (Throwable ignored) {
}
}

public static AbstractOperation preprocessSecurityHook(Request request, String uri, String methodName, String className) {
try {
SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData();
if (!NewRelicSecurity.isHookProcessingActive() || securityMetaData.getRequest().isEmpty()
) {
return null;
}

// Add Security IAST header
String iastHeader = NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier().getRaw();
if (iastHeader != null && !iastHeader.trim().isEmpty()) {
request.getHeaders().add(ServletHelper.CSEC_IAST_FUZZ_REQUEST_ID, iastHeader);
}

String csecParaentId = securityMetaData.getCustomAttribute(GenericHelper.CSEC_PARENT_ID, String.class);
if(StringUtils.isNotBlank(csecParaentId)){
request.getHeaders().add(GenericHelper.CSEC_PARENT_ID, csecParaentId);
}

SSRFOperation operation = new SSRFOperation(uri, className, methodName);
try {
NewRelicSecurity.getAgent().registerOperation(operation);
} finally {
if (operation.getApiID() != null && !operation.getApiID().trim().isEmpty() &&
operation.getExecutionId() != null && !operation.getExecutionId().trim().isEmpty()) {
// Add Security distributed tracing header
request.getHeaders().add(ServletHelper.CSEC_DISTRIBUTED_TRACING_HEADER, SSRFUtils.generateTracingHeaderValue(securityMetaData.getTracingHeaderValue(), operation.getApiID(), operation.getExecutionId(), NewRelicSecurity.getAgent().getAgentUUID()));
}
}
return operation;
} catch (Throwable e) {
if (e instanceof NewRelicSecurityException) {
e.printStackTrace();
throw e;
}
}
return null;
}

public static void releaseLock(int hashCode) {
try {
GenericHelper.releaseLock(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode);
} catch (Throwable ignored) {
}
}

public static boolean acquireLockIfPossible(int hashCode) {
try {
return GenericHelper.acquireLockIfPossible(NR_SEC_CUSTOM_ATTRIB_NAME, hashCode);
} catch (Throwable ignored) {
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.ning.http.client;

import com.newrelic.agent.security.instrumentation.ning.http_1_0.NingHelper;
import com.newrelic.api.agent.NewRelic;
import com.newrelic.api.agent.Segment;
import com.newrelic.api.agent.security.schema.AbstractOperation;
import com.newrelic.api.agent.weaver.MatchType;
import com.newrelic.api.agent.weaver.Weave;
import com.newrelic.api.agent.weaver.Weaver;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.Future;

@Weave(type = MatchType.Interface, originalName = "com.ning.http.client.AsyncHttpProvider")
public class AsyncHttpProvider_Instrumentation {

public <T> Future<T> execute(Request request, AsyncHandler<T> handler) throws IOException {
boolean isLockAcquired = NingHelper.acquireLockIfPossible(this.hashCode());
AbstractOperation operation = null;
URI uri = null;
Future<T> returnObj = null;

try {
uri = new URI(request.getUrl());
String scheme = uri.getScheme();

if (isLockAcquired && (scheme == null || scheme.equals("http") || scheme.equals("https"))) {
operation = NingHelper.preprocessSecurityHook(request, uri.toString(), NingHelper.METHOD_NAME_EXECUTE, this.getClass().getName());
}
} catch (URISyntaxException uriSyntaxException) {
// Instrumentation won't work and normal execution will continue
}

try {
returnObj = Weaver.callOriginal();
} finally {
if (isLockAcquired) {
NingHelper.releaseLock(this.hashCode());
}
}
NingHelper.registerExitOperation(isLockAcquired, operation);

return returnObj;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
*
* * Copyright 2020 New Relic Corporation. All rights reserved.
* * SPDX-License-Identifier: Apache-2.0
*
*/

package com.ning.http.client;

import com.newrelic.api.agent.weaver.Weave;

@Weave(originalName = "com.ning.http.client.RequestBuilderBase")
abstract class RequestBuilderBase_Instrumentation {

@Weave(originalName = "com.ning.http.client.RequestBuilderBase$RequestImpl")
private abstract static class RequestImpl_Instrumentation {
private Headers headers;

// Added this instrumentation to return modifiable headers instead
public Headers getHeaders() {
return headers;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package play;

import com.newrelic.api.agent.weaver.SkipIfPresent;

/**
* Play v1 instrumentation is implemented using its own set of pointcuts that don't work well with our async APIs. This
* class is present in Play v1 but not v2, and will cause this module NOT to load if the customer is using Play v1.
*/
@SkipIfPresent
public class CorePlugin {
}
Loading
Loading