HonoChainAuthHandler extends ChainAuthHandlerImpl implements HonoHttpAuthHandler { @Override public ChainAuthHandler append(final AuthHandler handler) { if (handler instanceof HonoHttpAuthHandler) { final PreCredentialsValidationHandler<HttpContext> nestedPreCredValidationHandler = ((HonoHttpAuthHandler) handler) .getPreCredentialsValidationHandler(); if (nestedPreCredValidationHandler != null && !nestedPreCredValidationHandler.equals(preCredentialsValidationHandler)) { LOG.error("{} has PreCredentialsValidationHandler set - not supported in ChainAuthHandler", handler); throw new IllegalArgumentException("handler with a PreCredentialsValidationHandler not supported here"); } } return super.append(handler); } HonoChainAuthHandler();  HonoChainAuthHandler(final PreCredentialsValidationHandler<HttpContext> preCredentialsValidationHandler); @Override ChainAuthHandler append(final AuthHandler handler); @Override PreCredentialsValidationHandler<HttpContext> getPreCredentialsValidationHandler(); @Override void parseCredentials(final RoutingContext context, final Handler<AsyncResult<JsonObject>> handler);  }
@SuppressWarnings({ "unchecked", "rawtypes" }) @Test public void testHandleFailsWithStatusCodeFromAuthProvider() { final AuthProvider authProvider = mock(AuthProvider.class); final AuthHandler chainedAuthHandler = new AuthHandlerImpl(authProvider) { @Override public void parseCredentials(final RoutingContext context, final Handler<AsyncResult<JsonObject>> handler) { handler.handle(Future.succeededFuture(new JsonObject())); } }; final HonoChainAuthHandler authHandler = new HonoChainAuthHandler(); authHandler.append(chainedAuthHandler); final ServiceInvocationException error = new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE); doAnswer(invocation -> { final Handler handler = invocation.getArgument(1); handler.handle(Future.failedFuture(error)); return null; }).when(authProvider).authenticate(any(JsonObject.class), any(Handler.class)); final HttpServerRequest req = mock(HttpServerRequest.class); final HttpServerResponse resp = mock(HttpServerResponse.class); final Map<String, Object> ctxMap = new HashMap<>(); final RoutingContext ctx = mock(RoutingContext.class); when(ctx.put(anyString(), any())).thenAnswer(invocation -> { ctxMap.put(invocation.getArgument(0), invocation.getArgument(1)); return ctx; }); when(ctx.get(anyString())).thenAnswer(invocation -> ctxMap.get(invocation.getArgument(0))); when(ctx.request()).thenReturn(req); when(ctx.response()).thenReturn(resp); authHandler.handle(ctx); verify(ctx).fail(error); }
@SuppressWarnings({ "unchecked", "rawtypes" }) @Test public void testPreCredentialsValidationHandlerGetsInvoked() { final JsonObject parsedCredentials = new JsonObject().put("someKey", "someValue"); final AbstractDeviceCredentials deviceCredentials = mock(AbstractDeviceCredentials.class); final DeviceUser deviceUser = new DeviceUser("tenant", "device"); final DeviceCredentialsAuthProvider<?> authProvider2 = mock(DeviceCredentialsAuthProvider.class); doReturn(deviceCredentials).when(authProvider2).getCredentials(any(JsonObject.class)); doAnswer(invocation -> { final Handler handler = invocation.getArgument(2); handler.handle(Future.succeededFuture(deviceUser)); return null; }).when(authProvider2).authenticate(any(), any(), any()); final AuthProvider authProvider1 = mock(AuthProvider.class); final AuthHandler nestedAuthHandler1 = new AuthHandlerImpl(authProvider1) { @Override public void parseCredentials(final RoutingContext context, final Handler<AsyncResult<JsonObject>> handler) { handler.handle(Future.failedFuture(new HttpStatusException(HttpURLConnection.HTTP_UNAUTHORIZED))); } }; final AuthHandler nestedAuthHandler2 = new AuthHandlerImpl(authProvider2) { @Override public void parseCredentials(final RoutingContext context, final Handler<AsyncResult<JsonObject>> handler) { handler.handle(Future.succeededFuture(parsedCredentials)); } }; final PreCredentialsValidationHandler<HttpContext> preCredValidationHandler = mock( PreCredentialsValidationHandler.class); when(preCredValidationHandler.handle(eq(deviceCredentials), any())).thenReturn(Future.succeededFuture()); final HonoChainAuthHandler authHandler = new HonoChainAuthHandler(preCredValidationHandler); authHandler.append(nestedAuthHandler1); authHandler.append(nestedAuthHandler2); final String authorization = "BASIC " + Base64.getEncoder().encodeToString("user:password".getBytes(StandardCharsets.UTF_8)); final MultiMap headers = mock(MultiMap.class); when(headers.get(eq(HttpHeaders.AUTHORIZATION))).thenReturn(authorization); final HttpServerRequest req = mock(HttpServerRequest.class); when(req.headers()).thenReturn(headers); final HttpServerResponse resp = mock(HttpServerResponse.class); final RoutingContext routingContext = mock(RoutingContext.class); final Map<String, Object> routingContextMap = new HashMap<>(); when(routingContext.put(any(), any())).thenAnswer(invocation -> { routingContextMap.put(invocation.getArgument(0), invocation.getArgument(1)); return routingContext; }); when(routingContext.get(any())).thenAnswer(invocation -> routingContextMap.get(invocation.getArgument(0))); when(routingContext.remove(any())).thenAnswer(invocation -> routingContextMap.remove(invocation.getArgument(0))); when(routingContext.request()).thenReturn(req); when(routingContext.response()).thenReturn(resp); when(routingContext.currentRoute()).thenReturn(mock(Route.class)); authHandler.handle(routingContext); verify(routingContext).setUser(eq(deviceUser)); verify(preCredValidationHandler).handle(eq(deviceCredentials), any()); }