简体   繁体   中英

NTLM authentication java

I'm programming NTLM authentication in Java EE. If "windows integrated authentication" is enabled in the browser like Internet Explorer so everything works good (the browser send user's name to the server ). But if "windows integrated authentication" is disabled like Mozilla firefox, the browser display an at authentication form where user have to enter his login and password. My problem is: In the second case when the user enter his login and password, i can get login from the server side, but i can't get password. I have to get a password otherwise every user only just have to know the username of another user to authenticate in his place.

My code below:

 protected void processRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    /**
     * NTLM
     */
    String auth = request.getHeader("Authorization");
    //No NTLM authentification
    if (auth == null) {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setHeader("WWW-Authenticate", "NTLM");
        return;
    }
    //check what client sent
    if (auth.startsWith("NTLM")) {
        byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
        int off = 0, length, offset;

        if (msg[8] == 1) {
            off = 18;
            byte z = 0;
            byte[] msg1 = {(byte) 'N', (byte) 'T', (byte) 'L', (byte) 'M', (byte) 'S',
                (byte) 'S', (byte) 'P', z,
                (byte) 2, z, z, z, z, z, z, z,
                (byte) 40, z, z, z, (byte) 1, (byte) 130, z, z,
                z, (byte) 2, (byte) 2, (byte) 2, z, z, z, z,
                z, z, z, z, z, z, z, z};

            // send ntlm type2 msg
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setHeader("WWW-Authenticate", "NTLM " + new sun.misc.BASE64Encoder().encodeBuffer(msg1).trim());
            return;
        } //receive ntlm type 3 msg
        else if (msg[8] == 3) {
            off = 30;

            //username
            length = msg[off + 9] * 256 + msg[off + 8];
            offset = msg[off + 11] * 256 + msg[off + 10];
            username = new String(msg, offset, length);

            //remoteHost
            length = msg[off + 17] * 256 + msg[off + 16];
            offset = msg[off + 19] * 256 + msg[off + 18];
            remoteHost = new String(msg, offset, length);

            //domain
            length = msg[off + 1] * 256 + msg[off];
            offset = msg[off + 3] * 256 + msg[off + 2];
            domain = new String(msg, offset, length);
        } else {
            return;
        }

    }
    /**
     * END NTLM
     */

    request.setAttribute("username", username);
    request.setAttribute("remoteHost", remoteHost);
    request.setAttribute("domain", domain);
    request.setAttribute("ipAdress", request.getRemoteAddr());
    request.setAttribute("remotePort", request.getRemotePort());
    request.setAttribute("protocol", request.getProtocol());
    this.getServletContext().getRequestDispatcher("/WEB-INF/index.jsp").forward(request, response);

You need to send the following HTTP header in order to get the password from client:

WWW-Authenticate: Basic realm="insert realm"

The problem is how to decide whether to request NTLM or Basic authentication. One approach is to first ask for NTLM, in case the response cannot be verified, then ask for Basic (and therefore get the password). You could also detect on server side which browser your client uses or from which IP is he accessing and decide whether to use NTLM or Basic based on this data.

Some browsers can also handle getting both NTLM and Basic headers at the same time and decide on which one to use based on their capabilities:

WWW-Authenticate: NTLM
WWW-Authenticate: Basic realm="insert realm"
String auth = request.getHeader("Authorization");
//No NTLM authentification
if (auth == null) {
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    response.setHeader("WWW-Authenticate", "NTLM");
    return;
}
  //when the integrated authentication is disabled
 //basic authentication
 if((auth !=null)&&(!auth.startsWith("NTLM")))
{
        {
        StringTokenizer st = new StringTokenizer(auth);
        if(st.hasMoreTokens()){

            String basic = st.nextToken();
            if (basic.equalsIgnoreCase("Basic")) {
            try{
              String credentials = new String(Base64.decode(st.nextToken()));  
                int p = credentials.indexOf(":");
                if (p != -1) {
                     username = credentials.substring(0, p).trim();
                     password = credentials.substring(p + 1).trim();
                } 
            }catch(Exception e){


            }
        }
        } 
    }

    }

//check what client sent
if (auth.startsWith("NTLM")) {
    byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
    int off = 0, length, offset;

    if (msg[8] == 1) {
        off = 18;
        byte z = 0;
        byte[] msg1 = {(byte) 'N', (byte) 'T', (byte) 'L', (byte) 'M', (byte) 'S',
            (byte) 'S', (byte) 'P', z,
            (byte) 2, z, z, z, z, z, z, z,
            (byte) 40, z, z, z, (byte) 1, (byte) 130, z, z,
            z, (byte) 2, (byte) 2, (byte) 2, z, z, z, z,
            z, z, z, z, z, z, z, z};

        // send ntlm type2 msg
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setHeader("WWW-Authenticate", "NTLM " + new sun.misc.BASE64Encoder().encodeBuffer(msg1).trim());
        return;
    } //receive ntlm type 3 msg
    else if (msg[8] == 3) {
        off = 30;

        //username
        length = msg[off + 9] * 256 + msg[off + 8];
        offset = msg[off + 11] * 256 + msg[off + 10];
        username = new String(msg, offset, length);

        //remoteHost
        length = msg[off + 17] * 256 + msg[off + 16];
        offset = msg[off + 19] * 256 + msg[off + 18];
        remoteHost = new String(msg, offset, length);

        //domain
        length = msg[off + 1] * 256 + msg[off];
        offset = msg[off + 3] * 256 + msg[off + 2];
        domain = new String(msg, offset, length);
    } else {
        return;
    }

}

Why are you wasting your time with proprietary stuff? Use Kerberos .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM