Use crypto.randomUUID() to generate UUIDs for Keycloak JS (#33518)

Closes #33515

Signed-off-by: Jon Koops <jonkoops@gmail.com>
This commit is contained in:
Jon Koops 2024-10-03 17:07:57 +02:00 committed by GitHub
parent c8ca0462a4
commit b475f936d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 27 additions and 14 deletions

View file

@ -418,7 +418,7 @@ const keycloak = new Keycloak('http://keycloak-server/path/to/keycloak.json');
== Methods for login are now `async` == Methods for login are now `async`
Keycloak JS now utilizes the Web Crypto API to calculate the SHA-256 digests needed to support PKCE. Due to the asynchronous nature of this API the following public methods will now always return a `Promise`: Keycloak JS now utilizes the Web Crypto API for various cryptographic functions. Due to the asynchronous nature of this API the following public methods will now always return a `Promise`:
- `login()` - `login()`
- `createLoginUrl()` - `createLoginUrl()`
@ -443,7 +443,7 @@ Make sure to update your code to `await` these methods.
== A secure context is now required == A secure context is now required
Keycloak JS now requires a link:https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts[secure context] to run. The reason for this is that the library now uses the Web Crypto API to calculate the SHA-256 digests needed to support PKCE. This API is only available in secure contexts, which are contexts that are served over HTTPS, `localhost` or a `.localhost` domain. If you are using the library in a non-secure context you'll need to update your development environment to use a secure context. Keycloak JS now requires a link:https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts[secure context] to run. The reason for this is that the library now uses the Web Crypto API for various cryptographic functions. This API is only available in secure contexts, which are contexts that are served over HTTPS, `localhost` or a `.localhost` domain. If you are using the library in a non-secure context you'll need to update your development environment to use a secure context.
= Stricter startup behavior for build-time options = Stricter startup behavior for build-time options

View file

@ -53,7 +53,11 @@ function Keycloak (config) {
var logWarn = createLogger(console.warn); var logWarn = createLogger(console.warn);
if (!globalThis.isSecureContext) { if (!globalThis.isSecureContext) {
logWarn('[KEYCLOAK] Keycloak JS should only be used in a secure context: https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts'); logWarn(
"[KEYCLOAK] Keycloak JS must be used in a 'secure context' to function properly as it relies on browser APIs that are otherwise not available.\n" +
"Continuing to run your application insecurely will lead to unexpected behavior and breakage.\n\n" +
"For more information see: https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts"
);
} }
kc.init = function (initOptions) { kc.init = function (initOptions) {
@ -341,9 +345,7 @@ function Keycloak (config) {
throw new Error("Web Crypto API is not available."); throw new Error("Web Crypto API is not available.");
} }
const array = new Uint8Array(len); return crypto.getRandomValues(new Uint8Array(len));
crypto.getRandomValues(array);
return array;
} }
function generateCodeVerifier(len) { function generateCodeVerifier(len) {
@ -1007,13 +1009,11 @@ function Keycloak (config) {
} }
function createUUID() { function createUUID() {
var hexDigits = '0123456789abcdef'; if (typeof crypto === "undefined" || typeof crypto.randomUUID === "undefined") {
var s = generateRandomString(36, hexDigits).split(""); throw new Error("Web Crypto API is not available.");
s[14] = '4'; }
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
s[8] = s[13] = s[18] = s[23] = '-'; return crypto.randomUUID();
var uuid = s.join('');
return uuid;
} }
function parseCallback(url) { function parseCallback(url) {

View file

@ -473,6 +473,9 @@ importers:
rfc4648: rfc4648:
specifier: ^1.5.3 specifier: ^1.5.3
version: 1.5.3 version: 1.5.3
uuid:
specifier: ^10.0.0
version: 10.0.0
devDependencies: devDependencies:
'@rollup/plugin-commonjs': '@rollup/plugin-commonjs':
specifier: ^26.0.1 specifier: ^26.0.1

View file

@ -14,7 +14,8 @@
"patternfly": "^3.59.5", "patternfly": "^3.59.5",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"rfc4648": "^1.5.3" "rfc4648": "^1.5.3",
"uuid": "^10.0.0"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-commonjs": "^26.0.1",

View file

@ -1,4 +1,5 @@
import { sha256 } from '@noble/hashes/sha256'; import { sha256 } from '@noble/hashes/sha256';
import { v4 as uuidv4 } from 'uuid';
// Shim for Web Crypto API specifically for Keycloak JS, as this API can sometimes be missing, for example in an insecure context: // Shim for Web Crypto API specifically for Keycloak JS, as this API can sometimes be missing, for example in an insecure context:
// https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts // https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts
@ -32,3 +33,11 @@ if (typeof crypto.getRandomValues === "undefined") {
} }
}); });
} }
if (typeof crypto.randomUUID === "undefined") {
Object.defineProperty(crypto, "randomUUID", {
value: () => {
return uuidv4();
}
});
}