@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); }