HttpUrlConnection doesn't find the NTLM challenge on Android
Asked Answered
S

3

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?

Sailer answered 18/6, 2013 at 18:15 Comment(2)
An example using HttpURLConnection and jcifs.Aerosol
If you find any solution please shrareJaquith
M
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

Minoan answered 29/10, 2013 at 5:39 Comment(5)
Thank! Yeah, looks like there is no way to do this with the current HttpURLConnection class. RegardsSailer
@Sailer 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: #18861319Signalment
@Signalment 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.Sailer
@Sailer 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?Signalment
is there any alternative for NTLM auth header in httpsurlconnection in androidJaquith
S
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());
    }
}
Subauricular answered 17/8, 2016 at 21:10 Comment(0)
D
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.

Disorder answered 21/8, 2014 at 8:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.