diff --git a/src/oidc.js b/src/oidc.js index 0ab8d20b8..1ef4cd1fe 100644 --- a/src/oidc.js +++ b/src/oidc.js @@ -391,7 +391,7 @@ function renderInteractionPage(provider) { if (app) { options.name = app.label || app.fqdn; - // options.iconUrl = app.iconUrl; + options.iconUrl = app.iconUrl; } return res.render('login', options); @@ -409,7 +409,7 @@ function renderInteractionPage(provider) { const user = await users.get(session.accountId); options.name = app.label || app.fqdn; - // options.iconUrl = app.iconUrl; + options.iconUrl = app.iconUrl; options.hasAccess = apps.canAccess(app, user); } else { options.hasAccess = true; @@ -451,9 +451,9 @@ function interactionLogin(provider) { const [verifyError, user] = await safe(verifyFunc(username, password, users.AP_WEBADMIN, { totpToken })); if (verifyError && verifyError.reason === BoxError.INVALID_CREDENTIALS) return next(new HttpError(401, verifyError.message)); - if (verifyError && verifyError.reason === BoxError.NOT_FOUND) return next(new HttpError(401, 'Unauthorized')); + if (verifyError && verifyError.reason === BoxError.NOT_FOUND) return next(new HttpError(401, 'Username and password does not match')); if (verifyError) return next(new HttpError(500, verifyError)); - if (!user) return next(new HttpError(401, 'Unauthorized')); + if (!user) return next(new HttpError(401, 'Username and password does not match')); // TODO we may have to check what else the Account class provides, in which case we have to map those things const result = { @@ -728,6 +728,7 @@ async function start() { app.get (`${ROUTE_PREFIX}/interaction/:uid/abort`, setNoCache, interactionAbort(provider)); app.use(ROUTE_PREFIX, provider.callback()); + app.use(middleware.lastMile()); await util.promisify(gHttpServer.listen.bind(gHttpServer))(constants.OIDC_PORT, '127.0.0.1'); } diff --git a/src/oidc_templates/login.ejs b/src/oidc_templates/login.ejs index e953e4e31..d328e66c4 100644 --- a/src/oidc_templates/login.ejs +++ b/src/oidc_templates/login.ejs @@ -71,10 +71,12 @@
+

+

@@ -89,6 +91,9 @@ document.getElementById('loginForm').addEventListener('submit', function (event) { event.preventDefault(); + document.getElementById('passwordError').innerText = ''; + document.getElementById('totpError').innerText = ''; + var apiUrl = '<%= submitUrl %>'; console.log('submit', apiUrl); @@ -98,19 +103,37 @@ document.getElementById('loginForm').addEventListener('submit', function (event) totpToken: document.getElementById('inputTotpToken').value }; + let res; fetch(apiUrl, { method: 'POST', body: JSON.stringify(body), headers: { 'Content-type': 'application/json; charset=UTF-8' } }).then(function (response) { - if (response.ok) return response.json(); - return Promise.reject(response); + res = response; + return res.json(); // we always return objects }).then(function (data) { + console.log(res, data); + if (res.status === 401) { + if (data.message === 'Username and password does not match') { + document.getElementById('inputPassword').value = ''; + document.getElementById('inputPassword').focus(); + document.getElementById('passwordError').innerText = 'Invalid username or password'; + } else if (data.message.indexOf('totpToken') !== -1) { + document.getElementById('inputTotpToken').value = ''; + document.getElementById('inputTotpToken').focus(); + document.getElementById('totpError').innerText = 'Missing or invalid 2FA Token'; + } else { + throw new Error('Something went wrong'); + } + } else if (res.status !== 200) { + throw new Error('Something went wrong'); + } + if (data.redirectTo) window.location.href = data.redirectTo; else console.log('login success but missing redirectTo in data:', data); }).catch(function (error) { - if (error.status === 401) document.getElementById('inputPassword').value = '' - console.warn('Something went wrong.', error); + document.getElementById('passwordError').innerText = 'Unexpected error. Try again later.'; + console.warn(error, res); }); });