Hii @tmortagne !
I created this thread to ask some specific questions and also to explain my approach regarding the project so that we are on the same page.
First of all, I should tell my plan for the UI, which may look something like this.
We will take the username of an existing XWiki user as input here and show him the same screen with some info on the screen like āNo credentials foundā if itās the first time on that browser when he clicks Authenticate.
When he now clicks Register, we will show him a message, something like a āCredentials added, now authenticate yourselfā on the same screen. When the user then, clicks Authenticate we will show him http://server/xwiki/bin/view/Main/
.
When the user clicks Skip WebAuthn, he will be shown the default form login. This is my proposal regarding the flow of events. Please tell if you disagree.
How should I go on implementing this type of UI? Using a velocity template?
Now, I will tell you about the URLs and the endpoints that will be used. When the user sets WebAuthn as an authenticator in xwiki.cfg
, and clicks login, the URL will change from http://server/xwiki/bin/view/Main/
to http://server/xwiki/webauthn
.
When the user clicks on Register, we will send a POST request to http://server/xwiki/webauthn/register
with form data(XWiki username). After this, we get a JSON response which looks somewhat like this:
{
"success":true,
"request":{
"username":"DamianArado",
"requestId":"ETJGtRenYaL7BHjPDau-0wsNYix2HaCGx4V68Kdg0ag",
"publicKeyCredentialCreationOptions": {
"rp": {
"name":"XWiki",
"id":"localhost"
},
"user": {
"name":"DamianArado",
"id":"1SeQVG9ieFoJrGeyqXFPklCX9GWMVE5BL-ohpkcMsSQ"},
"challenge":"OqxBgzUXiT5-IWASySdQSp74nnrK7eu0P0BKvgIm5z8",
"pubKeyCredParams":[{"alg":-7,"type":"public-key"},{"alg":-8,"type":"public-key"},{"alg":-257,"type":"public-key"}],
"excludeCredentials":[],
"authenticatorSelection":{"requireResidentKey":false,"userVerification":"preferred"},
"attestation":"direct","extensions":{}
}
}
After receiving the response from the client we construct a public-key credential from the response and send that to http://server/xwiki/webauthn/register/finish
which will return a RegistrationResult if successful and throw an exception if not. In case itās successful:
{
"success":true,
"request":{
"username":"DamianArado",
"requestId":"ETJGtRenYaL7BHjPDau-0wsNYix2HaCGx4V68Kdg0ag",
"publicKeyCredentialCreationOptions":{
"rp":{
"name":"XWiki",
"id":"localhost"
},
"user":{
"name":"DamianArado",
"id":"1SeQVG9ieFoJrGeyqXFPklCX9GWMVE5BL-ohpkcMsSQ"
},
"challenge":"OqxBgzUXiT5-IWASySdQSp74nnrK7eu0P0BKvgIm5z8",
"pubKeyCredParams":[{"alg":-7,"type":"public-key"},{"alg":-8,"type":"public-key"},{"alg":-257,"type":"public-key"}],
"excludeCredentials":[],
"authenticatorSelection":{"requireResidentKey":false,"userVerification":"preferred"},
"attestation":"direct","extensions":{}},
"sessionToken":"1FDDyvgBYWykyOQ8q-kYajrr9LBtWORB-3eiNfHcPWo"
},
"response":{
"requestId":"ETJGtRenYaL7BHjPDau-0wsNYix2HaCGx4V68Kdg0ag",
"credentialId":"z-doFbbAaYP-aGrnh_kM7ItNuIJdIGctivAXDfcHvmY"
}
Now, we will redirect the user to http://server/xwiki/webauthn
and the credentials will be stored as dedicated xobjects in the XWiki User Profile under XWiki.WebAuthn xclass.
When the user has WebAuthn credentials stored (in XWiki User Profile) and clicks on Authenticate, we send a POST request to http://server/xwiki/webauthn/authenticate
and get a JSON response like:
{
"success":true,
"request":{
"requestId":"Vy8nYDKf6wP8tSApt0RiCMtK1SMSZkeREjs0tS2Zk_M",
"publicKeyCredentialRequestOptions":{
"challenge":"L_I1b-bdlNhdd8nt3gvARNHgjYww29XQ_8QRmun2snE",
"rpId":"localhost",
"allowCredentials":[{
"type":"public-key",
"id":"z-doFbbAaYP-aGrnh_kM7ItNuIJdIGctivAXDfcHvmY"
}],
"userVerification":"preferred",
"extensions":{"appid":"https://localhost:8080"}},
"username":"DamianArado"
}
After this, we wrap it in an assertion request and send a POST request on http://server/xwiki/webauthn/authenticate/finish
which will return a response somewhat like:
{
"success":true,
"request":{
"requestId":"Vy8nYDKf6wP8tSApt0RiCMtK1SMSZkeREjs0tS2Zk_M",
"publicKeyCredentialRequestOptions":{
"challenge":"L_I1b-bdlNhdd8nt3gvARNHgjYww29XQ_8QRmun2snE",
"rpId":"localhost",
"allowCredentials":[{
"type":"public-key","id":"z-doFbbAaYP-aGrnh_kM7ItNuIJdIGctivAXDfcHvmY"
}],
"userVerification":"preferred",
"extensions":{
"appid":"https://localhost:8080"
}},
"username":"DamianArado"
},
"response":{
"requestId":"Vy8nYDKf6wP8tSApt0RiCMtK1SMSZkeREjs0tS2Zk_M",
"credential":{
"id":"z-doFbbAaYP-aGrnh_kM7ItNuIJdIGctivAXDfcHvmY",
"response":{
"authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFAAAAAQ",
"clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiTF9JMWItYmRsTmhkZDhudDNndkFSTkhnall3dzI5WFFfOFFSbXVuMnNuRSIsIm9yaWdpbiI6Imh0dHBzOi8vbG9jYWxob3N0Ojg0NDMiLCJjcm9zc09yaWdpbiI6ZmFsc2V9","signature":"cd2Aw-4lA2AmhyioHiR04l8_kjvu6SN5_EWWS-jEN7E-d-mOHqZSJDGehvd_SkspkSnQ5lg5k9TCoXTghkFbJkvmCqfXBGp3-HN2Yz2QsgBoCRwGVrg1q3bN_BUlJcSFP_ZFepAjZFW7Rs6w1Uyg9Sq4kpKhT-90by62MUZsKPq-mXDKIN4jtiKWOzirm68EOQmoURQv7N7IaTIpJvkTeib_f7HVkFwJLR34phLwMLArg4iIyElNpf2PWNb4Vxucjw1MkO7yNYoilpI9OrSKL62VymhnNuVrbtpXukpY5ZafuDjnLRiOQME9XKGRGLd14_Tu9QqVZX71AOQ4AyK18g",
"userHandle":"1SeQVG9ieFoJrGeyqXFPklCX9GWMVE5BL-ohpkcMsSQ"
},
"clientExtensionResults":{
"appid":false
},
"type":"public-key"
}},"registrations":[{
"signatureCount":1,
"userIdentity":{
"name":"DamianArado",
"id":"1SeQVG9ieFoJrGeyqXFPklCX9GWMVE5BL-ohpkcMsSQ"},
"credential":{
"credentialId":"z-doFbbAaYP-aGrnh_kM7ItNuIJdIGctivAXDfcHvmY",
"userHandle":"1SeQVG9ieFoJrGeyqXFPklCX9GWMVE5BL-ohpkcMsSQ",
"publicKeyCose":"pAM5AQABAyBZAQDC_4GE6sPOysEwHJyeWy6a1n3llh8lCu_RwPsGpLnQs_7IUrV1AuVAkDssa4wKJU1Lv9RHhOqL21t2QzahFP2fg-n5F0Www2pb6RgXKfs2gU1aOgAyuhG7bBiWo-aEKaMxbUWklEgRxi2k4SW1qiv2d37xFJGM2yb4Qy6E_Rzt7OOvMCFYFz5J1nqfWUWnGnMALHS9qW-KHXpxe27PxCj4H3KcsVnUZdIam0HBknvD9HntT2khm_0G7dZA1Ehpl_ZXYTHtylFzq5OImcL_HwAUaqzOX01KlFNE_OAYNrfbyE2jFH5vGp9V95TOZ1jIDFqeZq2Y4hFA72PPcj93K95_IUMBAAE","
signatureCount":1
},
"attestationMetadata":{
"trusted":true
},
"username":"DamianArado",
"registrationTime":"2021-08-09T21:33:08.483Z"
}
We will then redirect the user to http://server/xwiki/bin/view/Main/
.
Thomas, how should I handle these URLs? WDYT? You told me that " in practice you could also simply have if/else on the element which follow /webauthn/
in the URL.", but I canāt understand that.
And regarding the flow, please tell if I need to explain something moreā¦or if my approach is incorrect.
The requests and responses that I mentioned above are the constraints due to the library, so I will have to implement it accordingly.
Thanks in advance, for your time!