Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.RoutingContext;

/**
Expand Down Expand Up @@ -60,7 +62,7 @@ private Handler<Promise<Object>> createBlockingHandler(RoutingContext context) {
KeycloakSession session = sessionFactory.create();

configureContextualData(context, createClientConnection(context.request()), session);
configureEndHandler(context, promise, session);
configureEndHandler(context, session);

KeycloakTransactionManager tx = session.getTransactionManager();

Expand All @@ -87,20 +89,26 @@ private Handler<Promise<Object>> createBlockingHandler(RoutingContext context) {
* Creates a handler to close the {@link KeycloakSession} before the response is written to response but after Resteasy
* is done with processing its output.
*/
private void configureEndHandler(RoutingContext context, Promise<Object> promise, KeycloakSession session) {
private void configureEndHandler(RoutingContext context, KeycloakSession session) {
context.addHeadersEndHandler(event -> {
try {
close(session);
} catch (Throwable cause) {
promise.fail(cause);
context.response().headers().clear();
context.response().putHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN);
context.response().putHeader(HttpHeaderNames.CONTENT_LENGTH, "0");
context.response().setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code());
unexpectedErrorResponse(context.response());
}
});
}

private void unexpectedErrorResponse(HttpServerResponse response) {
response.headers().clear();
response.putHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN);
response.putHeader(HttpHeaderNames.CONTENT_LENGTH, "0");
response.setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code());
response.putHeader(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
// writes an empty buffer to replace any data previously written
response.write(Buffer.buffer(""));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
response.write(Buffer.buffer(""));
response.write(Buffer.buffer(""));
response.end();

Make it sense to end the requests here? I guess that should prevent any additional writes on the request.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried that and it seems unnecessary because that is done later by vert.x itself.

}

private void configureContextualData(RoutingContext context, ClientConnection connection, KeycloakSession session) {
Resteasy.pushContext(ClientConnection.class, connection);
Resteasy.pushContext(KeycloakSession.class, session);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,9 @@ public static void assumeNotAuthServerQuarkus() {
Assume.assumeFalse("Doesn't work on auth-server-quarkus",
AuthServerTestEnricher.AUTH_SERVER_CONTAINER.equals("auth-server-quarkus"));
}

public static void assumeAuthServerQuarkus() {
Assume.assumeTrue("Only works on auth-server-quarkus",
AuthServerTestEnricher.AUTH_SERVER_CONTAINER.equals("auth-server-quarkus"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,35 @@
package org.keycloak.testsuite.admin.authentication;

import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.ContainerAssume;

import javax.ws.rs.BadRequestException;
import javax.ws.rs.ClientErrorException;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.keycloak.testsuite.util.Matchers.body;
import static org.keycloak.testsuite.util.Matchers.statusCodeIs;

Expand Down Expand Up @@ -428,4 +439,37 @@ public void editExecutionFlowTest() {
Assert.assertEquals("This is another child flow3", executionReps.get(0).getDescription());
}

@Test
public void failWithLongDescription() {
ContainerAssume.assumeAuthServerQuarkus();
AuthenticationFlowRepresentation rep = authMgmtResource.getFlows().stream()
.filter(new Predicate<AuthenticationFlowRepresentation>() {
@Override
public boolean test(AuthenticationFlowRepresentation rep) {
return "docker auth".equals(rep.getAlias());
}
}).findAny().orElse(null);

assertNotNull(rep);

StringBuilder name = new StringBuilder();

while (name.length() < 300) {
name.append("invalid");
}

rep.setDescription(name.toString());

try {
authMgmtResource.updateFlow(rep.getId(), rep);
} catch (InternalServerErrorException isee) {
try (Response response = isee.getResponse()) {
assertEquals(500, response.getStatus());
assertEquals(0, response.getLength());
assertEquals(0, ByteArrayInputStream.class.cast(response.getEntity()).available());
}
} catch (Exception e) {
fail("Unexpected exception");
}
}
}