replace the index page

This commit is contained in:
Dusan Jakub
2023-09-27 12:12:52 +02:00
parent dedcf5115e
commit 9af3b6431b
4 changed files with 46 additions and 310 deletions

View File

@@ -0,0 +1,30 @@
package com.ysoft.geecon;
import io.quarkus.qute.CheckedTemplate;
import io.quarkus.qute.TemplateInstance;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/")
public class IndexResource {
@GET
@Produces(MediaType.TEXT_HTML)
public TemplateInstance index() {
return Templates.index();
}
@CheckedTemplate
public static class Templates {
public static native TemplateInstance index();
}
}

View File

@@ -1,56 +0,0 @@
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();
}
}

View File

@@ -1,254 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
<link href="favicon.ico" rel="icon" type="image/x-icon">
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" rel="stylesheet">
<!-- <link type="text/css" rel="stylesheet" href="css/style.css" />-->
<link href="https://fonts.googleapis.com" rel="preconnect"/>
<link crossorigin href="https://fonts.gstatic.com" rel="preconnect"/>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap"
rel="stylesheet"/>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script charset="UTF-8" src="/js/webauthn-debug.js" type="text/javascript"></script>
<style>
.code {
white-space: pre;
}
.step {
display: none;
}
</style>
</head>
<body>
<div class="container">
<input id="userName" placeholder="User name"/><br/>
<button class="nextBtn" id="login">Login</button>
<button class="nextBtn" id="register">Register</button>
</div>
<div class="container step" id="server1-request">
The interaction starts with an AJAX call.
<div class="code">POST <span id="server1-url"></span>
<div id="server1-call"></div>
</div>
<button class="nextBtn">Request challenge</button>
</div>
<div class="container step" id="server1-response">
The server prepares a challenge for the browser to sign.
<div class="code" id="server1-response-body"></div>
<button class="nextBtn">Continue</button>
</div>
<div class="container step" id="navigator-request">
The challenge is passed to the browser call:
<div class="code" id="navigator-call"></div>
<button class="nextBtn">Call Webauthn API</button>
</div>
<div class="container step" id="navigator-response">
Which responds:
<div class="code" id="navigator-response-body"></div>
The <strong>response.clientDataJSON</strong> are base64 encoded:
<div class="code" id="navigator-clientDataJSON"></div>
<button class="nextBtn">Finish the interaction</button>
</div>
</div>
<div id="result"></div>
<div id="trace"></div>
<form action="#" method="POST">
<input name="sessionId" type="hidden" value="somesessionid">
<div id="form-generated"></div>
</form>
<script type="text/javascript">
function tryDecodeBase64(str) {
try {
return atob(str);
} catch (e) {
return e + "";
}
}
function tracer(stage, params) {
console.log(stage, params)
switch (stage) {
case "register-request":
return traceRegisterRequest(params);
case "register-response":
return traceRegisterResponse(params);
case "credentials-create-request":
return traceCredentialsCreateRequest(params);
case "credentials-create-response":
return traceCredentialsCreateResponse(params);
case "login-request":
return traceLoginRequest(params);
case "login-response":
return traceLoginResponse(params);
case "credentials-get-request":
return traceCredentialsGetRequest(params);
case "credentials-get-response":
return traceCredentialsGetResponse(params);
default:
return traceGeneric(stage, params);
}
}
function continueButton(where, result) {
const button = $("button", $(where)).show();
if (button.length) {
return new Promise((resolve, reject) => {
button.click(() => {
resolve(result);
$(button).hide();
});
});
} else {
return Promise.resolve(result);
}
}
function traceRegisterRequest(params) {
$(".step").hide();
$("#server1-request").show();
$("#server1-url").html(params.url)
$("#server1-call").html(JSON.stringify(params.body, null, 2));
return continueButton("#server1-request", params);
}
function traceRegisterResponse(params) {
$("#server1-response").show();
$("#server1-response-body").html(JSON.stringify(params, null, 2));
return continueButton("#server1-response", params);
}
function traceLoginRequest(params) {
$(".step").hide();
$("#server1-request").show();
$("#server1-url").html(params.url)
$("#server1-call").html(JSON.stringify(params.body, null, 2));
return continueButton("#server1-request", params);
}
function traceLoginResponse(params) {
$("#server1-response").show();
$("#server1-response-body").html(JSON.stringify(params, null, 2));
return continueButton("#server1-response", params);
}
function traceCredentialsCreateRequest(challenge) {
$("#navigator-request").show();
$("#navigator-call").html("navigator.credentials.create({ publicKey: ... });");
return continueButton("#navigator-request", challenge);
}
function traceCredentialsCreateResponse(response) {
$("#navigator-response").show();
$("#navigator-response-body").html(JSON.stringify(response, null, 2));
$("#navigator-clientDataJSON").html(JSON.stringify(JSON.parse(tryDecodeBase64(response.response.clientDataJSON)), null, 2));
return continueButton("#navigator-response", response);
}
function traceCredentialsGetRequest(challenge) {
$("#navigator-request").show();
$("#navigator-call").html("navigator.credentials.get({ publicKey: ... });");
return continueButton("#navigator-request", challenge);
}
function traceCredentialsGetResponse(response) {
$("#navigator-response").show();
$("#navigator-response-body").html(JSON.stringify(response, null, 2));
$("#navigator-clientDataJSON").html(JSON.stringify(JSON.parse(tryDecodeBase64(response.response.clientDataJSON)), null, 2));
return continueButton("#navigator-response", response);
}
function traceGeneric(stage, params) {
const content = JSON.stringify(params);
const trace = $("<div class='container'></div>").attr("id", stage).html(content).appendTo("#trace");
return continueButton(trace, params);
}
function form(action, fields) {
const $form = $("form").attr("action", action);
const $fields = $("#form-generated", $form).empty()
for ([key, value] of Object.entries(fields)) {
console.log(key);
$("<input type='hidden'>").attr("name", key).val(value).appendTo($fields)
}
$form.submit();
}
const webAuthn = new WebAuthn({
callbackPath: '/q/webauthn/callback',
registerPath: '/q/webauthn/register',
loginPath: '/q/webauthn/login',
// loginCallbackPath: '/webauthn/login',
// registerCallbackPath: '/webauthn/register',
debuggingFunction: tracer
});
const result = document.getElementById('result');
const loginButton = document.getElementById('login');
loginButton.onclick = () => {
var userName = document.getElementById('userName').value;
result.replaceChildren();
webAuthn.loginOnly({name: userName})
.then(body => {
form("/webauthn/login", {
'webAuthnId': body.id,
'webAuthnRawId': body.rawId,
'webAuthnResponseClientDataJSON': body.response.clientDataJSON,
'webAuthnResponseAuthenticatorData': body.response.authenticatorData,
'webAuthnResponseSignature': body.response.signature,
'webAuthnResponseUserHandle': body.response.userHandle,
'webAuthnType': body.type
});
})
.catch(err => {
result.append("Login failed: " + err);
console.error(err);
});
return false;
};
const registerButton = document.getElementById('register');
registerButton.onclick = () => {
var userName = document.getElementById('userName').value;
// var firstName = document.getElementById('firstName').value;
// var lastName = document.getElementById('lastName').value;
result.replaceChildren();
webAuthn.registerOnly({name: userName, displayName: userName /*firstName + " " + lastName*/})
.then(body => {
form("/webauthn/register", {
'webAuthnId': body.id,
'webAuthnRawId': body.rawId,
'webAuthnResponseAttestationObject': body.response.attestationObject,
'webAuthnResponseClientDataJSON': body.response.clientDataJSON,
'webAuthnType': body.type
});
})
.catch(err => {
result.append("Registration failed: " + err);
console.error(err);
});
return false;
};
</script>
</body>
</html>

View File

@@ -0,0 +1,16 @@
{#include base}
{#title}Welcome{/title}
<div class="container">
<div class="row">
<div class="col s12 m6 offset-m3">
<div class="card">
<div class="card-content centered">
<span class="card-title center-align">Welcome</span>
<h6 style="margin: 50px 0;">Please start your journey at <a
href="https://oauth-playground.online">https://oauth-playground.online</a></h6>
</div>
</div>
</div>
</div>
</div>
{/include}