NTLM authentication using spring - java

I have a service I want to use in my application. The service uses NTLM authentication for authentication and I am trying to make a REST call with NTLM Auth.
I tried the suggestion in this thread How to set NTLM authentication in rest template Header in Spring
But it gave me a 500 error (the 401 went away though)
Only Web services with a [ScriptService] attribute on the class definition can be called from script.

#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) throws NoSuchAlgorithmException, KeyManagementException {
// IF you want to disable the ssl certification validation
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
String user = "username";
String password = "password";
String domain = "domain"; // optional
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new NTCredentials(user, password, null, domain));
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLContext(sslContext)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setDefaultCredentialsProvider(credentialsProvider)
.build();
HttpComponentsClientHttpRequestFactory customRequestFactory = new HttpComponentsClientHttpRequestFactory();
customRequestFactory.setHttpClient(httpClient);
RestTemplate build = builder.requestFactory(() -> customRequestFactory).build();
return build;
}

Related

Impossible to start multiple HTTPS connections from Spring application

I have a Spring Boot application that tries to open a javax.net.ssl.HttpsURLConnection to a server but the response received is: java.io.IOException: Server returned HTTP response code: 403 for URL: https://serverIP:8443/path
When the keyStore, trustStore and their passwords are set as system properties the request works correctly and the expected JSON response is received:
System.setProperty("javax.net.ssl.keyStore", "src/main/resources/myKeyStore.p12");
System.setProperty("javax.net.ssl.trustStore", "src/main/resources/myTrustStore.truststore");
System.setProperty("javax.net.ssl.keyStorePassword", "myPassword");
System.setProperty("javax.net.ssl.trustStorePassword", "myPassword");
But the 403 response code is received when trying to set the information in SSLContext, instead of setting the system properties, by using this method that returns an SSLContext object:
public static SSLContext getSslContext(String trustStoreFile, String keystoreFile, String password)
throws GeneralSecurityException, IOException {
final KeyStore keystore = KeyStore.getInstance("pkcs12"); // also tried with JKS
try (final InputStream inKeystore = new FileInputStream(keystoreFile)) {
keystore.load(inKeystore, password.toCharArray());
}
try (final InputStream inTruststore = new FileInputStream(trustStoreFile)) {
keystore.load(inTruststore, password.toCharArray());
}
final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX"); // also tried with .getDefaultAlgorithm()
keyManagerFactory.init(keystore, password.toCharArray());
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keystore);
X509TrustManager x509Tm = null;
for (final TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
if (trustManager instanceof X509TrustManager) {
x509Tm = (X509TrustManager) trustManager;
break;
}
}
final X509TrustManager finalTm = x509Tm;
final X509ExtendedTrustManager customTm = new X509ExtendedTrustManager() {
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return finalTm.getAcceptedIssuers();
}
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] xcs, String string, Socket socket) throws CertificateException {
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] xcs, String string, Socket socket) throws CertificateException {
}
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException {
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException {
}
};
final SSLContext sslContext = SSLContext.getInstance("TLS"); // also tried with SSL
sslContext.init(
keyManagerFactory.getKeyManagers(),
new TrustManager[]{customTm},
new SecureRandom());
final HostnameVerifier allHostsValid = new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
return sslContext;
}
OBS: The trustStore and keyStore have the same password, that's why the method has only one password parameter and used for both key and trust manager factories.
The way the getSslContext method is called and used is:
final SSLContext sslContext = SSLContextHelper.getSslContext("src/main/resources/myTrustStore.truststore",
"src/main/resources/myKeyStore.p12",
"myPassword");
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
final URL url = new URL("https://serverIP:8443/path");
final HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(sslSocketFactory);
// tried adding some headers to the request
urlConnection.addRequestProperty("Content-Type", "application/json");
urlConnection.addRequestProperty("Accept", "application/json");
urlConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0");
urlConnection.connect();
final InputStream inputstream = urlConnection.getInputStream();
The error is thrown at the last line when trying to get the inputStream of the URL connection.
Also, I tried using the following classes from org.apache.http: SSLConnectionSocketFactory, HttpClient, HttpGet, HttpResponse but response code is still 403.
I can only think that there is something missing from the SSL configuration because the system properties work. Any suggestions on what I miss setting in the SSLContext/SSLSocketFactory or how can I solve/better debug the problem are welcome! Thanks!
I managed to open the HTTPS connections only by using Spring's RestTemplate (org.springframework.web.client.RestTemplate) that uses the org.apache.http.client.HttpClient.
The method for getting the RestTemplate that has in its SSLContext the keyStore, trustStore and their passwords is the following:
public RestTemplate getRestTemplate(final String keyStoreFile, final String trustStoreFile,
final String password) throws Exception {
final SSLContext sslContext = SSLContextBuilder.create()
.loadKeyMaterial(ResourceUtils.getFile(keyStoreFile), password.toCharArray(), password.toCharArray())
.loadTrustMaterial(ResourceUtils.getFile(trustStoreFile), password.toCharArray())
.build();
final HttpClient client = HttpClients.custom()
.setSSLContext(sslContext)
.build();
final HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpComponentsClientHttpRequestFactory.setHttpClient(client);
return new RestTemplate(httpComponentsClientHttpRequestFactory);
}
The way that the RestTemplate is used for the HTTPS call is:
final String keyStoreFile = "src/main/resources/myKeyStore.p12";
final String trustStoreFile = "src/main/resources/myTrustStore.truststore";
final String password = "myPassword"; // same password for keyStore and trustStore
final String response = getRestTemplate(keyStoreFile, trustStoreFile, password).getForObject("https://serverIP:8443/path", String.class);
LOGGER.info("Response received: " + response);
Hope this helps anyone, had a lot of struggle with the HTTPS connections :)

when i use httpclient access https web for digest auth and ingore ssl auth, but the ssl error?

public class ttttt {
public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("SSLv3");
// 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
X509TrustManager trustManager = new X509TrustManager() {
#Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
#Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sc.init(null, new TrustManager[] { trustManager }, null);
return sc;
}
public static <NameValuePair, ConnectionSocketFactory> void main(String[] args) throws Exception {
String body = "";
//采用绕过验证的方式处理https请求
SSLContext sslcontext = createIgnoreVerifySSL();
//设置协议http和https对应的处理socket链接工厂的对象
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", (ConnectionSocketFactory) PlainConnectionSocketFactory.INSTANCE)
.register("https", (ConnectionSocketFactory) new SSLConnectionSocketFactory(sslcontext))
.build();
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager((Registry<org.apache.http.conn.socket.ConnectionSocketFactory>) socketFactoryRegistry);
HttpClients.custom().setConnectionManager(connManager);
HttpHost target = new HttpHost("192.168.93.46", 8443, "https");
HttpClientContext context = HttpClientContext.create();
DefaultHttpClient client = new DefaultHttpClient();
client.getCredentialsProvider().setCredentials(new AuthScope(null, -1, null), new UsernamePasswordCredentials("cdrapi", "cdrapi123"));
HttpPost post = new HttpPost(URI.create("/cdrapi?format=xml"));
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add((NameValuePair) new BasicNameValuePair("domain", "username"));
post.setEntity((HttpEntity) new UrlEncodedFormEntity((List<? extends org.apache.http.NameValuePair>) nvps, HTTP.UTF_8));
BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials("cdrapi", "cdrapi123"));
BasicAuthCache authCache = new BasicAuthCache();
DigestScheme digestAuth = new DigestScheme();
digestAuth.overrideParamter("algorithm", "MD5");
digestAuth.overrideParamter("realm", "passwd");
digestAuth.overrideParamter("nonce", "5b3edf3c:cd95b19ed02ecab20f7a9aa24c3373df");
//digestAuth.overrideParamter("nonce", Long.toString(new Random().nextLong(), 36));
digestAuth.overrideParamter("qop", "auth");
digestAuth.overrideParamter("nc", "0");
digestAuth.overrideParamter("cnonce", DigestScheme.createCnonce());
Header auth = digestAuth.authenticate(new
UsernamePasswordCredentials("cdrapi", "cdrapi123"), post);
System.out.println(auth.getName());
System.out.println(auth.getValue());
post.setHeader(auth);
authCache.put(target, digestAuth);
context.setCredentialsProvider(credsProvider);
context.setAuthCache(authCache);
HttpGet httpget = new HttpGet("/cdrapi?format=xml");
CloseableHttpResponse response = client.execute(target, httpget, context);
}
}
Authorization
Digest username="cdrapi", realm="passwd", nonce="5b3edf3c:cd95b19ed02ecab20f7a9aa24c3373df", uri="/cdrapi?format=xml", response="8a5889daee18112d7849e5b77ab015b6", qop=auth, nc=00000001, cnonce="215922d8ee580938", algorithm=MD5
Exception in thread "main" 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
This line has no effect because you ignore the builder it creates for you:
HttpClients.custom().setConnectionManager(connManager);
You then create your client like this which doesn't know anything about your custom connection manager.
DefaultHttpClient client = new DefaultHttpClient();
Solution:
CloseableHttpClient client =
HttpClients.custom().setConnectionManager(connManager)
.build();

javax.net.ssl.SSLHandshakeException: Handshake failed in Android 7.0

I am calling API to login but I am getting error of ssl handshake in Android 7.0, other than this version everything is working fine. I am using retrofit.
Following is the error.
SSL handshake terminated: ssl=0xcbcd0340: Failure in SSL library, usually a protocol error
error:1000043e:SSL routines:OPENSSL_internal:TLSV1_ALERT_INAPPROPRIATE_FALLBACK (external/boringssl/src/ssl/s3_pkt.c:610 0xebc87640:0x00000001)
Also as said by someone to add the following code so that this issue will be resolved but still no luck,
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
.build();
okHttpClient.connectionSpecs(Collections.singletonList(spec));
I have even tried to letgo trust each and every certificate but still no luck. Following is the code.
public static OkHttpClient.Builder sslSocketFactory(OkHttpClient.Builder okHttpClient)
{
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_0)
.allEnabledCipherSuites()
.build();
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final javax.net.ssl.SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
//////// OkHttpClient.Builder builder = new OkHttpClient.Builder();
okHttpClient.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
okHttpClient.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Following are my ssllabs tested using android 7.0
ssllabs test
In all other android versions all API's are working fine I do get response, but I am not able to get response in version 7.0.
Actually it's more likely to be a ssl_ciphers server-side settings problem.
Assuming nginx, change your ssl_ciphers settings to the one recommended by openHab :
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!EDH:!kEDH:!PSK:!SRP:!kECDH;
Don't forget to reload (systemctl reload nginx) and now all problematic android devices should work just fine.

Random javax.net.ssl.SSLExceptions using OkHttp client

In my android app am using a okhttp client which trusts all ssl certificates. The problem is, am facing random SSLExceptions. For example 8 out of 10 calls fail due to SSLExceptions and 2 succeed.
Any pointers on why this might be happening?
Please let me know if you need more info.
stack trace:
javax.net.ssl.SSLException: Connection closed by peer
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)
at com.squareup.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:103)
at com.squareup.okhttp.Connection.connect(Connection.java:143)
at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:185)
at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341)
at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330)
at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
at com.squareup.okhttp.Call.getResponse(Call.java:273)
at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:230)
at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:201)
at com.squareup.okhttp.Call.execute(Call.java:81)
at retrofit.client.OkClient.execute(OkClient.java:53)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:326)
at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:278)
at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at retrofit.Platform$Android$2$1.run(Platform.java:142)
at java.lang.Thread.run(Thread.java:841)
This is how i create the okHttp client:
private OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
return createOkHttpClientWithTimeout(sslSocketFactory);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
protected OkHttpClient createOkHttpClientWithTimeout(SSLSocketFactory sslSocketFactory) {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setConnectTimeout(CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
okHttpClient.setReadTimeout(READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
okHttpClient.setSslSocketFactory(sslSocketFactory);
okHttpClient.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
return okHttpClient;
}
Note: I know that trusting all SSL certificates is bad.

openid4java YadisException peer not authenticated error

I am writing a Java JSP code that authenthicates against a WSO2 IS server using openid. I have taken the example code from de developer so I get the following:
<%
ConsumerManager manager = new ConsumerManager ();
String _returnURL = "https://192.168.15.48:9443/ficlient/secret.jsp";
List discoveries = manager.discover("https://myserverIP/openid");
DiscoveryInformation discovered = manager.associate(discoveries);
session.setAttribute("discovered", discovered);
AuthRequest authReq = manager.authenticate(discovered, _returnURL);
nextlink = authReq.getDestinationUrl(true);
%>
Secret data
On the 3rd line (List discoveries...) I get an exception:
org.openid4java.discovery.yadis.YadisException: 0x704: I/O transport error: peer not authenticated
I have understood that this is due to a non valid ssl certificate issued for the https comunication and have tried including the following (as found on Internet), to avoid the verification:
<%
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) {}
public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) {}
}
};
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
} catch (Exception e) {}
%>
But it is still not working. What have I missed?
I finally solved it by using Oltu libraries for authenthication.

Categories