From c5a921d590cd7e2a53960677732bad23107f98b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vav=C5=99=C3=ADk?= Date: Sat, 10 Sep 2022 23:14:20 +0200 Subject: [PATCH] Provide option to set Form based auth encrypted cookie as HttpOnly --- .../io/quarkus/security/webauthn/WebAuthnRecorder.java | 2 +- .../vertx/http/security/FormAuthCookiesTestCase.java | 4 +++- .../io/quarkus/vertx/http/runtime/FormAuthConfig.java | 6 ++++++ .../vertx/http/runtime/security/HttpSecurityRecorder.java | 2 +- .../http/runtime/security/PersistentLoginManager.java | 8 ++++++-- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java index 873028288fc59..ff44d478c63c8 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java @@ -69,7 +69,7 @@ public WebAuthnAuthenticationMechanism get() { WebAuthnRunTimeConfig config = WebAuthnRecorder.this.config.getValue(); PersistentLoginManager loginManager = new PersistentLoginManager(key, config.cookieName, config.sessionTimeout.toMillis(), - config.newCookieInterval.toMillis()); + config.newCookieInterval.toMillis(), false); String loginPage = config.loginPage.startsWith("/") ? config.loginPage : "/" + config.loginPage; return new WebAuthnAuthenticationMechanism(loginManager, loginPage); } diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/FormAuthCookiesTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/FormAuthCookiesTestCase.java index 99937ebaee9bd..c8dcde7d138df 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/FormAuthCookiesTestCase.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/FormAuthCookiesTestCase.java @@ -43,6 +43,7 @@ import io.quarkus.test.common.http.TestHTTPResource; import io.restassured.RestAssured; import io.restassured.filter.cookie.CookieFilter; +import io.restassured.matcher.RestAssuredMatchers; public class FormAuthCookiesTestCase { @@ -57,6 +58,7 @@ public class FormAuthCookiesTestCase { "quarkus.http.auth.form.timeout=PT2S\n" + "quarkus.http.auth.form.new-cookie-interval=PT1S\n" + "quarkus.http.auth.form.cookie-name=laitnederc-sukrauq\n" + + "quarkus.http.auth.form.http-only-cookie=true\n" + "quarkus.http.auth.session.encryption-key=CHANGEIT-CHANGEIT-CHANGEIT-CHANGEIT-CHANGEIT\n"; @RegisterExtension @@ -104,7 +106,7 @@ public void testFormBasedAuthSuccess() { .assertThat() .statusCode(302) .header("location", containsString("/admin%E2%9D%A4")) - .cookie("laitnederc-sukrauq", notNullValue()); + .cookie("laitnederc-sukrauq", RestAssuredMatchers.detailedCookie().value(notNullValue()).httpOnly(true)); RestAssured .given() diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/FormAuthConfig.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/FormAuthConfig.java index 328a81ac3966f..d7b396f06dbf0 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/FormAuthConfig.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/FormAuthConfig.java @@ -97,4 +97,10 @@ public class FormAuthConfig { */ @ConfigItem(defaultValue = "quarkus-credential") public String cookieName; + + /** + * Set the HttpOnly attribute to prevent access to the cookie via JavaScript. + */ + @ConfigItem(defaultValue = "false") + public boolean httpOnlyCookie; } diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityRecorder.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityRecorder.java index 48a55cba4d3de..c12a7bbfca269 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityRecorder.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityRecorder.java @@ -260,7 +260,7 @@ public FormAuthenticationMechanism get() { } FormAuthConfig form = buildTimeConfig.auth.form; PersistentLoginManager loginManager = new PersistentLoginManager(key, form.cookieName, form.timeout.toMillis(), - form.newCookieInterval.toMillis()); + form.newCookieInterval.toMillis(), form.httpOnlyCookie); String loginPage = form.loginPage.startsWith("/") ? form.loginPage : "/" + form.loginPage; String errorPage = form.errorPage.startsWith("/") ? form.errorPage : "/" + form.errorPage; String landingPage = form.landingPage.startsWith("/") ? form.landingPage : "/" + form.landingPage; diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PersistentLoginManager.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PersistentLoginManager.java index f52f4d7163d25..bb98e0b1d5ef3 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PersistentLoginManager.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PersistentLoginManager.java @@ -35,11 +35,14 @@ public class PersistentLoginManager { private final long timeoutMillis; private final SecureRandom secureRandom = new SecureRandom(); private final long newCookieIntervalMillis; + private final boolean httpOnlyCookie; - public PersistentLoginManager(String encryptionKey, String cookieName, long timeoutMillis, long newCookieIntervalMillis) { + public PersistentLoginManager(String encryptionKey, String cookieName, long timeoutMillis, long newCookieIntervalMillis, + boolean httpOnlyCookie) { this.cookieName = cookieName; this.newCookieIntervalMillis = newCookieIntervalMillis; this.timeoutMillis = timeoutMillis; + this.httpOnlyCookie = httpOnlyCookie; try { if (encryptionKey == null) { this.secretKey = KeyGenerator.getInstance("AES").generateKey(); @@ -131,7 +134,8 @@ public void save(String value, RoutingContext context, String cookieName, Restor message.put(iv); message.put(encrypted); String cookieValue = Base64.getEncoder().encodeToString(message.array()); - context.addCookie(Cookie.cookie(cookieName, cookieValue).setPath("/").setSecure(secureCookie)); + context.addCookie( + Cookie.cookie(cookieName, cookieValue).setPath("/").setSecure(secureCookie).setHttpOnly(httpOnlyCookie)); } catch (Exception e) { throw new RuntimeException(e); }