I need to consume an API which is secured by OAuth2. For that I am using OAuth2RestTemplate.
But am getting below error:
java.net.ConnectException: Connection timed out: connect
This is happening due to proxy issue. I Know how to set proxy in RestTemplate :
SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("Proxy host", 8080));
clientHttpRequestFactory.setProxy(proxy);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
The same way I tried to set for OAuth2RestTemplate :
#Bean
public OAuth2RestOperations restTemplate(OAuth2ClientContext oauth2ClientContext) {
OAuth2RestTemplate client = new OAuth2RestTemplate(resource(), oauth2ClientContext);
SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_HOST, PROXY_PORT));
clientHttpRequestFactory.setProxy(proxy);
client.setRequestFactory(clientHttpRequestFactory);
return client;
}
But it is not working and giving "Connection timed out" exception. This is happening because of this first line OAuth2RestTemplate client = new OAuth2RestTemplate(resource(), oauth2ClientContext); which tries to get Access token that means there also it needs proxy setting. if I add below lines then it works:
System.setProperty("https.proxyHost", "urproxy.com");
System.setProperty("https.proxyPort", "8080");
But I can not use System.setProperties("","") option as we do not have permission to set on tomcat server.
I researched but could not find any way to set proxy in OAuth2RestTemplate while creating this object.
Any help would be appreciated. Thanks
OAuth2RestTemplate just creates a set of AccessTokenProvider to retrieve the token from authorization server according to different kinds of grant types. For example AuthorizationCodeAccessTokenProvider is used to retrieve access token with grant type authorization_code. The token providers themselves initiate some RestTemplate to send the request but do not use OAuth2RestTemplate just created. One way might resolve the issue. That is to create you own AccessTokenProvider and set the request factory.
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
Proxy proxy= new Proxy(Type.HTTP, new InetSocketAddress(PROXY_HOST, PROXY_PORT));
requestFactory.setProxy(proxy);
AuthorizationCodeAccessTokenProvider authorizationCodeAccessTokenProvider = new AuthorizationCodeAccessTokenProvider();
authorizationCodeAccessTokenProvider.setRequestFactory(requestFactory);
ImplicitAccessTokenProvider implicitAccessTokenProvider = new ImplicitAccessTokenProvider();
implicitAccessTokenProvider.setRequestFactory(requestFactory);
AccessTokenProvider accessTokenProvider = new AccessTokenProviderChain(
Arrays.<AccessTokenProvider> asList(authorizationCodeAccessTokenProvider, implicitAccessTokenProvider));
OAuth2RestTemplate client = new OAuth2RestTemplate(github(), oauth2ClientContext);
client.setAccessTokenProvider(accessTokenProvider);
You could also add ResourceOwnerPasswordAccessTokenProvider and ClientCredentialsAccessTokenProvider to the OAuth2RestTemplate.
This RestTemplate provides a workaround:
/**
* An OAuth2RestTemplate with proxy support.
*
* #author E.K. de Lang
*/
public class ProxySupportingOAuth2RestTemplate
extends OAuth2RestTemplate
{
private static final Logger LOG = LogFactory.getLogger(ProxySupportingOAuth2RestTemplate.class);
private final SimpleClientHttpRequestFactory factory;
public ProxySupportingOAuth2RestTemplate(OAuth2ProtectedResourceDetails resource, OAuth2ClientContext context,
AccessTokenProvider accessTokenProvider)
{
super(resource, context);
factory = new SimpleClientHttpRequestFactory();
super.setRequestFactory(factory);
super.setAccessTokenProvider(accessTokenProvider);
// To fix issue: https://github.com/spring-projects/spring-security-oauth/issues/459 also set the factory of the token-provider.
if (accessTokenProvider instanceof OAuth2AccessTokenSupport) {
((OAuth2AccessTokenSupport) accessTokenProvider).setRequestFactory(factory);
}
else {
throw new UnsupportedOperationException("accessTokenProvider must extend OAuth2AccessTokenSupport");
}
}
public void setProxy(Proxy proxy)
{
if (LOG.isDebugEnabled()) {
LOG.debug("setProxy:" + proxy);
}
if (super.getRequestFactory() == factory) {
factory.setProxy(proxy);
}
else {
throw new UnsupportedOperationException("RequestFactory has changed.");
}
}
}
Related
I have rest template config similar to the following. I am trying to release a connection from the pool if I get a status code that does not equal 2XX (long story but need this code). Is here a way I can get the connection Manager and release a specific connection?
#Bean
public RestTemplate restTemplate() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100);
connectionManager.setDefaultMaxPerRoute(20);
RequestConfig requestConfig = RequestConfig
.custom()
.setConnectionRequestTimeout(5000) // timeout to get connection from pool
.setSocketTimeout(5000) // standard connection timeout
.setConnectTimeout(5000) // standard connection timeout
.build();
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig).build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(requestFactory);
}
Looking for a way to accomplish something similar to the following
if(!httpStatusCode.substr(1).equals("2")) {
restTemplate.getConnectionPool().relase().thisConnection();
}
enter code here
I have two pieces of code using HttpClient,
First part in case that the end point requires SSL
Second is proxy connection with basic authentication
My question Is how can I make this code conditional so in cases i have SSL + Proxy or SSL only
I have hard time figuring out how to set the default credentials for example after I created the client using the client in the SSL part
.setDefaultCredentialsProvider(credsProvider)
This part is how I create the Client when I need SSL
CloseableHttpClient client = null;
if(conf.isUseSslConfig()) {
SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(new File(conf.getTrustStoreLocation()), conf.getTrustStorePassword().toCharArray(), new TrustSelfSignedStrategy()).build();
// Allow protocols
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,conf.getTlsVersions(), null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
client = HttpClients.custom().setSSLSocketFactory(sslsf).build();
}else {
client= HttpClients.createDefault();
}
And this part is how I create the Client when I need Proxy authentication:
if(conf.isUseProxyConfig()){
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope("fakeProxy.xerox.com", 80),
new UsernamePasswordCredentials("xeroxUser","fakePassword123"));
HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider).build();
}
So the bottom line is how to make the two sections work together so in case
Call with SSL + Proxy and authentication
Call with only SSL
Call with only Proxy and authentication
You can write code this way to get multiple conditions resolved :
CloseableHttpClient client = null;
if(conf.isUseSslConfig() && conf.isUseProxyConfig()) {
setSSLSetting(client);
setProxy()
}else if(conf.isUseSslConfig()) {
setSSLSetting(client);
}else {
client= HttpClients.createDefault();
}
private void setProxy(){
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope("fakeProxy.xerox.com", 80),new UsernamePasswordCredentials("xeroxUser","fakePassword123"));
}
private void setSSLSetting(CloseableHttpClient client){
SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(new File(conf.getTrustStoreLocation()), conf.getTrustStorePassword().toCharArray(), new TrustSelfSignedStrategy()).build();
// Allow protocols
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,conf.getTlsVersions(), null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
client = HttpClients.custom().setSSLSocketFactory(sslsf).build();
}
or you can create methods that return client with different settings and configs like this :
final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", new PlainConnectionSocketFactory()).register("https", sslsf).build();
final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
private CloseableHttpClient createHttpClient(String headerName, String value) throws NoSuchAlgorithmException, KeyManagementException,KeyStoreException {
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
Header header = new BasicHeader(headerName,value);
List<Header> headers = new ArrayList<>();
headers.add(header);
RequestConfig reqConfig = RequestConfig.custom().setConnectionRequestTimeout(long milli seconds).build();
CloseableHttpClient httpclient = HttpClients.custom().
setDefaultHeaders(headers).
setDefaultRequestConfig(reqConfig).
setConnectionManager(cm).
build();
return httpclient;
}
I am using Spring Rest Template inside a Spring Boot Application.
I always get 401 Unauthorized error even though I am passing the credentials.
I am able to access this service by Chrome REST Web Service Client.
Is there a simplified way to access the REST template in SpringBoot.
Below is the code snippet done so far which results in 401 error
private DetailsBean invokeDetailsRestService(UserParam userParam){
ResponseEntity<DetailsBean> responseEntity = null;
String url = "https://dev.com/app/identifyuser/";
RestClientConfig restClientConfig =new RestClientConfig("user123","pass123");
responseEntity= restClientConfig.postForEntity(url, userParam, DetailsBean.class);
log.debug("User Details : {} ", responseEntity.getBody());
return responseEntity.getBody();
}
public ClientHttpRequestFactory getRequestFactory(String userName,String password){
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials( new AuthScope(null, -1), new UsernamePasswordCredentials(userName,password) );
HttpClient httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
return new HttpComponentsClientHttpRequestFactory(httpClient);
}
RestClientConfig class
public RestClientConfig(String username, String password) {
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(null, -1),
new UsernamePasswordCredentials(username, password));
HttpClient httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
}
Error:
WARN c7af55b5-1cac-4db6-a202-202416c27ba4
12612 --- [apr-8082-exec-8] o.a.http.impl.auth.HttpAuthenticator
: NEGOTIATE authentication error:
No valid credentials provided (Mechanism level:
No valid credentials provided (Mechanism level:
Failed to find any Kerberos tgt))
The authorization issue was fixed with the below code..
Credentials should be passed to a Spring REST Template with the below code:
String userAndPass = "Test:Test123";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
headers.add("Authorization", "Basic " + Base64Utility.encode(userAndPass.getBytes()));
I faced similar issue when i'm trying to make call to webservice, this solved my issue:
restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor("userName", "password"));
restTemplate.postForObject('','',''');
Pass the credentials like this, it should solve the issue.
I used spring boot 2.2.4.RELEASE version. then I work below way.
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(username, password));
RequestDto requestDto = new RequestDto();
// set parameter
ResponseDto response = restTemplate.postForObject(URL, requestDto, ResponseDto.class);
Or
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(username, password);
RequestDto requestDto = new RequestDto();
// set parameter
HttpEntity<RequestDto> request = new HttpEntity<>(requestDto, headers);
ResponseDto response = restTemplate.postForObject(URL, request, ResponseDto.class);
My development environment is behind a proxy so i need to set the proxy information to the rest template, that's all good when i use a HttpComponentsClientHttpRequestFactory and set the proxy setting in the httpClient and set it in the template.
But now i have a rest service that needs basic auth. And to set the basic auth credentials, i need to set them in the httpClient on the rest template. But i see that the getparams method in the httpClient is depricated, so i can't just update the existing client in the template, and if i create a new httpclient object, i will overwrite the proxy info that were set during the application bootstrapping.
So is there some way that i could extract the httpClient from the rest template and update it? Or is there any other way to tackle this?
Thanks.
Configure the httpClient as follows:
HttpHost target = new HttpHost("hostname", 80, "http");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(target.getHostName(), target.getPort()),
new UsernamePasswordCredentials("user", "passwd"));
HttpHost proxy = new HttpHost("proxy", 12345);
CloseableHttpClient httpclient = HttpClients.custom()
.setProxy(proxy)
.setDefaultCredentialsProvider(credsProvider).build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpclient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
See also HttpClient Examples
The above solution did not work for me i work around the above and finally make it work with small modifications.
RestTemplate restTemplate = new RestTemplate();
HttpHost proxy =null;
RequestConfig config=null;
String credentials = this.env.getProperty("uname") + ":" + this.env.getProperty("pwd");
String encodedAuthorization = Base64.getEncoder().encodeToString(credentials.getBytes());
Header header = new BasicHeader(HttpHeaders.AUTHORIZATION, "Basic " + encodedAuthorization);
List<Header> headers = new ArrayList<>();
headers.add(header);
if(Boolean.valueOf(env.getProperty("proxyFlag"))){
proxy = new HttpHost(this.env.getProperty("proxyHost"), Integer.parseInt(env.getProperty("proxyPort")), "http");
config= RequestConfig.custom().setProxy(proxy).build();
}else{
config= RequestConfig.custom().build();
}
CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config)
.setDefaultHeaders(headers).build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
restTemplate.setRequestFactory(factory);
return restTemplate;
I'm looking to do something like the following:
#HystrixCommand(fallbackMethod = "returnLastGoodCachedCopy")
void performRequest(String someArg) {
// Make HTTP request using RestTemplate configured with EHCache
}
void returnLastGoodCachedCopy(String someArg) {
// Return the last successful response
}
For a little more background I am using Spring Boot, and setting up the RestTemplate like so to use EHCache:
#Bean
public RestTemplate restTemplate() {
return new RestTemplate(clientHttpRequestFactory());
}
#Bean
public CloseableHttpClient httpClient() {
CacheConfig cacheConfig = CacheConfig.custom()
.setMaxCacheEntries(this.httpClientProperties.getMaxCacheEntries())
.setMaxObjectSize(this.httpClientProperties.getMaxObjectSize())
.setHeuristicCachingEnabled(this.httpClientProperties.getHeuristicLifetimeEnabled())
.setHeuristicDefaultLifetime(this.httpClientProperties.getHeuristicLifetimeSeconds()).build();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(this.httpClientProperties.getConnectTimeout())
.setSocketTimeout(this.httpClientProperties.getSocketTimeout()).build();
Ehcache httpEhcache = (Ehcache) this.ehCacheManager.getCache(httpClientProperties.getCacheName())
.getNativeCache();
EhcacheHttpCacheStorage ehcacheHttpCacheStorage = new EhcacheHttpCacheStorage(httpEhcache);
CloseableHttpClient cachingClient = CachingHttpClients.custom().setCacheConfig(cacheConfig)
.setHttpCacheStorage(ehcacheHttpCacheStorage).setDefaultRequestConfig(requestConfig).build();
return cachingClient;
}
private ClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient());
return factory;
}
So my one thought was to use the same request EHCache, but I'm not sure that's an appropriate solution considering that cache is based on cache-control headers, which I'd like to be separated from so I can return a valid response regardless if it is expired or not.
My other thought was to configure a separate EHCache cache, and store the responses myself, then I can access those more easily considering I set the format of the key and the value.
Before I go down this path I want to see if there is already anything built into Hystrix that handles this situation, or if there are any other recommended approaches.