diff --git a/extensions/security-webauthn/deployment/src/main/java/io/quarkus/security/webauthn/deployment/QuarkusSecurityWebAuthnProcessor.java b/extensions/security-webauthn/deployment/src/main/java/io/quarkus/security/webauthn/deployment/QuarkusSecurityWebAuthnProcessor.java index 64a531b612357..277fa595c6b5d 100644 --- a/extensions/security-webauthn/deployment/src/main/java/io/quarkus/security/webauthn/deployment/QuarkusSecurityWebAuthnProcessor.java +++ b/extensions/security-webauthn/deployment/src/main/java/io/quarkus/security/webauthn/deployment/QuarkusSecurityWebAuthnProcessor.java @@ -70,7 +70,7 @@ public static class IsEnabled implements BooleanSupplier { WebAuthnBuildTimeConfig config; public boolean getAsBoolean() { - return config.enabled; + return config.enabled(); } } diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnBuildTimeConfig.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnBuildTimeConfig.java index 9a7b8471a1c26..f5fe9557ecb5b 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnBuildTimeConfig.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnBuildTimeConfig.java @@ -1,14 +1,16 @@ package io.quarkus.security.webauthn; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; -@ConfigRoot(name = "webauthn") -public class WebAuthnBuildTimeConfig { +@ConfigRoot +@ConfigMapping(prefix = "quarkus.webauthn") +public interface WebAuthnBuildTimeConfig { /** * If the WebAuthn extension is enabled. */ - @ConfigItem(defaultValue = "true") - public boolean enabled; + @WithDefault("true") + boolean enabled(); } diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java index 01203d39ab610..23788400a772b 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java @@ -41,7 +41,7 @@ public class WebAuthnController { public WebAuthnController(WebAuthnSecurity security, WebAuthnRunTimeConfig config, IdentityProviderManager identityProviderManager, WebAuthnAuthenticationMechanism authMech) { - origin = config.origin.orElse(null); + origin = config.origin().orElse(null); if (origin != null) { Origin o = Origin.parse(origin); domain = o.host(); 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 d61bf70b3522c..19f3ee77e1487 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 @@ -67,11 +67,11 @@ public WebAuthnAuthenticationMechanism get() { key = httpConfiguration.getValue().encryptionKey.get(); } WebAuthnRunTimeConfig config = WebAuthnRecorder.this.config.getValue(); - PersistentLoginManager loginManager = new PersistentLoginManager(key, config.cookieName, - config.sessionTimeout.toMillis(), - config.newCookieInterval.toMillis(), false, config.cookieSameSite.name(), - config.cookiePath.orElse(null)); - String loginPage = config.loginPage.startsWith("/") ? config.loginPage : "/" + config.loginPage; + PersistentLoginManager loginManager = new PersistentLoginManager(key, config.cookieName(), + config.sessionTimeout().toMillis(), + config.newCookieInterval().toMillis(), false, config.cookieSameSite().name(), + config.cookiePath().orElse(null)); + String loginPage = config.loginPage().startsWith("/") ? config.loginPage() : "/" + config.loginPage(); return new WebAuthnAuthenticationMechanism(loginManager, loginPage); } }; diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRunTimeConfig.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRunTimeConfig.java index 54c2a9737e0ef..bba52cf08f4e8 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRunTimeConfig.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRunTimeConfig.java @@ -5,10 +5,12 @@ import java.util.Optional; import java.util.OptionalInt; +import io.quarkus.runtime.annotations.ConfigDocDefault; import io.quarkus.runtime.annotations.ConfigGroup; -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; import io.vertx.ext.auth.webauthn.Attestation; import io.vertx.ext.auth.webauthn.AuthenticatorAttachment; import io.vertx.ext.auth.webauthn.AuthenticatorTransport; @@ -18,13 +20,14 @@ /** * Webauthn runtime configuration object. */ -@ConfigRoot(name = "webauthn", phase = ConfigPhase.RUN_TIME) -public class WebAuthnRunTimeConfig { +@ConfigMapping(prefix = "quarkus.webauthn") +@ConfigRoot(phase = ConfigPhase.RUN_TIME) +public interface WebAuthnRunTimeConfig { /** * SameSite attribute values for the session cookie. */ - public enum CookieSameSite { + enum CookieSameSite { STRICT, LAX, NONE @@ -42,8 +45,7 @@ public enum CookieSameSite { * Please note that WebAuthn API will not work on pages loaded over HTTP, unless it is localhost, * which is considered secure context. */ - @ConfigItem - public Optional origin; + Optional origin(); /** * Authenticator Transports allowed by the application. Authenticators can interact with the user web browser @@ -62,15 +64,14 @@ public enum CookieSameSite { *
  • {@code INTERNAL} - Hardware security chips (e.g.: Intel TPM2.0)
  • * */ - @ConfigItem(defaultValueDocumentation = "USB,NFC,BLE,INTERNAL") - public Optional> transports; + @ConfigDocDefault("USB,NFC,BLE,INTERNAL") + Optional> transports(); /** * Your application is a relying party. In order for the user browser to correctly present you to the user, basic * information should be provided that will be presented during the user verification popup messages. */ - @ConfigItem - public RelyingPartyConfig relyingParty; + RelyingPartyConfig relyingParty(); /** * Kind of Authenticator Attachment allowed. Authenticators can connect to your device in two forms: @@ -83,15 +84,14 @@ public enum CookieSameSite { * For security reasons your application may choose to restrict to a specific attachment mode. If omitted, then * any mode is permitted. */ - @ConfigItem - public Optional authenticatorAttachment; + Optional authenticatorAttachment(); /** * Resident key required. A resident (private) key, is a key that cannot leave your authenticator device, this * means that you cannot reuse the authenticator to log into a second computer. */ - @ConfigItem(defaultValueDocumentation = "false") - public Optional requireResidentKey; + @ConfigDocDefault("false") + Optional requireResidentKey(); /** * User Verification requirements. Webauthn applications may choose {@code REQUIRED} verification to assert that @@ -104,16 +104,16 @@ public enum CookieSameSite { *
  • {@code DISCOURAGED} - User should avoid interact with the browser
  • * */ - @ConfigItem(defaultValueDocumentation = "REQUIRED") - public Optional userVerification; + @ConfigDocDefault("REQUIRED") + Optional userVerification(); /** * Non-negative User Verification timeout. Authentication must occur within the timeout, this will prevent the user * browser from being blocked with a pop-up required user verification, and the whole ceremony must be completed * within the timeout period. After the timeout, any previously issued challenge is automatically invalidated. */ - @ConfigItem(defaultValueDocumentation = "60s") - public Optional timeout; + @ConfigDocDefault("60s") + Optional timeout(); /** * Device Attestation Preference. During registration, applications may want to attest the device. Attestation is a @@ -133,8 +133,8 @@ public enum CookieSameSite { * unaltered. * */ - @ConfigItem(defaultValueDocumentation = "NONE") - public Optional attestation; + @ConfigDocDefault("NONE") + Optional attestation(); /** * Allowed Public Key Credential algorithms by preference order. Webauthn mandates that all authenticators must @@ -145,15 +145,15 @@ public enum CookieSameSite { * Note that the use of stronger algorithms, e.g.: {@code EdDSA} may require Java 15 or a cryptographic {@code JCE} * provider that implements the algorithms. */ - @ConfigItem(defaultValueDocumentation = "ES256,RS256") - public Optional> pubKeyCredParams; + @ConfigDocDefault("ES256,RS256") + Optional> pubKeyCredParams(); /** * Length of the challenges exchanged between the application and the browser. * Challenges must be at least 32 bytes. */ - @ConfigItem(defaultValueDocumentation = "64") - public OptionalInt challengeLength; + @ConfigDocDefault("64") + OptionalInt challengeLength(); /** * Extensions are optional JSON blobs that can be used during registration or authentication that can enhance the @@ -178,18 +178,17 @@ public enum CookieSameSite { //private List rootCrls; @ConfigGroup - public static class RelyingPartyConfig { + interface RelyingPartyConfig { /** * The id (or domain name of your server) */ - @ConfigItem - public Optional id; + Optional id(); /** * A user friendly name for your server */ - @ConfigItem(defaultValue = "Quarkus server") - public String name; + @WithDefault("Quarkus server") + String name(); } // FIXME: merge with form config? @@ -197,16 +196,16 @@ public static class RelyingPartyConfig { /** * The login page */ - @ConfigItem(defaultValue = "/login.html") - public String loginPage; + @WithDefault("/login.html") + String loginPage(); /** * The inactivity (idle) timeout * * When inactivity timeout is reached, cookie is not renewed and a new login is enforced. */ - @ConfigItem(defaultValue = "PT30M") - public Duration sessionTimeout; + @WithDefault("PT30M") + Duration sessionTimeout(); /** * How old a cookie can get before it will be replaced with a new cookie with an updated timeout, also @@ -223,24 +222,24 @@ public static class RelyingPartyConfig { * That is, no timeout is tracked on the server side; the timestamp is encoded and encrypted in the cookie * itself, and it is decrypted and parsed with each request. */ - @ConfigItem(defaultValue = "PT1M") - public Duration newCookieInterval; + @WithDefault("PT1M") + Duration newCookieInterval(); /** * The cookie that is used to store the persistent session */ - @ConfigItem(defaultValue = "quarkus-credential") - public String cookieName; + @WithDefault("quarkus-credential") + String cookieName(); /** * SameSite attribute for the session cookie. */ - @ConfigItem(defaultValue = "strict") - public CookieSameSite cookieSameSite = CookieSameSite.STRICT; + @WithDefault("strict") + CookieSameSite cookieSameSite(); /** * The cookie path for the session cookies. */ - @ConfigItem(defaultValue = "/") - public Optional cookiePath = Optional.of("/"); + @WithDefault("/") + Optional cookiePath(); } diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java index e76f5554e6a90..dfb5b7f67f0eb 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java @@ -36,41 +36,41 @@ public WebAuthnSecurity(WebAuthnRunTimeConfig config, Vertx vertx, WebAuthnAuthe // create the webauthn security object WebAuthnOptions options = new WebAuthnOptions(); RelyingParty relyingParty = new RelyingParty(); - if (config.relyingParty.id.isPresent()) { - relyingParty.setId(config.relyingParty.id.get()); + if (config.relyingParty().id().isPresent()) { + relyingParty.setId(config.relyingParty().id().get()); } // this is required - relyingParty.setName(config.relyingParty.name); + relyingParty.setName(config.relyingParty().name()); options.setRelyingParty(relyingParty); - if (config.attestation.isPresent()) { - options.setAttestation(config.attestation.get()); + if (config.attestation().isPresent()) { + options.setAttestation(config.attestation().get()); } - if (config.authenticatorAttachment.isPresent()) { - options.setAuthenticatorAttachment(config.authenticatorAttachment.get()); + if (config.authenticatorAttachment().isPresent()) { + options.setAuthenticatorAttachment(config.authenticatorAttachment().get()); } - if (config.challengeLength.isPresent()) { - options.setChallengeLength(config.challengeLength.getAsInt()); + if (config.challengeLength().isPresent()) { + options.setChallengeLength(config.challengeLength().getAsInt()); } - if (config.pubKeyCredParams.isPresent()) { - options.setPubKeyCredParams(config.pubKeyCredParams.get()); + if (config.pubKeyCredParams().isPresent()) { + options.setPubKeyCredParams(config.pubKeyCredParams().get()); } - if (config.requireResidentKey.isPresent()) { - options.setRequireResidentKey(config.requireResidentKey.get()); + if (config.requireResidentKey().isPresent()) { + options.setRequireResidentKey(config.requireResidentKey().get()); } - if (config.timeout.isPresent()) { - options.setTimeoutInMilliseconds(config.timeout.get().toMillis()); + if (config.timeout().isPresent()) { + options.setTimeoutInMilliseconds(config.timeout().get().toMillis()); } - if (config.transports.isPresent()) { - options.setTransports(config.transports.get()); + if (config.transports().isPresent()) { + options.setTransports(config.transports().get()); } - if (config.userVerification.isPresent()) { - options.setUserVerification(config.userVerification.get()); + if (config.userVerification().isPresent()) { + options.setUserVerification(config.userVerification().get()); } webAuthn = WebAuthn.create(vertx, options) // where to load/update authenticators data .authenticatorFetcher(database::fetcher) .authenticatorUpdater(database::updater); - origin = config.origin.orElse(null); + origin = config.origin().orElse(null); if (origin != null) { Origin o = Origin.parse(origin); domain = o.host();