@Test
  public void testHeadersAreRemoved() throws Exception {
    HttpBasicAuthFilter filter = new HttpBasicAuthFilter(null, null, failureHandler);
    filter.setCacheHeader(false);

    Exchange exchange = newExchange();
    Request request = newRequest();
    request.getHeaders().putSingle(AUTHORIZATION_HEADER, "Basic azerty");

    doAnswer(
            new Answer<Promise<Response, NeverThrowsException>>() {
              @Override
              public Promise<Response, NeverThrowsException> answer(
                  final InvocationOnMock invocation) throws Throwable {
                // Produce a valid response with an authentication challenge
                Response response = new Response();
                response.setStatus(Status.OK);
                response.getHeaders().putSingle(AUTHENTICATE_HEADER, "Realm toto");
                return Promises.newResultPromise(response);
              }
            })
        .when(terminalHandler)
        .handle(eq(exchange), argThat(new AbsenceOfHeaderInRequest(AUTHORIZATION_HEADER)));

    Response response = filter.filter(exchange, request, terminalHandler).getOrThrow();

    // Verify that the outgoing message has no authenticate header
    assertThat(response.getHeaders().get(AUTHENTICATE_HEADER)).isNull();
  }
  JsonValue performDynamicClientRegistration(
      final Context context,
      final JsonValue clientRegistrationConfiguration,
      final URI registrationEndpoint)
      throws RegistrationException {
    final Request request = new Request();
    request.setMethod("POST");
    request.setUri(registrationEndpoint);
    request.setEntity(clientRegistrationConfiguration.asMap());

    final Response response;
    try {
      response = blockingCall(registrationHandler, context, request);
    } catch (InterruptedException e) {
      throw new RegistrationException(
          format("Interrupted while waiting for '%s' response", request.getUri()), e);
    }
    if (!CREATED.equals(response.getStatus())) {
      throw new RegistrationException(
          "Cannot perform dynamic registration: this can be caused "
              + "by the distant server(busy, offline...) "
              + "or a malformed registration response.");
    }
    try {
      return getJsonContent(response);
    } catch (OAuth2ErrorException e) {
      throw new RegistrationException(
          "Cannot perform dynamic registration: invalid response JSON content.");
    }
  }
  /**
   * 2 consecutive requests are sharing the same session. The first one should build and cache the
   * Authorization header after a round trip to the next handler (firstly answer with a challenge).
   * The second should simply re-use the cached value
   *
   * @throws Exception
   */
  @Test
  public void tesAuthorizationHeaderCaching() throws Exception {
    HttpBasicAuthFilter filter =
        new HttpBasicAuthFilter(
            Expression.valueOf("bjensen", String.class),
            Expression.valueOf("hifalutin", String.class),
            failureHandler);
    filter.setCacheHeader(true);

    // No value cached for the first call
    // Subsequent invocations get the cached value
    when(session.get(endsWith(":userpass"))).thenReturn(null, INITIAL_CREDENTIALS);

    basicAuthServerAnswersUnauthorizedThenSuccess(INITIAL_CREDENTIALS);

    Exchange first = newExchange();
    Request firstRequest = newRequest();
    Response firstResponse = filter.filter(first, firstRequest, terminalHandler).getOrThrow();

    Exchange second = newExchange();
    Request secondRequest = newRequest();
    Response secondResponse = filter.filter(second, secondRequest, terminalHandler).getOrThrow();

    // Terminal handler should be called 3 times, not 4
    verify(terminalHandler, times(3)).handle(any(Exchange.class), any(Request.class));
    // Session should be updated with cached value
    verify(session).put(endsWith(":userpass"), eq(INITIAL_CREDENTIALS));

    // Responses should be OK for all outgoing responses
    assertThat(firstResponse.getStatus()).isEqualTo(Status.OK);
    assertThat(secondResponse.getStatus()).isEqualTo(Status.OK);
  }
 // 1st time called: Mock a 401 (Unauthorized status) response
 @Override
 public Promise<Response, NeverThrowsException> answer(InvocationOnMock invocation)
     throws Throwable {
   Response response = new Response();
   response.setStatus(Status.UNAUTHORIZED);
   response.getHeaders().putSingle(AUTHENTICATE_HEADER, "Basic realm=\"Login\"");
   return Promises.newResultPromise(response);
 }
    @Override
    public Promise<Response, NeverThrowsException> answer(InvocationOnMock invocation)
        throws Throwable {
      Request request = (Request) invocation.getArguments()[1];

      // Verify the authorization header: base64(user:pass)
      assertThat(request.getHeaders().getFirst(AUTHORIZATION_HEADER))
          .isEqualTo("Basic " + credentials);

      // Produce a valid response, no special headers are required
      Response response = new Response();
      response.setStatus(Status.OK);
      return Promises.newResultPromise(response);
    }
  @Test
  public void testNominalInteraction() throws Exception {
    HttpBasicAuthFilter filter =
        new HttpBasicAuthFilter(
            Expression.valueOf("bjensen", String.class),
            Expression.valueOf("hifalutin", String.class),
            failureHandler);
    filter.setCacheHeader(false);

    basicAuthServerAnswersUnauthorizedThenSuccess(INITIAL_CREDENTIALS);

    Exchange exchange = newExchange();
    Request request = newRequest();
    Response response = filter.filter(exchange, request, terminalHandler).getOrThrow();

    assertThat(response.getStatus()).isEqualTo(Status.OK);
  }
  @Test(dataProvider = "invalidUserNames")
  public void testConformanceErrorIsProducedWhenUsernameContainsColon(final String username)
      throws Exception {
    HttpBasicAuthFilter filter =
        new HttpBasicAuthFilter(
            Expression.valueOf(username, String.class),
            Expression.valueOf("dont-care", String.class),
            failureHandler);
    filter.setCacheHeader(false);

    basicAuthServerAnswersUnauthorizedThenSuccess(INITIAL_CREDENTIALS);

    Response response = filter.filter(newExchange(), newRequest(), terminalHandler).get();
    assertThat(response.getStatus()).isEqualTo(Status.INTERNAL_SERVER_ERROR);
    assertThat(response.getEntity().getString())
        .contains("username must not contain a colon ':' character");
  }
  @Test
  public void shouldThrottleConcurrentRequests() throws Exception {
    CountDownLatch latch1 = new CountDownLatch(1);
    CountDownLatch latch2 = new CountDownLatch(1);

    FakeTimeService time = new FakeTimeService(0);
    final ThrottlingFilter filter =
        new ThrottlingFilter(time, 1, duration("3 seconds"), DEFAULT_PARTITION_EXPR);

    // This one has to be called as there are enough tokens in the bucket.
    final Handler handler1 = new LatchHandler(latch1, latch2);

    Runnable r =
        new Runnable() {

          @Override
          public void run() {
            filter.filter(mock(Context.class), new Request(), handler1);
          }
        };
    Thread t1 = new Thread(r);
    t1.setName("Filter for request #1");
    t1.start();
    latch2.await();

    time.advance(duration("2 seconds"));
    try {
      // This one does not have to be called as there no token anymore in the bucket.
      Handler handler2 = mock(Handler.class, "handler2");
      Promise<Response, NeverThrowsException> promise2 =
          filter.filter(mock(Context.class), new Request(), handler2);

      verifyZeroInteractions(handler2);

      Response response = promise2.get(20, TimeUnit.SECONDS);
      assertThat(response.getStatus()).isEqualTo(Status.TOO_MANY_REQUESTS);
      assertThat(response.getHeaders().getFirst("Retry-After")).isEqualTo("1");
    } finally {
      latch1.countDown();
      t1.join();
    }
  }
  @Test
  public void testRefreshAuthenticationHeader() throws Exception {

    HttpBasicAuthFilter filter =
        new HttpBasicAuthFilter(
            Expression.valueOf("bjensen", String.class),
            Expression.valueOf("${exchange.password}", String.class),
            failureHandler);
    filter.setCacheHeader(true);

    // Mock cache content for credentials
    when(session.get(endsWith(":userpass")))
        .thenReturn(null, INITIAL_CREDENTIALS, INITIAL_CREDENTIALS, REFRESHED_CREDENTIALS);

    // Scenario:
    //  first request (cache the value after initial round-trip)
    //  second request (cached value is OK)
    //  third request (cached value is no longer valid, trigger a refresh)
    doAnswer(new UnauthorizedAnswer())
        .doAnswer(new AuthorizedAnswer(INITIAL_CREDENTIALS))
        .doAnswer(new AuthorizedAnswer(INITIAL_CREDENTIALS))
        .doAnswer(new UnauthorizedAnswer())
        .doAnswer(new AuthorizedAnswer(REFRESHED_CREDENTIALS))
        .when(terminalHandler)
        .handle(any(Exchange.class), any(Request.class));

    // Initial round-trip
    Exchange first = newExchange();
    first.put("password", "hifalutin");
    Response firstResponse = filter.filter(first, newRequest(), terminalHandler).getOrThrow();

    // Usage of cached value
    Exchange second = newExchange();
    Response secondResponse = filter.filter(second, newRequest(), terminalHandler).getOrThrow();

    // Cached value is no longer valid, trigger a user/pass refresh
    Exchange third = newExchange();
    third.put("password", "hifalutin2");
    Response thirdResponse = filter.filter(third, newRequest(), terminalHandler).getOrThrow();

    // Terminal handler should be called 5 times, not 6
    // first: 2 times
    // second: 1 time
    // third: 2 times
    verify(terminalHandler, times(5)).handle(any(Exchange.class), any(Request.class));
    // Session should be updated with cached value 2 times
    verify(session).put(endsWith(":userpass"), eq(INITIAL_CREDENTIALS));
    verify(session).put(endsWith(":userpass"), eq(REFRESHED_CREDENTIALS));

    // Responses should be OK for all outgoing responses
    assertThat(firstResponse.getStatus()).isEqualTo(Status.OK);
    assertThat(secondResponse.getStatus()).isEqualTo(Status.OK);
    assertThat(thirdResponse.getStatus()).isEqualTo(Status.OK);
  }
 // Disabled due to incompatibility with JDK7 Rhino.
 @Test(enabled = false)
 public void testSendFromJavaScript() throws Exception {
   final ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("js");
   engine.put("http", client);
   final Object response =
       engine.eval(
           script(
               // @formatter:off
               "var Request = Java.type('org.forgerock.http.protocol.Request')",
               "",
               "var request = new Request()",
               "request.uri = 'http://example.com'",
               "request.method = 'GET'",
               "",
               "http.send(request).get()"
               // @formatter:on
               ));
   assertThat(((Response) response).getStatus()).isEqualTo(Status.OK);
 }
 @Test
 public void testSend() throws Exception {
   final Request request = new Request().setUri("http://example.com").setMethod("GET");
   final Response response = client.send(request).get();
   assertThat(response.getStatus()).isEqualTo(Status.OK);
 }