Test Rest Template With Proxy In Spring Boot - java

I have a simple rest-template code in spring-boot. I need to test it somehow but I couldn’t find a way. Do you have any suggestion?
My code looks like:
#Override
public RestTemplate buildRestTemplate()
{
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(PROXY_HOST, PROXY_PORT), new UsernamePasswordCredentials(PROXY_USER, PROXY_PASS));
var client = HttpClientBuilder.create()
.useSystemProperties()
.setProxy(new HttpHost(PROXY_HOST, PROXY_PORT))
.setDefaultCredentialsProvider(credentialsProvider)
.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy())
.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(30000).build())
.build();
var requestFactory = new HttpComponentsClientHttpRequestFactory(client);
return restTemplateBuilder.requestFactory(() -> requestFactory).build();
}
Actually, I try to find a way to test it with MockRestServiceServer but I couldn't find it.

Related

Need help to Bypass SSL certificate validation with rest template

I have one requirement i.e. to bypass SSL verification while connecting to webservice using rest template.
Currently I am implementing proxy to rest template via below code.
SimpleClientHttpRequestFactory clientHttpRequestFactory = new
SimpleClientHttpRequestFactory();
Proxy proxy = new Proxy(Proxy.Type.HTTP,new InetSocketAddress(proxyHost,
Integer.parseInt(proxyPort)));
clientHttpRequestFactory.setProxy(proxy);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
ResponseEntity<String> responseEntity= restTemplate.exchange(url,HttpMethod.POST,
entity,String.class);
response = responseEntity.getBody();
How can I modify my Rest template so while connecting to URL it doesn't look for SSL certificate Validation.
I do checked couple of solutions online for this but all are implemented with
HttpComponentsClientHttpRequestFactory
which don't have provision to pass proxy host and server (Java.net.proxy object).
Can anyone help me here, I am stuck from long on this.
Solution I found online is below
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
restTemplate = new RestTemplate(requestFactory);
Thanks,
Anshu

Closing socket HttpClient in bean (CloseableHttpClient) - need to do this? JAVA

Should I worry about to release a socket allocated by clientBuilder.build() in this code:
#Bean("proxyRestTemplate")
#LoadBalanced
public RestTemplate proxyRestTemplate() {
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(proxyUrl, proxyPort),
new UsernamePasswordCredentials(proxyUsername, proxyPassword)
);
HttpHost myProxy = new HttpHost(proxyUrl, proxyPort);
HttpClientBuilder clientBuilder = HttpClientBuilder.create();
clientBuilder.setProxy(myProxy).setDefaultCredentialsProvider(credsProvider).disableCookieManagement();
HttpClient httpClient = clientBuilder.build();
HttpComponentsClientHttpRequestFactory factory = new CustomHttpComponentsClientHttpRequestFactory();
factory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(factory);
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(basicAuthUsername, basicAuthPassword));
return restTemplate;
}
I sincerely hope this will be a short and simple question
Thank you in advance for your help.

How to connect Elasticsearch(8.x) using Java low level client configuration as RestHightLevelClient is deprecated

I am new to ElasticSearch and trying to establish connection to elasticsearch using Java Lowlevel rest client configuration as RestHightLevelClient is deprecated.The documentation says to add below code but I am not sure where the code needs to be added.
RestClient restClient = RestClient.builder(
new HttpHost("localhost", 9200, "http"),
new HttpHost("localhost", 9201, "http")).build();
The below RestHightLevelClient configuration works fine but it is deprecated.
#Configuration
#EnableElasticsearchRepositories(basePackages = "com.demo.elasticsearch.repositories")
#ComponentScan(basePackages = {"com.demo.elasticsearch"})
public class ElasticSearchConfiguration
extends AbstractElasticsearchConfiguration
{
#Override
public RestHighLevelClient elasticsearchClient() {
ClientConfiguration clientConfiguration =
ClientConfiguration
.builder()
.connectedTo("host:port")
.usingSsl()
.withBasicAuth("username","password")
.build();
return RestClients.create(clientConfiguration).rest();
}
}
Can someone please help me with java low level rest client config
EDIT:
Try replacing your second code-block with this one:
#Configuration
#EnableElasticsearchRepositories(basePackages = "com.demo.elasticsearch.repositories")
#ComponentScan(basePackages = {"com.demo.elasticsearch"})
public class ElasticSearchConfiguration
extends AbstractElasticsearchConfiguration
{
RestClient restClient = RestClient.builder(
new HttpHost("localhost", 9200, "http"),
new HttpHost("localhost", 9201, "http")).build();
// Create the transport with a Jackson mapper
ElasticsearchTransport transport = new RestClientTransport(
restClient, new JacksonJsonpMapper());
// And create the API client
ElasticsearchClient esClient = new
ElasticsearchClient(transport);
return esClient;
}
This worked for me to get the connection working with a local elasticsearch.
Old post:
I am struggeling with this too. I also try to connect with BasicAuth to https URL.
I found the following documentation: https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/_basic_authentication.html
Maybe it is helpful for you. Let me know in case you managed to solve this problem.
I currently replaced your block with
#Bean
public ElasticsearchClient elasticsearchClient() {
final CredentialsProvider credentialsProvider =
new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(user, password));
RestClientBuilder builder = RestClient.builder(
new HttpHost("mycustomurlHidden.com", 9243))
.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
public HttpAsyncClientBuilder customizeHttpClient(
HttpAsyncClientBuilder httpClientBuilder) {
return httpClientBuilder
.setDefaultCredentialsProvider(credentialsProvider);
}
});
I am still getting an error, but maybe it works for you

Why is my Session gone when using RestTemplate to access Spring MVC?

I am trying to access a Spring MVC app. That uses a CSRF Token. I do an initial GET to receive the Token. Then add it to my POST with my JSESSIONID. However, during debug the Server app doesn't find my JSESSIONID. And therefore, doesn't authenticate my token, and gives me 403.
I can't tell but it looks like my GET JSESSIONID doesn't get saved in the server HTTP Session repository.
Is there a way, to validate:
The session is in the server context?
Am I sending the correct header data?
Here's my code:
public String testLogin() {
ResponseEntity<String> response =
restTemplate.getForEntity(LOGIN_RESOURCE_URL, String.class);
List<String> cookies = new ArrayList<String>();
cookies = response.getHeaders().get("Set-Cookie");
String[] firstString = cookies.get(0).split("=|;");
String jsessionPart = firstString[1];
String[] secondString = cookies.get(1).split("=|;");
String tokenPart = secondString[1];
BasicCookieStore cookieStore = new BasicCookieStore();
BasicClientCookie cookie = new BasicClientCookie("JSESSIONID",
jsessionPart);
cookie.setDomain(".mydomain.com");
cookie.setPath("/");
cookieStore.addCookie(cookie);
BasicClientCookie cookie2 = new BasicClientCookie("X-XSRF-TOKEN",
tokenPart);
cookie2.setDomain(".mydomain.com");
cookie2.setPath("/");
cookieStore.addCookie(cookie2);
HttpClient client = HttpClientBuilder
.create()
.setDefaultCookieStore(cookieStore)
.disableRedirectHandling()
.build();
HttpComponentsClientHttpRequestFactory factory = new
HttpComponentsClientHttpRequestFactory();
factory.setHttpClient(client);
RestTemplate postTemplate = new RestTemplate(factory);
HttpEntity<?> requestEntity = new HttpEntity<Object>(body, headers);
ResponseEntity<String> response = postTemplate.exchange(loginUserUrl,
HttpMethod.POST, requestEntity,String.class);
To your code sample I added user name and password plus changed the content type. The 403 still happens whether i sent content type or not:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// if you need to pass form parameters in request with headers.
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
try {
map.add( URLEncoder.encode("username", "UTF-8"),
URLEncoder.encode("userdev", "UTF-8") );
map.add(URLEncoder.encode("password", "UTF-8"),
URLEncoder.encode("devpwd","UTF-8") );
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>
(map, headers);
ResponseEntity<String> response =
this.restTemplate(builder).exchange(RESOURCE_URL, HttpMethod.POST,
requestEntity, String.class);
Instead of messing around with cookies yourself let the framework, Apache HttpClient, handle this for you. Configure the RestTemplate to work with a properly configured HttpClient.
Something like this should do the trick
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.requestFactory(this::requestFactory)
.build();
}
#Bean
public HttpComponentsClientHttpRequestFactory requestFactory() {
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.DEFAULT)
.setExpectContinueEnabled(true)
.build();
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setDefaultCookieStore(new BasicCookieStore())
.setDefaultRequestConfig(defaultRequestConfig).build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return requestFactory;
}
This will configure the RestTemplate to use a HttpClient that stores cookies in a CookieStore in between requests. Reuse the configured RestTemplate and don't create a new one because you might need it.

Add Custom ClientHttpRequestInterceptor in RestTemplateBuilder with HttpComponentsClientHttpRequestFactory

I need to add a Custom Header in all my RestTemplate Client requests. So I implemented ClientHttpRequestInterceptor. And I add the interceptor in my RestTemplateBuilder config like shown below. The problem is that when the RestTemplate makes the HTTP call it throws following exception:
java.lang.ClassCastException: org.springframework.http.client.InterceptingClientHttpRequestFactory cannot be cast to org.springframework.http.client.HttpComponentsClientHttpRequestFactory
RestTemplate Bean Creation :
#Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager();
poolingConnectionManager.setMaxTotal(restTemplateProps.getMaxConnectionsPerPool());
poolingConnectionManager.setDefaultMaxPerRoute(restTemplateProps.getMaxDefaultConnectionPerRoute());
CloseableHttpClient client = HttpClientBuilder.create().setConnectionManager(poolingConnectionManager).build();
ClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(client);
restTemplateBuilder = restTemplateBuilder.additionalInterceptors(new MyClientHttpRequestInterceptor());
return restTemplateBuilder.requestFactory(clientHttpRequestFactory).build();
}
Also, I am updating the timeouts later in below code:
protected void setRestTemplateTimeouts() {
HttpComponentsClientHttpRequestFactory rf =
(HttpComponentsClientHttpRequestFactory) restTemplate.getRequestFactory();
rf.setConnectTimeout(restTemplateProps.getConnectionTimeout());
rf.setReadTimeout(restTemplateProps.getSocketTimeout());
}
Can anyone help me fix this?
The problem was, I was trying to set the connect and read timeouts after setting the ClientHttpRequestInterceptor.
In my setRestTemplateTimeouts() method when I try to fetch & typecast requestFactory to HttpComponentsClientHttpRequestFactory, I get the ClassCastException exception because restTemplate.getRequestFactory() returns InterceptingClientHttpRequestFactory instead of HttpComponentsClientHttpRequestFactory. This is because I added an interceptor in my restTemplate object.
Solution is to set the timeouts before setting interceptor because you can't set timeouts after setting an interceptor. Refer the code below:
#Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager();
poolingConnectionManager.setMaxTotal(restTemplateProps.getMaxConnectionsPerPool());
poolingConnectionManager.setDefaultMaxPerRoute(restTemplateProps.getMaxDefaultConnectionPerRoute());
CloseableHttpClient client = HttpClientBuilder.create().setConnectionManager(poolingConnectionManager).build();
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(client);
clientHttpRequestFactory.setConnectTimeout(restTemplateProps.getConnectionTimeout());
clientHttpRequestFactory.setReadTimeout(restTemplateProps.getSocketTimeout());
restTemplateBuilder = restTemplateBuilder.additionalInterceptors(new MyClientHttpRequestInterceptor());
return restTemplateBuilder.requestFactory(clientHttpRequestFactory).build();
}
This is how i manage to get the interceptor to log both request and response without throwing exception - Attempted read from closed stream.
#Bean
public RestTemplate getRestTemplateConfig()
throws KeyStoreException, IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyManagementException {
SSLContext context = SSLContextBuilder
.create()
.loadKeyMaterial(ResourceUtils.getFile("/opt/cert/keystore.jks"),
"password".toCharArray(),
"password".toCharArray())
.build();
HttpClient client = HttpClients
.custom()
.setSSLContext(context)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(client);
RestTemplate restTemplate = new RestTemplate(requestFactory);
//Provide a buffer for the outgoing/incoming stream, allowing the response body to be read multiple times
// (if not configured, the interceptor reads the Response stream, and then returns body=null when responding to the data)
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(requestFactory));
restTemplate.setErrorHandler(new RestTemplateResponseErrorHandler());
restTemplate.setInterceptors(Collections.<ClientHttpRequestInterceptor>singletonList(
new RestTemplateInterceptor()));
restTemplate.getMessageConverters().add(jacksonSupportsMoreTypes());
return restTemplate;
}
private HttpMessageConverter jacksonSupportsMoreTypes() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Arrays.asList( MediaType.APPLICATION_OCTET_STREAM));
return converter;
}

Categories