Skip to content

Commit

Permalink
Merge pull request #37815 from gsmet/3.6.4-backports-1
Browse files Browse the repository at this point in the history
3.6.4 backports 1
  • Loading branch information
gsmet authored Dec 19, 2023
2 parents abfe0d2 + 27bf076 commit 9bca238
Show file tree
Hide file tree
Showing 23 changed files with 188 additions and 44 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/ci-actions-incremental.yml
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,9 @@ jobs:
# We do this so we can get better analytics for the downloaded version of the build images
- name: Update Docker Client User Agent
run: |
cat <<< $(jq '.HttpHeaders += {"User-Agent": "Quarkus-CI-Docker-Client"}' ~/.docker/config.json) > ~/.docker/config.json
if [ -f ~/.docker/config.json ]; then
cat <<< $(jq '.HttpHeaders += {"User-Agent": "Quarkus-CI-Docker-Client"}' ~/.docker/config.json) > ~/.docker/config.json
fi
- name: Build
env:
TEST_MODULES: ${{matrix.test-modules}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1309,12 +1309,14 @@ boolean isRestartNeeded(String changedFile) {
}
}
// Then try to match a new file that was added to a resource root
Boolean ret = watchedFilePaths.get(changedFile);
Boolean ret = watchedFilePaths != null ? watchedFilePaths.get(changedFile) : null;
if (ret == null) {
ret = false;
for (Entry<Predicate<String>, Boolean> e : watchedFilePredicates) {
if (e.getKey().test(changedFile)) {
ret = ret || e.getValue();
ret = Boolean.FALSE;
if (watchedFilePredicates != null) {
for (Entry<Predicate<String>, Boolean> e : watchedFilePredicates) {
if (e.getKey().test(changedFile)) {
ret = ret || e.getValue();
}
}
}
}
Expand Down
45 changes: 29 additions & 16 deletions devtools/cli/src/main/java/io/quarkus/cli/QuarkusCli.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import jakarta.inject.Inject;

Expand Down Expand Up @@ -96,7 +97,9 @@ public int run(String... args) throws Exception {
boolean pluginCommand = args.length >= 1 && (args[0].equals("plug") || args[0].equals("plugin"));

try {
boolean existingCommand = checkMissingCommand(cmd, args).isEmpty();
Optional<String> missingCommand = checkMissingCommand(cmd, args);

boolean existingCommand = missingCommand.isEmpty();
// If the command already exists and is not a help command (that lists subcommands) or plugin command, then just execute
// without dealing with plugins.
// The reason that we check if its a plugin command is that plugin commands need PluginManager initialization.
Expand All @@ -108,8 +111,7 @@ public int run(String... args) throws Exception {
pluginManager.syncIfNeeded();
Map<String, Plugin> plugins = new HashMap<>(pluginManager.getInstalledPlugins());
pluginCommandFactory.populateCommands(cmd, plugins);
Optional<String> missing = checkMissingCommand(cmd, args);
missing.ifPresent(m -> {
missingCommand.ifPresent(m -> {
try {
Map<String, Plugin> installable = pluginManager.getInstallablePlugins();
if (installable.containsKey(m)) {
Expand All @@ -119,11 +121,13 @@ public int run(String... args) throws Exception {
output.info("Command %s not installed but the following plugin is available:\n%s", m,
table.getContent());
if (interactiveMode && Prompt.yesOrNo(true,
"Would you like to install it now ?",
"Would you like to install it now?",
args)) {
pluginManager.addPlugin(m).ifPresent(added -> plugins.put(added.getName(), added));
pluginCommandFactory.populateCommands(cmd, plugins);
}
} else {
output.error("Command %s is missing and can't be installed.", m);
}
} catch (Exception e) {
output.error("Command %s is missing and can't be installed.", m);
Expand All @@ -136,7 +140,7 @@ public int run(String... args) throws Exception {
}

/**
* Recursivelly processes the arguments passed to the command and checks wether a subcommand is missing.
* Process the arguments passed and return an identifier of the potentially missing subcommand if any.
*
* @param root the root command
* @param args the arguments passed to the root command
Expand All @@ -148,17 +152,26 @@ public Optional<String> checkMissingCommand(CommandLine root, String[] args) {
}

try {
ParseResult result = root.parseArgs(args);
if (args.length == 1) {
return Optional.empty();
}
CommandLine next = root.getSubcommands().get(args[0]);
if (next == null) {
return Optional.of(args[0]);
}
String[] remaining = new String[args.length - 1];
System.arraycopy(args, 1, remaining, 0, remaining.length);
return checkMissingCommand(next, remaining).map(nextMissing -> root.getCommandName() + "-" + nextMissing);
ParseResult currentParseResult = root.parseArgs(args);
StringBuilder missingCommand = new StringBuilder();

do {
if (missingCommand.length() > 0) {
missingCommand.append("-");
}
missingCommand.append(currentParseResult.commandSpec().name());

List<String> unmatchedSubcommands = currentParseResult.unmatched().stream()
.filter(u -> !u.startsWith("-")).collect(Collectors.toList());
if (!unmatchedSubcommands.isEmpty()) {
missingCommand.append("-").append(unmatchedSubcommands.get(0));
return Optional.of(missingCommand.toString());
}

currentParseResult = currentParseResult.subcommand();
} while (currentParseResult != null);

return Optional.empty();
} catch (UnmatchedArgumentException e) {
return Optional.of(args[0]);
}
Expand Down
1 change: 0 additions & 1 deletion docs/src/main/asciidoc/deploying-to-google-cloud.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,6 @@ Finally, you need to configure your datasource specifically to use the socket fa
----
quarkus.datasource.db-kind=postgresql
quarkus.datasource.jdbc.url=jdbc:postgresql:///mydatabase <1>
quarkus.datasource.jdbc.driver=org.postgresql.Driver
quarkus.datasource.username=quarkus
quarkus.datasource.password=quarkus
quarkus.datasource.jdbc.additional-jdbc-properties.cloudSqlInstance=project-id:gcp-region:instance <2>
Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/mongodb-panache.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ This can be achieved by setting to DEBUG the following log category inside your

[source,properties]
----
quarkus.log.category."io.quarkus.mongodb.panache.runtime".level=DEBUG
quarkus.log.category."io.quarkus.mongodb.panache.common.runtime".level=DEBUG
----

== The PojoCodecProvider: easy object to BSON document conversion.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/rabbitmq-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ Type: _boolean_ | false | `false`

Type: _string_ | false | `#`

| [.no-hyphens]#*content-type-override*# | Override the content_type attribute of the incoming message, should be a valid MINE type
| [.no-hyphens]#*content-type-override*# | Override the content_type attribute of the incoming message, should be a valid MIME type

Type: _string_ | false |

Expand Down
3 changes: 2 additions & 1 deletion docs/src/main/asciidoc/security-csrf-prevention.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ include::_attributes.adoc[]

https://owasp.org/www-community/attacks/csrf[Cross-Site Request Forgery (CSRF)] is an attack that forces an end user to execute unwanted actions on a web application in which they are currently authenticated.

Quarkus Security provides a CSRF prevention feature which implements https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie[Double Submit Cookie] and [CSRF Request Header] techniques.
Quarkus Security provides a CSRF prevention feature which implements https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie[Double Submit Cookie] and <<csrf-request-header>> techniques.

`Double Submit Cookie` technique requires that the CSRF token sent as `HTTPOnly`, optionally signed, cookie to the client, and
directly embedded in a hidden form input of server-side rendered HTML forms, or submitted as a request header value.
Expand Down Expand Up @@ -139,6 +139,7 @@ You can get `HMAC` signatures created for the generated CSRF tokens and have the
quarkus.csrf-reactive.token-signature-key=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow
----

[[csrf-request-header]]
== CSRF Request Header

If HTML `form` tags are not used and you need to pass CSRF token as a header, then inject the header name and token, for example, into HTMX:
Expand Down
4 changes: 2 additions & 2 deletions docs/src/main/asciidoc/security-getting-started-tutorial.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -462,9 +462,9 @@ As you can see in this code sample, you do not need to start the test container

[NOTE]
====
When you start your application in dev mode, `Dev Services for PostgreSQL` launches a `PostgreSQL` `devmode` container so that you can start developing your application.
When you start your application in dev mode, Dev Services for PostgreSQL launches a PostgreSQL dev mode container so that you can start developing your application.
While developing your application, you can add tests one by one and run them using the xref:continuous-testing.adoc[Continuous Testing] feature.
`Dev Services for PostgreSQL` supports testing while you develop by providing a separate `PostgreSQL` test container that does not conflict with the `devmode` container.
Dev Services for PostgreSQL supports testing while you develop by providing a separate PostgreSQL test container that does not conflict with the dev mode container.
====

=== Use Curl or a browser to test your application
Expand Down
4 changes: 2 additions & 2 deletions docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ public class GreetingResourceTest {
}
----

If you recall, when the application was started in devmode, the following could be seen in the CLI window:
If you recall, when the application was started in dev mode, the following could be seen in the CLI window:

image::auth0-devmode-started.png[Auth0 DevMode started]

Expand Down Expand Up @@ -1075,7 +1075,7 @@ Open a browser, access http://localhost:8080/hello and get the name displayed in

== Troubleshooting

The steps described in this tutorial should work exactly as the tutorial describes. You might have to clear the browser cookies when accessing the updated Quarkus endpoint if you have already completed the authentication. You might need to restart the Quarkus application manually in devmode but it is not expected. If you need help completing this tutorial, you can get in touch with the Quarkus team.
The steps described in this tutorial should work exactly as the tutorial describes. You might have to clear the browser cookies when accessing the updated Quarkus endpoint if you have already completed the authentication. You might need to restart the Quarkus application manually in dev mode but it is not expected. If you need help completing this tutorial, you can get in touch with the Quarkus team.

== Summary

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ To make Dev UI more useful for supporting the development of OIDC `web-app` appl
It will ensure that all Dev UI options described in <<develop-service-applications,Developing OpenID Connect Service Applications>> will be available when your `web-app` application is run in dev mode. The limitation of this approach is that both access and ID tokens returned with the code flow and acquired with Dev UI will be sent to the endpoint as HTTP `Bearer` tokens - which will not work well if your endpoint requires the injection of `IdToken`.
However, it will work as expected if your `web-app` application only uses the access token, for example, as a source of roles or to get `UserInfo`, even if it is assumed to be a `service` application in dev mode.

Even a better option is to use a `hybrid` application type in devmode:
Even a better option is to use a `hybrid` application type in dev mode:

[source,properties]
----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ public class CustomTenantResolver implements TenantResolver {

You can define multiple tenants in your configuration file, just make sure they have a unique alias so that you can map them properly when resolving a tenant from your `TenantResolver` implementation.

However, using a static tenant resolution (configuring tenants in `application.properties` and resolving them with `TenantResolver`) prevents testing the endpoint with `Dev Services for Keycloak` since `Dev Services for Keycloak` has no knowledge of how the requests will be mapped to individual tenants and can not dynamically provide tenant-specific `quarkus.oidc.<tenant-id>.auth-server-url` values and therefore using `%prod` prefixes with the tenant-specific URLs in `application.properties` will not work in tests or devmode.
However, using a static tenant resolution (configuring tenants in `application.properties` and resolving them with `TenantResolver`) prevents testing the endpoint with `Dev Services for Keycloak` since `Dev Services for Keycloak` has no knowledge of how the requests will be mapped to individual tenants and can not dynamically provide tenant-specific `quarkus.oidc.<tenant-id>.auth-server-url` values and therefore using `%prod` prefixes with the tenant-specific URLs in `application.properties` will not work in test or dev mode.

[NOTE]
====
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ The pattern of authenticating with a given provider, where the endpoint uses eit

== HTTPS Redirect URL

Some providers will only accept HTTPS-based redirect URLs. Tools such as https://ngrok.com/[ngrok] https://linuxhint.com/set-up-use-ngrok/[can be set up] to help testing such providers with Quarkus endpoints running on localhost in devmode.
Some providers will only accept HTTPS-based redirect URLs. Tools such as https://ngrok.com/[ngrok] https://linuxhint.com/set-up-use-ngrok/[can be set up] to help testing such providers with Quarkus endpoints running on localhost in dev mode.

== Rate Limiting

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ public void filter(ResteasyReactiveContainerRequestContext requestContext, Routi

String cookieToken = getCookieToken(routing, config);
if (cookieToken != null) {
routing.put(CSRF_TOKEN_KEY, cookieToken);

try {
int cookieTokenSize = Base64.getUrlDecoder().decode(cookieToken).length;
// HMAC SHA256 output is 32 bytes long
Expand Down Expand Up @@ -98,10 +96,10 @@ public void filter(ResteasyReactiveContainerRequestContext requestContext, Routi
// unsafe HTTP method, token is required

// Check the header first
String csrfTokenInHeader = requestContext.getHeaderString(config.tokenHeaderName);
if (csrfTokenInHeader != null) {
String csrfTokenHeaderParam = requestContext.getHeaderString(config.tokenHeaderName);
if (csrfTokenHeaderParam != null) {
LOG.debugf("CSRF token found in the token header");
verifyCsrfToken(requestContext, routing, config, cookieToken, csrfTokenInHeader);
verifyCsrfToken(requestContext, routing, config, cookieToken, csrfTokenHeaderParam);
return;
}

Expand All @@ -128,9 +126,9 @@ public void filter(ResteasyReactiveContainerRequestContext requestContext, Routi

ResteasyReactiveRequestContext rrContext = (ResteasyReactiveRequestContext) requestContext
.getServerRequestContext();
String csrfToken = (String) rrContext.getFormParameter(config.formFieldName, true, false);
String csrfTokenFormParam = (String) rrContext.getFormParameter(config.formFieldName, true, false);
LOG.debugf("CSRF token found in the form parameter");
verifyCsrfToken(requestContext, routing, config, cookieToken, csrfToken);
verifyCsrfToken(requestContext, routing, config, cookieToken, csrfTokenFormParam);
return;

} else if (cookieToken == null) {
Expand Down Expand Up @@ -159,6 +157,7 @@ private void verifyCsrfToken(ResteasyReactiveContainerRequestContext requestCont
requestContext.abortWith(badClientRequest());
return;
} else {
routing.put(CSRF_TOKEN_KEY, csrfToken);
routing.put(CSRF_TOKEN_VERIFIED, true);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.vertx.core.datagram.DatagramSocketOptions;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.impl.NoStackTraceException;
import io.vertx.core.metrics.MetricsOptions;
import io.vertx.core.net.NetClientOptions;
import io.vertx.core.net.NetServerOptions;
Expand Down Expand Up @@ -60,7 +61,7 @@ public MetricsOptions newOptions() {
@Override
public HttpServerMetrics<?, ?, ?> createHttpServerMetrics(HttpServerOptions options, SocketAddress localAddress) {
if (httpBinderConfiguration == null) {
throw new IllegalStateException("HttpBinderConfiguration was not found");
throw new NoStackTraceException("HttpBinderConfiguration was not found");
}
if (httpBinderConfiguration.isServerEnabled()) {
log.debugf("Create HttpServerMetrics with options %s and address %s", options, localAddress);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.List;
import java.util.Map;
Expand All @@ -13,17 +17,24 @@
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedHashMap;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.ext.ContextResolver;

import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;
import org.jboss.resteasy.reactive.server.jackson.JacksonBasicMessageBodyReader;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import com.fasterxml.jackson.databind.ObjectMapper;

import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder;
import io.quarkus.rest.client.reactive.TestJacksonBasicMessageBodyReader;
import io.quarkus.test.QuarkusUnitTest;
Expand Down Expand Up @@ -78,6 +89,7 @@ public Map<String, List<String>> callClient(String uri) {
}
}

@RegisterProvider(ErroneousJacksonBasicMessageBodyReader.class)
public interface Client {
@GET
Map<String, List<String>> get();
Expand All @@ -101,6 +113,20 @@ public ClientHeadersFactory getContext(Class<?> aClass) {
}
}

@Priority(Priorities.USER + 100)
public static class ErroneousJacksonBasicMessageBodyReader extends JacksonBasicMessageBodyReader {
public ErroneousJacksonBasicMessageBodyReader() {
super(new ObjectMapper());
}

@Override
public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException, WebApplicationException {
throw new IllegalStateException("should never be called");
}
}

public static class CustomClientHeadersFactory implements ClientHeadersFactory {

private final String value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ public final class Types {
// TODO: add a extensible banning mechanism based on predicates if we find that this set needs to grow...
private static final Set<DotName> BANNED_INTERFACE_TYPES = new HashSet<>(
Arrays.asList(DotName.createSimple("java.lang.constant.ConstantDesc"),
DotName.createSimple("java.lang.constant.Constable")));
DotName.createSimple("java.lang.constant.Constable"),
DotName.createSimple("java.util.SequencedCollection")));

private Types() {
}
Expand Down
Loading

0 comments on commit 9bca238

Please sign in to comment.