Alternatives for JCIFS NTLM library

后端 未结 7 675
长发绾君心
长发绾君心 2020-12-29 06:26

Are there any alternatives for JCIFS NTLM library?

相关标签:
7条回答
  • 2020-12-29 07:30

    Actually jcifs is good and you can test easily the 4-way handshake locally with Windows IIS and a keep alive java Socket.

    This 2004 Apache pseudo code is useful to build the algorithm with jcifs using generateType1Msg() and generateType3Msg(), even Apache promotes an example as an alternative to HttpClient.

    The old Apache code from 2004 works but authentication is unstable, you get HTTP/1.1 401 Unauthorized frequently, also this really old code from Luigi Dragone does not work anymore. On the other hand Apache's HttpClient runs smoothly but the handshake is done behind the scene (fyi. HttpClient requires new NTCredentials() to define user's authentication).

    Here's an example to test the handshake locally on IIS, on port 81 without a domain. You need to change the host, port, user and password and HTTP headers appropriately, eventually WWW-Authenticate if you are not using IIS.

    HTTP/1.1 200 OK means the authentication is correct, otherwise you get HTTP/1.1 401 Unauthorized.

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    import jcifs.ntlmssp.NtlmFlags;
    import jcifs.ntlmssp.Type1Message;
    import jcifs.ntlmssp.Type2Message;
    import jcifs.ntlmssp.Type3Message;
    import jcifs.util.Base64;
    
    import org.apache.http.impl.auth.NTLMEngineException;
    
    public class TestNTLM {
    
        public static void main(String[] args) throws UnknownHostException, IOException, NTLMEngineException {
            Socket s = new Socket("127.0.0.1", 81);
            s.setKeepAlive(true);
            InputStream is = s.getInputStream();
            OutputStream os = s.getOutputStream();
            BufferedReader r = new BufferedReader(new InputStreamReader(is));
            BufferedWriter w = new BufferedWriter(new OutputStreamWriter(os));
    
            String host = "127.0.0.1:81";
            String hostDomain = "";
            String user = "My_Windows_Username";
            String password = "My_Windows_Password";
    
            w.write("GET http://127.0.0.1:81/ HTTP/1.1\n");
            w.write("Host: 127.0.0.1:81\n");
            w.write("Authorization: NTLM " + TestNTLM.generateType1Msg(hostDomain, host) + "\n\n");
            System.out.println("[First Message Sent]");
            w.flush();
    
            String resp = "", line = "";
            int contentLength = 0;
            while((line = r.readLine()) != null){
                if(line.length() == 0)
                    break;
                System.out.println(line);
                if(line.startsWith("Content-Length"))
                    contentLength = Integer.parseInt(line.substring(line.indexOf(":") + 1).trim());
                else if(line.startsWith("WWW-Authenticate"))
                    resp = line.substring(line.indexOf(":") + 1).trim();
            }
            r.skip(contentLength);
    
            System.out.println("\n[Second Message Received]");
            System.out.println("Proxy-Authenticate: " + resp);
            resp = resp.substring(resp.indexOf(" ")).trim();
    
            w.write("GET http://127.0.0.1:81/ HTTP/1.1\n");
            w.write("Host: 127.0.0.1:81\n");
            w.write("Authorization: NTLM " + TestNTLM.generateType3Msg(user, password, hostDomain, host, new String(resp)) + "\n\n");
    
            w.flush();
            System.out.println("\n[Third Message Sent]");
    
            while((line = r.readLine()) != null){
                System.out.println(line);
                if(line.length() == 0)
                    break;
            }
        }
    
        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 static String generateType1Msg(final String domain, final String workstation)
                throws NTLMEngineException {
            final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation);
            return Base64.encode(type1Message.toByteArray());
        }
    
        public static 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(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, password, domain,
                    username, workstation, type3Flags);
            return Base64.encode(type3Message.toByteArray());
        }
    }
    
    0 讨论(0)
提交回复
热议问题