NTLM Authentication in Android

前端 未结 2 898
走了就别回头了
走了就别回头了 2020-12-10 05:42

I am developing an Android application which access Sharepoint Web Service and does SOAP processing. I tried various ways like JCIFS, etc. Nothing worked.

Could any

相关标签:
2条回答
  • 2020-12-10 06:14

    Check this...........................

    http://www.robertkuzma.com/2011/07/manipulating-sharepoint-list-items-with-android-java-and-ntlm-authentication/

    0 讨论(0)
  • 2020-12-10 06:34

    I'm not expert in NTLM but I successfully connected to our backend using JCIFS library and some manual work with the headers.

    I also use OkHttp 3 library for network connection, but you could probably adapt my code to other libraries.

    The main idea is that you have to negotiate with the server to connect.

    Step 1:

    When you try to connect the 1st time you'll fail and receive some information in the header:

    WWW-Authenticate: Negotiate

    WWW-Authenticate: NTLM

    Step 2:

    You need to generate a Key of type 1 (with optional domain & workstation parameters) using the jcifs library, and try to connect again. You'll fail again but receive some useful information in the header:

    WWW-Authenticate: NTLM very_long_challenge_key

    Step 3:

    You need to generate a Key of type 3 with that challenge key + login + password, using the jcifs library. Then the connection will succeed!

    Now some code, add the dependency to the libraries in the build.gradle file of your app:

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

    The jar can be found here: https://jcifs.samba.org/src/

    Then the NTLMAuthenticator class

    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;
        }
    
    }
    

    Then when you create your OkHttpClient, add this authenticator:

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

    And then do your requests as usual.

    0 讨论(0)
提交回复
热议问题