2006-05-21

NTLM 인증

윈도우 인트라넷 환경에서 NTLM(Windows NT LAN Manager) 프로토콜로 SSO(Single Sign On)를 구현하는 경우가 있다.

자바(JSP)에서 NTLM 프로토콜을 이용해서 윈도우 도메인 이름과 사용자 계정을 획득하는 방법이다.

<%@ page contentType="text/html; charset=UTF-8" %>

<%
String auth = request.getHeader("Authorization");
if (auth == null) {
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    response.setHeader("WWW-Authenticate", "NTLM");
    response.flushBuffer();
    return;
    // 이 응답을 받은 IE 웹 브라우저는 다시 요청을 보낸다.
}

if (auth.startsWith("NTLM ")) {
    byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
    int off = 0, length, offset;
    if (msg[8] == 1) {
        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, // this line is 'nonce'
                        z, z, z, z, z, z, z, z };
        response.setContentLength(0);
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        String value = "NTLM " + new sun.misc.BASE64Encoder().encodeBuffer(msg1);

        // 웹로직에서는 Header 값에 CRLF 문자를 포함하면 예외가 발생함.
        response.setHeader("WWW-Authenticate", value.replaceAll("\n", ""));
        response.flushBuffer();
        return;
        // 이 응답을 받은 IE 웹 브라우저는 다시 요청을 보낸다.
    } else if (msg[8] == 3) {
        // 최종적으로 윈도우 도메인 이름과 사용자 계정을 도출할 수 있는 요청이다.
        String remoteHost = null;
        String domain = null;
        String username = null;

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

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

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

        // 사용자 계정에 포함된 특수 문자 제거
        username = username.replaceAll("\\W", "");
        return;
    }
}
%>


물론 이 경우에는 MS IE 웹 브라우저만을 사용해야 한다.


참고 자료



No comments: