Skip to content

Commit

Permalink
Merge pull request #46073 from gsmet/configmapping-rest
Browse files Browse the repository at this point in the history
REST - Switch some remaining config to @ConfigMapping
  • Loading branch information
gsmet authored Feb 4, 2025
2 parents 04d9b5a + 591962e commit 5ac2f62
Show file tree
Hide file tree
Showing 20 changed files with 129 additions and 184 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-AlegacyConfigRoot=true</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-AlegacyConfigRoot=true</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-AlegacyConfigRoot=true</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
Expand Down
3 changes: 0 additions & 3 deletions extensions/resteasy-classic/resteasy/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,6 @@
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-AlegacyConfigRoot=true</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
Expand Down
3 changes: 0 additions & 3 deletions extensions/resteasy-reactive/rest-client/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,6 @@
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-AlegacyConfigRoot=true</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
Expand Down
3 changes: 0 additions & 3 deletions extensions/resteasy-reactive/rest-csrf/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,6 @@
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-AlegacyConfigRoot=true</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.quarkus.csrf.reactive;
package io.quarkus.csrf.reactive.deployment;

import io.quarkus.deployment.Feature;
import io.quarkus.deployment.annotations.BuildStep;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.quarkus.csrf.reactive;
package io.quarkus.csrf.reactive.deployment;

import java.util.function.BooleanSupplier;

Expand Down Expand Up @@ -31,7 +31,7 @@ public static class IsEnabled implements BooleanSupplier {
RestCsrfBuildTimeConfig config;

public boolean getAsBoolean() {
return config.enabled;
return config.enabled();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.quarkus.csrf.reactive.deployment;

import io.quarkus.runtime.annotations.ConfigRoot;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;

/**
* Build time configuration for CSRF Reactive Filter.
*/
@ConfigRoot
@ConfigMapping(prefix = "quarkus.rest-csrf")
public interface RestCsrfBuildTimeConfig {
/**
* If filter is enabled.
*/
@WithDefault("true")
boolean enabled();
}
3 changes: 0 additions & 3 deletions extensions/resteasy-reactive/rest-csrf/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,6 @@
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-AlegacyConfigRoot=true</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void filter(ResteasyReactiveContainerRequestContext requestContext, Routi
try {
int cookieTokenSize = Base64.getUrlDecoder().decode(cookieToken).length;
// HMAC SHA256 output is 32 bytes long
int expectedCookieTokenSize = config.tokenSignatureKey.isPresent() ? 32 : config.tokenSize;
int expectedCookieTokenSize = config.tokenSignatureKey().isPresent() ? 32 : config.tokenSize();
if (cookieTokenSize != expectedCookieTokenSize) {
LOG.debugf("Invalid CSRF token cookie size: expected %d, got %d", expectedCookieTokenSize,
cookieTokenSize);
Expand All @@ -90,12 +90,12 @@ public void filter(ResteasyReactiveContainerRequestContext requestContext, Routi
if (cookieToken == null) {
generateNewCsrfToken(routing, config);
} else {
String csrfTokenHeaderParam = requestContext.getHeaderString(config.tokenHeaderName);
String csrfTokenHeaderParam = requestContext.getHeaderString(config.tokenHeaderName());
if (csrfTokenHeaderParam != null) {
LOG.debugf("CSRF token found in the token header");
// Verify the header, make sure the header value, possibly signed, is returned as the next cookie value
verifyCsrfToken(requestContext, routing, config, cookieToken, csrfTokenHeaderParam);
} else if (!config.tokenSignatureKey.isEmpty()) {
} else if (!config.tokenSignatureKey().isEmpty()) {
// If the signature is required, then we can not use the current cookie value
// as the HTML form token key because it represents a signed value of the previous key
// and it will lead to the double-signing issue if this value is reused as the key.
Expand All @@ -109,11 +109,11 @@ public void filter(ResteasyReactiveContainerRequestContext requestContext, Routi
}
routing.put(NEW_COOKIE_REQUIRED, true);
}
} else if (config.verifyToken) {
} else if (config.verifyToken()) {
// unsafe HTTP method, token is required

// Check the header first
String csrfTokenHeaderParam = requestContext.getHeaderString(config.tokenHeaderName);
String csrfTokenHeaderParam = requestContext.getHeaderString(config.tokenHeaderName());
if (csrfTokenHeaderParam != null) {
LOG.debugf("CSRF token found in the token header");
verifyCsrfToken(requestContext, routing, config, cookieToken, csrfTokenHeaderParam);
Expand All @@ -124,7 +124,7 @@ public void filter(ResteasyReactiveContainerRequestContext requestContext, Routi
MediaType mediaType = requestContext.getMediaType();
if (!isMatchingMediaType(mediaType, MediaType.APPLICATION_FORM_URLENCODED_TYPE)
&& !isMatchingMediaType(mediaType, MediaType.MULTIPART_FORM_DATA_TYPE)) {
if (config.requireFormUrlEncoded) {
if (config.requireFormUrlEncoded()) {
LOG.debugf("Request has the wrong media type: %s", mediaType);
requestContext.abortWith(badClientRequest());
return;
Expand All @@ -143,7 +143,7 @@ public void filter(ResteasyReactiveContainerRequestContext requestContext, Routi

ResteasyReactiveRequestContext rrContext = (ResteasyReactiveRequestContext) requestContext
.getServerRequestContext();
String csrfTokenFormParam = (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, csrfTokenFormParam);

Expand All @@ -155,7 +155,7 @@ public void filter(ResteasyReactiveContainerRequestContext requestContext, Routi

private void generateNewCsrfToken(RoutingContext routing, RestCsrfConfig config) {
// Set the CSRF cookie with a randomly generated value
byte[] tokenBytes = new byte[config.tokenSize];
byte[] tokenBytes = new byte[config.tokenSize()];
secureRandom.nextBytes(tokenBytes);
routing.put(CSRF_TOKEN_BYTES_KEY, tokenBytes);
routing.put(CSRF_TOKEN_KEY, Base64.getUrlEncoder().withoutPadding().encodeToString(tokenBytes));
Expand All @@ -173,8 +173,8 @@ private void verifyCsrfToken(ResteasyReactiveContainerRequestContext requestCont
requestContext.abortWith(badClientRequest());
return;
} else {
String expectedCookieTokenValue = config.tokenSignatureKey.isPresent()
? CsrfTokenUtils.signCsrfToken(csrfToken, config.tokenSignatureKey.get())
String expectedCookieTokenValue = config.tokenSignatureKey().isPresent()
? CsrfTokenUtils.signCsrfToken(csrfToken, config.tokenSignatureKey().get())
: csrfToken;
if (!cookieToken.equals(expectedCookieTokenValue)) {
LOG.debug("CSRF token value is wrong");
Expand Down Expand Up @@ -227,15 +227,15 @@ public void filter(ContainerRequestContext requestContext,
final RestCsrfConfig config = configInstance.get();

String cookieValue = null;
if (config.tokenSignatureKey.isPresent()) {
if (config.tokenSignatureKey().isPresent()) {
byte[] csrfTokenBytes = (byte[]) routing.get(CSRF_TOKEN_BYTES_KEY);

if (csrfTokenBytes == null) {
LOG.debug("CSRF Request Filter did not set the property " + CSRF_TOKEN_BYTES_KEY
+ ", no CSRF cookie will be created");
return;
}
cookieValue = CsrfTokenUtils.signCsrfToken(csrfTokenBytes, config.tokenSignatureKey.get());
cookieValue = CsrfTokenUtils.signCsrfToken(csrfTokenBytes, config.tokenSignatureKey().get());
} else {
String csrfToken = (String) routing.get(CSRF_TOKEN_KEY);

Expand All @@ -258,7 +258,7 @@ public void filter(ContainerRequestContext requestContext,
* @return An Optional containing the token, or an empty Optional if the token cookie is not present or is invalid
*/
private static String getCookieToken(RoutingContext routing, RestCsrfConfig config) {
Cookie cookie = routing.getCookie(config.cookieName);
Cookie cookie = routing.getCookie(config.cookieName());

if (cookie == null) {
LOG.debug("CSRF token cookie is not set");
Expand All @@ -269,19 +269,19 @@ private static String getCookieToken(RoutingContext routing, RestCsrfConfig conf
}

private static boolean isCsrfTokenRequired(RoutingContext routing, RestCsrfConfig config) {
return config.createTokenPath
return config.createTokenPath()
.map(value -> value.contains(routing.normalizedPath())).orElse(true);
}

private static void createCookie(String cookieTokenValue, RoutingContext routing, RestCsrfConfig config) {

ServerCookie cookie = new CookieImpl(config.cookieName, cookieTokenValue);
cookie.setHttpOnly(config.cookieHttpOnly);
cookie.setSecure(config.cookieForceSecure || routing.request().isSSL());
cookie.setMaxAge(config.cookieMaxAge.toSeconds());
cookie.setPath(config.cookiePath);
if (config.cookieDomain.isPresent()) {
cookie.setDomain(config.cookieDomain.get());
ServerCookie cookie = new CookieImpl(config.cookieName(), cookieTokenValue);
cookie.setHttpOnly(config.cookieHttpOnly());
cookie.setSecure(config.cookieForceSecure() || routing.request().isSSL());
cookie.setMaxAge(config.cookieMaxAge().toSeconds());
cookie.setPath(config.cookiePath());
if (config.cookieDomain().isPresent()) {
cookie.setDomain(config.cookieDomain().get());
}
routing.response().addCookie(cookie);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ public class CsrfTokenParameterProvider {
private final String csrfHeaderName;

public CsrfTokenParameterProvider(RestCsrfConfig config) {
this.csrfFormFieldName = config.formFieldName;
this.csrfCookieName = config.cookieName;
this.csrfHeaderName = config.tokenHeaderName;
this.csrfFormFieldName = config.formFieldName();
this.csrfCookieName = config.cookieName();
this.csrfHeaderName = config.tokenHeaderName();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,83 +4,83 @@
import java.util.Optional;
import java.util.Set;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;

/**
* Runtime configuration for CSRF Reactive Filter.
*/
@ConfigRoot(phase = ConfigPhase.RUN_TIME)
public class RestCsrfConfig {
@ConfigMapping(prefix = "quarkus.rest-csrf")
public interface RestCsrfConfig {
/**
* Form field name which keeps a CSRF token.
*/
@ConfigItem(defaultValue = "csrf-token")
public String formFieldName;
@WithDefault("csrf-token")
String formFieldName();

/**
* Token header which can provide a CSRF token.
*/
@ConfigItem(defaultValue = "X-CSRF-TOKEN")
public String tokenHeaderName;
@WithDefault("X-CSRF-TOKEN")
String tokenHeaderName();

/**
* CSRF cookie name.
*/
@ConfigItem(defaultValue = "csrf-token")
public String cookieName;
@WithDefault("csrf-token")
String cookieName();

/**
* CSRF cookie max age.
*/
@ConfigItem(defaultValue = "2H")
public Duration cookieMaxAge;
@WithDefault("2H")
Duration cookieMaxAge();

/**
* CSRF cookie path.
*/
@ConfigItem(defaultValue = "/")
public String cookiePath;
@WithDefault("/")
String cookiePath();

/**
* CSRF cookie domain.
*/
@ConfigItem
public Optional<String> cookieDomain;
Optional<String> cookieDomain();

/**
* If enabled the CSRF cookie will have its 'secure' parameter set to 'true'
* when HTTP is used. It may be necessary when running behind an SSL terminating reverse proxy.
* The cookie will always be secure if HTTPS is used even if this property is set to false.
*/
@ConfigItem(defaultValue = "false")
public boolean cookieForceSecure;
@WithDefault("false")
boolean cookieForceSecure();

/**
* Set the HttpOnly attribute to prevent access to the cookie via JavaScript.
*/
@ConfigItem(defaultValue = "true")
public boolean cookieHttpOnly = true;
@WithDefault("true")
boolean cookieHttpOnly();

/**
* Create CSRF token only if the HTTP GET relative request path matches one of the paths configured with this property.
* Use a comma to separate multiple path values.
*
*/
@ConfigItem
public Optional<Set<String>> createTokenPath;
Optional<Set<String>> createTokenPath();

/**
* Random CSRF token size in bytes.
*/
@ConfigItem(defaultValue = "16")
public int tokenSize;
@WithDefault("16")
int tokenSize();

/**
* CSRF token HMAC signature key, if this key is set then it must be at least 32 characters long.
*/
@ConfigItem
public Optional<String> tokenSignatureKey;
Optional<String> tokenSignatureKey();

/**
* Verify CSRF token in the CSRF filter.
Expand All @@ -95,8 +95,8 @@ public class RestCsrfConfig {
* is available, has the correct {@linkplain #tokenSize} in bytes and that the Content-Type HTTP header is
* either 'application/x-www-form-urlencoded' or 'multipart/form-data'.
*/
@ConfigItem(defaultValue = "true")
public boolean verifyToken;
@WithDefault("true")
boolean verifyToken();

/**
* Require that only 'application/x-www-form-urlencoded' or 'multipart/form-data' body is accepted for the token
Expand All @@ -105,6 +105,6 @@ public class RestCsrfConfig {
* This property is only effective if {@link #verifyToken} property is enabled and {@link #tokenHeaderName} is not
* configured.
*/
@ConfigItem(defaultValue = "true")
public boolean requireFormUrlEncoded;
@WithDefault("true")
boolean requireFormUrlEncoded();
}
Loading

0 comments on commit 5ac2f62

Please sign in to comment.