Skip to content

Commit

Permalink
Merge branch 'main' into patch-5
Browse files Browse the repository at this point in the history
  • Loading branch information
andlinger authored Dec 14, 2023
2 parents b8dddec + ecdd3b2 commit 51f9792
Show file tree
Hide file tree
Showing 23 changed files with 124 additions and 104 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -55,4 +55,4 @@ jobs:
run: ./mvnw -B --settings .github/mvn-settings.xml -Dquickly-ci install

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
2 changes: 1 addition & 1 deletion .github/workflows/preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
with:
repository: quarkusio/quarkusio.github.io
- name: Download PR Artifact
uses: dawidd6/action-download-artifact@v2
uses: dawidd6/action-download-artifact@v3
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
workflow_conclusion: success
Expand Down
4 changes: 2 additions & 2 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@
<kotlin.coroutine.version>1.7.3</kotlin.coroutine.version>
<azure.toolkit-lib.version>0.27.0</azure.toolkit-lib.version>
<kotlin-serialization.version>1.6.2</kotlin-serialization.version>
<dekorate.version>4.1.0</dekorate.version> <!-- Please check with Java Operator SDK team before updating -->
<dekorate.version>4.1.1</dekorate.version> <!-- Please check with Java Operator SDK team before updating -->
<maven-invoker.version>3.2.0</maven-invoker.version>
<awaitility.version>4.2.0</awaitility.version>
<jboss-logmanager.version>3.0.2.Final</jboss-logmanager.version>
Expand Down Expand Up @@ -217,7 +217,7 @@
<aesh.version>2.7</aesh.version>
<aesh-readline.version>2.4</aesh-readline.version>
<jansi.version>2.4.0</jansi.version> <!-- Keep in sync with aesh-readline and dekorate -->
<jgit.version>6.7.0.202309050840-r</jgit.version>
<jgit.version>6.8.0.202311291450-r</jgit.version>
<!-- these two artifacts needs to be compatible together -->
<strimzi-oauth.version>0.14.0</strimzi-oauth.version>
<strimzi-oauth.nimbus.version>9.37.3</strimzi-oauth.nimbus.version>
Expand Down
2 changes: 1 addition & 1 deletion devtools/cli/distribution/jreleaser-maintenance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ project:
java:
groupId: io.quarkus
artifactId: quarkus-cli
version : 11
version : 17
tags:
- cli
- quarkus
Expand Down
2 changes: 1 addition & 1 deletion devtools/cli/distribution/jreleaser-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ project:
java:
groupId: io.quarkus
artifactId: quarkus-cli
version : 11
version : 17
tags:
- cli
- quarkus
Expand Down
2 changes: 1 addition & 1 deletion devtools/cli/distribution/jreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ project:
java:
groupId: io.quarkus
artifactId: quarkus-cli
version : 11
version : 17
tags:
- cli
- quarkus
Expand Down
2 changes: 1 addition & 1 deletion docs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<roaster-jdt.version>2.26.0.Final</roaster-jdt.version>
<maven-model-helper.version>21</maven-model-helper.version>
<eclipse-collections.version>11.1.0</eclipse-collections.version>
<jgit.version>6.7.0.202309050840-r</jgit.version>
<jgit.version>6.8.0.202311291450-r</jgit.version>

<quarkus-home-url>https://quarkus.io</quarkus-home-url>
<quarkus-base-url>https://github.com/quarkusio/quarkus</quarkus-base-url>
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
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
77 changes: 0 additions & 77 deletions docs/src/main/asciidoc/security-openid-connect-dev-services.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -340,83 +340,6 @@ quarkus.oidc.devui.grant.type=password
quarkus.oidc.devui.grant-options.password.audience=http://localhost:8080
----

== Dev Services and UI Support for other OpenID Connect Providers

Your custom extension would need to extend `quarkus-oidc` and add the dependencies required to support your provider to the extension's `deployment` module only.

The build step dealing with the `Dev Services` should additionally register two runtime properties into the "io.quarkus.quarkus-oidc" namespace: `oidcProviderName` (for example, `Google`) and `oidcProviderUrlBase` (for example: `mycompany.devservices-google`) for the `OpenID Connect Card` to link to the Dev UI page representing your provider, for example:

[source,java]
----
package io.quarkus.oidc.okta.runtime;
import java.util.function.Supplier;
import io.quarkus.runtime.annotations.Recorder;
// This simple recorder is the only code which will be located in the extension's `runtime` module
@Recorder
public class OktaDevServicesRecorder {
public Supplier<String> getProviderName() {
return new Supplier<String>() {
@Override
public String get() {
return "OKTA";
}
};
}
public Supplier<String> getProviderUrlBase() {
return new Supplier<String>() {
@Override
public String get() {
return "io.quarkus" + "." + "quarkus-oidc-okta";
}
};
}
}
package io.quarkus.oidc.okta.deployment.devservices;
import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT;
import java.util.Optional;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.Consume;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.RuntimeConfigSetupCompleteBuildItem;
import io.quarkus.devconsole.spi.DevConsoleRouteBuildItem;
import io.quarkus.devconsole.spi.DevConsoleRuntimeTemplateInfoBuildItem;
public class OktaDevConsoleProcessor {
@BuildStep(onlyIf = IsDevelopment.class)
@Record(value = RUNTIME_INIT)
public void setOidcProviderProperties(BuildProducer<DevConsoleRuntimeTemplateInfoBuildItem> provider,
OktaDevServicesRecorder recorder,
Optional<DevServicesConfigBuildItem> configProps) {
if (configProps.isPresent()) {
provider.produce(new DevConsoleRuntimeTemplateInfoBuildItem("io.quarkus", "quarkus-oidc", "oidcProviderName",
recorder.getProviderName()));
provider.produce(new DevConsoleRuntimeTemplateInfoBuildItem("io.quarkus", "quarkus-oidc", "oidcProviderUrlBase",
recorder.getProviderUrlBase()));
}
}
}
----

Additionally, the extension should produce a `io.quarkus.oidc.deployment.devservices.OidcProviderBuildItem` to disable the default `Dev Services for Keycloak`, instead of the users having to type `quarkus.keycloak.devservices.enabled=false`.

Please follow the xref:dev-ui.adoc[Dev UI] tutorial as well as check the `extensions/oidc/deployment` sources for more ideas.

== Non Application Root Path Considerations

This document refers to the `http://localhost:8080/q/dev-ui` Dev UI URL in several places where `q` is a default non application root path. If you customize `quarkus.http.root-path` and/or `quarkus.http.non-application-root-path` properties then replace `q` accordingly, please see https://quarkus.io/blog/path-resolution-in-quarkus/[Path Resolution in Quarkus] for more information.
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 @@ -36,7 +36,7 @@ public void visit(KubernetesListBuilder list) {
.endSelector()
.addNewEndpoint()
.withScheme(scheme)
.withNewTargetPort(targetPort)
.withNewTargetPort(Integer.parseInt(targetPort)) //This needs to be passed as int
.withPath(path)
.withInterval(interval + "s")
.withHonorLabels(honorLabels)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,7 @@ NativeImageConfigBuildItem build(
}

builder.addRuntimeReinitializedClass("io.netty.util.internal.PlatformDependent")
.addRuntimeReinitializedClass("io.netty.util.internal.PlatformDependent0")
.addRuntimeReinitializedClass("io.netty.buffer.PooledByteBufAllocator");
.addRuntimeReinitializedClass("io.netty.util.internal.PlatformDependent0");

if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.buffer.UnpooledByteBufAllocator")) {
builder.addRuntimeReinitializedClass("io.netty.buffer.UnpooledByteBufAllocator")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ public class TestResource {
@Inject
Template csrfTokenForm;

@Inject
Template csrfTokenFirstForm;

@Inject
Template csrfTokenSecondForm;

@Inject
Template csrfTokenHeader;

Expand All @@ -49,6 +55,14 @@ public TemplateInstance getCsrfTokenForm() {
return csrfTokenForm.instance();
}

@GET
@Path("/csrfTokenFirstForm")
@Produces(MediaType.TEXT_HTML)
@Authenticated
public TemplateInstance getCsrfTokenFirstForm() {
return csrfTokenFirstForm.instance();
}

@GET
@Path("/csrfTokenWithFormRead")
@Produces(MediaType.TEXT_HTML)
Expand All @@ -71,6 +85,22 @@ public String postCsrfTokenForm(@FormParam("name") String name, @HeaderParam("X-
return name + ":" + routingContext.get("csrf_token_verified", false) + ":tokenHeaderIsSet=" + (csrfHeader != null);
}

@POST
@Path("/csrfTokenFirstForm")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_HTML)
public TemplateInstance postCsrfTokenFirstForm() {
return csrfTokenSecondForm.instance();
}

@POST
@Path("/csrfTokenSecondForm")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_PLAIN)
public String postCsrfTokenSecondForm(@FormParam("name") String name, @HeaderParam("X-CSRF-TOKEN") String csrfHeader) {
return name + ":" + routingContext.get("csrf_token_verified", false) + ":tokenHeaderIsSet=" + (csrfHeader != null);
}

@POST
@Path("/csrfTokenWithFormRead")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
quarkus.csrf-reactive.cookie-name=csrftoken
quarkus.csrf-reactive.create-token-path=/service/csrfTokenForm,/service/csrfTokenWithFormRead,/service/csrfTokenMultipart,/service/csrfTokenWithHeader
quarkus.csrf-reactive.create-token-path=/service/csrfTokenForm,/service/csrfTokenFirstForm,/service/csrfTokenSecondForm,/service/csrfTokenWithFormRead,/service/csrfTokenMultipart,/service/csrfTokenWithHeader
quarkus.csrf-reactive.token-signature-key=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow

quarkus.http.auth.basic=true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSRF Token First Form Test</title>
</head>
<body>
<h1>CSRF Test</h1>

<form action="/service/csrfTokenFirstForm" method="post">
<input type="hidden" name="{inject:csrf.parameterName}" value="{inject:csrf.token}" />

<p>Your Name: <input type="text" name="name" /></p>
<p><input type="submit" name="submit"/></p>
</form>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSRF Token Second Form Test</title>
</head>
<body>
<h1>CSRF Test</h1>

<form action="/service/csrfTokenSecondForm" method="post">
<input type="hidden" name="{inject:csrf.parameterName}" value="{inject:csrf.token}" />

<p>Your Name: <input type="text" name="name" /></p>
<p><input type="submit" name="submit"/></p>
</form>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,36 @@ public void testCsrfTokenInForm() throws Exception {
}
}

@Test
public void testCsrfTokenTwoForms() throws Exception {
try (final WebClient webClient = createWebClient()) {
webClient.addRequestHeader("Authorization", basicAuth("alice", "alice"));
HtmlPage htmlPage = webClient.getPage("http://localhost:8081/service/csrfTokenFirstForm");

assertEquals("CSRF Token First Form Test", htmlPage.getTitleText());

HtmlForm loginForm = htmlPage.getForms().get(0);

loginForm.getInputByName("name").setValueAttribute("alice");

assertNotNull(webClient.getCookieManager().getCookie("csrftoken"));

htmlPage = loginForm.getInputByName("submit").click();

assertEquals("CSRF Token Second Form Test", htmlPage.getTitleText());

loginForm = htmlPage.getForms().get(0);

loginForm.getInputByName("name").setValueAttribute("alice");

TextPage textPage = loginForm.getInputByName("submit").click();
assertNotNull(webClient.getCookieManager().getCookie("csrftoken"));
assertEquals("alice:true:tokenHeaderIsSet=false", textPage.getContent());

webClient.getCookieManager().clearCookies();
}
}

@Test
public void testCsrfTokenWithFormRead() throws Exception {
try (final WebClient webClient = createWebClient()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ public void assertGeneratedResources() throws IOException {
assertThat(spec.getEndpoints()).hasSize(1);
assertThat(spec.getEndpoints().get(0)).isInstanceOfSatisfying(Endpoint.class, e -> {
assertThat(e.getScheme()).isEqualTo("http");
assertThat(e.getTargetPort().getStrVal()).isEqualTo("9090");
assertThat(e.getTargetPort().getStrVal()).isNull();
assertThat(e.getTargetPort().getIntVal()).isEqualTo(9090);
assertThat(e.getPath()).isEqualTo("/absolute-metrics");
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ public void assertGeneratedResources() throws IOException {
assertThat(spec.getEndpoints()).hasSize(1);
assertThat(spec.getEndpoints().get(0)).isInstanceOfSatisfying(Endpoint.class, e -> {
assertThat(e.getScheme()).isEqualTo("http");
assertThat(e.getTargetPort().getStrVal()).isEqualTo("9090");
assertThat(e.getTargetPort().getStrVal()).isNull();
assertThat(e.getTargetPort().getIntVal()).isEqualTo(9090);
assertThat(e.getPath()).isEqualTo("/q/met");
});
});
Expand Down
Loading

0 comments on commit 51f9792

Please sign in to comment.