MM-19096 – simplify custom login process (#1053)

* simplify custom login process

- remove need for temporarily trusting 3rd party hostname

* code review tweaks

* fix reducer

* review tweaks

* removing requirement for /login as start
This commit is contained in:
Dean Whillier
2019-10-06 18:28:38 -04:00
committed by GitHub
parent 24fdd05860
commit 2591656610

View File

@@ -372,8 +372,6 @@ function handleAppWebContentsCreated(dc, contents) {
// initialize custom login tracking // initialize custom login tracking
customLogins[contents.id] = { customLogins[contents.id] = {
inProgress: false, inProgress: false,
startingURL: null,
externalHostname: null,
}; };
contents.on('will-attach-webview', (event, webPreferences) => { contents.on('will-attach-webview', (event, webPreferences) => {
@@ -383,60 +381,35 @@ function handleAppWebContentsCreated(dc, contents) {
contents.on('will-navigate', (event, url) => { contents.on('will-navigate', (event, url) => {
const contentID = event.sender.id; const contentID = event.sender.id;
const parsedUrl = new URL(url); const parsedURL = parseURL(url);
const urlIsTrusted = isTrustedURL(parsedUrl);
const urlIsTrustedExternalLoginPath = parsedUrl.hostname === customLogins[contentID].externalHostname;
// don't prevent custom login attempts (oath, saml) if (isTrustedURL(parsedURL)) {
if (!urlIsTrusted && !urlIsTrustedExternalLoginPath) { return;
event.preventDefault();
// reset custom login if in progress
if (customLogins[contentID].inProgress) {
customLogins[contentID].inProgress = false;
customLogins[contentID].externalHostname = null;
// redirect to starting url if set
if (customLogins[contentID].startingURL) {
event.sender.loadURL(customLogins[contentID].startingURL);
customLogins[contentID].startingURL = null;
}
}
} }
if (customLogins[contentID].inProgress) {
return;
}
event.preventDefault();
}); });
// handle custom login requests (oath, saml): // handle custom login requests (oath, saml):
// 1. are we navigating to a supported local custom login path from the `/login` page? (did-start-navigation listener) // 1. are we navigating to a supported local custom login path from the `/login` page?
// - indicate custom login is in progress and store starting point for possible reset // - indicate custom login is in progress
// 2. is a custom login in progress but we don't have the 3rd party hostname yet? (will-redirect listener) // 2. are we finished with the custom login process?
// - store 3rd party hostname to trust subsequent navigation changes within that hostname // - indicate custom login is NOT in progress
// 3. are we finished with the custom login process? (did-start-navigation listener)
// - indicate custom login is NOT in progress and clear any stored 3rd party hostname's
contents.on('did-start-navigation', (event, url) => { contents.on('did-start-navigation', (event, url) => {
const contentID = event.sender.id; const contentID = event.sender.id;
const parsedUrl = new URL(url); const parsedURL = parseURL(url);
const urlIsTrusted = isTrustedURL(parsedUrl);
const urlIsCustomLoginPath = isCustomLoginURL(parsedUrl);
const previousPage = event.sender.history[event.sender.history.length - 1];
if (urlIsTrusted && urlIsCustomLoginPath && !customLogins[contentID].inProgress && previousPage.endsWith('/login')) { if (!isTrustedURL(parsedURL)) {
customLogins[contentID].inProgress = true; return;
customLogins[contentID].startingURL = event.sender.getURL();
} else if (urlIsTrusted && customLogins[contentID].inProgress && customLogins[contentID].externalHostname) {
customLogins[contentID].inProgress = false;
customLogins[contentID].externalHostname = null;
} }
});
contents.on('will-redirect', (event, url) => { if (isCustomLoginURL(parsedURL)) {
const contentID = event.sender.id; customLogins[contentID].inProgress = true;
const parsedUrl = new URL(url); } else if (customLogins[contentID].inProgress) {
const urlIsTrusted = isTrustedURL(parsedUrl); customLogins[contentID].inProgress = false;
const previousPage = event.sender.history[event.sender.history.length - 1];
const previousPageIsTrusted = isTrustedURL(previousPage);
if (!urlIsTrusted && previousPageIsTrusted && customLogins[contentID].inProgress && !customLogins[contentID].externalHostname) {
customLogins[contentID].externalHostname = parsedUrl.hostname;
} }
}); });
@@ -763,40 +736,49 @@ function handleMainWindowWebContentsCrashed() {
// helper functions // helper functions
// //
function isTrustedURL(url) { function parseURL(url) {
if (!url) { if (!url) {
return null;
}
if (url instanceof URL) {
return url;
}
try {
return new URL(url);
} catch (e) {
return null;
}
}
function isTrustedURL(url) {
const parsedURL = parseURL(url);
if (!parsedURL) {
return false; return false;
} }
const teamURLs = config.teams.reduce((urls, team) => {
let parsedUrl = url; const parsedTeamURL = parseURL(team.url);
if (typeof url === 'string') { if (parsedTeamURL) {
try { return urls.concat(parsedTeamURL);
parsedUrl = new URL(url);
} catch (e) {
return false;
} }
} return urls;
}, []);
const trustedURLs = config.teams.map((team) => new URL(team.url)); for (const teamURL of teamURLs) {
if (parsedURL.origin === teamURL.origin) {
for (const trustedURL of trustedURLs) {
if (parsedUrl.origin === trustedURL.origin) {
return true; return true;
} }
} }
return false; return false;
} }
function isCustomLoginURL(url) { function isCustomLoginURL(url) {
if (!isTrustedURL(url)) { const parsedURL = parseURL(url);
if (!parsedURL) {
return false; return false;
} }
let parsedUrl = url; if (!isTrustedURL(parsedURL)) {
if (typeof url === 'string') { return false;
parsedUrl = new URL(url);
} }
const urlPath = parsedUrl.pathname; const urlPath = parsedURL.pathname;
for (const regexPath of customLoginRegexPaths) { for (const regexPath of customLoginRegexPaths) {
if (urlPath.match(regexPath)) { if (urlPath.match(regexPath)) {
return true; return true;