How to create NTLM Authentication Using spring - java

I am using NTLM authentication for my service. How to create the NTLM authentication in my API service call can anyone help with that? I need the complete coding for NTLM authentication

We use the following code to work with NTLM in production. As you can see it checks whether configuration is correct by sending simple HTTP GET.
package xxx;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.auth.*;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.impl.auth.NTLMSchemeFactory;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;
import java.util.Arrays;
#Configuration
public class Configuration {
#Bean
public WebServiceMessageSender messageSender(
#Autowired final Credentials credentials,
#Autowired final HttpUriRequest handshake,
#Value("${service.timeout}") final int timeout
) {
HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender();
CredentialsProvider credentialsProvider;
Registry<AuthSchemeProvider> registry;
RequestConfig requestConfig;
credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, credentials);
registry = RegistryBuilder.<AuthSchemeProvider> create()
.register(AuthSchemes.NTLM, new NTLMSchemeFactory())
.build();
HttpRequestInterceptor interceptor =
(request, context) -> request.removeHeaders(HttpHeaders.CONTENT_LENGTH);
requestConfig = RequestConfig.custom()
.setConnectTimeout(timeout)
.build();
CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultRequestConfig(requestConfig)
.setDefaultAuthSchemeRegistry(registry)
.setDefaultCredentialsProvider(credentialsProvider)
.addInterceptorFirst(interceptor)
.build();
try {
CloseableHttpResponse r = httpClient.execute(handshake);
if (log.isInfoEnabled()) {
log.info("Handshake initiated, response headers: {}",
Arrays.toString(r.getAllHeaders())
);
}
} catch (Exception e) {
log.error("Could not execute HTTP handshake request (method = {})",
handshake.getMethod(), e
);
}
messageSender.setHttpClient(httpClient);
return messageSender;
}
#Bean
public Credentials credentials(
#Value("${service.auth.username}") String user,
#Value("${service.auth.password}") String pass,
#Value("${service.auth.workstation}") String workstation,
#Value("${service.auth.domain}") String domain
) {
return new org.apache.http.auth.NTCredentials(user, pass, workstation, domain);
}
#Bean
public HttpUriRequest handshake(#Value("${service.uri}") final String uri) {
return new HttpGet(uri);
}
}
application.properties looks like this:
service.uri=http://somehost/somepath/SomeService.svc
service.action=http://somehost1/somepath1
service.timeout=3000
service.auth.username=someuser
service.auth.password=somepassword
service.auth.domain=somedomain
service.auth.workstation=anything

Related

Spring API doesn't login and send infos (get&set) to React with JWT with same code

The title is self explanatory, I have this API made in Spring, and after JWT implementation I can login, but the gets doesn't work anymore.
But if I comment the the CorsConfigurationSource corsConfigurationSource() and the Lombok annotation #RequiredArgsConstructor in SecurityConfig, the login stop to work, but all the gets work beautifully.
I'll post the class SecurityConfig, AuthorizationFilter and the AuthenticationFilter respectively for you guys try to see whats going wrong.
import org.alterdata.shopback.app.security.AuthenticationFilter;
import org.alterdata.shopback.app.security.AuthorizationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
#Configuration
#EnableWebSecurity
#RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
UserDetailsService userDetailsService;
#Autowired
BCryptPasswordEncoder bCryptPasswordEncoder;
#Override
protected void configure(HttpSecurity http) throws Exception {
AuthenticationFilter authenticationFilter = new AuthenticationFilter(authenticationManagerBean());
http.cors().and().csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers("/login").permitAll()
.antMatchers("/cadastrar/**").hasAnyAuthority("ADMIN")
.antMatchers("/cadastro/**").hasAnyAuthority("ADMIN")
.anyRequest().authenticated();
http.addFilter(authenticationFilter);
http.addFilterBefore(new AuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Bean
#Override
public AuthenticationManager authenticationManager()throws Exception{
return super.authenticationManager();
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE","OPTIONS", "HEAD"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Arrays;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.auth0.jwt.exceptions.JWTVerificationException;
import io.jsonwebtoken.JwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.bytebuddy.implementation.bind.annotation.IgnoreForBinding.Verifier;
import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE;
#Slf4j
public class AuthorizationFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if(request.getServletPath().equals("/login")) {
filterChain.doFilter(request, response);
}else {
String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if(authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
try {
String token = authorizationHeader.substring("Bearer ".length());
Algorithm algorithm = Algorithm.HMAC256("segredinho".getBytes());
JWTVerifier jwtVerifier = JWT.require(algorithm).build();
DecodedJWT decodedJWT = jwtVerifier.verify(token);
String user = decodedJWT.getSubject();
String [] roles = decodedJWT.getClaim("roles").asArray(String.class);
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
Arrays.stream(roles).forEach(role ->{
authorities.add(new SimpleGrantedAuthority(role));
});
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user,null, authorities);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
}catch(Exception e){
log.error("erro ao realizar o login! {}", e.getMessage());
response.setHeader("erro", e.getMessage());
response.setStatus(401);
Map<String, String> error = new HashMap<>();
error.put("mensagem de erro", e.getMessage());
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getOutputStream(), error);
}
}else {
filterChain.doFilter(request, response);
}
}
}
}
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import org.springframework.web.bind.annotation.CrossOrigin;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
#CrossOrigin(origins = {"*"})
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;
public AuthenticationFilter (AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
try{
String nome = request.getParameter("nome");
String senha = request.getParameter("senha");
UsernamePasswordAuthenticationToken uspsToken = new UsernamePasswordAuthenticationToken(nome, senha);
//response.setHeader("teste", String.valueOf(uspsToken));
return authenticationManager.authenticate(uspsToken);
}catch (Exception e){
throw new RuntimeException();
}
}
// #Override
// public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
// throws AuthenticationException {
// try{
// UserPasswordAuthRequest userPasswordAuthRequest = new ObjectMapper()
// .readValue(request.getInputStream(), UserPasswordAuthRequest.class);
//
// Authentication authentication = new UsernamePasswordAuthenticationToken(
// userPasswordAuthRequest.getNome(),
// userPasswordAuthRequest.getSenha()
// );
// return authenticationManager.authenticate(authentication);
// }catch (IOException e){
// throw new RuntimeException();
// }
// }
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
User user = (User) authResult.getPrincipal();
Algorithm algorithm = Algorithm.HMAC256("segredinho".getBytes());
String tokenAcesso = JWT.create().withSubject(user.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + 10*60*1000*60))
.withIssuer(request.getRequestURL()
.toString()).withClaim("roles", user.getAuthorities()
.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
.sign(algorithm);
String tokenRefresh = JWT.create().withSubject(user.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + 10*60*1000*60))
.withIssuer(request.getRequestURL()
.toString()).withClaim("roles", user.getAuthorities()
.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
.sign(algorithm);
Map<String, String> tokens = new HashMap<>();
tokens.put("tokenacesso", tokenAcesso);
tokens.put("tokenrefresh", tokenRefresh);
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getOutputStream(),tokens);
}
}
First try to call your api with Postman, else i think you need to add authorization jwt header to every api request after you login.
export default function authHeader() {
const user = JSON.parse(localStorage.getItem('user'));
if (user && user.accessToken) {
return { Authorization: 'Bearer ' + user.accessToken };
} else {
return {};
}
}
and then call your api like this:
return axios.get(API_URL + 'user', { headers: authHeader() });
for more informations try to visit: https://www.bezkoder.com/react-jwt-auth/
I just fixed using this global cors
#Bean
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}

Jackson: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token

I wrote a micro-service to make a HTTP call to an API. Code is as given below.
Connector Application
package com.ajay.dashboard.service;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
#SpringBootApplication
public class DellDashboardConnectorApplication {
public static void main(String[] args) {
SpringApplication.run(DellDashboardConnectorApplication.class, args);
}
#Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
Connector COntroller
package com.ajay.dashboard.service.controller;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.http.client.utils.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/*
* Created by Kulkaa
*/
#RestController
public class DellDashboardController {
private static final Logger logger = LoggerFactory.getLogger(DellDashboardController.class);
#CrossOrigin(origins = "http://localhost:8080")
#RequestMapping(method = RequestMethod.GET, value = "/incident", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> retrieveAllCircles(HttpServletRequest request) throws UnsupportedEncodingException {
logger.info("DellDashboardController -> retrieveAllIncidents : invoked.");
RestTemplate restTemplate =new RestTemplate();
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
messageConverters.add(converter);
restTemplate.setMessageConverters(messageConverters);
String formUrl = "api";
final String sysparm_query = "incident_stateNOT%20IN6%2C7%5Eassignment_group%3D4122c7f8f09cc1002283ac3a043ae3e6";
final String sysparm_display_value = "true";
final String sysparm_exclude_reference_link = "true";
try {
URIBuilder builder = new URIBuilder(formUrl);
builder.addParameter("sysparm_query", sysparm_query);
builder.addParameter("sysparm_display_value", sysparm_display_value);
builder.addParameter("sysparm_exclude_reference_link", sysparm_exclude_reference_link);
String actualUrl = builder.toString();
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic U2VydmljZV9Nb2JpbGVSZXBvcnRpbmc6U2VydmljZV9Nb2JpbGVSZXBvcnRpbmc=");
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
return restTemplate.exchange(actualUrl, HttpMethod.GET, entity, String.class);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return retrieveAllCircles(request);
}
}
When I build it by using mvn clean install, it runs perfectly. However, when I run it as SpringBoot app, I get below error:
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.lang.String out of START_OBJECT token
at [Source: (PushbackInputStream); line: 1, column: 1]
Do I need to deserialize it by using POJO class?
JSON being mapped is in the format:
{
"result": [{
data here
}]
}
Is it a json object?
Try creating a null entity. This might work
HttpEntity<String> entity = new HttpEntity<String>(null,headers);
The JSON content is invalid, so the parser breaks. So this would induce an empty content.

Testing RestTemplate with Custom HttpClient

I am developing a Spring Boot Application which calls a REST-API which frequently performs a 303 See Other redirect to the proper location.
For a given resource I start with a random initial URL, intercept the redirect to store the proper location for the next request and at last perform the redirect.
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
#Configuration
class RestTemplateFactory {
private static final Logger LOG = LoggerFactory.getLogger(RestTemplateFactory.class);
#Autowired
KeyMap keyMap;
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
HttpClient httpClient = HttpClientBuilder
.create()
.setRedirectStrategy(new DefaultRedirectStrategy() {
#Override
public boolean isRedirected(HttpRequest request, HttpResponse response,
HttpContext context) throws ProtocolException {
if (super.isRedirected(request, response, context)) {
String redirectURL = response.getFirstHeader("Location").getValue();
LOG.debug("Intercepted redirect: original={}, redirect={}", request.getRequestLine(),
redirectURL);
keyMap.put(redirectURL);
return true;
}
return false;
}
})
.build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
return builder
.requestFactory(requestFactory)
.build();
}
}
(The class KeyMap is used to store the location for some domain key, which is stored in a ThreadLocal before the RestTemplate is invoked.)
Question: How can I test this special RestTemplate?

Set timeout to WS https call in Spring (HttpsUrlConnectionMessageSender)

I am trying to set timeout for WS call. I extended WebServiceGatewaySupport and was trying to set to Sender timeout like this:
public Object marshalSendAndReceive(Object requestPayload) {
WebServiceTemplate wsTemplate = this.getWebServiceTemplate();
for (WebServiceMessageSender sender : wsTemplate.getMessageSenders()) {
try {
HttpComponentsMessageSender httpSender = (HttpComponentsMessageSender) sender;
httpSender.setReadTimeout(3000);
httpSender.setConnectionTimeout(2000);
} catch (ClassCastException | NumberFormatException cex) {
logger.warn("Cannot set WS timeout: " + cex.getMessage());
}
}
return wsTemplate.marshalSendAndReceive(requestPayload);
}
(credit to question #6733744)
However I get: Cannot set WS timeout: org.springframework.ws.transport.http.HttpsUrlConnectionMessageSender cannot be cast to org.springframework.ws.transport.http.HttpComponentsMessageSender
Can timeout be set to HttpsUrlConnectionMessageSender somehow? Or is there any other way to set timeout to https ws call in spring-boot?
Thank you.
I had the same issue, and managed to make it work using HttpComponentsMessageSender. Here is my code:
HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender();
HttpClient httpClient = HttpClientFactory.getHttpsClient(sslUtils, timeout);
messageSender.setHttpClient(httpClient);
webServiceTemplate.setMessageSender(messageSender);
I also created a new factory class HttpClientFactory that sets the SSL and timeout:
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
public class HttpClientFactory {
private static CloseableHttpClient client;
private HttpClientFactory() {
}
public static HttpClient getHttpsClient(SslUtils sslUtils, int timeout) throws Exception {
if (client != null) {
return client;
}
SSLContext sslcontext = getSSLContext(sslUtils);
SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext, new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
HttpClientBuilder httpClientBuilder = HttpClients.custom();
httpClientBuilder.addInterceptorFirst(new ContentLengthHeaderRemover());
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(timeout)
.setConnectionRequestTimeout(timeout)
.setSocketTimeout(timeout)
.build();
return httpClientBuilder.setSSLSocketFactory(factory)
.setDefaultRequestConfig(config)
.build();
}
private static class ContentLengthHeaderRemover implements HttpRequestInterceptor {
#Override
public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
request.removeHeaders(HTTP.CONTENT_LEN);
}
}
public static void releaseInstance() {
client = null;
}
private static SSLContext getSSLContext(SslUtils sslUtils) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(sslUtils.getKeystore().getInputStream(), sslUtils.getKeyPwd().toCharArray());
sslUtils.getKeystore().getInputStream().close();
KeyStore ts = KeyStore.getInstance("JKS");
ts.load(sslUtils.getTrustStore().getInputStream(), sslUtils.getTrustPwd().toCharArray());
sslUtils.getTrustStore().getInputStream().close();
SSLContextBuilder sslContextBuilder = SSLContexts.custom();
try {
sslContextBuilder = SSLContexts.custom().loadKeyMaterial(ks, ssl.getKeyPwd().toCharArray());
} catch (UnrecoverableKeyException e) {
e.printStack();
}
sslContextBuilder.loadTrustMaterial(ts, new TrustSelfSignedStrategy());
return sslContextBuilder.build();
}
}
For information the SslUtils is just a bean class that holds the keystore and truststore informations' :
public class SslUtils {
private Resource keystore;
private String keyPwd;
private Resource trustStore;
private String trustPwd;
// Getters and Setters
}
This works for me and let me use both SSL and timeout at the same. I hope this will help others.
You're getting a cast exception because HttpsUrlConnectionMessageSender and HttpComponentsMessageSender are not compatible types. They both share the same superclass (WebServiceMessageSender), but you can't cast one to the other. I think you can just use a HttpComponentsMessageSender in your WebServiceTemplate configuration. See How to set timeout in Spring WebServiceTemplate and Spring webServiceTemplate connection timeout property

How to call HTTPS restful web services using Spring RestTemplate

I am using Tomcat7, Spring framework for ReST web services.
I am trying to call an https web service using Spring RestTemplate.
I am getting the following error:
unable to find valid certification path to requested target; nested
exception is javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
I check online at stackoverflow. I tried the sample code from the url:
Access Https Rest Service using Spring RestTemplate
I couldn't get it to work.
Can anybody please tell me based on the code below what do I need to change?
Also can anybody tell me or provide me with the pom.xml file which java libraries would I need?
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.journaldev.spring.controller.EmpRestURIConstants;
import com.journaldev.spring.model.CostControlPost;
import com.journaldev.spring.model.Employee;
import com.journaldev.spring.model.RfxForUpdate;
import static org.junit.Assert.*;
import org.apache.commons.codec.binary.Base64;
import javax.net.ssl.*;
import java.io.*;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class TestExample2
{
public static final String SERVER_LIST="https://abc/sourcing/testServices";
#Test
public void testGetListOfServiceNames()
{
try
{
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(SERVER_LIST,HttpMethod.GET,null,String.class);
assertNotNull(response);
}
catch(Exception e)
{
System.out.println("e:"+e.getMessage());
}
}
}
Either you need to have certificates in your keystore or you can accept all certificates (kind off ignore certificate validation)
So you can re-define bean of rest template as
import javax.net.ssl.SSLContext;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import java.security.cert.X509Certificate;
#Bean
public RestTemplate restTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
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 restTemplate = new RestTemplate(requestFactory);
return restTemplate;
}
You should not need additional jars except for apache core, client and dependencies.

Categories