use of io.vertx.ext.web.handler.HttpException in project hono by eclipse.
the class DefaultFailureHandler method handle.
/**
* Handles routing failures.
* <p>
* This method simply delegates to the next handler if the response is already
* ended or the context is not failed.
*
* @param ctx The failing routing context.
*/
@Override
public void handle(final RoutingContext ctx) {
if (ctx.failed()) {
if (ctx.response().ended()) {
LOG.debug("skipping processing of failed route, response already ended");
} else {
LOG.debug("handling failed route for request [method: {}, URI: {}, status: {}] - {}", ctx.request().method(), HttpUtils.getAbsoluteURI(ctx.request()), ctx.statusCode(), ctx.getBody(), ctx.failure());
if (ctx.failure() != null) {
if (ctx.failure() instanceof ServiceInvocationException) {
final ServiceInvocationException e = (ServiceInvocationException) ctx.failure();
sendError(ctx.response(), e.getErrorCode(), e.getMessage());
} else if (ctx.failure() instanceof HttpException) {
final HttpException e = (HttpException) ctx.failure();
sendError(ctx.response(), e.getStatusCode(), e.getMessage());
} else {
LOG.debug("unexpected internal failure", ctx.failure());
sendError(ctx.response(), HttpURLConnection.HTTP_INTERNAL_ERROR, ctx.failure().getMessage());
}
} else if (ctx.statusCode() != -1) {
sendError(ctx.response(), ctx.statusCode(), null);
} else {
sendError(ctx.response(), HttpURLConnection.HTTP_INTERNAL_ERROR, "Internal Server Error");
}
}
} else {
LOG.debug("skipping processing of non-failed route");
ctx.next();
}
}
use of io.vertx.ext.web.handler.HttpException in project hono by eclipse.
the class AuthHandlerTools method processException.
/**
* Processes an exception that occurred while trying to authenticate
* a device.
* <p>
* This method checks if the given exception is an {@code HttpException}
* and if so, tries to extract the root cause of the problem from its
* <em>cause</em> field. If the root cause is a {@link ServiceInvocationException}
* the routing context is failed with that exception (provided the status code
* isn't 302, in which case the context is ended with a <em>Location</em> header).
* <p>
* In all other cases, the routing context is failed with the given exception.
* <p>
* Note that the routing context is failed with just the exception, no status
* code. Setting the status code on the response corresponding to the exception
* is to be done in the failure handler, e.g. as implemented in the
* {@link org.eclipse.hono.service.http.DefaultFailureHandler}.
*
* @param ctx The routing context.
* @param exception The cause of failure to process the request.
* @param authenticateHeader The value to return in the HTTP Authenticate header.
* @see io.vertx.ext.web.handler.impl.AuthenticationHandlerImpl
*/
public static void processException(final RoutingContext ctx, final Throwable exception, final String authenticateHeader) {
if (exception instanceof HttpException) {
final Throwable failure = Optional.ofNullable(exception.getCause()).map(c -> {
if (c instanceof ServiceInvocationException) {
// extract and use root cause
return c;
} else {
return exception;
}
}).orElse(exception);
final int statusCode;
final String payload;
if (failure instanceof ServiceInvocationException) {
final ServiceInvocationException sie = (ServiceInvocationException) exception.getCause();
statusCode = sie.getErrorCode();
payload = null;
} else {
statusCode = ((HttpException) exception).getStatusCode();
payload = ((HttpException) exception).getPayload();
}
switch(statusCode) {
case 302:
ctx.response().putHeader(HttpHeaders.LOCATION, payload).setStatusCode(302).end("Redirecting to " + payload + ".");
return;
case 401:
if (authenticateHeader != null) {
ctx.response().putHeader("WWW-Authenticate", authenticateHeader);
}
// fall through
default:
// rely on DefaultFailureHandler to extract/apply the status code
ctx.fail(failure);
}
} else {
ctx.fail(exception);
}
}
use of io.vertx.ext.web.handler.HttpException in project hono by eclipse.
the class HonoBasicAuthHandler method authenticate.
@Override
public void authenticate(final RoutingContext context, final Handler<AsyncResult<User>> handler) {
parseAuthorization(context, parseAuthorization -> {
if (parseAuthorization.failed()) {
handler.handle(Future.failedFuture(parseAuthorization.cause()));
return;
}
final String suser;
final String spass;
try {
// decode the payload
final String decoded = new String(Base64.getDecoder().decode(parseAuthorization.result()));
final int colonIdx = decoded.indexOf(":");
if (colonIdx != -1) {
suser = decoded.substring(0, colonIdx);
spass = decoded.substring(colonIdx + 1);
} else {
suser = decoded;
spass = null;
}
} catch (RuntimeException e) {
handler.handle(Future.failedFuture(new HttpException(400, e)));
return;
}
final var credentials = new JsonObject().put("username", suser).put("password", spass);
final ExecutionContextAuthHandler<HttpContext> authHandler = new ExecutionContextAuthHandler<>((DeviceCredentialsAuthProvider<?>) authProvider, preCredentialsValidationHandler) {
@Override
public Future<JsonObject> parseCredentials(final HttpContext context) {
return Future.succeededFuture(credentials);
}
};
authHandler.authenticateDevice(HttpContext.from(context)).map(deviceUser -> (User) deviceUser).onComplete(handler);
});
}
use of io.vertx.ext.web.handler.HttpException in project hono by eclipse.
the class HonoBasicAuthHandlerTest method testHandleFailsForMalformedAuthorizationHeader.
/**
* Verifies that the handler returns the status code {@link HttpURLConnection#HTTP_BAD_REQUEST} in case of malformed
* authorization header.
*/
@Test
public void testHandleFailsForMalformedAuthorizationHeader() {
final DeviceCredentialsAuthProvider<?> authProvider = mock(DeviceCredentialsAuthProvider.class);
final HonoBasicAuthHandler authHandler = new HonoBasicAuthHandler(authProvider, "test");
// WHEN trying to authenticate a request using the HTTP BASIC scheme
final String authorization = "BASIC test test";
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 ctx = mock(RoutingContext.class);
when(ctx.request()).thenReturn(req);
when(ctx.response()).thenReturn(resp);
when(ctx.currentRoute()).thenReturn(mock(Route.class));
authHandler.handle(ctx);
// THEN the routing context is failed with a 400 error
final ArgumentCaptor<Throwable> error = ArgumentCaptor.forClass(Throwable.class);
verify(ctx).fail(error.capture());
assertThat(error.getValue()).isInstanceOf(HttpException.class);
assertThat(((HttpException) error.getValue()).getStatusCode()).isEqualTo(HttpURLConnection.HTTP_BAD_REQUEST);
}
Aggregations