Skip to content

Commit f162b4b

Browse files
committed
rework iframe mechanics
1 parent b1f5260 commit f162b4b

6 files changed

Lines changed: 127 additions & 90 deletions

File tree

src/CheckSessionHtml.js

Lines changed: 0 additions & 47 deletions
This file was deleted.

src/CheckSessionIFrame.js

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,69 @@
22
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
33

44
import Log from './Log';
5-
import CheckSessionHtml from './CheckSessionHtml';
65

76
const DefaultInterval = 2000;
87

98
export default class CheckSessionIFrame {
10-
constructor(callback) {
9+
constructor(callback, client_id, url, interval) {
1110
this._callback = callback;
11+
this._client_id = client_id;
12+
this._url = url;
13+
this._interval = interval || DefaultInterval;
14+
15+
var idx = url.indexOf("/", url.indexOf("//") + 2);
16+
this._frame_origin = url.substr(0, idx);
1217

13-
this._boundMessageEvent = this._message.bind(this);
14-
window.addEventListener("message", this._boundMessageEvent, false);
15-
1618
this._frame = window.document.createElement("iframe");
1719
this._frame.style.display = "none";
20+
this._frame.src = url;
1821
window.document.body.appendChild(this._frame);
19-
this._frame.document.write(CheckSessionHtml);
22+
23+
this._boundMessageEvent = this._message.bind(this);
24+
window.addEventListener("message", this._boundMessageEvent, false);
2025
}
2126

2227
_message(e) {
23-
Log.info("CheckSessionIFrame._message");
24-
25-
if (e.origin === this._origin &&
26-
e.source === this._popup.window
28+
if (e.origin === this._frame_origin &&
29+
e.source === this._frame.contentWindow
2730
) {
28-
Log.info("processing message", e.data);
29-
this._callback();
31+
if (e.data === "error"){
32+
Log.error("error message from check session op iframe");
33+
this.stop();
34+
}
35+
else if (e.data === "changed"){
36+
Log.info("changed message from check session op iframe");
37+
this.stop();
38+
this._callback();
39+
}
40+
else {
41+
Log.info(e.data + " message from check session op iframe");
42+
}
3043
}
3144
}
3245

33-
get _origin() {
34-
return window.location.protocol + "//" + window.location.host;
46+
start(session_state) {
47+
if (this._session_state !== session_state) {
48+
Log.info("CheckSessionIFrame.start");
49+
50+
this.stop();
51+
52+
this._session_state = session_state;
53+
54+
this._timer = window.setInterval(() => {
55+
this._frame.contentWindow.postMessage(this._client_id + " " + this._session_state, this._frame_origin);
56+
}, this._interval);
57+
}
3558
}
3659

37-
init(client_id, check_session_iframe, session_state, interval) {
38-
let msg = {
39-
client_id: client_id,
40-
check_session_iframe : check_session_iframe,
41-
session_state : session_state,
42-
check_interval: interval || DefaultInterval
43-
};
44-
this._frame.postMessage(msg, this._origin);
60+
stop() {
61+
Log.info("CheckSessionIFrame.stop");
62+
63+
this._session_state = null;
64+
65+
if (this._timer) {
66+
window.clearInterval(this._timer);
67+
this._timer = null;
68+
}
4569
}
4670
}

src/SessionMonitor.js

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,79 @@
22
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
33

44
import Log from './Log';
5-
import MetadataService from './MetadataService';
65
import CheckSessionIFrame from './CheckSessionIFrame';
76

87
export default class SessionMonitor {
98

10-
constructor(settings, MetadataServiceCtor = MetadataService, CheckSessionIFrameCtor = CheckSessionIFrame) {
11-
if (!settings) {
12-
Log.error("No settings passed to SessionMonitor");
13-
throw new Error("settings");
9+
constructor(userManager, CheckSessionIFrameCtor = CheckSessionIFrame) {
10+
if (!userManager) {
11+
Log.error("No user manager passed to SessionMonitor");
12+
throw new Error("userManager");
1413
}
1514

16-
this._settings = settings;
17-
this._metadataService = new MetadataServiceCtor(this._settings);
18-
this._checkSessionIFrame = new CheckSessionIFrameCtor(this._callback);
15+
this._userManager = userManager;
16+
this._CheckSessionIFrameCtor = CheckSessionIFrameCtor;
17+
18+
this._userManager.events.addUserLoaded(this._start.bind(this));
19+
this._userManager.events.addUserUnloaded(this._stop.bind(this));
20+
21+
this._userManager.getUser().then(user => {
22+
if (user) {
23+
this._start(user);
24+
}
25+
}).catch(err => {
26+
// catch to suppress errors since we're in a ctor
27+
Log.error("SessionMonitor ctor; error from getUser:", err.message);
28+
});
1929
}
2030

21-
_callback() {
22-
Log.info("SessionMonitor.callback happened");
31+
get _settings() {
32+
return this._userManager.settings;
33+
}
34+
get _metadataService() {
35+
return this._userManager.metadataService;
36+
}
37+
get _client_id(){
38+
return this._settings.client_id;
39+
}
40+
get _checkSessionInterval(){
41+
return this._settings.checkSessionInterval;
2342
}
2443

25-
initialize(user) {
26-
let client_id = this._settings.client_id;
44+
_start(user) {
2745
let session_state = user.session_state;
28-
let interval = this._settings.checkSessionInterval;
46+
Log.info("SessionMonitor._start; session_state:", session_state);
2947

30-
return this._promise = this._metadataService.getCheckSessionIframe(url => {
31-
this._checkSessionIFrame.init(client_id, url, session_state, interval);
32-
});
48+
if (!this._checkSessionIFrame) {
49+
this._metadataService.getCheckSessionIframe().then(url => {
50+
if (url) {
51+
Log.info("Initializing check session iframe")
52+
53+
let client_id = this._client_id;
54+
let interval = this._checkSessionInterval;
55+
56+
this._checkSessionIFrame = new this._CheckSessionIFrameCtor(this._callback.bind(this), client_id, url, interval);
57+
this._checkSessionIFrame.start(session_state);
58+
}
59+
else {
60+
Log.warn("No check session iframe found in the metadata");
61+
}
62+
}).catch(err => {
63+
// catch to suppress errors since we're in non-promise callback
64+
Log.error("Error from getCheckSessionIframe:", err.message);
65+
});
66+
}
67+
else {
68+
this._checkSessionIFrame.start(session_state);
69+
}
70+
}
71+
72+
_stop() {
73+
Log.info("SessionMonitor._stop");
74+
this._checkSessionIFrame.stop();
75+
}
76+
77+
_callback() {
78+
Log.info("SessionMonitor._callback; user has changed login status");
3379
}
3480
}

src/UserManager.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,29 @@ import UserManagerSettings from './UserManagerSettings';
77
import User from './User';
88
import UserManagerEvents from './UserManagerEvents';
99
import SilentRenewService from './SilentRenewService';
10+
import SessionMonitor from './SessionMonitor';
1011

1112
export default class UserManager extends OidcClient {
12-
constructor(settings = {}) {
13+
constructor(settings = {},
14+
SilentRenewServiceCtor = SilentRenewService,
15+
SessionMonitorCtor = SessionMonitor
16+
) {
1317

1418
if (!(settings instanceof UserManagerSettings)) {
1519
settings = new UserManagerSettings(settings);
1620
}
1721
super(settings);
1822

19-
20-
// order is important for these two properties; SilentRenewService depends on the events.
2123
this._events = new UserManagerEvents(settings);
2224

25+
// order is important for the following properties; these services depend upon the events.
2326
if (this.settings.automaticSilentRenew) {
2427
Log.info("automaticSilentRenew is configured, setting up silent renew")
25-
this._silentRenewService = new SilentRenewService(this);
28+
this._silentRenewService = new SilentRenewServiceCtor(this);
29+
}
30+
if (this.settings.monitorSession) {
31+
Log.info("monitorSession is configured, setting up session monitor")
32+
this._sessionMonitor = new SessionMonitorCtor(this);
2633
}
2734
}
2835

@@ -66,7 +73,6 @@ export default class UserManager extends OidcClient {
6673

6774
return this._storeUser(null).then(() => {
6875
Log.info("user removed from storage");
69-
7076
this._events.unload();
7177
});
7278
}

src/UserManagerSettings.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export default class UserManagerSettings extends OidcClientSettings {
1919
silent_redirect_uri,
2020
silentRequestTimeout,
2121
automaticSilentRenew = false,
22+
monitorSession = true,
2223
accessTokenExpiringNotificationTime = DefaultAccessTokenExpiringNotificationTime,
2324
redirectNavigator = new RedirectNavigator(),
2425
popupNavigator = new PopupNavigator(),
@@ -36,6 +37,8 @@ export default class UserManagerSettings extends OidcClientSettings {
3637
this._automaticSilentRenew = !!automaticSilentRenew;
3738
this._accessTokenExpiringNotificationTime = accessTokenExpiringNotificationTime;
3839

40+
this._monitorSession = monitorSession;
41+
3942
this._redirectNavigator = redirectNavigator;
4043
this._popupNavigator = popupNavigator;
4144
this._iframeNavigator = iframeNavigator;
@@ -66,6 +69,10 @@ export default class UserManagerSettings extends OidcClientSettings {
6669
return this._accessTokenExpiringNotificationTime;
6770
}
6871

72+
get monitorSession() {
73+
return this._monitorSession;
74+
}
75+
6976
get redirectNavigator() {
7077
return this._redirectNavigator;
7178
}

test/unit/UserManager.spec.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ describe("UserManager", function () {
4040
settings = {
4141
authority: 'http://sts/oidc',
4242
client_id: 'client',
43+
monitorSession : false,
4344
navigator: stubNavigator,
4445
userStore: stubUserStore,
4546
stateStore: stubStateStore,

0 commit comments

Comments
 (0)