Проверка подлинности NTLM в веб-приложении (Java)

Я использую следующий фильтр для включения аутентификации NTLM в своем веб-приложении.

Я получаю приглашение аутентификации браузера Windows. Работает нормально. За исключением того факта, что - я не могу сказать, прошла ли аутентификация успешно или не удалось!!! * В обоих случаях ошибок нет. * В каждом случае печатается имя пользователя (правильное или нет), рабочая станция и т. Д.

package com.test;
import java.io.IOException;
import java.io.PrintStream;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jcifs.ntlmssp.Type3Message;
import com.sun.xml.internal.ws.util.StringUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class NTLMUserFilter implements Filter {
    private FilterConfig filterConfig = null;
    private String userDomain = null;
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        String username = null;
        //first, get the user agent
        String useragent = request.getHeader("user-agent");
        //if you're using IE, you can continue
        if ((useragent.indexOf("MSIE") > -1)){
            //Always do the ntlm check (for IE POST back)
            try{
                String auth = request.getHeader("Authorization");
                if (auth == null)
                {
                  response.setHeader("WWW-Authenticate", "NTLM");
                  response.setStatus(response.SC_UNAUTHORIZED);
                  response.setContentLength(0) ;
                  response.flushBuffer();
                  return;
                }
                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, z, z, z, z, z, z, z, z};
                    response.setHeader("WWW-Authenticate", "NTLM " + new sun.misc.BASE64Encoder().encodeBuffer(msg1));
                    response.setStatus(response.SC_UNAUTHORIZED);
                    response.setContentLength(0) ;
                    response.flushBuffer();
                    return;
                  }
                  else if (msg[8] == 3)
                  {
                      //Did Authentication Succeed? All this is always printed.

                      Type3Message type3 = new Type3Message(msg);

                      System.out.println("osUser: " + type3.getUser());
                      System.out.println("osRemoteHost: + " + type3.getWorkstation());
                      System.out.println("osDomain: " + type3.getDomain());

                  }
                }
            }catch(Exception e){
                System.out.println(e) ;
            }
            //System.out.println("Suc);


            }

        try {
            chain.doFilter(req, res);
        } catch (IOException e) {
            System.out.println(e);
        } catch (ServletException e) {
            System.out.println(e);
        }
    }
public void destroy()
   {
     this.filterConfig = null;
   }
}

Файл web.xml прост:

<filter>
    <filter-name>ntlmFilter</filter-name>
    <filter-class>
        com.test.NTLMUserFilter
    </filter-class>
</filter>

<!-- Filter mapping configuration   -->

<filter-mapping>
    <filter-name>ntlmFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>   

2 ответа

Решение

Вы получаете сообщение типа 3, но ничего не делаете с ним, кроме распечатки деталей. Вам нужно проверить ответ клиента на этом этапе и отправить 200 (если разрешено) или 401 (если нет).

Однако доставленное вами сообщение типа 1 состоит из статических байтов и - хотя оно побудит клиента отправить ответ - в большинстве случаев не имеет смысла. Не исключено, что вы можете реализовать полный стек аутентификации NTLM самостоятельно, но ваш код просто не будет работать.

Вы можете исследовать решение NTLM для Java или (при условии, что вы работаете в Windows) вы можете вызвать необходимые функции аутентификации, такие как AcceptSecurityContext с JNI.

Как сказал Эдвард, простое извлечение имени из NTLM-сообщения типа 3 (ответ) ничего не говорит о том, имеет ли право клиент, сгенерировавший его, сделать это.

NTLM не похож на Kerberos, где есть подписанный токен, который служба может проверить самостоятельно; Вы должны каждый раз устанавливать соединение с контроллером домена, чтобы узнать, является ли токен действительным. Реализация соединения MSRPC для проверки токена NTLM - действительно тяжелая работа.

В старые времена вы могли сделать это в JCIFS, используя jcifs.smb.SmbSession, а также jcifs.http.NtlmHttpFilter сделал бы только это для вас. Однако это работает только для NTLMv1, который устарел, небезопасен и вряд ли будет использоваться для чего-либо. (Я полагаю, что ntlm-java, связанный выше, также только для NTLMv1.)

Попробуйте проект ntlmv2auth.

NTLM-over-HTTP достаточно проблем в заднице, так как обычно лучше использовать любой другой метод аутентификации, доступный вам.

Другие вопросы по тегам