Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue381 #382

Merged
merged 9 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ue-auth",
"altName": "UE-Auth",
"version": "1.41.3",
"version": "1.42.6",
"description": "UE Auth is a multi-tenant OIDC Provider, User Management, B2B Product Access, and Roles/Permissions Management system intended to create a single hybrid solution to serve as Identity and Access for both self-registered B2C Apps and Enterprise B2B Solutions",
"private": false,
"license": "SEE LICENSE IN ./LICENSE.md",
Expand Down
2 changes: 1 addition & 1 deletion src/api/accounts/accountOidcInterface.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class Account {
if(checkTimeout) throw undefined;
}
if(await account.verifyPassword(password)) {
return { accountId: account.id, mfaEnabled: account.mfa.enabled };
return { accountId: account.id, mfaEnabled: account.mfa.enabled, email: account.email };
} else {
if(thresholds === true) {
try {
Expand Down
2 changes: 1 addition & 1 deletion src/api/accounts/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ const api = {
try {
if(!req.authGroup) throw Boom.forbidden();
if(!req.query.lookup) throw Boom.badRequest('Username, email or phone is required');
const user = await acct.getAccountByEmailUsernameOrPhone(req.authGroup.id, req.query.lookup);
const user = await acct.getAccountByEmailUsernameOrPhone(req.authGroup.id, decodeURIComponent(req.query.lookup));
if(!user) throw Boom.notFound(req.query.lookup);
if(req.query.state) {
try {
Expand Down
10 changes: 9 additions & 1 deletion src/api/oidc/interactions/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,11 +378,18 @@ const api = {
authGroup: authGroup.id,
providerKey: req.body.providerKey
});
//need the email address for the display name
account = {
accountId: status.accountId,
mfaEnabled: true,
mfaProven: true
};
try {
const user = await acc.getAccount(authGroup.id, status?.accountId);
account.email = user?.email
} catch (e) {
console.error('unable to look up the user for a display email');
}
}
} else{
// in v7 this is referred to as findByLogin
Expand Down Expand Up @@ -443,11 +450,12 @@ const api = {
try {
await challenges.revokeAllDevices(authGroup, req.globalSettings, account);
bindData = await challenges.bindUser(authGroup, req.globalSettings, account);
instructions = await challenges.bindInstructions(authGroup, req.globalSettings, bindData);
instructions = await challenges.bindInstructions(authGroup, req.globalSettings, bindData, account?.email);
} catch (error) {
console.error(error);
}
if(!bindData || !instructions) throw Boom.badRequest(`The ${authGroup.name} platform now requires MFA to be enabled. We attempted to automatically do this for you but ran into an issue accessing the MFA provider. Please try again later and if the issue continues, contact the administrator.`);
// todo - evaluate if this is the right place for the mfa update on the user record.
const enableMFA = await acc.enableMFA(authGroup.id, account.accountId);
if(enableMFA !== true) throw Boom.badRequest(`The ${authGroup.name} platform now requires MFA to be enabled. We attempted to automatically do this for you but ran into an issue accessing your account. Please contact the administrator.`);
const client = await provider.Client.find(params.client_id);
Expand Down
10 changes: 8 additions & 2 deletions src/api/plugins/challenge/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,13 @@ export default {

// if not, create a onetime use access token and
// send with instructions to request email or device confirmation
try {
await acct.sendAccountLockNotification(authGroup, account, req.globalSettings);
} catch (e) {
console.error(e?.data || e?.message || e);
if(config.ENV === 'production') throw Boom.failedDependency('Unable to send lock notification - there may be a security issue.')
}

await acct.sendAccountLockNotification(authGroup, account, req.globalSettings);
const meta = {
sub: req.user.id || req.user.sub,
email: req.user.email,
Expand Down Expand Up @@ -332,10 +337,11 @@ async function bindAndSendInstructions(req, mfaAcc, account) {
console.error(e);
throw Boom.failedDependency('Unable to set MFA for this account. Please try again later.');
}
// todo - evaluate whether there is a better time to do this in the process.
const update = await acc.enableMFA(authGroup.id, account.id);
if(!update || !bindData) {
throw Boom.failedDependency('Unable to set MFA for this account. Please try again later.');
}
const instructions = await challenge.bindInstructions(authGroup, req.globalSettings, bindData);
const instructions = await challenge.bindInstructions(authGroup, req.globalSettings, bindData, account.email);
return { ...instructions, warnings };
}
4 changes: 2 additions & 2 deletions src/api/plugins/challenge/challenge.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ async function interfaceSelector(ag, global) {
}

const chApi = {
async bindInstructions(ag, global, bindData) {
async bindInstructions(ag, global, bindData, displayName) {
const { pInterface, provider } = await interfaceSelector(ag, global);
if(pInterface) return pInterface.bindInstructions(provider, bindData);
if(pInterface) return pInterface.bindInstructions(provider, bindData, displayName);
return undefined;
},
async devices(ag, global, account) {
Expand Down
3 changes: 2 additions & 1 deletion src/api/plugins/challenge/http-proxy/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import events from '../eventProcessor';
const config = require('../../../../config');

const httpProxyApi = {
async bindInstructions(provider, bindData) {
async bindInstructions(provider, bindData, displayName) {
const instructions = provider?.proxyEnableInstructions.replace(/</g, '&lt;').replace(/>/g, '&gt;').split('--');
const out = {
instructions,
displayName,
setupScreen: `${provider.proxyEnableScreen}?`,
setupScreenButtonText: provider.proxyEnableScreenButtonText,
qrCode: bindData.qrCode || false
Expand Down
31 changes: 7 additions & 24 deletions src/api/plugins/challenge/privakey/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const APP_LINKS = {

const pkApi = {
returnAPI: API,
async bindInstructions(provider, bindData) {
async bindInstructions(provider, bindData, displayName) {
const instructions = [
`Download the AuthWallet app, available on <a target='_blank' href='${APP_LINKS.android}'>Google Play</a> and the <a target='_blank' href="${APP_LINKS.ios}">App Store.</a>`,
'Open the app on your device and select to Add Service.',
Expand All @@ -42,6 +42,10 @@ const pkApi = {
bindData.appSpaceGuid
}&appSpaceName=${
bindData.appSpaceName
}&privakeyId=${
bindData.privakeyId
}&displayName=${
displayName
}`
};
},
Expand Down Expand Up @@ -100,7 +104,8 @@ const pkApi = {
}
};
const pkey = await axios(options);
if(!pkey?.data?.sessionToken || !pkey?.data?.appSpaceGuid || !pkey?.data?.appSpaceName) {
if(!pkey?.data?.sessionToken || !pkey?.data?.appSpaceGuid ||
!pkey?.data?.appSpaceName || !pkey?.data?.privakeyId) {
console.error(pkey);
throw Boom.failedDependency('Bind request unsuccessful');
}
Expand Down Expand Up @@ -132,29 +137,7 @@ const pkApi = {
output.accountId = data.accountId;
return output;
},
/*
async finishWebAuthNReq(event, accountId, credential) {
hide(flashContainer);
event.preventDefault();
const options = {
method: 'post',
url: `${domain}/api/${authGroupId}/webauthn/finish`,
headers: {
Authorization: `bearer ${token}`
},
data: {
accountId,
credential
}
};
showSpinner();
const result = await axios(options);
hideSpinner();
if(result?.data?.data?.success !== true) throw new Error('not logged in');
return result.data.data;
},

*/
async finishAuth(provider, authGroup, data) {
//ignoring provider parameter for this implementation
const options = {
Expand Down
3 changes: 1 addition & 2 deletions views/challenge/recovermfa.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ window.addEventListener( 'load', async function () {
if(!username) throw 'Email required';
const options = {
method: 'get',
url: `${domain}/api/${authGroupId}/account/login/options?lookup=${username}&state=${state}`
url: `${domain}/api/${authGroupId}/account/login/options?lookup=${encodeURIComponent(username)}&state=${state}`
};
showSpinner();
const result = await axios(options);
Expand Down Expand Up @@ -217,7 +217,6 @@ window.addEventListener( 'load', async function () {
},
data
};
console.info(options);
const result = await axios(options);
hideSpinner()
if(result?.status === 200) {
Expand Down
2 changes: 1 addition & 1 deletion views/login/qrcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ window.addEventListener( 'load', async function () {
var qr = new QRious({
element: document.getElementById('qrcode'),
size: 500,
value: qrCode
value: qrCode.replace(/&amp;/g, '&')
});
}
})();
Expand Down
Loading
Loading