[java-idp-plugin-webauthn] branch main updated: Cleanup webauthn-json JavaScript
Phil Smart
philip.smart at jisc.ac.uk
Mon Jan 22 12:57:42 UTC 2024
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch main
in repository java-idp-plugin-webauthn.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-webauthn.git;a=commit;h=5651b3e0941392cff441181192f1bbc84c167992
The following commit(s) were added to refs/heads/main by this push:
new 5651b3e Cleanup webauthn-json JavaScript
5651b3e is described below
commit 5651b3e0941392cff441181192f1bbc84c167992
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Mon Jan 22 12:57:39 2024 +0000
Cleanup webauthn-json JavaScript
- Cleanup views
- JS functions are supplied by @github/webauthn-json
---
.../authn/webauthn/conf/doc/webauthn-json-license | 7 +
...n-json.js => webauthn-json.browser-ponyfill.js} | 110 ++++++----
.../js/webauthn-json.browser-ponyfill.js.map | 7 +
.../plugin/authn/webauthn/js/webauthn-json.js.map | 7 -
.../plugin/authn/webauthn/js/webauthn-support.js | 16 --
.../plugin/authn/webauthn/js/webauthn-yubico.js | 171 ---------------
.../webauthn/views/webauthn-auth-old-backup.vm | 241 ---------------------
.../plugin/authn/webauthn/views/webauthn-authn.vm | 36 ++-
.../authn/webauthn/views/webauthn-register.vm | 17 +-
.../authn/webauthn/views/webauthn-registered.vm | 92 --------
.../webauthn/views/webauthn-username-entry.vm | 5 +-
11 files changed, 132 insertions(+), 577 deletions(-)
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/conf/doc/webauthn-json-license b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/conf/doc/webauthn-json-license
new file mode 100644
index 0000000..700c0ae
--- /dev/null
+++ b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/conf/doc/webauthn-json-license
@@ -0,0 +1,7 @@
+Copyright (c) 2019 GitHub, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-json.js b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-json.browser-ponyfill.js
similarity index 67%
rename from webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-json.js
rename to webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-json.browser-ponyfill.js
index d6ef38b..3ae6bd4 100644
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-json.js
+++ b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-json.browser-ponyfill.js
@@ -17,28 +17,31 @@ function bufferToBase64url(buffer) {
str += String.fromCharCode(charCode);
}
const base64String = btoa(str);
- const base64urlString = base64String.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
+ const base64urlString = base64String.replace(/\+/g, "-").replace(
+ /\//g,
+ "_"
+ ).replace(/=/g, "");
return base64urlString;
}
// src/webauthn-json/convert.ts
var copyValue = "copy";
var convertValue = "convert";
-function convert(conversionFn, schema2, input) {
- if (schema2 === copyValue) {
+function convert(conversionFn, schema, input) {
+ if (schema === copyValue) {
return input;
}
- if (schema2 === convertValue) {
+ if (schema === convertValue) {
return conversionFn(input);
}
- if (schema2 instanceof Array) {
- return input.map((v) => convert(conversionFn, schema2[0], v));
+ if (schema instanceof Array) {
+ return input.map((v) => convert(conversionFn, schema[0], v));
}
- if (schema2 instanceof Object) {
+ if (schema instanceof Object) {
const output = {};
- for (const [key, schemaField] of Object.entries(schema2)) {
- if (schemaField.deriveFn) {
- const v = schemaField.deriveFn(input);
+ for (const [key, schemaField] of Object.entries(schema)) {
+ if (schemaField.derive) {
+ const v = schemaField.derive(input);
if (v !== void 0) {
input[key] = v;
}
@@ -53,28 +56,32 @@ function convert(conversionFn, schema2, input) {
output[key] = null;
continue;
}
- output[key] = convert(conversionFn, schemaField.schema, input[key]);
+ output[key] = convert(
+ conversionFn,
+ schemaField.schema,
+ input[key]
+ );
}
return output;
}
}
-function derived(schema2, deriveFn) {
+function derived(schema, derive) {
return {
required: true,
- schema: schema2,
- deriveFn
+ schema,
+ derive
};
}
-function required(schema2) {
+function required(schema) {
return {
required: true,
- schema: schema2
+ schema
};
}
-function optional(schema2) {
+function optional(schema) {
return {
required: false,
- schema: schema2
+ schema
};
}
@@ -116,12 +123,22 @@ var publicKeyCredentialWithAttestation = {
type: required(copyValue),
id: required(copyValue),
rawId: required(convertValue),
+ authenticatorAttachment: optional(copyValue),
response: required({
clientDataJSON: required(convertValue),
attestationObject: required(convertValue),
- transports: derived(copyValue, (response) => response.getTransports?.() || [])
+ transports: derived(
+ copyValue,
+ (response) => {
+ var _a;
+ return ((_a = response.getTransports) == null ? void 0 : _a.call(response)) || [];
+ }
+ )
}),
- clientExtensionResults: derived(simplifiedClientExtensionResultsSchema, (pkc) => pkc.getClientExtensionResults())
+ clientExtensionResults: derived(
+ simplifiedClientExtensionResultsSchema,
+ (pkc) => pkc.getClientExtensionResults()
+ )
};
var credentialRequestOptions = {
mediation: optional(copyValue),
@@ -139,19 +156,17 @@ var publicKeyCredentialWithAssertion = {
type: required(copyValue),
id: required(copyValue),
rawId: required(convertValue),
+ authenticatorAttachment: optional(copyValue),
response: required({
clientDataJSON: required(convertValue),
authenticatorData: required(convertValue),
signature: required(convertValue),
userHandle: required(convertValue)
}),
- clientExtensionResults: derived(simplifiedClientExtensionResultsSchema, (pkc) => pkc.getClientExtensionResults())
-};
-var schema = {
- credentialCreationOptions,
- publicKeyCredentialWithAttestation,
- credentialRequestOptions,
- publicKeyCredentialWithAssertion
+ clientExtensionResults: derived(
+ simplifiedClientExtensionResultsSchema,
+ (pkc) => pkc.getClientExtensionResults()
+ )
};
// src/webauthn-json/basic/api.ts
@@ -159,31 +174,48 @@ function createRequestFromJSON(requestJSON) {
return convert(base64urlToBuffer, credentialCreationOptions, requestJSON);
}
function createResponseToJSON(credential) {
- return convert(bufferToBase64url, publicKeyCredentialWithAttestation, credential);
-}
-async function create(requestJSON) {
- const credential = await navigator.credentials.create(createRequestFromJSON(requestJSON));
- return createResponseToJSON(credential);
+ return convert(
+ bufferToBase64url,
+ publicKeyCredentialWithAttestation,
+ credential
+ );
}
function getRequestFromJSON(requestJSON) {
return convert(base64urlToBuffer, credentialRequestOptions, requestJSON);
}
function getResponseToJSON(credential) {
- return convert(bufferToBase64url, publicKeyCredentialWithAssertion, credential);
-}
-async function get(requestJSON) {
- const credential = await navigator.credentials.get(getRequestFromJSON(requestJSON));
- return getResponseToJSON(credential);
+ return convert(
+ bufferToBase64url,
+ publicKeyCredentialWithAssertion,
+ credential
+ );
}
// src/webauthn-json/basic/supported.ts
function supported() {
return !!(navigator.credentials && navigator.credentials.create && navigator.credentials.get && window.PublicKeyCredential);
}
+
+// src/webauthn-json/browser-ponyfill.ts
+async function create(options) {
+ const response = await navigator.credentials.create(
+ options
+ );
+ response.toJSON = () => createResponseToJSON(response);
+ return response;
+}
+async function get(options) {
+ const response = await navigator.credentials.get(
+ options
+ );
+ response.toJSON = () => getResponseToJSON(response);
+ return response;
+}
export {
create,
get,
- schema,
+ createRequestFromJSON as parseCreationOptionsFromJSON,
+ getRequestFromJSON as parseRequestOptionsFromJSON,
supported
};
-//# sourceMappingURL=webauthn-json.js.map
+//# sourceMappingURL=webauthn-json.browser-ponyfill.js.map
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-json.browser-ponyfill.js.map b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-json.browser-ponyfill.js.map
new file mode 100644
index 0000000..3ab30b5
--- /dev/null
+++ b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-json.browser-ponyfill.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/webauthn-json/base64url.ts", "../../src/webauthn-json/convert.ts", "../../src/webauthn-json/basic/schema.ts", "../../src/webauthn-json/basic/api.ts", "../../src/webauthn-json/basic/supported.ts", "../../src/webauthn-json/browser-ponyfill.ts"],
+ "sourcesContent": ["export type Base64urlString = string;\n\nexport function base64urlToBuffer(\n baseurl64String: Base64urlString,\n): ArrayBuffer {\n // Base64url to Base64\n const padding = \"==\".slice(0, (4 - (baseurl64String.length % 4)) % 4);\n const base64String =\n baseurl64String.replace(/-/g, \"+\").replace(/_/g, \"/\") + padding;\n\n // Base64 to binary string\n const str = atob(base64String);\n\n // Binary string to buffer\n const buffer = new ArrayBuffer(str.le [...]
+ "mappings": ";AAEO,SAAS,kBACd,iBACa;AAEb,QAAM,UAAU,KAAK,MAAM,IAAI,IAAK,gBAAgB,SAAS,KAAM,CAAC;AACpE,QAAM,eACJ,gBAAgB,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG,IAAI;AAG1D,QAAM,MAAM,KAAK,YAAY;AAG7B,QAAM,SAAS,IAAI,YAAY,IAAI,MAAM;AACzC,QAAM,WAAW,IAAI,WAAW,MAAM;AACtC,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,aAAS,KAAK,IAAI,WAAW,CAAC;AAAA,EAChC;AACA,SAAO;AACT;AAEO,SAAS,kBAAkB,QAAsC;AAEtE,QAAM,WAAW,IAAI,WAAW,MAAM;AACtC,MAAI,MAAM;AACV,aAAW,YAAY,UAAU;AAC/B,WAAO,OAAO,aAAa,QAAQ;AAAA,EACrC;AAGA,QAAM,eAAe,K [...]
+ "names": []
+}
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-json.js.map b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-json.js.map
deleted file mode 100644
index 9d6aa22..0000000
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-json.js.map
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "version": 3,
- "sources": ["../../src/webauthn-json/base64url.ts", "../../src/webauthn-json/convert.ts", "../../src/webauthn-json/basic/schema.ts", "../../src/webauthn-json/basic/api.ts", "../../src/webauthn-json/basic/supported.ts"],
- "sourcesContent": ["export type Base64urlString = string;\n\nexport function base64urlToBuffer(\n baseurl64String: Base64urlString,\n): ArrayBuffer {\n // Base64url to Base64\n const padding = \"==\".slice(0, (4 - (baseurl64String.length % 4)) % 4);\n const base64String =\n baseurl64String.replace(/-/g, \"+\").replace(/_/g, \"/\") + padding;\n\n // Base64 to binary string\n const str = atob(base64String);\n\n // Binary string to buffer\n const buffer = new ArrayBuffer(str.le [...]
- "mappings": ";AAEO,2BACL,iBACa;AAEb,QAAM,UAAU,KAAK,MAAM,GAAI,KAAK,gBAAgB,SAAS,KAAM;AACnE,QAAM,eACJ,gBAAgB,QAAQ,MAAM,KAAK,QAAQ,MAAM,OAAO;AAG1D,QAAM,MAAM,KAAK;AAGjB,QAAM,SAAS,IAAI,YAAY,IAAI;AACnC,QAAM,WAAW,IAAI,WAAW;AAChC,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,aAAS,KAAK,IAAI,WAAW;AAAA;AAE/B,SAAO;AAAA;AAGF,2BAA2B,QAAsC;AAEtE,QAAM,WAAW,IAAI,WAAW;AAChC,MAAI,MAAM;AACV,aAAW,YAAY,UAAU;AAC/B,WAAO,OAAO,aAAa;AAAA;AAI7B,QAAM,eAAe,KAAK;AAI1B,QAAM,kBAAkB,aACrB,QAAQ,OAAO,KACf,QAAQ,OAAO,KACf,QAAQ,MA [...]
- "names": []
-}
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-support.js b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-support.js
deleted file mode 100644
index 006d9c9..0000000
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-support.js
+++ /dev/null
@@ -1,16 +0,0 @@
-document.addEventListener('DOMContentLoaded', function() {
- var coll = document.getElementsByClassName("collapsible");
- var i;
-
- for (i = 0; i < coll.length; i++) {
- coll[i].addEventListener("click", function() {
- this.classList.toggle("active");
- var content = this.nextElementSibling;
- if (content.style.display === "block") {
- content.style.display = "none";
- } else {
- content.style.display = "block";
- }
- });
- }
-});
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-yubico.js b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-yubico.js
deleted file mode 100644
index 2cf5335..0000000
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/js/webauthn-yubico.js
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright (c) 2018, Yubico AB
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-// list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-(function(root, factory) {
- if (typeof define === 'function' && define.amd) {
- define(['base64url'], factory);
- } else if (typeof module === 'object' && module.exports) {
- module.exports = factory(require('base64url'));
- } else {
- root.webauthn = factory(root.base64url);
- }
-})(this, function(base64url) {
-
- function extend(obj, more) {
- return Object.assign({}, obj, more);
- }
-
- /**
- * Create a WebAuthn credential.
- *
- * @param request: object - A PublicKeyCredentialCreationOptions object, except
- * where binary values are base64url encoded strings instead of byte arrays
- *
- * @return a PublicKeyCredentialCreationOptions suitable for passing as the
- * `publicKey` parameter to `navigator.credentials.create()`
- */
- function decodePublicKeyCredentialCreationOptions(request) {
- const excludeCredentials = request.excludeCredentials.map(credential => extend(
- credential, {
- id: base64url.toByteArray(credential.id),
- }));
-
- const publicKeyCredentialCreationOptions = extend(
- request, {
- attestation: 'direct',
- user: extend(
- request.user, {
- id: base64url.toByteArray(request.user.id),
- }),
- challenge: base64url.toByteArray(request.challenge),
- excludeCredentials,
- });
-
- return publicKeyCredentialCreationOptions;
- }
-
- /**
- * Create a WebAuthn credential.
- *
- * @param request: object - A PublicKeyCredentialCreationOptions object, except
- * where binary values are base64url encoded strings instead of byte arrays
- *
- * @return the Promise returned by `navigator.credentials.create`
- */
- function createCredential(request) {
- return navigator.credentials.create({
- publicKey: decodePublicKeyCredentialCreationOptions(request),
- });
- }
-
- /**
- * Perform a WebAuthn assertion.
- *
- * @param request: object - A PublicKeyCredentialRequestOptions object,
- * except where binary values are base64url encoded strings instead of byte
- * arrays
- *
- * @return a PublicKeyCredentialRequestOptions suitable for passing as the
- * `publicKey` parameter to `navigator.credentials.get()`
- */
- function decodePublicKeyCredentialRequestOptions(request) {
- const allowCredentials = request.allowCredentials && request.allowCredentials.map(credential => extend(
- credential, {
- id: base64url.toByteArray(credential.id),
- }));
-
- const publicKeyCredentialRequestOptions = extend(
- request, {
- allowCredentials,
- challenge: base64url.toByteArray(request.challenge),
- });
-
- return publicKeyCredentialRequestOptions;
- }
-
- /**
- * Perform a WebAuthn assertion.
- *
- * @param request: object - A PublicKeyCredentialRequestOptions object,
- * except where binary values are base64url encoded strings instead of byte
- * arrays
- *
- * @return the Promise returned by `navigator.credentials.get`
- */
- function getAssertion(request) {
- console.log('Get assertion', request);
- return navigator.credentials.get({
- publicKey: decodePublicKeyCredentialRequestOptions(request),
- });
- }
-
-
- /** Turn a PublicKeyCredential object into a plain object with base64url encoded binary values */
- function responseToObject(response) {
- if (response.u2fResponse) {
- return response;
- } else {
- let clientExtensionResults = {};
-
- try {
- clientExtensionResults = response.getClientExtensionResults();
- } catch (e) {
- console.error('getClientExtensionResults failed', e);
- }
-
- if (response.response.attestationObject) {
- return {
- type: response.type,
- id: response.id,
- response: {
- attestationObject: bytesToBase64(response.response.attestationObject),
- clientDataJSON: bytesToBase64(response.response.clientDataJSON),
- },
- clientExtensionResults,
- };
- } else {
- return {
- type: response.type,
- id: response.id,
- response: {
- authenticatorData: base64url.fromByteArray(response.response.authenticatorData),
- clientDataJSON: base64url.fromByteArray(response.response.clientDataJSON),
- signature: base64url.fromByteArray(response.response.signature),
- userHandle: response.response.userHandle && base64url.fromByteArray(response.response.userHandle),
- },
- clientExtensionResults,
- };
- }
- }
- }
-
- return {
- decodePublicKeyCredentialCreationOptions,
- decodePublicKeyCredentialRequestOptions,
- createCredential,
- getAssertion,
- responseToObject,
- };
-
-});
\ No newline at end of file
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-auth-old-backup.vm b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-auth-old-backup.vm
deleted file mode 100644
index 81212ad..0000000
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-auth-old-backup.vm
+++ /dev/null
@@ -1,241 +0,0 @@
-##
-## Velocity Template for DisplayWebauthnView view-state
-##
-## Velocity context will contain the following properties
-## flowExecutionUrl - the form action location
-## flowRequestContext - the Spring Web Flow RequestContext
-## flowExecutionKey - the SWF execution key (this is built into the flowExecutionUrl)
-## profileRequestContext - root of context tree
-## authenticationContext - context with authentication request information
-## authenticationErrorContext - context with login error state
-## webauthnContext = web authentication context
-## authenticationWarningContext - context with login warning state
-## rpUIContext - the context with SP UI information from the metadata
-## encoder - HTMLEncoder class
-## request - HttpServletRequest
-## response - HttpServletResponse
-## environment - Spring Environment object for property resolution
-## custom - arbitrary object injected by deployer
-##
-#set ($rpContext = $profileRequestContext.getSubcontext('net.shibboleth.idp.profile.context.RelyingPartyContext'))
-##
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width,initial-scale=1.0">
- <title>#springMessageText("idp.title", "Web Login Service")</title>
- <link rel="stylesheet" type="text/css" href="$request.getContextPath()/css/main.css">
-
-
- </head>
-
- <!-- FIXME Externalise this-->
- <script>
-
-
- const base64abc = [
- "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
- "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
- "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
- "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
- "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"
- ];
-
-
- const base64codes = [
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0, 255, 255,
- 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
- 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
- ];
-
- function bytesToBase64(bytes) {
- let result = '', i, l = bytes.length;
- for (i = 2; i < l; i += 3) {
- result += base64abc[bytes[i - 2] >> 2];
- result += base64abc[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)];
- result += base64abc[((bytes[i - 1] & 0x0F) << 2) | (bytes[i] >> 6)];
- result += base64abc[bytes[i] & 0x3F];
- }
- if (i === l + 1) { // 1 octet yet to write
- result += base64abc[bytes[i - 2] >> 2];
- result += base64abc[(bytes[i - 2] & 0x03) << 4];
- result += "==";
- }
- if (i === l) { // 2 octets yet to write
- result += base64abc[bytes[i - 2] >> 2];
- result += base64abc[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)];
- result += base64abc[(bytes[i - 1] & 0x0F) << 2];
- result += "=";
- }
- return result;
- }
-
- function responseToObject(response) {
- if (response.u2fResponse) {
- return response;
- } else {
- let clientExtensionResults = {};
-
- try {
- clientExtensionResults = response.getClientExtensionResults();
- } catch (e) {
- console.error('getClientExtensionResults failed', e);
- }
-
- if (response.response.attestationObject) {
- return {
- type: response.type,
- id: response.id,
- response: {
- attestationObject: Base64EncodeUrl(bytesToBase64(ensureUint8Array(response.response.attestationObject))),
- clientDataJSON: Base64EncodeUrl(bytesToBase64(ensureUint8Array(response.response.clientDataJSON))),
- },
- clientExtensionResults,
- };
- } else {
- return {
- type: response.type,
- id: response.id,
- response: {
- authenticatorData: Base64EncodeUrl(bytesToBase64(ensureUint8Array(response.response.authenticatorData))),
- clientDataJSON: Base64EncodeUrl(bytesToBase64(ensureUint8Array(response.response.clientDataJSON))),
- signature: Base64EncodeUrl(bytesToBase64(ensureUint8Array(response.response.signature))),
- userHandle: response.response.userHandle && Base64EncodeUrl(bytesToBase64(ensureUint8Array(response.response.userHandle))),
- },
- clientExtensionResults,
- };
- }
- }
- }
-
- if (!window.PublicKeyCredential){
- console.log("Bad client, died");
- }
-
- function ensureUint8Array(arg) {
- if (arg instanceof ArrayBuffer) {
- return new Uint8Array(arg);
- } else {
- return arg;
- }
- }
- /**
- * use this to make a Base64 encoded string URL friendly,
- * i.e. '+' and '/' are replaced with '-' and '_' also any trailing '='
- * characters are removed
- *
- * @param {String} str the encoded string
- * @returns {String} the URL friendly encoded String
- */
- function Base64EncodeUrl(str){
- return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
- }
-
- const publicKeyCredentialCreationOptions = {
- challenge: Uint8Array.from(
- "$webauthnContext.serverChallengeBase64", c => c.charCodeAt(0)),
- rp: {
- name: "Shib",
- id: "localhost",
- },
- user: {
- id: Uint8Array.from(
- "UZSL85T9AFC", c => c.charCodeAt(0)),
- name: "phil1001 at jisc.ac.uk",
- displayName: "Phil",
- },
- pubKeyCredParams: [{alg: -7, type: "public-key"}],
- authenticatorSelection: {
- authenticatorAttachment: "cross-platform",
- userVerification: "preferred"
- },
- timeout: 60000,
- attestation: "direct"
- };
-
-
- async function register() {
- const credential = await navigator.credentials.create({
- publicKey: publicKeyCredentialCreationOptions
- }).catch(console.error);
-
- console.log("Credential: "+credential);
- console.log(responseToObject(credential));
- console.log(JSON.stringify(credential.response));
- try{
- document.getElementById("publicKeyCredential").value = JSON.stringify(responseToObject(credential));
-
- } catch (err) {
- console.log(err);
- }
-
- }
-
- async function authenticate() {
- try{
- console.log("authenticating");
- const assertion = await navigator.credentials.get({
- publicKey: {
- challenge: Uint8Array.from(
- "$webauthnContext.serverChallengeBase64", c => c.charCodeAt(0)),
- allowCredentials: [{
- id: new Uint8Array($webauthnContext.existingCredentialId),
- type: 'public-key',
- transports: ['usb', 'ble', 'nfc'],
- }],
- timeout: 60000,
- }
- });
- console.log(assertion);
- document.getElementById("publicKeyAssertion").value = JSON.stringify(responseToObject(assertion));
- document.getElementById("authn-submit").click();
- } catch (err) {
- console.log(err);
- }
-
-
-
- }
-
- </script>
-
- <body>
- <div class="wrapper">
- <div class="container">
- <header>
- <img src="$request.getContextPath()#springMessage("idp.logo")" alt="#springMessageText("idp.logo.alt-text", "logo")">
- </header>
-
- <div class="content">
- <div class="column one">
-
-
-
- <button class="form-element form-button" onclick="authenticate();">Authenticate</button>
- <form id="authn-form" action="$flowExecutionUrl" method="post">
- #parse("csrf/csrf.vm")
- <textarea id="publicKeyAssertion" name="publicKeyAssertion" rows="10" cols="50">
- </textarea>
- <button id="authn-submit" class="form-element form-button" type="submit" name="_eventId_authenticate">Submit Authenticate</button>
- </form>
-
-
- </div>
-
- </div>
-
- <footer>
- <div class="container container-footer">
- <p class="footer-text">#springMessageText("idp.footer", "Insert your footer text here.")</p>
- </div>
- </footer>
- </div>
-
- </body>
-</html>
\ No newline at end of file
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-authn.vm b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-authn.vm
index 5ccd4b3..90cb141 100644
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-authn.vm
+++ b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-authn.vm
@@ -31,13 +31,22 @@
<script type="text/javascript" src="$request.getContextPath()/js/webauthn-support.js"></script>
<link rel="stylesheet" type="text/css" href="$request.getContextPath()#springMessageText(" idp.css", "/css/placeholder.css" )">
<link rel="stylesheet" type="text/css" href="$request.getContextPath()/css/webauthn.css">
- <script type="module">
- import * as webauthnJson from "$request.getContextPath()/js/webauthn-json.js";
+ <script type="module">
+
+ import {
+ get,
+ parseRequestOptionsFromJSON,
+ supported,
+ } from "$request.getContextPath()/js/webauthn/webauthn-json.browser-ponyfill.js";
async function authenticate() {
var pkCredRequestOptions = $webauthnContext.publicKeyCredentialRequestOptionsJSON;
- console.log("Raw request options", pkCredRequestOptions);
- await webauthnJson.get({ publicKey: pkCredRequestOptions })
+ var parsedRequestOptions = parseRequestOptionsFromJSON({ publicKey: pkCredRequestOptions });
+ #if($debug == "true")
+ console.log("Raw request options", pkCredRequestOptions);
+ console.log("Parsed request options", parsedRequestOptions);
+ #end
+ await get(parsedRequestOptions)
.then(function (assertion){
document.getElementById("publicKeyAssertion").value = JSON.stringify(assertion);
document.getElementById("authenticationSubmit").click();
@@ -70,6 +79,25 @@
</header>
<section>
+ #*
+ //
+ // SP Description & Logo (optional)
+ // These idpui lines will display added information (if available
+ // in the metadata) about the Service Provider (SP) that requested
+ // authentication. These idpui lines are "active" in this example
+ // (not commented out) - this extra SP info will be displayed.
+ // Remove or comment out these lines to stop the display of the
+ // added SP information.
+ //
+ *#
+ #set ($logo = $rpUIContext.getLogo())
+ #if ($logo)
+ <img class="service-logo" src= "$encoder.encodeForHTMLAttribute($logo)" alt="$encoder.encodeForHTMLAttribute($serviceName)">
+ #end
+ #set ($desc = $rpUIContext.getServiceDescription())
+ #if ($desc)
+ <p>$encoder.encodeForHTML($desc)</p>
+ #end
<div class="content">
<div class="column one">
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-register.vm b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-register.vm
index 093890e..98d7822 100644
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-register.vm
+++ b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-register.vm
@@ -32,13 +32,22 @@
<link rel="stylesheet" type="text/css" href="$request.getContextPath()#springMessageText("idp.css", "/css/placeholder.css" )">
<link rel="stylesheet" type="text/css" href="$request.getContextPath()/css/webauthn.css">
<script type="module">
- import * as webauthnJson from "$request.getContextPath()/js/webauthn-json.js";
+
+ import {
+ parseCreationOptionsFromJSON,
+ create,
+ supported,
+ } from "$request.getContextPath()/js/webauthn/webauthn-json.browser-ponyfill.js";
async function register() {
- var pkCredOptions = $webauthnRegContext.publicKeyCredentialCreationOptionsJSON;
- await webauthnJson.create({ publicKey: pkCredOptions })
+ var pkCredOptions = $webauthnRegContext.publicKeyCredentialCreationOptionsJSON;
+ var pkCredOptionsParsed = parseCreationOptionsFromJSON({ publicKey: pkCredOptions });
+ #if($debug == "true")
+ console.log("Raw creation options", pkCredOptions);
+ console.log("Parsed creation options", pkCredOptionsParsed);
+ #end
+ await create(pkCredOptionsParsed)
.then(function (attestation){
- console.log("attestation: ",attestation);
var nickname = prompt("Credential Nickname");
document.getElementById("credentialNickname").value = nickname;
document.getElementById("authenticatorAttestation").value = JSON.stringify(attestation);
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-registered.vm b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-registered.vm
deleted file mode 100644
index 8a3633a..0000000
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-registered.vm
+++ /dev/null
@@ -1,92 +0,0 @@
-##
-## Velocity Template for DisplayWebauthnView view-state
-##
-## Velocity context will contain the following properties
-## flowExecutionUrl - the form action location
-## flowRequestContext - the Spring Web Flow RequestContext
-## flowExecutionKey - the SWF execution key (this is built into the flowExecutionUrl)
-## profileRequestContext - root of context tree
-## authenticationContext - context with authentication request information
-## authenticationErrorContext - context with login error state
-## webauthnRegContext = WebAuthn registration context
-## authenticationWarningContext - context with login warning state
-## rpUIContext - the context with SP UI information from the metadata
-## encoder - HTMLEncoder class
-## request - HttpServletRequest
-## response - HttpServletResponse
-## environment - Spring Environment object for property resolution
-## custom - arbitrary object injected by deployer
-##
-#set ($rpContext = $profileRequestContext.getSubcontext('net.shibboleth.idp.profile.context.RelyingPartyContext'))
-##
-<!DOCTYPE html>
-<html>
-
-<head>
- <title>#springMessageText("idp.title", "Web Login Service")</title>
- <meta charset="UTF-8" />
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">
- <link rel="stylesheet" type="text/css" href="$request.getContextPath()#springMessageText("
- idp.css", "/css/placeholder.css" )">
- <link rel="stylesheet" type="text/css" href="$request.getContextPath()/css/webauthn.css">
-</head>
-
-
-
-<body>
- <main class="main">
- <header>
- <img class="main-logo" src="$request.getContextPath()#springMessageText("
- idp.logo", "/images/placeholder-logo.png" )" alt="#springMessageText(" idp.logo.alt-text", "logo" )" />
-
- #set ($serviceName = $rpUIContext.serviceName)
- #if ($serviceName && !$rpContext.getRelyingPartyId().contains($serviceName))
- <h1>#springMessageText("idp.login.loginTo", "Login to") $encoder.encodeForHTML($serviceName)</h1>
- #end
- </header>
- <section>
- <div class="centre">
- <p>You have registered your authenticator credentials successfully.</p>
-
- <hr />
- <p>Registered credentials</p>
- #if ($webauthnRegContext.existingCredentials)
- <table>
- <tr>
- <th>Key Name</th>
- <th>Transports</th>
- <th>Registration Time</th>
- </tr>
- #foreach($cred in $webauthnRegContext.existingCredentials)
- <tr>
- <td>$cred.nickname</td>
- <td>$cred.transports</td>
- <td>$cred.registrationTimestamp</td>
- </tr>
- #end
- </table>
- #else
- <div><span>You have no registered credentials</span></div>
- #end
- <br />
- <form id="doneButtonForm" action="$flowExecutionUrl" method="post">
- #parse("csrf/csrf.vm")
- <button id="doneButton" type="submit" name="_eventId_proceed">Done</button>
- </form>
- </div>
-
-
- </section>
- </main>
-
- <footer>
- <div class="container container-footer">
- <p class="footer-text">#springMessageText("idp.footer", "Insert your footer text here.")</p>
- </div>
- </footer>
- </div>
-
-</body>
-
-</html>
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-username-entry.vm b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-username-entry.vm
index c3965ff..68e9260 100644
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-username-entry.vm
+++ b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-username-entry.vm
@@ -69,8 +69,7 @@ $response.addHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes'
#end
<blockquote>#springMessageText("idp.duo.passwordless.explain", "If you've enrolled a passkey or device/token for passwordless login,
- please enter your username below and press the corresponding button. To bypass this option, just press the alternate button
- to perform a traditional login.")</blockquote>
+ please enter your username below and press the corresponding button.")</blockquote>
@@ -94,7 +93,7 @@ $response.addHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes'
<div class="grid">
<div class="grid-item">
<button type="submit" name="_eventId_proceed"
- >#springMessageText("idp.webauthn.passwordless.proceed", "Login with Passkey or Device")</button>
+ >#springMessageText("idp.webauthn.passwordless.proceed", "Login with Security Key")</button>
</div>
</div>
</form>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list