webauthn-authenticate.ftl 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. <#import "template.ftl" as layout>
  2. <@layout.registrationLayout; section>
  3. <#if section = "title">
  4. title
  5. <#elseif section = "header">
  6. ${kcSanitize(msg("webauthn-login-title"))?no_esc}
  7. <#elseif section = "form">
  8. <form id="webauth" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
  9. <div class="${properties.kcFormGroupClass!}">
  10. <input type="hidden" id="clientDataJSON" name="clientDataJSON"/>
  11. <input type="hidden" id="authenticatorData" name="authenticatorData"/>
  12. <input type="hidden" id="signature" name="signature"/>
  13. <input type="hidden" id="credentialId" name="credentialId"/>
  14. <input type="hidden" id="userHandle" name="userHandle"/>
  15. <input type="hidden" id="error" name="error"/>
  16. </div>
  17. </form>
  18. <#if authenticators??>
  19. <form id="authn_select" class="${properties.kcFormClass!}">
  20. <#list authenticators.authenticators as authenticator>
  21. <input type="hidden" name="authn_use_chk" value="${authenticator.credentialId}"/>
  22. </#list>
  23. </form>
  24. </#if>
  25. <form class="${properties.kcFormClass!}">
  26. <div class="${properties.kcFormGroupClass!}">
  27. <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
  28. <input id="authenticateWebAuthnButton" type="button" onclick="webAuthnAuthenticate()" value="${kcSanitize(msg("webauthn-doAuthenticate"))}"
  29. class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}">
  30. </div>
  31. </div>
  32. </form>
  33. <script type="text/javascript" src="${url.resourcesCommonPath}/node_modules/jquery/dist/jquery.min.js"></script>
  34. <script type="text/javascript" src="${url.resourcesPath}/js/base64url.js"></script>
  35. <script type="text/javascript">
  36. function webAuthnAuthenticate() {
  37. let isUserIdentified = ${isUserIdentified};
  38. if (!isUserIdentified) {
  39. doAuthenticate([]);
  40. return;
  41. }
  42. checkAllowCredentials();
  43. }
  44. function checkAllowCredentials() {
  45. let allowCredentials = [];
  46. let authn_use = document.forms['authn_select'].authn_use_chk;
  47. if (authn_use !== undefined) {
  48. if (authn_use.length === undefined) {
  49. allowCredentials.push({
  50. id: base64url.decode(authn_use.value, {loose: true}),
  51. type: 'public-key',
  52. });
  53. } else {
  54. for (let i = 0; i < authn_use.length; i++) {
  55. allowCredentials.push({
  56. id: base64url.decode(authn_use[i].value, {loose: true}),
  57. type: 'public-key',
  58. });
  59. }
  60. }
  61. }
  62. doAuthenticate(allowCredentials);
  63. }
  64. function doAuthenticate(allowCredentials) {
  65. // Check if WebAuthn is supported by this browser
  66. if (!window.PublicKeyCredential) {
  67. $("#error").val("${msg("webauthn-unsupported-browser-text")?no_esc}");
  68. $("#webauth").submit();
  69. return;
  70. }
  71. let challenge = "${challenge}";
  72. let userVerification = "${userVerification}";
  73. let rpId = "${rpId}";
  74. let publicKey = {
  75. rpId : rpId,
  76. challenge: base64url.decode(challenge, { loose: true })
  77. };
  78. let createTimeout = ${createTimeout};
  79. if (createTimeout !== 0) publicKey.timeout = createTimeout * 1000;
  80. if (allowCredentials.length) {
  81. publicKey.allowCredentials = allowCredentials;
  82. }
  83. if (userVerification !== 'not specified') publicKey.userVerification = userVerification;
  84. navigator.credentials.get({publicKey})
  85. .then((result) => {
  86. window.result = result;
  87. let clientDataJSON = result.response.clientDataJSON;
  88. let authenticatorData = result.response.authenticatorData;
  89. let signature = result.response.signature;
  90. $("#clientDataJSON").val(base64url.encode(new Uint8Array(clientDataJSON), { pad: false }));
  91. $("#authenticatorData").val(base64url.encode(new Uint8Array(authenticatorData), { pad: false }));
  92. $("#signature").val(base64url.encode(new Uint8Array(signature), { pad: false }));
  93. $("#credentialId").val(result.id);
  94. if(result.response.userHandle) {
  95. $("#userHandle").val(base64url.encode(new Uint8Array(result.response.userHandle), { pad: false }));
  96. }
  97. $("#webauth").submit();
  98. })
  99. .catch((err) => {
  100. $("#error").val(err);
  101. $("#webauth").submit();
  102. })
  103. ;
  104. }
  105. </script>
  106. <#elseif section = "info">
  107. </#if>
  108. </@layout.registrationLayout>