Skip to content

Commit 135d5bc

Browse files
authored
Merge pull request #4719 from AzureAD/logout-onredirectnavigate-interactioninprogress
Ensure interaction status is properly set during logout with onRedirectNavigate
2 parents d6a412f + a04ef85 commit 135d5bc

File tree

3 files changed

+121
-13
lines changed

3 files changed

+121
-13
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "Ensure interaction status is properly set during logout with onRedirectNavigate #4719",
4+
"packageName": "@azure/msal-browser",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

lib/msal-browser/src/interaction_client/RedirectClient.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,22 @@ export class RedirectClient extends StandardInteractionClient {
272272

273273
if (navigate !== false) {
274274
this.logger.verbose("Logout onRedirectNavigate did not return false, navigating");
275+
// Ensure interaction is in progress
276+
if (!this.browserStorage.getInteractionInProgress()) {
277+
this.browserStorage.setInteractionInProgress(true);
278+
}
275279
await this.navigationClient.navigateExternal(logoutUri, navigationOptions);
276280
return;
277281
} else {
282+
// Ensure interaction is not in progress
283+
this.browserStorage.setInteractionInProgress(false);
278284
this.logger.verbose("Logout onRedirectNavigate returned false, stopping navigation");
279285
}
280286
} else {
287+
// Ensure interaction is in progress
288+
if (!this.browserStorage.getInteractionInProgress()) {
289+
this.browserStorage.setInteractionInProgress(true);
290+
}
281291
await this.navigationClient.navigateExternal(logoutUri, navigationOptions);
282292
return;
283293
}

lib/msal-browser/test/interaction_client/RedirectClient.spec.ts

Lines changed: 104 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1996,38 +1996,128 @@ describe("RedirectClient", () => {
19961996
done();
19971997
return Promise.resolve(true);
19981998
});
1999+
browserStorage.setInteractionInProgress(true);
19992000
redirectClient.logout({
20002001
onRedirectNavigate: (url: string) => {
20012002
expect(url).toEqual(testLogoutUrl);
2002-
done();
20032003
return false;
20042004
}
2005-
});
2006-
const validatedLogoutRequest: CommonEndSessionRequest = {
2007-
correlationId: RANDOM_TEST_GUID,
2008-
postLogoutRedirectUri: TEST_URIS.TEST_REDIR_URI
2005+
})
2006+
.then(() => {
2007+
expect(browserStorage.getInteractionInProgress()).toBeFalsy();
2008+
2009+
const validatedLogoutRequest: CommonEndSessionRequest = {
2010+
correlationId: RANDOM_TEST_GUID,
2011+
postLogoutRedirectUri: TEST_URIS.TEST_REDIR_URI
2012+
};
2013+
expect(logoutUriSpy.calledWith(validatedLogoutRequest));
2014+
done();
2015+
})
2016+
});
2017+
2018+
it("doesnt navigate if onRedirectNavigate returns false (specific account)", (done) => {
2019+
const testAccountInfo: AccountInfo = {
2020+
homeAccountId: TEST_DATA_CLIENT_INFO.TEST_HOME_ACCOUNT_ID,
2021+
localAccountId: TEST_DATA_CLIENT_INFO.TEST_UID,
2022+
environment: "login.windows.net",
2023+
tenantId: "",
2024+
username: "",
2025+
idTokenClaims: {}
20092026
};
2010-
expect(logoutUriSpy.calledWith(validatedLogoutRequest));
2027+
2028+
const logoutUriSpy = sinon.stub(AuthorizationCodeClient.prototype, "getLogoutUri").returns(testLogoutUrl);
2029+
sinon.stub(NavigationClient.prototype, "navigateExternal").callsFake((urlNavigate: string, options: NavigationOptions): Promise<boolean> => {
2030+
// If onRedirectNavigate does not stop navigatation, this will be called, failing the test as done will be invoked twice
2031+
done();
2032+
return Promise.resolve(true);
2033+
});
2034+
browserStorage.setInteractionInProgress(true);
2035+
redirectClient.logout({
2036+
account: testAccountInfo,
2037+
onRedirectNavigate: (url: string) => {
2038+
expect(url).toEqual(testLogoutUrl);
2039+
return false;
2040+
}
2041+
})
2042+
.then(() => {
2043+
expect(browserStorage.getInteractionInProgress()).toBeFalsy();
2044+
2045+
const validatedLogoutRequest: CommonEndSessionRequest = {
2046+
correlationId: RANDOM_TEST_GUID,
2047+
postLogoutRedirectUri: TEST_URIS.TEST_REDIR_URI
2048+
};
2049+
expect(logoutUriSpy.calledWith(validatedLogoutRequest));
2050+
done();
2051+
})
20112052
});
20122053

20132054
it("does navigate if onRedirectNavigate returns true", (done) => {
20142055
const logoutUriSpy = sinon.stub(AuthorizationCodeClient.prototype, "getLogoutUri").returns(testLogoutUrl);
20152056
sinon.stub(NavigationClient.prototype, "navigateExternal").callsFake((urlNavigate: string, options: NavigationOptions): Promise<boolean> => {
2057+
expect(browserStorage.getInteractionInProgress()).toBeTruthy();
20162058
expect(urlNavigate).toEqual(testLogoutUrl);
2017-
done();
2059+
20182060
return Promise.resolve(true);
20192061
});
2062+
browserStorage.setInteractionInProgress(true);
20202063
redirectClient.logout({
20212064
onRedirectNavigate: (url) => {
20222065
expect(url).toEqual(testLogoutUrl);
20232066
return true;
20242067
}
2025-
});
2026-
const validatedLogoutRequest: CommonEndSessionRequest = {
2027-
correlationId: RANDOM_TEST_GUID,
2028-
postLogoutRedirectUri: TEST_URIS.TEST_REDIR_URI
2068+
})
2069+
.then(() => {
2070+
expect(browserStorage.getInteractionInProgress()).toBeTruthy();
2071+
2072+
// Reset after testing it was properly set
2073+
browserStorage.setInteractionInProgress(false);
2074+
2075+
const validatedLogoutRequest: CommonEndSessionRequest = {
2076+
correlationId: RANDOM_TEST_GUID,
2077+
postLogoutRedirectUri: TEST_URIS.TEST_REDIR_URI
2078+
};
2079+
expect(logoutUriSpy.calledWith(validatedLogoutRequest));
2080+
done();
2081+
})
2082+
});
2083+
2084+
it("does navigate if onRedirectNavigate returns true (specific account)", (done) => {
2085+
const testAccountInfo: AccountInfo = {
2086+
homeAccountId: TEST_DATA_CLIENT_INFO.TEST_HOME_ACCOUNT_ID,
2087+
localAccountId: TEST_DATA_CLIENT_INFO.TEST_UID,
2088+
environment: "login.windows.net",
2089+
tenantId: "",
2090+
username: "",
2091+
idTokenClaims: {}
20292092
};
2030-
expect(logoutUriSpy.calledWith(validatedLogoutRequest));
2093+
2094+
const logoutUriSpy = sinon.stub(AuthorizationCodeClient.prototype, "getLogoutUri").returns(testLogoutUrl);
2095+
sinon.stub(NavigationClient.prototype, "navigateExternal").callsFake((urlNavigate: string, options: NavigationOptions): Promise<boolean> => {
2096+
expect(urlNavigate).toEqual(testLogoutUrl);
2097+
2098+
return Promise.resolve(true);
2099+
});
2100+
browserStorage.setInteractionInProgress(true);
2101+
redirectClient.logout({
2102+
account: testAccountInfo,
2103+
onRedirectNavigate: (url) => {
2104+
expect(url).toEqual(testLogoutUrl);
2105+
return true;
2106+
}
2107+
})
2108+
.then(() => {
2109+
expect(browserStorage.getInteractionInProgress()).toBeTruthy();
2110+
2111+
// Reset after testing it was properly set
2112+
browserStorage.setInteractionInProgress(false);
2113+
2114+
const validatedLogoutRequest: CommonEndSessionRequest = {
2115+
correlationId: RANDOM_TEST_GUID,
2116+
postLogoutRedirectUri: TEST_URIS.TEST_REDIR_URI
2117+
};
2118+
expect(logoutUriSpy.calledWith(validatedLogoutRequest));
2119+
done();
2120+
})
20312121
});
20322122

20332123
it("errors thrown are cached for telemetry and logout failure event is raised", (done) => {
@@ -2104,7 +2194,8 @@ describe("RedirectClient", () => {
21042194
window.sessionStorage.setItem(AccountEntity.generateAccountCacheKey(testAccountInfo), JSON.stringify(testAccount));
21052195

21062196
await redirectClient.logout(validatedLogoutRequest).then(() => {
2107-
expect(window.sessionStorage.length).toBe(0);
2197+
// Interaction in progress
2198+
expect(window.sessionStorage.length).toBe(1);
21082199
});
21092200
});
21102201
});

0 commit comments

Comments
 (0)