Android: Autenticación NTLM, ksoap y conexiones persistentes

Después de trabajar con iOS y enfrentar desafíos de autenticación sin mucha curva de aprendizaje, descubrí que la autenticación de Windows es un proceso mucho más complicado en Java / Android.

Intenté varios enfoques diferentes, así que sin meterme demasiado en ellos, llegaré al que funcionó en su mayor parte. Ahora estoy usando la clase creada para NTLM y ksoap llamada NtlmTransport

Ahora me autentico con éxito de la siguiente manera:

NtlmTransport httpTransport = new NtlmTransport();
            httpTransport.setCredentials(serverURL, Login.username, Login.password, deviceIp, "DOMAINNAME");
            httpTransport.call(SOAP_ACTION, envelope);

Si observa la clase NtlmTransport, verá que devuelve los siguientes encabezados de setupNtlm ():

status Line HTTP / 1.1 200 OK Control de caché de configuración: privado, max-age = 0Setup Content-Type: text / html; charset = utf-8 Servidor de configuración: Microsoft-IIS / 8.0Setup X-AspNet-Version: 4.0.30319Setup Persistent-Auth: trueSetup X-Powered-By: ASP.NETFecha de configuración: martes, 17 de septiembre de 2013 20:57:45 GMT Longitud del contenido de configuración: 11549

The "Persistent-Auth: true es la principal que me preocupa en este momento. Estoy obteniendo los SoapObjects muy bien y puedo obtener los datos que necesito de esa conexión, pero tan pronto como intento acceder a la servicio web nuevamente, que presumiblemente puede ser golpeado después de la autenticación exitosa, no puedo acceder a un método diferente usando HttpTransportSE:

private void setSomething() {

    xml = null;
    final String SOAP_ACTION = "http://this.ismy.org/AWebServiceMethod";
    final String METHOD_NAME = "AWebServiceMethod";
    final String URL = protocol + "://" + host  + ":" + port + "/WebService.asmx";
    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    envelope.dotNet = true;
    envelope.setOutputSoapObject(request);
    envelope.implicitTypes = true;
    envelope.setAddAdornments(false);

    try
    {
        HttpTransportSE transport = new HttpTransportSE(URL);
        transport.debug = true;
        transport.call(SOAP_ACTION, envelope);
        xml = transport.responseDump.toString();
        Log.d(TAG, xml);
    }
    catch(SocketException ex)
    {
        Log.e("SocketException : " , "Error on setSomething() " + ex.getMessage());
    }
    catch (Exception e)
    {
        Log.e("Exception : " , "Error on setSomething() " + e.getMessage());
    }
}

Todo esto funciona bien como la tarea en segundo plano de una AsyncTask, que luego pasa el "xml" a un método XMLPullParser.

La pregunta principal aquí es por qué obtengo un:

Error en setSomething () No se encontraron desafíos de autenticación

??

Después de que IIS valida con éxito al usuario con un 200, ¿por qué me pide que vuelva a autenticarme? ¿Cómo puedo persistir ese primer desafío autenticado para alcanzar el método que quiera dentro de WebService.asmx? ¿Cuáles son los encabezados que deben agregarse / cambiarse para crear una sesión si es necesario? ¿Qué me estoy perdiendo que hace que todo este proceso NTLM funcione y persista durante más tiempo que el método WS que necesita superar los desafíos de autenticación?

EDIT: Agregando el código de la Biblioteca

Aquí está el enlace a laJCIFS de Apache

public static final class JCIFSEngine implements NTLMEngine {

    private static final int TYPE_1_FLAGS =
            NtlmFlags.NTLMSSP_NEGOTIATE_56 |
                    NtlmFlags.NTLMSSP_NEGOTIATE_128 |
                    NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 |
                    NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
                    NtlmFlags.NTLMSSP_REQUEST_TARGET;

    public String generateType1Msg(final String domain, final String workstation)
            throws NTLMEngineException {
        final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation);
        return jcifs.util.Base64.encode(type1Message.toByteArray());
    }

    public String generateType3Msg(final String username, final String password,
                                   final String domain, final String workstation, final String challenge)
            throws NTLMEngineException {
        Type2Message type2Message;
        try {
            type2Message = new Type2Message(jcifs.util.Base64.decode(challenge));
        } catch (final IOException exception) {
            throw new NTLMEngineException("Invalid NTLM type 2 message", exception);
        }
        final int type2Flags = type2Message.getFlags();
        final int type3Flags = type2Flags
                & (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
        final Type3Message type3Message = new Type3Message(type2Message, Login.password, "",
                Login.username, deviceIp, type3Flags);

            System.out.println("type3Message: " + type3Message.toByteArray());

        return jcifs.util.Base64.encode(type3Message.toByteArray());
    }
}

¿Entonces el "NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN" está causando este problema? ¿Hay otra bandera que se supone que debo configurar para mantener vivo? Además, encontré un gran recurso para una lista de banderas NTLM y más:http: //fossies.org/dox/jcifs-1.3.17/interfacejcifs_1_1ntlmssp_1_1NtlmFlags.htm

Respuestas a la pregunta(1)

Su respuesta a la pregunta