/** * 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); }
@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); }
@Test public void shouldUseDifferentBucketsWhenUsingValidPartitionKey() throws Exception { FakeTimeService time = new FakeTimeService(0); Expression<String> expr = Expression.valueOf("${matches(exchange.foo, 'bar-00') ?'bucket-00' :''}", String.class); ThrottlingFilter filter = new ThrottlingFilter(time, 1, duration("3 seconds"), expr); Handler handler = new ResponseHandler(Status.OK); // The time does not need to advance Exchange exchange = new Exchange(); Promise<Response, NeverThrowsException> promise; exchange.put("foo", "bar-00"); promise = filter.filter(exchange, new Request(), handler); assertThat(promise.get().getStatus()).isEqualTo(Status.OK); exchange.put("foo", "bar-00"); promise = filter.filter(exchange, new Request(), handler); assertThat(promise.get().getStatus()).isEqualTo(Status.TOO_MANY_REQUESTS); exchange.put("foo", "bar-01"); promise = filter.filter(exchange, new Request(), handler); assertThat(promise.get().getStatus()).isEqualTo(Status.OK); }
static { try { DEFAULT_PARTITION_EXPR = Expression.valueOf(ThrottlingFilter.DEFAULT_PARTITION_KEY, String.class); } catch (ExpressionException e) { throw new ExceptionInInitializerError(e); } }
@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"); }
/** * If there is no credentials provided, the filter should not try to forward the request more than * once */ @Test public void testNoCredentialsProvided() throws Exception { HttpBasicAuthFilter filter = new HttpBasicAuthFilter( Expression.valueOf("${null}", String.class), Expression.valueOf("${null}", String.class), failureHandler); filter.setCacheHeader(false); // Always answer with 401 doAnswer(new UnauthorizedAnswer()) .when(terminalHandler) .handle(any(Exchange.class), any(Request.class)); Exchange exchange = newExchange(); Request request = newRequest(); filter.filter(exchange, request, terminalHandler); verify(terminalHandler, times(1)).handle(exchange, request); verify(failureHandler).handle(exchange, request); }
/** * If there are credentials but invalid ones (not accepted by the target application), this filter * should try 2 times: one with the old credential (or no credential if none are cached), and * another one with the refreshed credentials. */ @Test public void testInvalidCredentialsProvided() throws Exception { HttpBasicAuthFilter filter = new HttpBasicAuthFilter( Expression.valueOf("bjensen", String.class), Expression.valueOf("hifalutin", String.class), failureHandler); filter.setCacheHeader(false); // Always answer with 401 doAnswer(new UnauthorizedAnswer()) .when(terminalHandler) .handle(any(Exchange.class), any(Request.class)); Exchange exchange = newExchange(); Request request = newRequest(); filter.filter(exchange, request, terminalHandler); // if credentials were rejected all the times, the failure Handler is invoked verify(terminalHandler, times(2)).handle(exchange, request); verify(failureHandler).handle(exchange, request); }
@Test public void shouldUseDefaultValueWithExpressionEvaluatingNull() throws Exception { FakeTimeService time = new FakeTimeService(0); Expression<String> expr = Expression.valueOf("${exchange.bar}", String.class); ThrottlingFilter filter = new ThrottlingFilter(time, 1, duration("3 seconds"), expr); Handler handler = new ResponseHandler(Status.OK); // The time does not need to advance Exchange exchange = new Exchange(); Promise<Response, NeverThrowsException> promise; promise = filter.filter(exchange, new Request(), handler); assertThat(promise.get().getStatus()).isEqualTo(Status.INTERNAL_SERVER_ERROR); }