diff --git a/src/main/java/com/ysoft/geecon/webauthn/LoginResource.java b/src/main/java/com/ysoft/geecon/webauthn/LoginResource.java new file mode 100644 index 0000000..c60ce5b --- /dev/null +++ b/src/main/java/com/ysoft/geecon/webauthn/LoginResource.java @@ -0,0 +1,56 @@ +package com.ysoft.geecon.webauthn; + +import com.ysoft.geecon.repo.UsersRepo; +import io.quarkus.security.webauthn.WebAuthnLoginResponse; +import io.quarkus.security.webauthn.WebAuthnRegisterResponse; +import io.quarkus.security.webauthn.WebAuthnSecurity; +import io.vertx.ext.auth.webauthn.Authenticator; +import io.vertx.ext.web.RoutingContext; +import jakarta.inject.Inject; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; + +import java.net.URI; + +@Path("webauthn") +public class LoginResource { + + @Inject + WebAuthnSecurity webAuthnSecurity; + @Inject + UsersRepo usersRepo; + + @Path("/login") + @POST + public Response login(@BeanParam WebAuthnLoginResponse webAuthnResponse, + RoutingContext ctx) { + // Input validation + if (!webAuthnResponse.isSet() + || !webAuthnResponse.isValid()) { + return Response.status(Status.BAD_REQUEST).build(); + } + + Authenticator authenticator = this.webAuthnSecurity.login(webAuthnResponse, ctx) + .await().indefinitely(); + + return Response.seeOther(URI.create("/")).build(); + } + + @Path("/register") + @POST + public Response register(@BeanParam WebAuthnRegisterResponse webAuthnResponse, + RoutingContext ctx) { + // Input validation + if (!webAuthnResponse.isSet() || !webAuthnResponse.isValid()) { + return Response.status(Status.BAD_REQUEST).build(); + } + + Authenticator authenticator = this.webAuthnSecurity.register(webAuthnResponse, ctx) + .await().indefinitely(); + + return Response.seeOther(URI.create("/")).build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/ysoft/geecon/webauthn/MyWebAuthnSetup.java b/src/main/java/com/ysoft/geecon/webauthn/MyWebAuthnSetup.java index 1629f5b..d79ab4d 100644 --- a/src/main/java/com/ysoft/geecon/webauthn/MyWebAuthnSetup.java +++ b/src/main/java/com/ysoft/geecon/webauthn/MyWebAuthnSetup.java @@ -6,6 +6,7 @@ import io.quarkus.security.webauthn.WebAuthnUserProvider; import io.smallrye.mutiny.Uni; import io.vertx.ext.auth.webauthn.AttestationCertificates; import io.vertx.ext.auth.webauthn.Authenticator; +import io.vertx.ext.web.RoutingContext; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -13,9 +14,13 @@ import java.util.List; @ApplicationScoped public class MyWebAuthnSetup implements WebAuthnUserProvider { + public static final String AUTHORIZED_USER = MyWebAuthnSetup.class.getPackageName() + "#AUTHORIZED_USER"; @Inject UsersRepo usersRepo; + @Inject + RoutingContext routingContext; + private static List toAuthenticators(List dbs) { return dbs.stream().map(MyWebAuthnSetup::toAuthenticator).toList(); } @@ -69,6 +74,9 @@ public class MyWebAuthnSetup implements WebAuthnUserProvider { usersRepo.register(new User(authenticator.getUserName(), null, List.of(credential1))); return Uni.createFrom().nullItem(); } else { + if (routingContext.get(AUTHORIZED_USER) != null) { + return Uni.createFrom().nullItem(); + } // returning (or duplicate) user with new credential -> reject, // as we do not provide a means to register additional credentials yet return Uni.createFrom().failure(new Throwable("Duplicate user")); diff --git a/src/main/resources/META-INF/resources/index.html b/src/main/resources/META-INF/resources/index.html index 80b5bc0..936eb69 100644 --- a/src/main/resources/META-INF/resources/index.html +++ b/src/main/resources/META-INF/resources/index.html @@ -3,7 +3,7 @@ Login - +