2012-01-07 2 views
7

나는 셰어 포인트 웹 서비스에 액세스하고 SOAP 처리를 수행하는 안드로이드 애플리케이션을 개발 중이다. 나는 JCIFS와 같은 다양한 방법을 시도했다.안드로이드에서 NTLM 인증

아무도 여기 도와 줄 수 있습니까? 나는 여러 날부터 그것을 인터넷 검색하지만,이 문제가있는 모든 사람들은 좌절하고 있습니다.

감사합니다, Indrajit

답변

5

NTLM 전문가는 아니지만 JCIFS 라이브러리를 사용하여 백엔드에 연결하고 헤더를 사용하여 수동 작업을 수행했습니다.

또한 네트워크 연결을 위해 OkHttp 3 라이브러리를 사용하지만 내 코드를 다른 라이브러리에 적용 할 수 있습니다.

주요 아이디어는 연결할 서버와 협상해야한다는 것입니다.

1 단계 :

WWW 인증을 협상 :

WWW 인증 :

당신이 실패 할 수 있습니다 1 시간을 연결하고 헤더에 몇 가지 정보를 수신하려고 : NTLM

2 단계 :

jcifs 라이브러리를 사용하여 유형 1 (선택적인 도메인 & 워크 스테이션 매개 변수 사용)의 키를 생성하고 다시 연결해야합니다. 다시 실패하지만, 몇 가지 유용한 헤더의 정보를받을 수 있습니다 :

WWW 인증 : very_long_challenge_key NTLM을

3 단계 : 당신은 그 문제와 유형 3의 키를 생성해야

key + login + password, jcifs 라이브러리 사용. 그러면 연결이 성공합니다! 항아리는 여기에서 찾을 수 있습니다

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

:

이제 몇 가지 코드는 앱의 build.gradle 파일의 라이브러리에 종속성을 추가 https://jcifs.samba.org/src/

그런 다음 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; 
    } 

} 

다음 OkHttpClient를 만들 때이 인증자를 추가하십시오.

OkHttpClient okHttpClient = new OkHttpClient.Builder() 
     .authenticator(new NTLMAuthenticator(login, password)) 
     // .some other init here if necessary 
     .build(); 

그런 다음 평소와 같이 요청하십시오.

+0

"평소와 같이 요청 하시겠습니까?"에 대해 자세히 설명해 주시겠습니까? Okhttp에 익숙하지 않다. –

+1

여기에 OkHttp에 대한 간단한 샘플이있다 : https://square.github.io/okhttp/#overview –