2012-01-07 23 views
7

Sto sviluppando un'applicazione Android che accede a Sharepoint Web Service e esegue l'elaborazione SOAP. Ho provato vari modi come JCIFS, ecc. Niente ha funzionato.Autenticazione NTLM in Android

Qualcuno potrebbe aiutarmi qui? Lo faccio su google da molti giorni, ma chiunque abbia questo problema è frustrato.

Grazie, Indrajit

risposta

5

Non sono esperto in NTLM ma sono riuscito a collegarmi al backend tramite la libreria JCIFS e il lavoro manuale con le intestazioni.

Io uso anche la libreria di OkHttp 3 per la connessione di rete, ma probabilmente si potrebbe adattare il mio codice ad altre librerie.

L'idea principale è che è necessario negoziare con il server per connettersi.

Fase 1:

Quando si tenta di connettere la 1a volta che verrete a mancare e ricevere alcune informazioni nell'intestazione:

WWW-Authenticate: Negoziare

WWW-Authenticate: NTLM

Fase 2:

È necessario generare una chiave di tipo 1 (con parametri di workstation & del dominio facoltativo) utilizzando la libreria jcifs e provare a connettersi di nuovo. Potrai fallire di nuovo, ma di ricevere alcune informazioni utili nella testata:

WWW-Authenticate: NTLM very_long_challenge_key

Fase 3:

È necessario generare una chiave di tipo 3 il fallo tasto + login + password, utilizzando la libreria jcifs. Quindi la connessione avrà successo!

Ora po 'di codice, aggiungere la dipendenza alle librerie nel file build.gradle della vostra applicazione:

compile files('libs/jcifs-1.3.18.jar') 
compile 'com.squareup.okhttp3:okhttp:3.4.1' 

Il vaso può essere trovato qui: https://jcifs.samba.org/src/

allora la classe NTLMAuthenticator

import android.support.annotation.NonNull; 

import java.io.IOException; 
import java.util.List; 

import jcifs.ntlmssp.NtlmFlags; 
import jcifs.ntlmssp.Type1Message; 
import jcifs.ntlmssp.Type2Message; 
import jcifs.ntlmssp.Type3Message; 
import jcifs.util.Base64; 
import okhttp3.Authenticator; 
import okhttp3.Credentials; 
import okhttp3.Request; 
import okhttp3.Response; 
import okhttp3.Route; 

/** 
* Created by Arnaud Guyon on 07.02.17. 
*/ 

public class NTLMAuthenticator implements Authenticator { 

    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; 

    private String mLogin; 
    private String mPassword; 
    private String mDomain; 
    private String mWorkstation; 

    public NTLMAuthenticator(@NonNull String login, @NonNull String password) { 
     this(login, password, "", ""); 
    } 

    public NTLMAuthenticator(@NonNull String login, @NonNull String password, @NonNull String domain, @NonNull String workstation) { 
     mLogin = login; 
     mPassword = password; 
     mDomain = domain; 
     mWorkstation = workstation; 
    } 

    @Override 
    public Request authenticate(Route route, Response response) throws IOException { 

     List<String> authHeaders = response.headers("WWW-Authenticate"); 
     if (authHeaders != null) { 
      boolean negociate = false; 
      boolean ntlm = false; 
      String ntlmValue = null; 
      for (String authHeader : authHeaders) { 
       if (authHeader.equalsIgnoreCase("Negotiate")) { 
        negociate = true; 
       } 
       if (authHeader.equalsIgnoreCase("NTLM")) { 
        ntlm = true; 
       } 
       if (authHeader.startsWith("NTLM ")) { 
        ntlmValue = authHeader.substring(5); 
       } 
      } 

      if (negociate && ntlm) { 
       String type1Msg = generateType1Msg(mDomain, mWorkstation); 
       String header = "NTLM " + type1Msg; 
       return response.request().newBuilder().header("Authorization", header).build(); 
      } else if (ntlmValue != null) { 
       String type3Msg = generateType3Msg(mLogin, mPassword, mDomain, mWorkstation, ntlmValue); 
       String ntlmHeader = "NTLM " + type3Msg; 
       return response.request().newBuilder().header("Authorization", ntlmHeader).build(); 
      } 
     } 

     if (responseCount(response) <= 3) { 
      String credential = Credentials.basic(mLogin, mPassword); 
      return response.request().newBuilder().header("Authorization", credential).build(); 
     } 

     return null; 
    } 

    private String generateType1Msg(@NonNull String domain, @NonNull String workstation) { 
     final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation); 
     byte[] source = type1Message.toByteArray(); 
     return Base64.encode(source); 
    } 

    private String generateType3Msg(final String login, final String password, final String domain, final String workstation, final String challenge) { 
     Type2Message type2Message; 
     try { 
      byte[] decoded = Base64.decode(challenge); 
      type2Message = new Type2Message(decoded); 
     } catch (final IOException exception) { 
      exception.printStackTrace(); 
      return null; 
     } 
     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, password, domain, 
       login, workstation, type3Flags); 
     return Base64.encode(type3Message.toByteArray()); 
    } 

    private int responseCount(Response response) { 
     int result = 1; 
     while ((response = response.priorResponse()) != null) { 
      result++; 
     } 
     return result; 
    } 

} 

Quindi, quando si crea il tuo OkHttpClient, aggiungere questo autenticatore:

E poi fai le tue richieste come al solito.

+0

Potresti approfondire "fai le tue richieste come al solito"? Non ho familiarità con OkHttp –

+1

Ci sono esempi semplici per OkHttp qui: https://square.github.io/okhttp/#overview –

Problemi correlati