Camel: Calling a HTTPS REST endpoint with a proxy - https

I'm consuming data from a REST endpoint with in the middle of the route a proxy. I'm having CNTLM running locally (localhost:3128 ): it will authenticate for me on the corporate proxy, so I don't need to pass my credentials.
I have been unable to get my rest call to work, despite numerous attempts. For e.g., getting:
SSLException: Unrecognized SSL message
Connection handshake abruptly terminated
Connection reset
you name it, have got it
Below the simplest version of the many attempts made.
Apparently (from internet reading), that should work, but it doesn't.
How should Camel be configured, in particular camel-http ?
Notes:
The REST API I'm calling is using HTTPS but doesn't require a certificate.
The code works on my local machine when no proxy is involved. It fails on the intranet where there is a proxy
#Component
public class MyRoute extends RouteBuilder
public void configure() throws Exception {
//Tried different way to set the proxy, including inline with toD(...)
System.setProperty("https.proxyHost", "localhost");
System.setProperty("https.proxyPort", "3128");
getCamelContext().getGlobalOptions().put("http.proxyHost", "localhost");
getCamelContext().getGlobalOptions().put("https.proxyPort", "3128");
getContext().getGlobalOptions().put("https.proxyHost", "localhost");
getContext().getGlobalOptions().put("https.proxyPort", "3128");
from("timer:credentials?repeatCount=1")
.setHeader(Exchange.HTTP_METHOD, constant("POST"))
.setBody(simple(jsonAuth))
.to(baseUrlApi +"/v1/auth/tokens/?bridgeEndpoint=true")
.unmarshal().json(JsonLibrary.Jackson, AuthResponseDto.class)
.setHeader("Authorization", simple("Bearer ${body.data.accessToken.token}"))
// etc..
}
}

Related

Spring Boot - Rest API not working on LAN

I have a simple Spring Boot application with a Rest API. It only accepts a simple GET request and returns a string.
#RestController
public class TestController {
#CrossOrigin(origins = "*", allowedHeaders = "*")
#GetMapping("/test")
public String getTest() {
return "test";
}
}
In my application.properties I have only one property set: server.port=29090
If I use my browser on the same device to test this, it works as expected. I go to http://localhost:29090/test, and it shows only the word test.
If I use another device in the same network for the GET request, going to http://192.168.1.2:29090/test, there is no response and eventually the request times out. The server is running Windows, I checked the firewall and there is indeed an inbound rule specifying port 29090 is allowed for TCP, on private, public and domain networks.
I suspected router misconfigurations, so I started up wireshark on the server machine to check network traffic. I do see the TCP SYN requests coming from the other device toward port 29090, so the router is working correctly, but there is no SYN-ACK reply from the server machine.
I did add the #CrossOrigin annotation in the code above after some googling, to see if that was the issue, but the problem persists. What could be the issue?

How to fix "NoHttpResponseException" when running Wiremock on jenkins?

I start a wiremock server in a integration test.
The IT pass in my local BUT some case failed in jenkins server, the error is
localhost:8089 failed to respond; nested exception is org.apache.http.NoHttpResponseException: localhost:8089 failed to respond
I try to add sleep(3000) in my test, that can fix the issue, But I don’t know the root cause of the issue, so the work around not a good idea
I also try to use #AutoConfigureWireMock(port=8089) to replace WireMockServer to start wiremock server, that could fix the problem, BUT I don't know how to do some configuration to the wiremock server using the annotation #AutoConfigureWireMock(port=8089).
Here my code to start a wiremock server, any suggestion to fix "NoHttpResponseException"?
#ContextConfiguration(
initializers = ConfigFileApplicationContextInitializer.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class BaseSpec extends Specification {
#Shared
WireMockServer wireMockServer
def setupSpec() {
wireMockServer = new WireMockServer(options().port(PORT).jettyHeaderBufferSize(12345)
.notifier(new ConsoleNotifier(new Boolean(System.getenv(“IT_WIREMOCK_LOG”) ?: ‘false’)))
.extensions(new ResponseTemplateTransformer(true)))
wireMockServer.start()
}
Apache HttpClient suffers from NoHttpResponseException from time to time. This is a very old problem.
Anyway, I guess in your case the problem might be caused by restarting the WireMock server between tests, and at the same time, Apache HttpClient pools HTTP connections and tries to reuse them between tests. If this is the case, there are two solutions:
Disable pooling HTTP connections in your tests. This makes sense because it's considered normal that the WireMock server can be restarted during tests execution. Alternatively, craft your WireMock stubs to always send "Connection": "close" among the headers. The outcome will be the same.
Switch from Apache HttpClient to Square OkHttp. OkHttp, although it pools http connections by default, is always able to gracefully recover from situations like a stale connection. Unfortunately the library from Apache is not so smart.
Coorect, as already written by G. Demecki it's not related to Wiremock.
It’s related to your application server, which is calling wiremock. Today it’s common, to reuse a connection to improve the performance in a micro service infrastructure. So connection-close-header, RequestScoped client, etc is not useful.
Check the apache http client:
httpclient-4.5.2 - PoolingHttpClientConnectionManager
documentation
The handling of stale connections was changed in version 4.4. Previously, the code would check every connection by default before re-using it. The code now only checks the connection if the elapsed time since the last use of the connection exceeds the timeout that has been set. The default timeout is set to 2000ms
Each time a wiremock-endpoint was destroyed and a new one was created for a new test class, it takes 2 seconds, until your application detects, that the previous connection is broken and a new one has to be opened.
If you don’t wait 2 seconds, such a NoHttpResponseException could be thrown, depends on the last check.
So a Thread.sleep(2000); looks ugly. But it's not so bad, as long we know why this is required.
Each time a wiremock endpoint is destroyed (because the wiremock server is restarted between tests) and a new one is created for a new test, it takes 2 seconds (as stated in documentation), until the application detects that the previous http connection is broken and a new one has to be opened.
The solution is to simply override the default keep-alive connection behaviour for every stub using .withHeader("Connection", "close"). Something like:
givenThat(get("/endpoint_path")
.withHeader("Authorization", equalTo(authHeader))
.willReturn(
ok()
.withBody(body)
.withHeader(HttpHeaders.CONNECTION, "close")
)
)
Also possible to do it globally using a transformer:
public class NoKeepAliveTransformer extends ResponseDefinitionTransformer {
#Override
public ResponseDefinition transform(Request request,
ResponseDefinition responseDefinition,
FileSource files,
Parameters parameters) {
return ResponseDefinitionBuilder
.like(responseDefinition)
.withHeader(CONNECTION, "close")
.build();
}
#Override
public String getName() {
return "keep-alive-disabler";
}
}
Then this transformer have to be registered when you create the wiremock server:
new WireMockServer(
options()
.port(port)
.extensions(NoKeepAliveTransformer.class)
)
Solution that worked for us in this situation was just adding retry to apache client:
#Configuration
public class FeignTestConfig {
#Bean
#Primary
public HttpClient testClient() {
return HttpClientBuilder.create().setRetryHandler((exception, executionCount, context) -> {
if (executionCount > 3) {
return false;
}
return exception instanceof org.apache.http.NoHttpResponseException || exception instanceof SocketException;
}).build();
}
}
Socket exception is there as well, because sometimes this exception is thrown instead of NoHttpResponse

tyrus websocket server programmatic endpoint

I am trying to create a websocket server using programmatic endpoints with tyrus 1.8.2. I have found that the constructor:
public Server(String hostName,
int port,
String contextPath,
Map<String,Object> properties,
Class<?>... configuration)
does not accept a class implementing ServerEndpointConfig. When I try that it throws a DeploymentException "Class XXX is not ServerApplicationConfig descendant nor has #ServerEndpoint annotation."
Since I am using programmatic endpoints (not annotated), this would seem to imply that I must implement ServerApplicationConfig. That is contrary to the websocket API documentation.
So when I implement ServerApplicationConfig, I no longer get this exception, and the server appears to start without problems, but it returns 404 to what I believe are valid connection attempts (correct host, port, and context path.)
What am I missing?
Additional information: I extended TyrusServerEndpointConfigurator and provided an override for the modifyHandshake() method. The server is returning 404's without ever calling this method.
The problem turned out to be confusion about the way Tyrus constructs the context path. There is a path passed to the Server constructor, and a path returned by the ServerEndpointConfig getPath() method. These are concatenated to form the full context path.
So if you specify "/server" in the Server constructor and "/endpoint" in ServerEndpointConfig.getPath(), the server will accept connection requests on "/server/endpoint".

forcing the Jersey Grizzly server to authenicate

I am performing acceptance tests against REST services written using Jersey. In my services, I need to get the name of the user who successfully authenticated (BASIC) using:
#Context private SecurityContext securityContext; //at class level
String username = securityContext.getUserPrincipal().getName() //inside a resource
I am using the Jersey client API and running against the Grizzly server. I set up the server as follows:
public class BaseResourceTest extends JerseyTest {
public BaseResourceTest() throws Exception {
super(new WebAppDescriptor.Builder("net.tds.adm.na.batchcut")
.contextPath(baseUri.getPath())
.contextParam("contextConfigLocation","classpath:testContext.xml")
.initParam("com.sun.jersey.api.json.POJOMappingFeature",
"true").servletClass(SpringServlet.class)
.contextListenerClass(ContextLoaderListener.class)
.build());
}
.......
}
In my tests, I pass an authorization header as follows:
WebResource resource = resource().path(_url);
return resource.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE).header(HttpHeaders.AUTHORIZATION, new String(Base64.encode("judge:smails"))).post(ClientResponse.class, _formData);
However, in my resources I get an NPE when trying to get the user name. I think I need to get the server to actively authenticate against a realm but I haven't found how to configure the server to do this. Has anybody had any experience with this?
Unfortunately Grizzly HttpServer doesn't support authentication at the moment.
But here you can find a simple example how to implement authentication using Jersey Filter.
http://simplapi.wordpress.com/2013/01/24/jersey-jax-rs-implements-a-http-basic-auth-decoder/

JerseyClient using DefaultHttpClient

I need to access a JAX-WS webservice protected by SSL using Jersey Client. I have successfully got this working with limited configuration and just letting the Client use the default HTTPURLConnection API.
This approach wont work however for my overall solution because it does not allow me the flexibility to change the credentials used when making a request to the WS. I'm trying to use DefaultHTTPClient instead and then passing it to the Client object on intialization.
NTCredentials credentials = new NTCredentials("username", "password",
computerName, domainName);
DefaultHttpClient httpClienttemp = new DefaultHttpClient();
DefaultHttpClient httpClient = wrapClient(httpClienttemp);
httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, credentials );
ClientConfig config = new DefaultClientConfig();
The wrapClient method creates an X509TrustManager and overrides the necessary methods so that all certificates are accepted. It also creates a SchemeRegistry entry for https access on port 443. This configuration results in a Connection refused exception.
The strange thing is, if i add an additional entry in the SchemeRegistry for http and give it a port of 443 then the request does get sent however a Connection Reset exception then gets thrown.
The Url i use to create the WebResource object is https however the SOAPAction i declare in the header uses http. Any ideas where im going wrong?
This is a limitation of the default HTTP Client (com.sun.jersey.api.client.Client) documented in the Jersey docs. You will have to use Apache HTTP Client to achieve this functionality.
Looks like someone already recommended doing this in the answer to your previous question: Jersey Client API - authentication.
EDIT: Corrected reference to the default Jersey HTTP Client to avoid confusion.

Resources