@Test
  public void testRequestAttributesForAccessLog() throws Exception {
    // PREPARE
    FilterDef filterDef = new FilterDef();
    filterDef.addInitParameter("protocolHeader", "x-forwarded-proto");
    filterDef.addInitParameter("remoteIpHeader", "x-my-forwarded-for");
    filterDef.addInitParameter("httpServerPort", "8080");

    MockHttpServletRequest request = new MockHttpServletRequest();
    request.setRemoteAddr("192.168.0.10");
    request.setHeader("x-my-forwarded-for", "140.211.11.130");
    request.setHeader("x-forwarded-proto", "http");

    // TEST
    HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);

    // VERIFY
    Assert.assertEquals(
        "org.apache.catalina.AccessLog.ServerPort",
        Integer.valueOf(8080),
        actualRequest.getAttribute(AccessLog.SERVER_PORT_ATTRIBUTE));

    Assert.assertEquals(
        "org.apache.catalina.AccessLog.RemoteAddr",
        "140.211.11.130",
        actualRequest.getAttribute(AccessLog.REMOTE_ADDR_ATTRIBUTE));

    Assert.assertEquals(
        "org.apache.catalina.AccessLog.RemoteHost",
        "140.211.11.130",
        actualRequest.getAttribute(AccessLog.REMOTE_HOST_ATTRIBUTE));
  }
  @Test
  public void testInvokeNotAllowedRemoteAddr() throws Exception {
    // PREPARE
    FilterDef filterDef = new FilterDef();
    filterDef.addInitParameter("internalProxies", "192\\.168\\.0\\.10|192\\.168\\.0\\.11");
    filterDef.addInitParameter("trustedProxies", "proxy1|proxy2|proxy3");
    filterDef.addInitParameter("remoteIpHeader", "x-forwarded-for");
    filterDef.addInitParameter("proxiesHeader", "x-forwarded-by");

    MockHttpServletRequest request = new MockHttpServletRequest();

    request.setRemoteAddr("not-allowed-internal-proxy");
    request.setRemoteHost("not-allowed-internal-proxy-host");
    request.setHeader("x-forwarded-for", "140.211.11.130, proxy1, proxy2");

    // TEST
    HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);

    // VERIFY
    String actualXForwardedFor = actualRequest.getHeader("x-forwarded-for");
    assertEquals(
        "x-forwarded-for must be unchanged", "140.211.11.130, proxy1, proxy2", actualXForwardedFor);

    String actualXForwardedBy = actualRequest.getHeader("x-forwarded-by");
    assertNull("x-forwarded-by must be null", actualXForwardedBy);

    String actualRemoteAddr = actualRequest.getRemoteAddr();
    assertEquals("remoteAddr", "not-allowed-internal-proxy", actualRemoteAddr);

    String actualRemoteHost = actualRequest.getRemoteHost();
    assertEquals("remoteHost", "not-allowed-internal-proxy-host", actualRemoteHost);
  }
  @Test
  public void testInvokeAllProxiesAreInternal() throws Exception {

    // PREPARE
    FilterDef filterDef = new FilterDef();
    filterDef.addInitParameter("internalProxies", "192\\.168\\.0\\.10|192\\.168\\.0\\.11");
    filterDef.addInitParameter("trustedProxies", "proxy1|proxy2|proxy3");
    filterDef.addInitParameter("remoteIpHeader", "x-forwarded-for");
    filterDef.addInitParameter("proxiesHeader", "x-forwarded-by");

    MockHttpServletRequest request = new MockHttpServletRequest();
    request.setRemoteAddr("192.168.0.10");
    request.setRemoteHost("remote-host-original-value");
    request.addHeader("x-forwarded-for", "140.211.11.130, 192.168.0.10, 192.168.0.11");

    // TEST
    HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);

    // VERIFY
    String actualXForwardedFor = actualRequest.getHeader("x-forwarded-for");
    assertNull("all proxies are internal, x-forwarded-for must be null", actualXForwardedFor);

    String actualXForwardedBy = actualRequest.getHeader("x-forwarded-by");
    assertNull("all proxies are internal, x-forwarded-by must be null", actualXForwardedBy);

    String actualRemoteAddr = actualRequest.getRemoteAddr();
    assertEquals("remoteAddr", "140.211.11.130", actualRemoteAddr);

    String actualRemoteHost = actualRequest.getRemoteHost();
    assertEquals("remoteHost", "140.211.11.130", actualRemoteHost);
  }
  @Test
  public void testWhenTheyHaveALowDefaultSessionTimeout() {
    httpServletRequest.setRemoteUser("bill");
    HttpSession session = httpServletRequest.getSession(true); // make a session
    session.setMaxInactiveInterval(5);

    botKiller.processRequest(httpServletRequest);

    assertEquals(5, session.getMaxInactiveInterval());
    assertNull(session.getAttribute(BotKiller.class.getName()));
  }
  @Test
  public void testRequestHasUserGetsDifferentTimeout() throws Exception {
    httpServletRequest.setRemoteUser("bill");
    HttpSession session = httpServletRequest.getSession(true); // make a session
    session.setMaxInactiveInterval(MAX_INACTIVE_INTERVAL);

    botKiller.processRequest(httpServletRequest);

    assertEquals(USER_LOW_INACTIVE_TIMEOUT, session.getMaxInactiveInterval());
    assertEquals(MAX_INACTIVE_INTERVAL, session.getAttribute(BotKiller.class.getName()));
  }
  @Test
  public void testErrorWhenCheckingUsernameDoesNotKillBotKiller() {
    botKiller =
        new BotKiller(
            new MockUserManager(null) {
              @Override
              public String getRemoteUsername(HttpServletRequest request) {
                throw new RuntimeException("a most unexpected error");
              }
            });

    httpServletRequest.setRemoteUser("bill");
    HttpSession session = httpServletRequest.getSession(true); // make a session
    session.setMaxInactiveInterval(MAX_INACTIVE_INTERVAL);

    botKiller.processRequest(httpServletRequest);

    assertEquals(LOW_INACTIVE_TIMEOUT, session.getMaxInactiveInterval());
    assertEquals(MAX_INACTIVE_INTERVAL, session.getAttribute(BotKiller.class.getName()));
  }
  @Test
  public void testIncomingRequestIsSecuredButProtocolHeaderSaysItIsNotWithDefaultValues()
      throws Exception {
    // PREPARE
    FilterDef filterDef = new FilterDef();
    filterDef.addInitParameter("protocolHeader", "x-forwarded-proto");

    MockHttpServletRequest request = new MockHttpServletRequest();
    request.setRemoteAddr("192.168.0.10");
    request.setSecure(true);
    request.setScheme("https");
    request.setHeader("x-forwarded-for", "140.211.11.130");
    request.setHeader("x-forwarded-proto", "http");

    // TEST
    HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);

    // VERIFY
    boolean actualSecure = actualRequest.isSecure();
    assertFalse(
        "request must be unsecured as header x-forwarded-proto said it is http", actualSecure);

    String actualScheme = actualRequest.getScheme();
    assertEquals(
        "scheme must be http as header x-forwarded-proto said it is http", "http", actualScheme);

    String actualRemoteAddr = actualRequest.getRemoteAddr();
    assertEquals("remoteAddr", "140.211.11.130", actualRemoteAddr);

    String actualRemoteHost = actualRequest.getRemoteHost();
    assertEquals("remoteHost", "140.211.11.130", actualRemoteHost);
  }
  @Test
  public void testInvokeUntrustedProxyInTheChain() throws Exception {
    // PREPARE
    FilterDef filterDef = new FilterDef();
    filterDef.addInitParameter("internalProxies", "192\\.168\\.0\\.10|192\\.168\\.0\\.11");
    filterDef.addInitParameter("trustedProxies", "proxy1|proxy2|proxy3");
    filterDef.addInitParameter("remoteIpHeader", "x-forwarded-for");
    filterDef.addInitParameter("proxiesHeader", "x-forwarded-by");

    MockHttpServletRequest request = new MockHttpServletRequest();

    request.setRemoteAddr("192.168.0.10");
    request.setRemoteHost("remote-host-original-value");
    request.setHeader("x-forwarded-for", "140.211.11.130, proxy1, untrusted-proxy, proxy2");

    // TEST
    HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);

    // VERIFY
    String actualXForwardedFor = actualRequest.getHeader("x-forwarded-for");
    assertEquals(
        "ip/host before untrusted-proxy must appear in x-forwarded-for",
        "140.211.11.130, proxy1",
        actualXForwardedFor);

    String actualXForwardedBy = actualRequest.getHeader("x-forwarded-by");
    assertEquals(
        "ip/host after untrusted-proxy must appear in  x-forwarded-by",
        "proxy2",
        actualXForwardedBy);

    String actualRemoteAddr = actualRequest.getRemoteAddr();
    assertEquals("remoteAddr", "untrusted-proxy", actualRemoteAddr);

    String actualRemoteHost = actualRequest.getRemoteHost();
    assertEquals("remoteHost", "untrusted-proxy", actualRemoteHost);
  }
  @Test
  public void testUidHeader() {
    MockHttpServletRequest request = new MockHttpServletRequest();
    request.setHeader("uid", "test");
    request.setHeader("uid1", "test1");
    request.setHeader("uid2", "test2");

    request.setHeader("shib-identity-provider", "url1");
    assertEquals("test1", service.getUserID(request));

    request.setHeader("shib-identity-provider", "url2");
    assertEquals("test2", service.getUserID(request));

    request.setHeader("shib-identity-provider", "another.url");
    assertEquals("test", service.getUserID(request));
  }
  @Test
  public void testNeverSeenThisSessionSoItsLowered() throws Exception {
    HttpSession session = httpServletRequest.getSession(true); // make a session
    session.setMaxInactiveInterval(MAX_INACTIVE_INTERVAL);

    botKiller.processRequest(httpServletRequest);

    assertEquals(LOW_INACTIVE_TIMEOUT, session.getMaxInactiveInterval());
    assertEquals(MAX_INACTIVE_INTERVAL, session.getAttribute(BotKiller.class.getName()));

    // now have a second request
    botKiller.processRequest(httpServletRequest);
    assertEquals(MAX_INACTIVE_INTERVAL, Integer.valueOf(session.getMaxInactiveInterval()));
    assertEquals(MAX_INACTIVE_INTERVAL, session.getAttribute(BotKiller.class.getName()));

    // any future requests is still the same timeout on the session

    for (int i = 0; i < 10; i++) {
      botKiller.processRequest(httpServletRequest);
      assertEquals(MAX_INACTIVE_INTERVAL, Integer.valueOf(session.getMaxInactiveInterval()));
      assertEquals(MAX_INACTIVE_INTERVAL, session.getAttribute(BotKiller.class.getName()));
    }
  }
  @Test
  public void testUserMetada() {
    MockHttpServletRequest request = new MockHttpServletRequest();
    request.setHeader("uid", "test");
    request.setHeader("uid1", "value1");
    request.setHeader("uid2", "value2");

    String idField = "username";

    request.setHeader("shib-identity-provider", "url1");
    assertEquals("value1", service.getUserMetadata(idField, request).get(idField));

    request.setHeader("shib-identity-provider", "url2");
    assertEquals("value2", service.getUserMetadata(idField, request).get(idField));

    request.setHeader("shib-identity-provider", "anotherUrl");
    assertEquals("test", service.getUserMetadata(idField, request).get(idField));
  }
  @Test
  public void testNoSessionIsAccidentallyEquated() throws Exception {
    botKiller.processRequest(httpServletRequest);

    assertNull(httpServletRequest.getSession(false));
  }