7

I'm trying to connect my Android app to an IIS server using the HttpUrlConnection class.

My server needs the user to be authenticate, so it is sending the following challenge to the client :

WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM

My problem is that HttpUrlConnection doesn't seems to parse it. So getPasswordAuthentication() is never call, and it return an IOException "no authentication challenges found".

Here is my code :

Authenticator.setDefault(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {                  

            return new PasswordAuthentication("myUsername", "myPassword".toCharArray());
    }               
});

URL url = new URL(myUrl);               
HttpURLConnection conn = (HttpURLConnection) url.openConnection();          

conn.setRequestMethod("GET");
conn.setRequestProperty("Accept-Encoding", "gzip");
conn.setRequestProperty("Accept-Charset", "UTF-8");         
conn.setRequestProperty("Accept", "*/*");
conn.setRequestProperty("Connection", "close");
conn.setDoOutput(true);
conn.setDoInput(true);          

try 
{   
    conn.connect();             
    status_code = conn.getResponseCode();   
}catch (IOException e) {
    ...             
}

I'm really starting to think that NTLM challenge is just not supported by HttpUrlConnection. I saw some libraries that seems to do the work, but I would prefer not to use external libraries.

Can somebody confirm if it is possible or not to make HttpUrlConnection handle NTLM challenge without external libs?

whyoz
  • 5,168
  • 47
  • 53
NLemay
  • 2,331
  • 3
  • 29
  • 45

3 Answers3

3

I've only been able to make it work with HttpClient by setting the AuthScheme and the library below: http://jcifs.samba.org/src/jcifs-krb5-1.3.17.zip.

HttpClient httpclient = new HttpClient(httpParameters, context);
NTCredentials creds = new NTCredentials(“username”, “password”, "", "dir");
httpclient.getCredentialsProvider().setCredentials(
              new AuthScope(context.getString(“whatever is your main URL”), -1), creds);
httpclient.getAuthSchemes().register("ntlm", new NTLMSchemeFactory());

Then you implement the the JCIFS engine and factory. You can find samples in http://hc.apache.org/httpcomponents-client-4.2.x/ntlm.html

  • Thank! Yeah, looks like there is no way to do this with the current HttpURLConnection class. Regards – NLemay Oct 29 '13 at 19:35
  • @NLemay I have a similar situation going on that I now have to revisit..once you successfully authenticate, what header needs to be added or what needs to be done to "keep-alive" that connection for a whole session? I wrote a detailed question here: http://stackoverflow.com/questions/18860819/android-ntlm-authentication-ksoap-and-persistent-connections – whyoz Jan 15 '14 at 18:47
  • @whyoz I just looked at your question, but I don't use your library so I don't have a clue. But did you tried eplozada' solution? HttpClient is a widespread library, you will get much more help for it. But I actually didn't tried myself, I just decided to not support NTLM on Android. – NLemay Jan 15 '14 at 19:11
  • @NLemay yeah, ultimately I can authenticate and get the 200 status, but how do I keep that alive? I could auth with eplozada's code, but that doesn't open the connection "for good." Any ideas on that issue? – whyoz Jan 15 '14 at 21:53
  • is there any alternative for NTLM auth header in httpsurlconnection in android – Suresh kumar Jul 20 '17 at 13:22
2

We can still make it work with HttpsURLConnection - Define an Authenticator and bypass Certvalidation (Trusting all Certs)

package com.infosec.utils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLConnection;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class SSLConnect {

        public static void main(String[] args) throws Exception {

            String urlString = System.getProperty("url", "https://yourURLgoesHere:8443/test?");
            CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
            Authenticator.setDefault(new MyAuthenticator("domainname\\yourname", "yourpassword"));


            URL url = new URL(urlString);
            URLConnection urlConnection = url.openConnection();
            HttpsURLConnection httpsUrlConnection = (HttpsURLConnection) urlConnection;
            SSLSocketFactory sslSocketFactory = createTrustAllSslSocketFactory();
            httpsUrlConnection.setSSLSocketFactory(sslSocketFactory);


            try (InputStream inputStream = httpsUrlConnection.getInputStream()) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                String line = null;
                while ((line = reader.readLine()) != null) {
              // if you want to print the content
                  System.out.println(line);

                }
            }
        }

      // Trust any Server that provides the SSL certificate by bypassing trust managers 

        private static SSLSocketFactory createTrustAllSslSocketFactory() throws Exception {
            TrustManager[] byPassTrustManagers = new TrustManager[] { new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }

                public void checkClientTrusted(X509Certificate[] chain, String authType) {
                }

                public void checkServerTrusted(X509Certificate[] chain, String authType) {
                }
            } };
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, byPassTrustManagers, new SecureRandom());
            return sslContext.getSocketFactory();
        }

}

// Authenticator which intercepts and provide required credential

class MyAuthenticator extends Authenticator {
    private String httpUsername;
    private String httpPassword;

    public MyAuthenticator(String httpUsername, String httpPassword) {
        this.httpUsername = httpUsername;
        this.httpPassword = httpPassword;
    }

    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        System.out.println("Scheme:" + getRequestingScheme());
        return new PasswordAuthentication(httpUsername, httpPassword.toCharArray());
    }
}
anandha
  • 21
  • 3
1

HttpUrlConnection works with NTLM using http://jcifs.samba.org/ The library just needs some minor adjustments like removing smb java code that you either don't need and fixing retrieving responseCode.

Balki
  • 688
  • 6
  • 9