diff --git a/adapters/oidc/js/src/main/resources/keycloak.d.ts b/adapters/oidc/js/src/main/resources/keycloak.d.ts index 2b8fd68292..b7495f649e 100644 --- a/adapters/oidc/js/src/main/resources/keycloak.d.ts +++ b/adapters/oidc/js/src/main/resources/keycloak.d.ts @@ -26,7 +26,7 @@ export = Keycloak; * Creates a new Keycloak client instance. * @param config A configuration object or path to a JSON config file. */ -declare function Keycloak(config?: Keycloak.KeycloakConfig | string): Keycloak.KeycloakInstance; +declare function Keycloak(config?: Keycloak.KeycloakConfig | string): Keycloak.KeycloakInstance; declare namespace Keycloak { type KeycloakAdapterName = 'cordova' | 'cordova-native' |'default' | any; @@ -34,7 +34,6 @@ declare namespace Keycloak { type KeycloakResponseMode = 'query'|'fragment'; type KeycloakResponseType = 'code'|'id_token token'|'code id_token token'; type KeycloakFlow = 'standard'|'implicit'|'hybrid'; - type KeycloakPromiseType = 'legacy' | 'native'; type KeycloakPkceMethod = 'S256'; interface KeycloakConfig { @@ -136,21 +135,6 @@ declare namespace Keycloak { */ flow?: KeycloakFlow; - /** - * Set the promise type. If set to `native` all methods returning a promise - * will return a native JavaScript promise. If not not specified then - * Keycloak specific legacy promise objects will be returned instead. - * - * Since native promises have become the industry standard it is highly - * recommended that you always specify `native` as the promise type. - * - * Note that in upcoming versions of Keycloak the default will be changed - * to `native`, and support for legacy promises will eventually be removed. - * - * @default legacy - */ - promiseType?: KeycloakPromiseType; - /** * Configures the Proof Key for Code Exchange (PKCE) method to use. * The currently allowed method is 'S256'. @@ -226,14 +210,18 @@ declare namespace Keycloak { type KeycloakPromiseCallback = (result: T) => void; - interface KeycloakPromise { + class KeycloakPromise extends Promise { /** * Function to call if the promised action succeeds. + * + * @deprecated Use `.then()` instead. */ success(callback: KeycloakPromiseCallback): KeycloakPromise; /** * Function to call if the promised action throws an error. + * + * @deprecated Use `.catch()` instead. */ error(callback: KeycloakPromiseCallback): KeycloakPromise; } @@ -281,20 +269,11 @@ declare namespace Keycloak { roles: string[]; } - // export interface KeycloakUserInfo {} - - /** - * Conditional CompatPromise type in order to support - * both legacy promises and native promises as return types. - */ - type CompatPromise = - TPromiseType extends 'native' ? Promise : KeycloakPromise; - /** * A client for the Keycloak authentication server. * @see {@link https://keycloak.gitbooks.io/securing-client-applications-guide/content/topics/oidc/javascript-adapter.html|Keycloak JS adapter documentation} */ - interface KeycloakInstance { + interface KeycloakInstance { /** * Is true if the user is authenticated, false otherwise. */ @@ -459,32 +438,32 @@ declare namespace Keycloak { * @param initOptions Initialization options. * @returns A promise to set functions to be invoked on success or error. */ - init(initOptions: KeycloakInitOptions): CompatPromise; + init(initOptions: KeycloakInitOptions): KeycloakPromise; /** * Redirects to login form. * @param options Login options. */ - login(options?: KeycloakLoginOptions): CompatPromise; + login(options?: KeycloakLoginOptions): KeycloakPromise; /** * Redirects to logout. * @param options Logout options. * @param options.redirectUri Specifies the uri to redirect to after logout. */ - logout(options?: any): CompatPromise; + logout(options?: any): KeycloakPromise; /** * Redirects to registration form. * @param options Supports same options as Keycloak#login but `action` is * set to `'register'`. */ - register(options?: any): CompatPromise; + register(options?: any): KeycloakPromise; /** * Redirects to the Account Management Console. */ - accountManagement(): CompatPromise; + accountManagement(): KeycloakPromise; /** * Returns the URL to login form. @@ -536,7 +515,7 @@ declare namespace Keycloak { * alert('Failed to refresh the token, or the session has expired'); * }); */ - updateToken(minValidity: number): CompatPromise; + updateToken(minValidity: number): KeycloakPromise; /** * Clears authentication state, including tokens. This can be useful if @@ -563,11 +542,11 @@ declare namespace Keycloak { * Loads the user's profile. * @returns A promise to set functions to be invoked on success or error. */ - loadUserProfile(): CompatPromise; + loadUserProfile(): KeycloakPromise; /** * @private Undocumented. */ - loadUserInfo(): CompatPromise; + loadUserInfo(): KeycloakPromise<{}, void>; } } diff --git a/adapters/oidc/js/src/main/resources/keycloak.js b/adapters/oidc/js/src/main/resources/keycloak.js index 74a9d8288c..0f179cb176 100755 --- a/adapters/oidc/js/src/main/resources/keycloak.js +++ b/adapters/oidc/js/src/main/resources/keycloak.js @@ -43,6 +43,16 @@ */ (function (r) { if (typeof exports === "object" && typeof module !== "undefined") { module.exports = r() } else if (typeof define === "function" && define.amd) { define([], r) } else { var e; if (typeof window !== "undefined") { e = window } else if (typeof global !== "undefined") { e = global } else if (typeof self !== "undefined") { e = self } else { e = this } e.base64js = r() } })(function () { var r, e, n; return function () { function r(e, n, t) { function o(f, i) { if (!n[f]) { if (!e[f]) { var u = "function" == typeof require && require; if (!i && u) return u(f, !0); if (a) return a(f, !0); var v = new Error("Cannot find module '" + f + "'"); throw v.code = "MODULE_NOT_FOUND", v } var d = n[f] = { exports: {} }; e[f][0].call(d.exports, function (r) { var n = e[f][1][r]; return o(n || r) }, d, d.exports, r, e, n, t) } return n[f].exports } for (var a = "function" == typeof require && require, f = 0; f < t.length; f++)o(t[f]); return o } return r }()({ "/": [function (r, e, n) { "use strict"; n.byteLength = d; n.toByteArray = h; n.fromByteArray = p; var t = []; var o = []; var a = typeof Uint8Array !== "undefined" ? Uint8Array : Array; var f = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; for (var i = 0, u = f.length; i < u; ++i) { t[i] = f[i]; o[f.charCodeAt(i)] = i } o["-".charCodeAt(0)] = 62; o["_".charCodeAt(0)] = 63; function v(r) { var e = r.length; if (e % 4 > 0) { throw new Error("Invalid string. Length must be a multiple of 4") } var n = r.indexOf("="); if (n === -1) n = e; var t = n === e ? 0 : 4 - n % 4; return [n, t] } function d(r) { var e = v(r); var n = e[0]; var t = e[1]; return (n + t) * 3 / 4 - t } function c(r, e, n) { return (e + n) * 3 / 4 - n } function h(r) { var e; var n = v(r); var t = n[0]; var f = n[1]; var i = new a(c(r, t, f)); var u = 0; var d = f > 0 ? t - 4 : t; for (var h = 0; h < d; h += 4) { e = o[r.charCodeAt(h)] << 18 | o[r.charCodeAt(h + 1)] << 12 | o[r.charCodeAt(h + 2)] << 6 | o[r.charCodeAt(h + 3)]; i[u++] = e >> 16 & 255; i[u++] = e >> 8 & 255; i[u++] = e & 255 } if (f === 2) { e = o[r.charCodeAt(h)] << 2 | o[r.charCodeAt(h + 1)] >> 4; i[u++] = e & 255 } if (f === 1) { e = o[r.charCodeAt(h)] << 10 | o[r.charCodeAt(h + 1)] << 4 | o[r.charCodeAt(h + 2)] >> 2; i[u++] = e >> 8 & 255; i[u++] = e & 255 } return i } function s(r) { return t[r >> 18 & 63] + t[r >> 12 & 63] + t[r >> 6 & 63] + t[r & 63] } function l(r, e, n) { var t; var o = []; for (var a = e; a < n; a += 3) { t = (r[a] << 16 & 16711680) + (r[a + 1] << 8 & 65280) + (r[a + 2] & 255); o.push(s(t)) } return o.join("") } function p(r) { var e; var n = r.length; var o = n % 3; var a = []; var f = 16383; for (var i = 0, u = n - o; i < u; i += f) { a.push(l(r, i, i + f > u ? u : i + f)) } if (o === 1) { e = r[n - 1]; a.push(t[e >> 2] + t[e << 4 & 63] + "==") } else if (o === 2) { e = (r[n - 2] << 8) + r[n - 1]; a.push(t[e >> 10] + t[e >> 4 & 63] + t[e << 2 & 63] + "=") } return a.join("") } }, {}] }, {}, [])("/") }); + /** + * [promise-polyfill]{@link https://github.com/taylorhakes/promise-polyfill} + * + * @version v8.1.3 + * @author Hakes, Taylor + * @copyright Hakes, Taylor 2014 + * @license MIT + */ + !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n():"function"==typeof define&&define.amd?define(n):n()}(0,function(){"use strict";function e(e){var n=this.constructor;return this.then(function(t){return n.resolve(e()).then(function(){return t})},function(t){return n.resolve(e()).then(function(){return n.reject(t)})})}function n(e){return!(!e||"undefined"==typeof e.length)}function t(){}function o(e){if(!(this instanceof o))throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=undefined,this._deferreds=[],c(e,this)}function r(e,n){for(;3===e._state;)e=e._value;0!==e._state?(e._handled=!0,o._immediateFn(function(){var t=1===e._state?n.onFulfilled:n.onRejected;if(null!==t){var o;try{o=t(e._value)}catch(r){return void f(n.promise,r)}i(n.promise,o)}else(1===e._state?i:f)(n.promise,e._value)})):e._deferreds.push(n)}function i(e,n){try{if(n===e)throw new TypeError("A promise cannot be resolved with itself.");if(n&&("object"==typeof n||"function"==typeof n)){var t=n.then;if(n instanceof o)return e._state=3,e._value=n,void u(e);if("function"==typeof t)return void c(function(e,n){return function(){e.apply(n,arguments)}}(t,n),e)}e._state=1,e._value=n,u(e)}catch(r){f(e,r)}}function f(e,n){e._state=2,e._value=n,u(e)}function u(e){2===e._state&&0===e._deferreds.length&&o._immediateFn(function(){e._handled||o._unhandledRejectionFn(e._value)});for(var n=0,t=e._deferreds.length;t>n;n++)r(e,e._deferreds[n]);e._deferreds=null}function c(e,n){var t=!1;try{e(function(e){t||(t=!0,i(n,e))},function(e){t||(t=!0,f(n,e))})}catch(o){if(t)return;t=!0,f(n,o)}}var a=setTimeout;o.prototype["catch"]=function(e){return this.then(null,e)},o.prototype.then=function(e,n){var o=new this.constructor(t);return r(this,new function(e,n,t){this.onFulfilled="function"==typeof e?e:null,this.onRejected="function"==typeof n?n:null,this.promise=t}(e,n,o)),o},o.prototype["finally"]=e,o.all=function(e){return new o(function(t,o){function r(e,n){try{if(n&&("object"==typeof n||"function"==typeof n)){var u=n.then;if("function"==typeof u)return void u.call(n,function(n){r(e,n)},o)}i[e]=n,0==--f&&t(i)}catch(c){o(c)}}if(!n(e))return o(new TypeError("Promise.all accepts an array"));var i=Array.prototype.slice.call(e);if(0===i.length)return t([]);for(var f=i.length,u=0;i.length>u;u++)r(u,i[u])})},o.resolve=function(e){return e&&"object"==typeof e&&e.constructor===o?e:new o(function(n){n(e)})},o.reject=function(e){return new o(function(n,t){t(e)})},o.race=function(e){return new o(function(t,r){if(!n(e))return r(new TypeError("Promise.race accepts an array"));for(var i=0,f=e.length;f>i;i++)o.resolve(e[i]).then(t,r)})},o._immediateFn="function"==typeof setImmediate&&function(e){setImmediate(e)}||function(e){a(e,0)},o._unhandledRejectionFn=function(e){void 0!==console&&console&&console.warn("Possible Unhandled Promise Rejection:",e)};var l=function(){if("undefined"!=typeof self)return self;if("undefined"!=typeof window)return window;if("undefined"!=typeof global)return global;throw Error("unable to locate global object")}();"Promise"in l?l.Promise.prototype["finally"]||(l.Promise.prototype["finally"]=e):l.Promise=o}); + var Keycloak = factory( root["sha256"], root["base64js"] ); root["Keycloak"] = Keycloak; @@ -51,6 +61,51 @@ } } })(window, function (sha256_imported, base64js_imported) { + if (typeof Promise === 'undefined') { + throw Error('Keycloak requires an environment that supports Promises. Make sure that you include the appropriate polyfill.'); + } + + var loggedPromiseDeprecation = false; + + function logPromiseDeprecation() { + if (!loggedPromiseDeprecation) { + loggedPromiseDeprecation = true; + console.warn('[KEYCLOAK] Usage of legacy style promise methods such as `.error()` and `.success()` has been deprecated and support will be removed in future versions. Use standard style promise methods such as `.then() and `.catch()` instead.'); + } + } + + function toKeycloakPromise(promise) { + promise.__proto__ = KeycloakPromise.prototype; + return promise; + } + + function KeycloakPromise(executor) { + return toKeycloakPromise(new Promise(executor)); + } + + KeycloakPromise.prototype = Object.create(Promise.prototype); + KeycloakPromise.prototype.constructor = KeycloakPromise; + + KeycloakPromise.prototype.success = function(callback) { + logPromiseDeprecation(); + + var promise = this.then(function handleSuccess(value) { + callback(value); + }); + + return toKeycloakPromise(promise); + }; + + KeycloakPromise.prototype.error = function(callback) { + logPromiseDeprecation(); + + var promise = this.catch(function handleError(error) { + callback(error); + }); + + return toKeycloakPromise(promise); + }; + function Keycloak (config) { if (!(this instanceof Keycloak)) { return new Keycloak(config); @@ -109,13 +164,6 @@ loginIframe.interval = initOptions.checkLoginIframeInterval; } - if (initOptions.promiseType === 'native') { - kc.useNativePromise = true; - } else { - console.warn('[KEYCLOAK] Using legacy promises is deprecated and will be removed in future versions. You can opt in to using native promises by setting `promiseType` to \'native\' when initializing Keycloak.'); - kc.useNativePromise = false; - } - if (initOptions.onLoad === 'login-required') { kc.loginRequired = true; } @@ -179,13 +227,13 @@ kc.flow = 'standard'; } - var promise = createPromise(false); + var promise = createPromise(); - var initPromise = createPromise(true); - initPromise.promise.success(function() { + var initPromise = createPromise(); + initPromise.promise.then(function() { kc.onReady && kc.onReady(kc.authenticated); promise.setSuccess(kc.authenticated); - }).error(function(errorData) { + }).catch(function(errorData) { promise.setError(errorData); }); @@ -196,19 +244,12 @@ if (!prompt) { options.prompt = 'none'; } - if (kc.useNativePromise) { - kc.login(options).then(function () { - initPromise.setSuccess(); - }).catch(function () { - initPromise.setError(); - }); - } else { - kc.login(options).success(function () { - initPromise.setSuccess(); - }).error(function () { - initPromise.setError(); - }); - } + + kc.login(options).then(function () { + initPromise.setSuccess(); + }).catch(function () { + initPromise.setError(); + }); } var checkSsoSilently = function() { @@ -238,14 +279,14 @@ switch (initOptions.onLoad) { case 'check-sso': if (loginIframe.enable) { - setupCheckLoginIframe().success(function() { - checkLoginIframe().success(function (unchanged) { + setupCheckLoginIframe().then(function() { + checkLoginIframe().then(function (unchanged) { if (!unchanged) { kc.silentCheckSsoRedirectUri ? checkSsoSilently() : doLogin(false); } else { initPromise.setSuccess(); } - }).error(function () { + }).catch(function () { initPromise.setError(); }); }); @@ -269,9 +310,9 @@ } if (callback && callback.valid) { - return setupCheckLoginIframe().success(function() { + return setupCheckLoginIframe().then(function() { processCallback(callback, initPromise); - }).error(function (e) { + }).catch(function (e) { initPromise.setError(); }); } else if (initOptions) { @@ -279,8 +320,8 @@ setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken); if (loginIframe.enable) { - setupCheckLoginIframe().success(function() { - checkLoginIframe().success(function (unchanged) { + setupCheckLoginIframe().then(function() { + checkLoginIframe().then(function (unchanged) { if (unchanged) { kc.onAuthSuccess && kc.onAuthSuccess(); initPromise.setSuccess(); @@ -288,15 +329,15 @@ } else { initPromise.setSuccess(); } - }).error(function () { + }).catch(function () { initPromise.setError(); }); }); } else { - kc.updateToken(-1).success(function() { + kc.updateToken(-1).then(function() { kc.onAuthSuccess && kc.onAuthSuccess(); initPromise.setSuccess(); - }).error(function() { + }).catch(function() { kc.onAuthError && kc.onAuthError(); if (initOptions.onLoad) { onLoad(); @@ -315,8 +356,8 @@ } } - configPromise.success(processInit); - configPromise.error(function() { + configPromise.then(processInit); + configPromise.catch(function() { promise.setError(); }); @@ -512,7 +553,7 @@ req.setRequestHeader('Accept', 'application/json'); req.setRequestHeader('Authorization', 'bearer ' + kc.token); - var promise = createPromise(false); + var promise = createPromise(); req.onreadystatechange = function () { if (req.readyState == 4) { @@ -537,7 +578,7 @@ req.setRequestHeader('Accept', 'application/json'); req.setRequestHeader('Authorization', 'bearer ' + kc.token); - var promise = createPromise(false); + var promise = createPromise(); req.onreadystatechange = function () { if (req.readyState == 4) { @@ -576,7 +617,7 @@ } kc.updateToken = function(minValidity) { - var promise = createPromise(false); + var promise = createPromise(); if (!kc.refreshToken) { promise.setError(); @@ -650,9 +691,9 @@ if (loginIframe.enable) { var iframePromise = checkLoginIframe(); - iframePromise.success(function() { + iframePromise.then(function() { exec(); - }).error(function() { + }).catch(function() { promise.setError(); }); } else { @@ -769,7 +810,7 @@ } function loadConfig(url) { - var promise = createPromise(true); + var promise = createPromise(); var configUrl; if (!config) { @@ -1117,15 +1158,7 @@ return result; } - function createPromise(internal) { - if (!internal && kc.useNativePromise) { - return createNativePromise(); - } else { - return createLegacyPromise(); - } - } - - function createNativePromise() { + function createPromise() { // Need to create a native Promise which also preserves the // interface of the custom promise type previously used by the API var p = { @@ -1137,55 +1170,16 @@ p.reject(result); } }; - p.promise = new Promise(function(resolve, reject) { + p.promise = new KeycloakPromise(function(resolve, reject) { p.resolve = resolve; p.reject = reject; }); return p; } - function createLegacyPromise() { - var p = { - setSuccess: function(result) { - p.success = true; - p.result = result; - if (p.successCallback) { - p.successCallback(result); - } - }, - - setError: function(result) { - p.error = true; - p.result = result; - if (p.errorCallback) { - p.errorCallback(result); - } - }, - - promise: { - success: function(callback) { - if (p.success) { - callback(p.result); - } else if (!p.error) { - p.successCallback = callback; - } - return p.promise; - }, - error: function(callback) { - if (p.error) { - callback(p.result); - } else if (!p.success) { - p.errorCallback = callback; - } - return p.promise; - } - } - } - return p; - } function setupCheckLoginIframe() { - var promise = createPromise(true); + var promise = createPromise(); if (!loginIframe.enable) { promise.setSuccess(); @@ -1251,7 +1245,7 @@ if (loginIframe.enable) { if (kc.token) { setTimeout(function() { - checkLoginIframe().success(function(unchanged) { + checkLoginIframe().then(function(unchanged) { if (unchanged) { scheduleCheckIframe(); } @@ -1262,7 +1256,7 @@ } function checkLoginIframe() { - var promise = createPromise(true); + var promise = createPromise(); if (loginIframe.iframe && loginIframe.iframeOrigin ) { var msg = kc.clientId + ' ' + (kc.sessionId ? kc.sessionId : ''); @@ -1283,17 +1277,17 @@ return { login: function(options) { window.location.replace(kc.createLoginUrl(options)); - return createPromise(false).promise; + return createPromise().promise; }, logout: function(options) { window.location.replace(kc.createLogoutUrl(options)); - return createPromise(false).promise; + return createPromise().promise; }, register: function(options) { window.location.replace(kc.createRegisterUrl(options)); - return createPromise(false).promise; + return createPromise().promise; }, accountManagement : function() { @@ -1303,7 +1297,7 @@ } else { throw "Not supported by the OIDC server"; } - return createPromise(false).promise; + return createPromise().promise; }, redirectUri: function(options, encodeHash) { @@ -1362,7 +1356,7 @@ return { login: function(options) { - var promise = createPromise(false); + var promise = createPromise(); var cordovaOptions = createCordovaOptions(options); var loginUrl = kc.createLoginUrl(options); @@ -1410,7 +1404,7 @@ }, logout: function(options) { - var promise = createPromise(false); + var promise = createPromise(); var logoutUrl = kc.createLogoutUrl(options); var ref = cordovaOpenWindowWrapper(logoutUrl, '_blank', 'location=no,hidden=yes'); @@ -1445,7 +1439,7 @@ }, register : function(options) { - var promise = createPromise(false); + var promise = createPromise(); var registerUrl = kc.createRegisterUrl(); var cordovaOptions = createCordovaOptions(options); var ref = cordovaOpenWindowWrapper(registerUrl, '_blank', cordovaOptions); @@ -1484,7 +1478,7 @@ return { login: function(options) { - var promise = createPromise(false); + var promise = createPromise(); var loginUrl = kc.createLoginUrl(options); universalLinks.subscribe('keycloak', function(event) { @@ -1499,7 +1493,7 @@ }, logout: function(options) { - var promise = createPromise(false); + var promise = createPromise(); var logoutUrl = kc.createLogoutUrl(options); universalLinks.subscribe('keycloak', function(event) { @@ -1514,7 +1508,7 @@ }, register : function(options) { - var promise = createPromise(false); + var promise = createPromise(); var registerUrl = kc.createRegisterUrl(options); universalLinks.subscribe('keycloak' , function(event) { universalLinks.unsubscribe('keycloak'); diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JavascriptTestExecutor.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JavascriptTestExecutor.java index 7e68e4a70b..2dff60cf38 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JavascriptTestExecutor.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JavascriptTestExecutor.java @@ -131,25 +131,12 @@ public class JavascriptTestExecutor { String arguments = argumentsBuilder.build(); - String script; - - // phantomjs do not support Native promises - if (argumentsBuilder.contains("promiseType", "native") && !"phantomjs".equals(System.getProperty("js.browser"))) { - script = "var callback = arguments[arguments.length - 1];" + - " window.keycloak.init(" + arguments + ").then(function (authenticated) {" + - " callback(\"Init Success (\" + (authenticated ? \"Authenticated\" : \"Not Authenticated\") + \")\");" + - " }, function () {" + - " callback(\"Init Error\");" + - " });"; - } else { - script = "var callback = arguments[arguments.length - 1];" + - " window.keycloak.init(" + arguments + ").success(function (authenticated) {" + - " callback(\"Init Success (\" + (authenticated ? \"Authenticated\" : \"Not Authenticated\") + \")\");" + - " }).error(function () {" + - " callback(\"Init Error\");" + - " });"; - } - + String script = "var callback = arguments[arguments.length - 1];" + + " window.keycloak.init(" + arguments + ").then(function (authenticated) {" + + " callback(\"Init Success (\" + (authenticated ? \"Authenticated\" : \"Not Authenticated\") + \")\");" + + " }).catch(function () {" + + " callback(\"Init Error\");" + + " });"; Object output = jsExecutor.executeAsyncScript(script); @@ -174,30 +161,16 @@ public class JavascriptTestExecutor { } public JavascriptTestExecutor refreshToken(int value, JavascriptStateValidator validator) { - String script; - if (useNativePromises()) { - script = "var callback = arguments[arguments.length - 1];" + - " window.keycloak.updateToken(" + Integer.toString(value) + ").then(function (refreshed) {" + - " if (refreshed) {" + - " callback(window.keycloak.tokenParsed);" + - " } else {" + - " callback('Token not refreshed, valid for ' + Math.round(window.keycloak.tokenParsed.exp + window.keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds');" + - " }" + - " }, function () {" + - " callback('Failed to refresh token');" + - " });"; - } else { - script = "var callback = arguments[arguments.length - 1];" + - " window.keycloak.updateToken(" + Integer.toString(value) + ").success(function (refreshed) {" + - " if (refreshed) {" + - " callback(window.keycloak.tokenParsed);" + - " } else {" + - " callback('Token not refreshed, valid for ' + Math.round(window.keycloak.tokenParsed.exp + window.keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds');" + - " }" + - " }).error(function () {" + - " callback('Failed to refresh token');" + - " });"; - } + String script = "var callback = arguments[arguments.length - 1];" + + " window.keycloak.updateToken(" + Integer.toString(value) + ").then(function (refreshed) {" + + " if (refreshed) {" + + " callback(window.keycloak.tokenParsed);" + + " } else {" + + " callback('Token not refreshed, valid for ' + Math.round(window.keycloak.tokenParsed.exp + window.keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds');" + + " }" + + " }).catch(function () {" + + " callback('Failed to refresh token');" + + " });"; Object output = jsExecutor.executeAsyncScript(script); @@ -208,12 +181,6 @@ public class JavascriptTestExecutor { return this; } - public boolean useNativePromises() { - return (boolean) jsExecutor.executeScript("if (typeof window.keycloak !== 'undefined') {" + - "return window.keycloak.useNativePromise" + - "} else { return false}"); - } - public JavascriptTestExecutor openAccountPage(JavascriptStateValidator validator) { jsExecutor.executeScript("window.keycloak.accountManagement()"); waitForPageToLoad(); @@ -234,22 +201,12 @@ public class JavascriptTestExecutor { public JavascriptTestExecutor getProfile(JavascriptStateValidator validator) { - String script; - if (useNativePromises()) { - script = "var callback = arguments[arguments.length - 1];" + + String script = "var callback = arguments[arguments.length - 1];" + " window.keycloak.loadUserProfile().then(function (profile) {" + " callback(profile);" + " }, function () {" + " callback('Failed to load profile');" + " });"; - } else { - script = "var callback = arguments[arguments.length - 1];" + - " window.keycloak.loadUserProfile().success(function (profile) {" + - " callback(profile);" + - " }).error(function () {" + - " callback('Failed to load profile');" + - " });"; - } Object output = jsExecutor.executeAsyncScript(script); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterTest.java index 612c8b0103..4d5ebfe38c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterTest.java @@ -601,22 +601,22 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest { @Test public void reentrancyCallbackTest() { testExecutor.logInAndInit(defaultArguments(), testUser, this::assertSuccessfullyLoggedIn) - .executeAsyncScript( - "var callback = arguments[arguments.length - 1];" + - "keycloak.updateToken(60).success(function () {" + - " event(\"First callback\");" + - " keycloak.updateToken(60).success(function () {" + - " event(\"Second callback\");" + - " callback(\"Success\");" + - " });" + - " }" + - ");" - , (driver1, output, events) -> { - waitUntilElement(events).text().contains("First callback"); - waitUntilElement(events).text().contains("Second callback"); - waitUntilElement(events).text().not().contains("Auth Logout"); - } - ); + .executeAsyncScript( + "var callback = arguments[arguments.length - 1];" + + "keycloak.updateToken(60).then(function () {" + + " event(\"First callback\");" + + " keycloak.updateToken(60).then(function () {" + + " event(\"Second callback\");" + + " callback(\"Success\");" + + " });" + + " }" + + ");" + , (driver1, output, events) -> { + waitUntilElement(events).text().contains("First callback"); + waitUntilElement(events).text().contains("Second callback"); + waitUntilElement(events).text().not().contains("Auth Logout"); + } + ); } @Test @@ -644,5 +644,20 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest { }); } + @Test + public void testRefreshTokenWithDeprecatedPromiseHandles() { + String refreshWithDeprecatedHandles = "var callback = arguments[arguments.length - 1];" + + " window.keycloak.updateToken(9999).success(function (refreshed) {" + + " callback('Success handle');" + + " }).catch(function () {" + + " callback('Catch handle');" + + " });"; + testExecutor.init(defaultArguments(), this::assertInitNotAuth) + .executeAsyncScript(refreshWithDeprecatedHandles, assertOutputContains("Catch handle")) + .login(this::assertOnLoginPage) + .loginForm(testUser, this::assertOnTestAppUrl) + .init(defaultArguments(), this::assertSuccessfullyLoggedIn) + .executeAsyncScript(refreshWithDeprecatedHandles, assertOutputContains("Success handle")); + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterWithNativePromisesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterWithNativePromisesTest.java deleted file mode 100644 index 6dce9bce0f..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterWithNativePromisesTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.keycloak.testsuite.javascript; - -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; -import org.keycloak.testsuite.util.javascript.JSObjectBuilder; - -import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement; - -public class JavascriptAdapterWithNativePromisesTest extends JavascriptAdapterTest { - @Override - protected JSObjectBuilder defaultArguments() { - return super.defaultArguments().add("promiseType", "native"); - } - - @Before - public void skipOnPhantomJS() { - Assume.assumeTrue("Native promises are not supported on PhantomJS", !"phantomjs".equals(System.getProperty("js.browser"))); - } - - @Test - @Override - public void reentrancyCallbackTest() { - testExecutor.logInAndInit(defaultArguments(), testUser, this::assertSuccessfullyLoggedIn) - .executeAsyncScript( - "var callback = arguments[arguments.length - 1];" + - "keycloak.updateToken(60).then(function () {" + - " event(\"First callback\");" + - " keycloak.updateToken(60).then(function () {" + - " event(\"Second callback\");" + - " callback(\"Success\");" + - " });" + - " }" + - ");" - , (driver1, output, events) -> { - waitUntilElement(events).text().contains("First callback"); - waitUntilElement(events).text().contains("Second callback"); - waitUntilElement(events).text().not().contains("Auth Logout"); - } - ); - } -}