KEYCLOAK-9346 Add new KeycloakPromise to support native promises
Co-authored-by: mhajas <mhajas@redhat.com>
This commit is contained in:
parent
bcb542d9cc
commit
c1bf183998
5 changed files with 161 additions and 258 deletions
|
@ -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<TPromise extends Keycloak.KeycloakPromiseType = 'legacy'>(config?: Keycloak.KeycloakConfig | string): Keycloak.KeycloakInstance<TPromise>;
|
||||
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<T> = (result: T) => void;
|
||||
|
||||
interface KeycloakPromise<TSuccess, TError> {
|
||||
class KeycloakPromise<TSuccess, TError> extends Promise<TSuccess> {
|
||||
/**
|
||||
* Function to call if the promised action succeeds.
|
||||
*
|
||||
* @deprecated Use `.then()` instead.
|
||||
*/
|
||||
success(callback: KeycloakPromiseCallback<TSuccess>): KeycloakPromise<TSuccess, TError>;
|
||||
|
||||
/**
|
||||
* Function to call if the promised action throws an error.
|
||||
*
|
||||
* @deprecated Use `.catch()` instead.
|
||||
*/
|
||||
error(callback: KeycloakPromiseCallback<TError>): KeycloakPromise<TSuccess, TError>;
|
||||
}
|
||||
|
@ -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 KeycloakPromiseType, TSuccess, TError> =
|
||||
TPromiseType extends 'native' ? Promise<TSuccess> : KeycloakPromise<TSuccess, TError>;
|
||||
|
||||
/**
|
||||
* 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<TPromise extends KeycloakPromiseType = 'legacy'> {
|
||||
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<TPromise, boolean, KeycloakError>;
|
||||
init(initOptions: KeycloakInitOptions): KeycloakPromise<boolean, KeycloakError>;
|
||||
|
||||
/**
|
||||
* Redirects to login form.
|
||||
* @param options Login options.
|
||||
*/
|
||||
login(options?: KeycloakLoginOptions): CompatPromise<TPromise, void, void>;
|
||||
login(options?: KeycloakLoginOptions): KeycloakPromise<void, void>;
|
||||
|
||||
/**
|
||||
* Redirects to logout.
|
||||
* @param options Logout options.
|
||||
* @param options.redirectUri Specifies the uri to redirect to after logout.
|
||||
*/
|
||||
logout(options?: any): CompatPromise<TPromise, void, void>;
|
||||
logout(options?: any): KeycloakPromise<void, void>;
|
||||
|
||||
/**
|
||||
* Redirects to registration form.
|
||||
* @param options Supports same options as Keycloak#login but `action` is
|
||||
* set to `'register'`.
|
||||
*/
|
||||
register(options?: any): CompatPromise<TPromise, void, void>;
|
||||
register(options?: any): KeycloakPromise<void, void>;
|
||||
|
||||
/**
|
||||
* Redirects to the Account Management Console.
|
||||
*/
|
||||
accountManagement(): CompatPromise<TPromise, void, void>;
|
||||
accountManagement(): KeycloakPromise<void, void>;
|
||||
|
||||
/**
|
||||
* 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<TPromise, boolean, boolean>;
|
||||
updateToken(minValidity: number): KeycloakPromise<boolean, boolean>;
|
||||
|
||||
/**
|
||||
* 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<TPromise, KeycloakProfile, void>;
|
||||
loadUserProfile(): KeycloakPromise<KeycloakProfile, void>;
|
||||
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
loadUserInfo(): CompatPromise<TPromise, {}, void>;
|
||||
loadUserInfo(): KeycloakPromise<{}, void>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue