6770 |
09 Jun 22 |
nicklas |
'use strict'; |
6750 |
30 May 22 |
nicklas |
2 |
|
6750 |
30 May 22 |
nicklas |
var WebAuthnLogin = function() |
6750 |
30 May 22 |
nicklas |
4 |
{ |
6750 |
30 May 22 |
nicklas |
var wa = {}; |
6750 |
30 May 22 |
nicklas |
var debug = 1; |
6750 |
30 May 22 |
nicklas |
7 |
|
6750 |
30 May 22 |
nicklas |
wa.initPage = function() |
6750 |
30 May 22 |
nicklas |
9 |
{ |
6759 |
01 Jun 22 |
nicklas |
if (navigator.credentials && navigator.credentials.get) |
6759 |
01 Jun 22 |
nicklas |
11 |
{ |
6759 |
01 Jun 22 |
nicklas |
var frm = document.forms['login']; |
6759 |
01 Jun 22 |
nicklas |
Events.addEventHandler(frm, 'before-login', wa.startWebAuthnLogin); |
6759 |
01 Jun 22 |
nicklas |
14 |
} |
6759 |
01 Jun 22 |
nicklas |
else |
6759 |
01 Jun 22 |
nicklas |
16 |
{ |
6759 |
01 Jun 22 |
nicklas |
if (Doc.element('login-error').style.display == 'none') |
6759 |
01 Jun 22 |
nicklas |
18 |
{ |
6759 |
01 Jun 22 |
nicklas |
wa.handleError('WebAuthn Security Keys are not supported by this browser!'); |
6759 |
01 Jun 22 |
nicklas |
20 |
} |
6759 |
01 Jun 22 |
nicklas |
21 |
} |
6750 |
30 May 22 |
nicklas |
22 |
} |
6750 |
30 May 22 |
nicklas |
23 |
|
6750 |
30 May 22 |
nicklas |
wa.handleError = function(error) |
6750 |
30 May 22 |
nicklas |
25 |
{ |
6750 |
30 May 22 |
nicklas |
console.log(error); |
6750 |
30 May 22 |
nicklas |
Doc.element('login-error').innerHTML = Strings.encodeTags(error.toString ? error.toString() : error); |
6750 |
30 May 22 |
nicklas |
Doc.show('login-error'); |
6750 |
30 May 22 |
nicklas |
29 |
} |
6750 |
30 May 22 |
nicklas |
30 |
|
6750 |
30 May 22 |
nicklas |
// Step 1. Start the login process by sending the |
6750 |
30 May 22 |
nicklas |
// login name to the server. Since this is "async" we need to abort the |
6750 |
30 May 22 |
nicklas |
// submission of the login form. |
6750 |
30 May 22 |
nicklas |
wa.startWebAuthnLogin = function(event) |
6750 |
30 May 22 |
nicklas |
35 |
{ |
6750 |
30 May 22 |
nicklas |
event.preventDefault(); |
6750 |
30 May 22 |
nicklas |
var frm = document.forms['login']; |
6750 |
30 May 22 |
nicklas |
var home = Data.get(frm, 'home'); |
6788 |
05 Aug 22 |
nicklas |
var passwordLess = Data.int(frm, 'password-less'); |
6750 |
30 May 22 |
nicklas |
var url = home+'/WebAuthn.servlet?ID='+App.getSessionId(); |
6750 |
30 May 22 |
nicklas |
url += '&cmd=StartWebAuthnLogin'; |
6788 |
05 Aug 22 |
nicklas |
url += '&passwordLess='+(passwordLess?1:0); |
6750 |
30 May 22 |
nicklas |
43 |
|
6788 |
05 Aug 22 |
nicklas |
var submitData = {}; |
6788 |
05 Aug 22 |
nicklas |
if (!passwordLess) |
6788 |
05 Aug 22 |
nicklas |
46 |
{ |
6788 |
05 Aug 22 |
nicklas |
submitData.login = frm.login.value; |
6788 |
05 Aug 22 |
nicklas |
submitData.password = frm.password.value; |
6788 |
05 Aug 22 |
nicklas |
49 |
} |
6750 |
30 May 22 |
nicklas |
try |
6750 |
30 May 22 |
nicklas |
51 |
{ |
6750 |
30 May 22 |
nicklas |
if (debug) App.debug('AJAX request: '+url); |
6750 |
30 May 22 |
nicklas |
var request = Ajax.getXmlHttpRequest(); |
6769 |
09 Jun 22 |
nicklas |
request.open("POST", url, true); |
6750 |
30 May 22 |
nicklas |
Ajax.setReadyStateHandler(request, wa.webAuthnLoginRequestRecieved, wa.webAuthnLoginRequestRecieved); |
6769 |
09 Jun 22 |
nicklas |
request.setRequestHeader("Content-Type", "application/json; charset=UTF-8"); |
6788 |
05 Aug 22 |
nicklas |
request.send(JSON.stringify(submitData)); |
6750 |
30 May 22 |
nicklas |
58 |
} |
6750 |
30 May 22 |
nicklas |
catch (e) |
6750 |
30 May 22 |
nicklas |
60 |
{ |
6750 |
30 May 22 |
nicklas |
wa.handleError(e); |
6750 |
30 May 22 |
nicklas |
62 |
} |
6750 |
30 May 22 |
nicklas |
63 |
} |
6750 |
30 May 22 |
nicklas |
64 |
|
6750 |
30 May 22 |
nicklas |
// Step 2. Pass the response from the server to the |
6750 |
30 May 22 |
nicklas |
// navigator.credentials.get() API |
6750 |
30 May 22 |
nicklas |
wa.webAuthnLoginRequestRecieved = function(request) |
6750 |
30 May 22 |
nicklas |
68 |
{ |
6750 |
30 May 22 |
nicklas |
if (debug) App.debug(request.responseText); |
6750 |
30 May 22 |
nicklas |
try |
6750 |
30 May 22 |
nicklas |
71 |
{ |
6750 |
30 May 22 |
nicklas |
var response = JSON.parse(request.responseText); |
6750 |
30 May 22 |
nicklas |
if (debug) App.debug(response); |
6750 |
30 May 22 |
nicklas |
if (response.status != 'ok') |
6750 |
30 May 22 |
nicklas |
75 |
{ |
6750 |
30 May 22 |
nicklas |
throw new Error(response.message); |
6750 |
30 May 22 |
nicklas |
77 |
} |
6750 |
30 May 22 |
nicklas |
78 |
|
6750 |
30 May 22 |
nicklas |
var reg = response.assertionRequest.publicKey; |
6750 |
30 May 22 |
nicklas |
80 |
|
6750 |
30 May 22 |
nicklas |
var publicKey = { |
6750 |
30 May 22 |
nicklas |
'publicKey': { |
6750 |
30 May 22 |
nicklas |
'challenge': WAUtils.base64ToUint8Array(reg.challenge), |
6750 |
30 May 22 |
nicklas |
'allowCredentials': wa.convertAllowedCredentials(reg.allowCredentials), |
6788 |
05 Aug 22 |
nicklas |
'userVerification': reg.userVerification, |
6750 |
30 May 22 |
nicklas |
'rpId': reg.rpId |
6750 |
30 May 22 |
nicklas |
87 |
}}; |
6750 |
30 May 22 |
nicklas |
if (debug) App.debug(publicKey); |
6750 |
30 May 22 |
nicklas |
89 |
|
6750 |
30 May 22 |
nicklas |
navigator.credentials.get(publicKey) |
6750 |
30 May 22 |
nicklas |
.then(wa.webAuthnLoginResponseCreated) |
6750 |
30 May 22 |
nicklas |
.catch(wa.handleError); |
6750 |
30 May 22 |
nicklas |
93 |
} |
6750 |
30 May 22 |
nicklas |
catch (e) |
6750 |
30 May 22 |
nicklas |
95 |
{ |
6750 |
30 May 22 |
nicklas |
wa.handleError(e); |
6750 |
30 May 22 |
nicklas |
97 |
} |
6750 |
30 May 22 |
nicklas |
98 |
} |
6750 |
30 May 22 |
nicklas |
99 |
|
6750 |
30 May 22 |
nicklas |
wa.convertAllowedCredentials = function(cred) |
6750 |
30 May 22 |
nicklas |
101 |
{ |
6750 |
30 May 22 |
nicklas |
var converted = []; |
6788 |
05 Aug 22 |
nicklas |
if (cred) |
6750 |
30 May 22 |
nicklas |
104 |
{ |
6788 |
05 Aug 22 |
nicklas |
for (var i = 0; i < cred.length; i++) |
6788 |
05 Aug 22 |
nicklas |
106 |
{ |
6788 |
05 Aug 22 |
nicklas |
converted[i] = { |
6788 |
05 Aug 22 |
nicklas |
'id': WAUtils.base64ToUint8Array(cred[i].id), |
6788 |
05 Aug 22 |
nicklas |
'type': cred[i].type |
6788 |
05 Aug 22 |
nicklas |
110 |
} |
6750 |
30 May 22 |
nicklas |
111 |
} |
6750 |
30 May 22 |
nicklas |
112 |
} |
6750 |
30 May 22 |
nicklas |
return converted; |
6750 |
30 May 22 |
nicklas |
114 |
} |
6750 |
30 May 22 |
nicklas |
115 |
|
6752 |
30 May 22 |
nicklas |
// Step 3. Get the response from the security key and save it as JSON |
6752 |
30 May 22 |
nicklas |
// in the hidden 'extraField' and submit the login form |
6750 |
30 May 22 |
nicklas |
wa.webAuthnLoginResponseCreated = function(publicKey) |
6750 |
30 May 22 |
nicklas |
119 |
{ |
6752 |
30 May 22 |
nicklas |
try |
6750 |
30 May 22 |
nicklas |
121 |
{ |
6752 |
30 May 22 |
nicklas |
if (debug) |
6752 |
30 May 22 |
nicklas |
123 |
{ |
6752 |
30 May 22 |
nicklas |
App.debug(publicKey); |
6788 |
05 Aug 22 |
nicklas |
console.log('rawId: '+WAUtils.byteArrayToBase64(publicKey.rawId)); |
6788 |
05 Aug 22 |
nicklas |
console.log('authenticatorData: '+WAUtils.byteArrayToBase64(publicKey.response.authenticatorData)); |
6788 |
05 Aug 22 |
nicklas |
console.log('clientDataJSON: '+WAUtils.byteArrayToBase64(publicKey.response.clientDataJSON)); |
6788 |
05 Aug 22 |
nicklas |
console.log('signature: '+WAUtils.byteArrayToBase64(publicKey.response.signature)); |
6788 |
05 Aug 22 |
nicklas |
console.log('userHandle: '+WAUtils.byteArrayToBase64(publicKey.response.userHandle)); |
6752 |
30 May 22 |
nicklas |
130 |
} |
6752 |
30 May 22 |
nicklas |
131 |
|
6752 |
30 May 22 |
nicklas |
var response = { |
6752 |
30 May 22 |
nicklas |
id: publicKey.id, |
6752 |
30 May 22 |
nicklas |
response: |
6752 |
30 May 22 |
nicklas |
135 |
{ |
6752 |
30 May 22 |
nicklas |
authenticatorData: WAUtils.byteArrayToBase64(publicKey.response.authenticatorData), |
6752 |
30 May 22 |
nicklas |
clientDataJSON: WAUtils.byteArrayToBase64(publicKey.response.clientDataJSON), |
6788 |
05 Aug 22 |
nicklas |
signature: WAUtils.byteArrayToBase64(publicKey.response.signature), |
6788 |
05 Aug 22 |
nicklas |
userHandle: WAUtils.byteArrayToBase64(publicKey.response.userHandle) |
6752 |
30 May 22 |
nicklas |
140 |
}, |
6752 |
30 May 22 |
nicklas |
clientExtensionResults: {}, |
6752 |
30 May 22 |
nicklas |
type: 'public-key' |
6752 |
30 May 22 |
nicklas |
143 |
}; |
6752 |
30 May 22 |
nicklas |
144 |
|
6752 |
30 May 22 |
nicklas |
if (debug) App.debug(response); |
6752 |
30 May 22 |
nicklas |
146 |
|
6752 |
30 May 22 |
nicklas |
var frm = document.forms['login']; |
6752 |
30 May 22 |
nicklas |
if (frm.extraField) |
6752 |
30 May 22 |
nicklas |
149 |
{ |
6752 |
30 May 22 |
nicklas |
frm.extraField.value = JSON.stringify(response); |
6752 |
30 May 22 |
nicklas |
151 |
} |
6752 |
30 May 22 |
nicklas |
else |
6752 |
30 May 22 |
nicklas |
153 |
{ |
6752 |
30 May 22 |
nicklas |
Forms.addHidden(frm, 'extraField', JSON.stringify(response)); |
6752 |
30 May 22 |
nicklas |
155 |
} |
6752 |
30 May 22 |
nicklas |
Login.submitLoginForm(); |
6750 |
30 May 22 |
nicklas |
157 |
} |
6752 |
30 May 22 |
nicklas |
catch (e) |
6752 |
30 May 22 |
nicklas |
159 |
{ |
6752 |
30 May 22 |
nicklas |
wa.handleError(e); |
6752 |
30 May 22 |
nicklas |
161 |
} |
6750 |
30 May 22 |
nicklas |
162 |
} |
6750 |
30 May 22 |
nicklas |
163 |
|
6750 |
30 May 22 |
nicklas |
return wa; |
6750 |
30 May 22 |
nicklas |
165 |
}(); |
6750 |
30 May 22 |
nicklas |
166 |
|
6750 |
30 May 22 |
nicklas |
167 |
|
6750 |
30 May 22 |
nicklas |
Doc.onLoad(WebAuthnLogin.initPage); |
6750 |
30 May 22 |
nicklas |
169 |
|