NTLM Authentication in Android.

I was developing an Android app which uses SOAP library to call .Net web services. Web services were not accessible directly. Before calling web services user must get authenticated. Here I met with concept called Windows Authentication.

I searched on internet for  NTLM authentication in Android. I came up with using DefaultHttpClient class provided in  org.apache.http.impl.client package.

I was able to log in by using below code ,

 NtlmTransport httpTransport = new NtlmTransport();
 httpTransport.setCredentials(URL, USERNAME, PASSWORD, "","");
 SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
 envelope.dotNet = true;    
 envelope.implicitTypes = true;
 envelope.setOutputSoapObject(request);                
 httpTransport.call(PRODUCT_DETAILS_SOAP_ACTION, envelope);

But It was not possible for me to call complex web services which accept some parameters. I searched on internet but I didn’t get any solution for that.I was using android-ntlm-master library project which has NtlmTransport.java class in it.This class extends org.ksoap2.transport.Transport class.To see what happens inside I extracted this org.ksoap2.transport.Transport class from ksoap library.

This is a abstract class for both HttpTransportSE and NtlmTransport class. I did one change here in Transport class.I added one method call() which looks like this,

public void call(String targetNamespace, SoapEnvelope envelope) throws IOException, XmlPullParserException {
      this.call(targetNamespace, envelope, (List)null);
   }

Now Transport.java class looks like this:

package org.ksoap2.transport;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Proxy;
import java.util.List;
import org.ksoap2.SoapEnvelope;
import org.kxml2.io.KXmlParser;
import org.kxml2.io.KXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;

public abstract class Transport {

   protected Proxy proxy;
   protected String url;
   protected int timeout;
   public boolean debug;
   public String requestDump;
   public String responseDump;
   private String xmlVersionTag;


   public Transport() {
      this.timeout = 20000;
      this.xmlVersionTag = "";
   }

   public Transport(String url) {
      this((Proxy)null, url);
   }

   public Transport(String url, int timeout) {
      this.timeout = 20000;
      this.xmlVersionTag = "";
      this.url = url;
      this.timeout = timeout;
   }

   public Transport(Proxy proxy, String url) {
      this.timeout = 20000;
      this.xmlVersionTag = "";
      this.proxy = proxy;
      this.url = url;
   }

   protected void parseResponse(SoapEnvelope envelope, InputStream is) throws XmlPullParserException, IOException {
      KXmlParser xp = new KXmlParser();
      xp.setFeature("http://xmlpull.org/v1/doc/features.html#process-namespaces", true);
      xp.setInput(is, (String)null);
      envelope.parse(xp);
   }

   protected byte[] createRequestData(SoapEnvelope envelope) throws IOException {
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      bos.write(this.xmlVersionTag.getBytes());
      KXmlSerializer xw = new KXmlSerializer();
      xw.setOutput(bos, (String)null);
      envelope.write(xw);
      xw.flush();
      bos.write(13);
      bos.write(10);
      bos.flush();
      return bos.toByteArray();
   }

   public void setUrl(String url) {
      this.url = url;
   }

   public void setXmlVersionTag(String tag) {
      this.xmlVersionTag = tag;
   }

   public void reset() {
   }

   public abstract List call(String var1, SoapEnvelope var2, List var3) throws IOException, XmlPullParserException;

   public void call(String targetNamespace, SoapEnvelope envelope) throws IOException, XmlPullParserException {
      this.call(targetNamespace, envelope, (List)null);
   }

   public abstract String getHost();

   public abstract int getPort();

   public abstract String getPath();
}
and NtlmTransport.java class:
package com.example.ksoapdemo;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeFactory;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.auth.NTLMScheme;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.ksoap2.HeaderProperty;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.transport.ServiceConnection;
import org.ksoap2.transport.Transport;
import org.xmlpull.v1.XmlPullParserException;
import org.apache.http.HttpEntity;
import eu.masconsult.android_ntlm.JCIFSEngine;

public class NtlmTransport extends Transport {

    static final String ENCODING = "utf-8";

    private final DefaultHttpClient client = new DefaultHttpClient();
    private final HttpContext localContext = new BasicHttpContext();
    private String urlString;
    private String user;
    private String password;
    private String ntDomain;
    private String ntWorkstation;

    public void setCredentials(String url, String user, String password,
                               String domain, String workStation) {
        this.urlString = url;
        this.user = user;
        this.password = password;
        this.ntDomain = domain;
        this.ntWorkstation = workStation;

    }

    public List call(String targetNamespace, SoapEnvelope envelope, List headers)
            throws IOException, XmlPullParserException {
        return call(targetNamespace, envelope, headers, null);
    }

    public List call(String soapAction, SoapEnvelope envelope, List headers, File outputFile)
            throws IOException, XmlPullParserException {
        
        HttpResponse resp = null;
        try {
            //setupNtlm(urlString, user, password);  
             DefaultHttpClient httpclient = new DefaultHttpClient();
             httpclient.getAuthSchemes().register("ntlm", new NTLMSchemeFactory());
             httpclient.getCredentialsProvider().setCredentials(            
                    new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),               
                    new NTCredentials(user, password, "", "")
             );
             HttpPost httpget = new HttpPost(urlString);       
             httpget.addHeader("soapaction",  soapAction);        
             httpget.addHeader("Content-Type", "text/xml; charset=utf-8");
             byte[] requestData = null;
             try {
                 requestData = createRequestData(envelope);                 
             } catch (IOException iOException) {
             }
             ByteArrayEntity byteArrayEntity = new ByteArrayEntity(requestData);
             httpget.setEntity(byteArrayEntity);                
             resp = httpclient.execute(httpget); 

             if(resp  == null) {
                System.out.println("Response is null");
             }
             HttpEntity respEntity = resp.getEntity();

             InputStream is = respEntity.getContent();
             if(is == null) {
                System.out.println("InputStream is null");
             }
             parseResponse(envelope, is);

        } catch (Exception ex) {
            // ex.printStackTrace();
        }

        if (resp != null) {
            return Arrays.asList(resp.getAllHeaders());
        } else {
            return null;
        }
    }

    private void setHeaders(String soapAction, SoapEnvelope envelope, HttpPost httppost, List headers) {
        byte[] requestData = null;
        try {
            requestData = createRequestData(envelope);
        } catch (IOException iOException) {
        }
        ByteArrayEntity byteArrayEntity = new ByteArrayEntity(requestData);
        httppost.setEntity(byteArrayEntity);
        httppost.addHeader("User-Agent", "kSOAP/2.0");
        httppost.addHeader("SOAPAction", soapAction);
        httppost.addHeader("Content-Type", "text/xml; charset=utf-8");
        //org.ksoap2.transport.Transport.USER_AGENT);
        // SOAPAction is not a valid header for VER12 so do not add
        // it
        // @see "http://code.google.com/p/ksoap2-android/issues/detail?id=67
      /*  if (envelope.version != SoapSerializationEnvelope.VER12) {
            httppost.addHeader("SOAPAction", soapAction);
        }

        if (envelope.version == SoapSerializationEnvelope.VER12) {
            httppost.addHeader("Content-Type", Transport.CONTENT_TYPE_SOAP_XML_CHARSET_UTF_8);
        } else {
            httppost.addHeader("Content-Type", Transport.CONTENT_TYPE_XML_CHARSET_UTF_8);
        }*/

        // Pass the headers provided by the user along with the call
        if (headers != null) {
            for (int i = 0; i < headers.size(); i++) {
                HeaderProperty hp = (HeaderProperty) headers.get(i);
                httppost.addHeader(hp.getKey(), hp.getValue());
                //System.out.println(hp.getKey()+":"+hp.getValue());
            }
        }
    }

    // Try to execute a cheap method first. This will trigger NTLM authentication
    public void setupNtlm(String dummyUrl, String userId, String password) {
        try {

            ((AbstractHttpClient) client).getAuthSchemes().register("ntlm", new NTLMSchemeFactory());

            NTCredentials creds = new NTCredentials(userId, password, ntWorkstation, ntDomain);
            client.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);

            HttpGet httpget = new HttpGet(dummyUrl);

            HttpResponse response1 = client.execute(httpget, localContext);
            HttpEntity entity1 = response1.getEntity();

            Header[] hArray = response1.getAllHeaders();
            int size = hArray.length;
          /*  StatusLine status = response1.getStatusLine();
            System.out.println("SERVER STATUS CODE"+status.getStatusCode());*/
            for (int i = 0; i < size; i ++) {
                Header h = hArray[i];
               //System.out.println(h.getName()+":"+h.getValue());
                if (h.getName().equals("WWW-Authenticate")) {
                    entity1.consumeContent();
                    throw new Exception("Failed Authentication");
                }
            }
           /* StatusLine status = response1.getStatusLine();
            System.out.println("SERVER STATUS CODE"+status.getStatusCode());
            String responseBody = EntityUtils.toString(entity1);
            System.out.println("================================");
            System.out.println(responseBody);
            System.out.println("================================");*/
            entity1.consumeContent();
        } catch (Exception ex) {
            // swallow
        }
    }

        //NTLM Scheme factory
    private class NTLMSchemeFactory implements AuthSchemeFactory {
        public AuthScheme newInstance(final HttpParams params) {
        // see http://www.robertkuzma.com/2011/07/
        // manipulating-sharepoint-list-items-with-android-java-and-ntlm-authentication/
            return new NTLMScheme(new JCIFSEngine());
        }
    }

    public ServiceConnection getServiceConnection() throws IOException
    {
        throw new IOException("Not using ServiceConnection in transport");
    }

    public String getHost() {
        String retVal = null;
        try {
            retVal = new URL(url).getHost();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return retVal;
    }

    public int getPort() {
        int retVal = -1;
        try {
            retVal = new URL(url).getPort();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return retVal;
    }

    public String getPath() {
        String retVal = null;
        try {
            retVal = new URL(url).getPath();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return retVal;
    }
}

To call any web service from your app one just needs to write below code:

      SoapObject request = new SoapObject(NAMESPACE, PRODUCT_DETAILS_METHOD_NAME);
      request.addProperty("ListingID", Integer.parseInt(Product_ID));
      NtlmTransport httpTransport = new NtlmTransport();
      httpTransport.setCredentials(URL, USERNAME, PASSWORD, "","");
      SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
      envelope.dotNet = true;    
      envelope.implicitTypes = true;
      envelope.setOutputSoapObject(request);                
      httpTransport.call(PRODUCT_DETAILS_SOAP_ACTION, envelope);
      SoapObject response = (SoapObject) envelope.getResponse();

I know this is not a one time authentication. Each time before calling web service one need to use this code.I need to use NtlmTransport class. But it solved my issue.

संगणक अभियंत्यांचे पसायदान

आता विश्वात्मके देवे ।येणे संगणक ज्ञाने तोषावे ।
तोषोनी आम्हा द्यावे । नोकरीदान हे ।।

जे बेरोजगार त्यास नोकरी लागो । त्यांना घसघशीत पगारवाढ लाभो ।
बॉसची त्यांवरी राहो । अभूतपूर्व प्रीती ।।

मालकशाही निघून जावो । कामगारांचे राज्य येवो ।
जो जे वांच्छिल तो तें लाहो । कामगार समाज हा ।।

सकळ कामगार मंडळी । संगणक अभियंत्यांची मांदियाळी ।
अनवरत भूमंडळी । भेटत राहो ।।

चला कंपनी मध्ये जाऊ । टाईम पास करून येऊ ।
व्यवस्थापक लोकांना दाखवुं । कधीच न केलेले काम ।।

कामचुकारपणा हे ज्यांचे लक्षण । deliveries उशीर हे ज्यांचे भूषण ।
ते समस्त कामगार जन । सोयरे होतु।।

किंबहुना आंतरजाली (Internet) । पडून राहू  तिन्ही काळी ।
सदैव कळफलक आदळी । खटा खटा ।।

आणि गुगल च्या कृपाशिर्वादाने । सदैव कोड copy -paste करणे ।
R&D केली म्हणून सांगणे । पचून जावे जी ।।

येथ म्हणे श्री विश्वेशराओ । हा होईल दान पसावो ।
येणे वरे कामगार सर्व । सुखिया झाले ।।

मराठी विश्व

असा बेभान हा वारा computer engineer साठी

असा हा प्रोजेक्ट चा पसारा , नवीन कोड कुठे टाकू .

डिलिवरीस उशीर झालेला ,सुट्टी कसा घेऊ ,कसा घेऊ

client ,प्रोजेक्ट manager  विखारी नजर टाकती

भिडे मेंदू फाटलेल्या प्रोजेक्टला , डोळ्यांचे भोवरे होती

जीवाची तगमग माझ्या कुणाला सांगू

मैत्रीचे ,नात्यांचे तोडले मी धागे

बुडाली सर्व नाती , बुडाले जिवलग मित्र मागे

दिला शाप दैवाने ,कुठे कसा मी फेडू

कंपनी च्या CEO चे विषारी शब्द झेलीत आलो

शेवटी राजीनामा देऊन मुक्त मी झालो

तुमचे तुम्ही बघून घ्या आता ,किती मी त्रास घेऊ .

campus selection कि कहाणी मुन्ना भाई कि जुबानी

साला आपुन जैसा year down को क्या मालूम campus selection किस चिडिया का नाम है

नोटस निकालके जैसा तैसा अपुन पास होता है ,कभी कभी backlog भी रखता है
आपण के साल ऐसे हि कटते है
फिर ये campus selection का लफडा कायको ,कायको
फिर बोले तो एक दिन आपण के कॉलेज मै एक कंपनी आई ,
आपण का खोपडी चक्कर खा गया ,साला aptitude कि किताब से टक्कर खा गया ,
फिर दिन रात आपण पढाई करणे लग गया
कंपनी aptitude में आपण clear हो गया
round आया group discussion का
और कंपनी HR आपण से बोली ,
यहा इंग्लिश आणि चाहिये ,टपोरी लोगोंका कोई काम नही
सालीने आपण को अपनी औकात दिखा दि
उस रात आपण पुरी रात जागता राहा
पर रोया नही
कायको रोयेगा ,कायको रोयेगा
साला है आपण टपोरी ,उसमे इतना  बुरा लगनेका क्या है
अगले दिन वही कॉलेज ,वही campus
वही टपरी पे गंदे ग्लास मै चाय लेना
वही दोस्तोन का अड्डा ,उसी तरह गप्पे लगाना
ऐसे हि दिन बित गये
कुछ दिनो बाद आपण के कॉलेज मै एक और कंपनी आई ,
आपण का खोपडी फिर से चक्कर खा गया ,साला aptitude कि किताब से फिर से  टक्कर खा गया ,
आपण फिर से दिन रात पढाई करणे लगा
aptitude clear हो गया ,
HR round आया ,आपण थोडा डर गया ,
जैसे तैसे interview देकर आपण घर आया ,
एक दिन mailbox मै एक mail देखा ,
साला आपण तो कंपनी मै select हो गया

प्रेम म्हणजे प्रेम असत ,पण सगळ्यांचच same नसत

प्रेम म्हणजे प्रेम असत ,पण सगळ्यांचच same नसत

काहीजणांचे उघड उघड असते
काहीजणांचे लपून छपून असते

काहीजणांचे अलिशान हॉटेल मध्ये
तर  काहीजणांचे रस्त्यावरच्या टपरी मध्ये असते

काहीजणांचे महागडे दागिने देऊन
तर काहीजणांचे साधे गुलाबाचे फुल देऊन असते

काहीजणांचे परदेशात जाऊन
तर  काहीजणांचे लोणावळा , खंडाळ्याला जाऊन असते

शेवटी प्रेम म्हणजे प्रेमच असते
पण ज्याच्या त्याच्या ऐपतीप्रमाणे असते

मनाचे श्लोक संसारी पुरुषांसाठी

मना सज्जना काही हित करावे

एक आपल्या बायकोसी मनी धरावे

महाराणी ती आपल्या सर्व संसाराची

जनी सांगता लाज ती कशाची

न बोले मना पत्नीवीन काही

परस्त्री विषयी बोलता काहीही सुख नाही

घडी घडी ने काळ आयुष्य नेतो

अंतकाळी तुला कोण साथ देतो

मना पत्नीवीन वाया का कष्ट करावे

मुलांमध्ये व्यर्थ का बसावे

सदा सर्वदा नाम तिचेच असावे

परस्त्री विषयी मनी पाप नसावे

मना वीट मानू नको पत्नीच्या बोलण्याचा

पुढे मागे संसार जोडेल कैसा

सुखाची घडी लोटता सुख आहे

पुढे सर्व जाईल फक्त पत्नीच राहे

मना सज्जना आणखी एक करावे

मरावे परी कधी लग्न न करावे

कणा कविता खास कंपनी बंद पडलेल्या CEO साठी

ओळखलत का मला उन्हाताणात आला कोणी ,

कपडे होते फाटके तुटके डोक्यावर केसांचा पत्ता नाही .
क्षणभर बसला नंतर हसला बोलला वरती पाहून,
कंपनी बंद पडली गेले employee पळून
निष्णात संगणक अभियन्त्यासारखे माझ्याभोवती नाचले ,
मोकळ्या हाती जातील कसे बक्कळ पगार घेऊन पळाले
कंपनी बुडाली ,घरावर जप्ती आली ,होते नव्हते ते सगळे गेले ,
प्रसाद म्हणून फुटके तुटके ऑफिस मात्र राहिले ,
२-३ fresher लोकांना घेऊन दिवस ढकलतो  आहे
client च्या शिव्या खात आहे ,उरलेले कर्ज फेडत आहे
दांडूक्याकडे हात जाताच हळूच उठला ,
मारू नका मला थोडा एकटे पणा वाटला
बंद पडली कंपनी तरी गेला नाही चाभरट  पणा
पाठीवरती हात ठेऊन फ़क़्त मला CEO म्हणा .

एका सज्जन मुलाने लिहिलेले आत्मवृत्त

सज्जन मी फार तसा कधी कोणत्या मुलीस छेडले नाही ,

दिसता सुंदर युवती मी कधी नजर वाकडी केली नाही
परी काल मंदिरी भेटली एक अनुपम युवती ,
पाहे मी टकमक तिला जसा भ्रमर फिरे फुलाभोवती
सुचेना मज काही रात्र दिन आता तीच दिसे
मज तरी वाटे ती स्वर्गीची अप्सरा कि रंभा असे
पुजारी मी तुझे प्रेम मंदिरातला ,
जय जगदंबे पूर्ण कदम्बे देह मी तुज अर्पिला .
अन्न पाणी गोड न लागे ध्यास तुझा लागला
वाट तुझी पाहता रात्रीचा दिन झाला
पडताच तुझा नेत्र कटाक्ष मन मयुर थॆ थॆ नाचे ,
पवित्र तुझे नाम सदैव वसे माझे वाचे
मन झाले माझे चंचल ,व्यर्थ भासे मज हि दुनिया ,
प्रेम वर्षाव करुनी कृतार्थ करी माझी काया
देवू  मी तुला सुवर्ण धाग्यांची साडी ,
कि आणू बसावयास हरणांची गाडी
सांग तुझी इच्छा काय केल्या तू प्रसन्न होशी

सेवक मी  तुझा कधी  कृपा दृष्टी करीशी

कामगार दिनाचे औचित्य साधून संगणक कामगारांनी केलेल्या काही मागण्या

आम्ही संगणक अभियंता असलो तरी शेवटी कामगारच आहोत . कामगार असल्यामुळे आमच्या काही अपेक्षा आहेत .

१>  दिवसाचे ८ तास काम करवून घेणे हे अतिशय अमानुष आहे . त्याऐवजी T२०  चा आदर्श घेऊन ६ तासाचे काम असावे .
२>  दर शनिवार रविवार सुट्टी असावी .
३>  दिवसभरात कमीत कमी ३ तास सुट्टी असावी .
४>  दुपारची वेळ कंटाळवाणी असते . त्यावेळेस कामगारांना झोपी जाण्याची परवानगी द्यावी .
५> बैठक खोली प्रमाणे खास झोप घेण्यासाठी एक खोली असावी
६> दुपारच्या कंटाळवाण्या वेळेत cheerleaders चा एक फक्कड dance कार्यक्रम असावा .
७> cheerleaders चा खर्च परवडत नसल्यास cheerleaders म्हणून HR ची नेमणूक करावी आणि त्यांना आवश्यक ते प्रशिक्षण द्यावे .
८> प्रकृती अस्वास्थ्यामुळे घेतलेल्या रजेसाठी वैद्यकीय प्रमाणपत्र मागू नये . खरे वैद्यकीय प्रमाणपत्र आम्ही दरवेळेस देऊ शकत नाही आणि खोटे वैद्यकीय प्रमाणपत्र देण्याची आमची हिम्मत नाही .
९> कंपनी तर्फे एक वेळचे जेवण मोफत दिले जावे . आठवड्यात कमीत कमी दोनदा मटन आणि शाकाहारी लोकांसाठी श्रीखंड पुरी यांचे जेवण असावे .
१०> दर महिन्यातून एकदा कंपनीची सहल काढण्यात यावी . त्यातसुद्धा  cheerleaders चा खास कार्यक्रम असावा . cheerleaders चा खर्च परवडत नसल्यास कंपनी मधील बर्यापैकी दिसणाऱ्या मुलीसुद्धा चालून जातील .
कृपया वरील मागण्या प्राधान्याने मान्य कराव्यात .

Just logic.Nothing else.