protected NtlmManager getNtlmManager(long companyId) throws SystemException {

    String domain =
        PrefsPropsUtil.getString(companyId, PropsKeys.NTLM_DOMAIN, PropsValues.NTLM_DOMAIN);
    String domainController =
        PrefsPropsUtil.getString(
            companyId, PropsKeys.NTLM_DOMAIN_CONTROLLER, PropsValues.NTLM_DOMAIN_CONTROLLER);
    String domainControllerName =
        PrefsPropsUtil.getString(
            companyId,
            PropsKeys.NTLM_DOMAIN_CONTROLLER_NAME,
            PropsValues.NTLM_DOMAIN_CONTROLLER_NAME);
    String serviceAccount =
        PrefsPropsUtil.getString(
            companyId, PropsKeys.NTLM_SERVICE_ACCOUNT, PropsValues.NTLM_SERVICE_ACCOUNT);
    String servicePassword =
        PrefsPropsUtil.getString(
            companyId, PropsKeys.NTLM_SERVICE_PASSWORD, PropsValues.NTLM_SERVICE_PASSWORD);

    NtlmManager ntlmManager = _ntlmManagers.get(companyId);

    if (ntlmManager == null) {
      ntlmManager =
          new NtlmManager(
              domain, domainController, domainControllerName, serviceAccount, servicePassword);

      _ntlmManagers.put(companyId, ntlmManager);
    } else {
      if (!Validator.equals(ntlmManager.getDomain(), domain)
          || !Validator.equals(ntlmManager.getDomainController(), domainController)
          || !Validator.equals(ntlmManager.getDomainControllerName(), domainControllerName)
          || !Validator.equals(ntlmManager.getServiceAccount(), serviceAccount)
          || !Validator.equals(ntlmManager.getServicePassword(), servicePassword)) {

        ntlmManager.setConfiguration(
            domain, domainController, domainControllerName, serviceAccount, servicePassword);
      }
    }

    return ntlmManager;
  }
  @Override
  protected void processFilter(
      HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws Exception {

    // Type 1 NTLM requests from browser can (and should) always immediately
    // be replied to with an Type 2 NTLM response, no matter whether we're
    // yet logging in or whether it is much later in the session.

    HttpSession session = request.getSession(false);

    long companyId = PortalInstances.getCompanyId(request);

    String authorization = GetterUtil.getString(request.getHeader(HttpHeaders.AUTHORIZATION));

    if (authorization.startsWith("NTLM")) {
      NtlmManager ntlmManager = getNtlmManager(companyId);

      String portalCacheKey = getPortalCacheKey(request);

      byte[] src = Base64.decode(authorization.substring(5));

      if (src[8] == 1) {
        byte[] serverChallenge = new byte[8];

        _secureRandom.nextBytes(serverChallenge);

        byte[] challengeMessage = ntlmManager.negotiate(src, serverChallenge);

        authorization = Base64.encode(challengeMessage);

        response.setContentLength(0);
        response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "NTLM " + authorization);
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        response.flushBuffer();

        _portalCache.put(portalCacheKey, serverChallenge);

        // Interrupt filter chain, send response. Browser will
        // immediately post a new request.

        return;
      }

      byte[] serverChallenge = _portalCache.get(portalCacheKey);

      if (serverChallenge == null) {
        response.setContentLength(0);
        response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "NTLM");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        response.flushBuffer();

        return;
      }

      NtlmUserAccount ntlmUserAccount = null;

      try {
        ntlmUserAccount = ntlmManager.authenticate(src, serverChallenge);
      } catch (Exception e) {
        if (_log.isErrorEnabled()) {
          _log.error("Unable to perform NTLM authentication", e);
        }
      } finally {
        _portalCache.remove(portalCacheKey);
      }

      if (ntlmUserAccount == null) {
        response.setContentLength(0);
        response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "NTLM");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        response.flushBuffer();

        return;
      }

      if (_log.isDebugEnabled()) {
        _log.debug("NTLM remote user " + ntlmUserAccount.getUserName());
      }

      request.setAttribute(WebKeys.NTLM_REMOTE_USER, ntlmUserAccount.getUserName());

      if (session != null) {
        session.setAttribute(WebKeys.NTLM_USER_ACCOUNT, ntlmUserAccount);
      }
    }

    String path = request.getPathInfo();

    if ((path != null) && path.endsWith("/login")) {
      NtlmUserAccount ntlmUserAccount = null;

      if (session != null) {
        ntlmUserAccount = (NtlmUserAccount) session.getAttribute(WebKeys.NTLM_USER_ACCOUNT);
      }

      if (ntlmUserAccount == null) {
        response.setContentLength(0);
        response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "NTLM");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        response.flushBuffer();

        return;
      } else {
        request.setAttribute(WebKeys.NTLM_REMOTE_USER, ntlmUserAccount.getUserName());
      }
    }

    processFilter(NtlmPostFilter.class, request, response, filterChain);
  }