Skip to content

Commit

Permalink
Merge branch 'UAT' into v1.6.0
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/resources/datarequest/datarequest.controller.js
  • Loading branch information
PaulMcCaffertyPA committed Nov 2, 2020
2 parents 2eb1449 + 3a858b3 commit f8b1cc1
Show file tree
Hide file tree
Showing 50 changed files with 5,900 additions and 1,285 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
# production
/build

/tmp

# misc
.DS_Store
npm-debug.log*
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"dependencies": {
"@google-cloud/monitoring": "^2.1.0",
"@google-cloud/storage": "^5.3.0",
"@sendgrid/mail": "^7.1.0",
"async": "^3.2.0",
"await-to-js": "^2.1.1",
Expand All @@ -20,7 +21,9 @@
"dotenv": "^8.2.0",
"esm": "^3.2.25",
"express": "^4.17.1",
"express-rate-limit": "^5.1.3",
"express-session": "^1.17.1",
"express-validator": "^6.6.1",
"googleapis": "^55.0.0",
"jose": "^2.0.2",
"jsonwebtoken": "^8.5.1",
Expand All @@ -30,6 +33,7 @@
"moment": "^2.27.0",
"mongoose": "^5.9.12",
"morgan": "^1.10.0",
"multer": "^1.4.2",
"oidc-provider": "^6.29.3",
"passport": "^0.4.1",
"passport-google-oauth": "^2.0.0",
Expand All @@ -40,6 +44,7 @@
"snyk": "^1.334.0",
"swagger-ui-express": "^4.1.4",
"test": "^0.6.0",
"uuid": "^8.3.1",
"yamljs": "^0.3.0"
},
"devDependencies": {
Expand Down
49 changes: 40 additions & 9 deletions src/config/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@ export const clients = [
client_id: process.env.MDWClientID || '',
client_secret: process.env.MDWClientSecret || '',
grant_types: ['authorization_code'],
//grant_types: ['authorization_code', 'implicit'],
response_types: ['code'],
//response_types: ['code'],
//grant_types: ['authorization_code', 'implicit'],
//response_types: ['code id_token'],
redirect_uris: process.env.MDWRedirectURI.split(",") || [''],
id_token_signed_response_alg: 'HS256'
id_token_signed_response_alg: 'HS256',
post_logout_redirect_uris: ['https://hdr.auth.metadata.works/logout','https://hdr.auth.metadata.works/auth/logout','http://localhost:8080/logout','http://localhost:8080/auth/logout']
},
{
//BC Platforms
client_id: process.env.BCPClientID || '',
client_secret: process.env.BCPClientSecret || '',
grant_types: ['authorization_code'],
//grant_types: ['authorization_code', 'implicit'],
response_types: ['code'],
//response_types: ['code'],
redirect_uris: [process.env.BCPRedirectURI || ''],
id_token_signed_response_alg: 'HS256'
grant_types: ['authorization_code', 'implicit'],
response_types: ['code id_token'],
redirect_uris: process.env.BCPRedirectURI.split(",") || [''],
id_token_signed_response_alg: 'HS256',
post_logout_redirect_uris: ['https://web.uatbeta.healthdatagateway.org/search?search=&logout=true']
}
];

Expand Down Expand Up @@ -63,6 +63,11 @@ export const features = {
introspection: { enabled: true },
revocation: { enabled: true },
encryption: { enabled: true },
rpInitiatedLogout: {
enabled: true,
logoutSource,
postLogoutSuccessSource
}
};

export const jwks = require('./jwks.json');
Expand All @@ -74,3 +79,29 @@ export const ttl = {
DeviceCode: 10 * 60,
RefreshToken: 1 * 24 * 60 * 60,
};

async function logoutSource(ctx, form) {
// @param ctx - koa request context
// @param form - form source (id="op.logoutForm") to be embedded in the page and submitted by
// the End-User
ctx.body = `<!DOCTYPE html>
<head>
<title>Logout Request</title>
<style>/* css and html classes omitted for brevity, see lib/helpers/defaults.js */</style>
</head>
<body>
<div>
<h1>Do you want to sign-out from ${ctx.host}?</h1>
${form}
<button autofocus type="submit" form="op.logoutForm" value="yes" name="logout">Yes, sign me out</button>
<button type="submit" form="op.logoutForm">No, stay signed in</button>
</div>
</body>
</html>`;
}

async function postLogoutSuccessSource(ctx) {
// @param ctx - koa request context
ctx.res.clearCookie('jwt');
ctx.res.status(200).redirect(process.env.homeURL+'/search?search=');
}
28 changes: 21 additions & 7 deletions src/config/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import bodyParser from 'body-parser';
import logger from 'morgan';
import passport from 'passport';
import cookieParser from 'cookie-parser';

import { connectToDatabase } from './db';
import { initialiseAuthentication } from '../resources/auth';

Expand All @@ -20,20 +19,14 @@ const Account = require('./account');
const configuration = require('./configuration');



const API_PORT = process.env.PORT || 3001;
const session = require('express-session');
var app = express();



configuration.findAccount = Account.findAccount;
const oidc = new Provider(process.env.api_url || 'http://localhost:3001', configuration);
oidc.proxy = true;




var domains = [process.env.homeURL];

var rx = /^([http|https]+:\/\/[a-z]+)\.([^/]*)/;
Expand Down Expand Up @@ -77,6 +70,20 @@ function setNoCache(req, res, next) {
next();
}

app.get('/api/v1/openid/endsession', setNoCache, (req, res, next) => {
passport.authenticate('jwt', async function (err, user, info) {
if (err || !user) {
return res.status(200).redirect(process.env.homeURL+'/search?search=');
}
oidc.Session.destory;
req.logout();
res.clearCookie('jwt');

return res.status(200).redirect(process.env.homeURL+'/search?search=');
})(req, res, next);
})


app.get('/api/v1/openid/interaction/:uid', setNoCache, (req, res, next) => {
passport.authenticate('jwt', async function (err, user, info) {

Expand Down Expand Up @@ -168,6 +175,8 @@ app.use('/api/v1/auth/register', require('../resources/user/user.register.route'
app.use('/api/v1/users', require('../resources/user/user.route'));
app.use('/api/v1/topics', require('../resources/topic/topic.route'));
app.use('/api/v1/publishers', require('../resources/publisher/publisher.route'));
app.use('/api/v1/teams', require('../resources/team/team.route'));
app.use('/api/v1/workflows', require('../resources/workflow/workflow.route'));
app.use('/api/v1/messages', require('../resources/message/message.route'));
app.use('/api/v1/reviews', require('../resources/tool/review.route'));
app.use('/api/v1/relatedobject/', require('../resources/relatedobjects/relatedobjects.route'));
Expand All @@ -181,12 +190,15 @@ app.use('/api/v1/linkchecker', require('../resources/linkchecker/linkchecker.rou
app.use('/api/v1/stats', require('../resources/stats/stats.router'));
app.use('/api/v1/kpis', require('../resources/stats/kpis.router'));

app.use('/api/v1/course', require('../resources/course/course.route'));

app.use('/api/v1/person', require('../resources/person/person.route'));

app.use('/api/v1/projects', require('../resources/project/project.route'));
app.use('/api/v1/papers', require('../resources/paper/paper.route'));
app.use('/api/v1/counter', require('../resources/tool/counter.route'));
app.use('/api/v1/coursecounter', require('../resources/course/coursecounter.route'));

app.use('/api/v1/discourse', require('../resources/discourse/discourse.route'));

app.use('/api/v1/datasets', require('../resources/dataset/dataset.route'));
Expand All @@ -198,6 +210,8 @@ app.use('/api/v1/collections', require('../resources/collections/collections.rou

app.use('/api/v1/analyticsdashboard', require('../resources/googleanalytics/googleanalytics.router'));

app.use('/api/v1/help', require('../resources/help/help.router'));

initialiseAuthentication(app);

// launch our backend into a port
Expand Down
117 changes: 72 additions & 45 deletions src/resources/auth/auth.route.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,99 @@
import express from 'express'
import { to } from 'await-to-js'
import { verifyPassword } from '../auth/utils'
import { login } from '../auth/strategies/jwt'
import { getUserByEmail } from '../user/user.repository'
import { getRedirectUrl } from '../auth/utils'
import passport from "passport";
import express from 'express';
import { to } from 'await-to-js';
import { verifyPassword } from '../auth/utils';
import { login } from '../auth/strategies/jwt';
import { getUserByEmail } from '../user/user.repository';
import { getRedirectUrl } from '../auth/utils';
import passport from 'passport';

const router = express.Router();

// @router POST /api/auth/login
// @desc login user
// @access Public
router.post('/login', async (req, res) => {
const { email, password } = req.body
const { email, password } = req.body;

const [err, user] = await to(getUserByEmail(email))
const [err, user] = await to(getUserByEmail(email));

const authenticationError = () => {
return res
.status(500)
.json({ success: false, data: "Authentication error!" })
}

if (!(await verifyPassword(password, user.password))) {
console.error('Passwords do not match')
return authenticationError()
}
const authenticationError = () => {
return res
.status(500)
.json({ success: false, data: 'Authentication error!' });
};

const [loginErr, token] = await to(login(req, user))
if (!(await verifyPassword(password, user.password))) {
console.error('Passwords do not match');
return authenticationError();
}

if (loginErr) {
console.error('Log in error', loginErr)
return authenticationError()
}
const [loginErr, token] = await to(login(req, user));

return res
.status(200)
.cookie('jwt', token, {
httpOnly: true
})
.json({
success: true,
data: getRedirectUrl(req.user.role)
})
if (loginErr) {
console.error('Log in error', loginErr);
return authenticationError();
}

return res
.status(200)
.cookie('jwt', token, {
httpOnly: true,
})
.json({
success: true,
data: getRedirectUrl(req.user.role),
});
});

// @router POST /api/auth/logout
// @desc logout user
// @access Private
router.get('/logout', function (req, res) {
req.logout();
res.clearCookie('jwt');
return res.json({ success: true });
for (var prop in req.cookies) {
res.clearCookie(prop);
}
return res.json({ success: true });
});

// @router GET /api/auth/status
// @desc Return the logged in status of the user and their role.
// @access Private
router.get('/status', function (req, res, next) {
passport.authenticate('jwt', function (err, user, info) {
if (err || !user) {
return res.json({ success: true, data: [{ role: "Reader", id: null, name: null, loggedIn: false }] });
}
else {
return res.json({ success: true, data: [{ role: req.user.role, id: req.user.id, name: req.user.firstname + " " + req.user.lastname, loggedIn: true, teams: req.user.teams }] });
}
})(req, res, next);
passport.authenticate('jwt', function (err, user, info) {
if (err || !user) {
return res.json({
success: true,
data: [{ role: 'Reader', id: null, name: null, loggedIn: false }],
});
} else {
// 1. Reformat teams array for frontend
let { teams } = req.user;
if(teams) {
teams = teams.map((team) => {
let { publisher, type, members } = team;
let member = members.find(member => {
return member.memberid.toString() === req.user._id.toString();
});
let { roles } = member;
return { ...publisher.toObject(), type, roles };
});
}
// 2. Return user info
return res.json({
success: true,
data: [
{
role: req.user.role,
id: req.user.id,
name: req.user.firstname + ' ' + req.user.lastname,
loggedIn: true,
teams,
},
],
});
}
})(req, res, next);
});
module.exports = router

module.exports = router;
3 changes: 3 additions & 0 deletions src/resources/auth/strategies/jwt.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const strategy = () => {
}

const verifyCallback = async (req, jwtPayload, cb) => {
if(typeof jwtPayload.data === 'string') {
jwtPayload.data = JSON.parse(jwtPayload.data);
}
const [err, user] = await to(getUserById(jwtPayload.data._id))

if (err) {
Expand Down
16 changes: 15 additions & 1 deletion src/resources/auth/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,20 @@ const signToken = (user) => {
)
}

const camundaToken = () => {
return jwt.sign(
// This structure must not change or the authenication between camunda and the gateway will fail
// username: An admin user the exists within the camunda-admin group
// groupIds: The admin group that has been configured on the camunda portal.
{ username: process.env.BPMN_ADMIN_USER, groupIds: ["camunda-admin"], tenantIds: []},
process.env.JWTSecret,
{ //Here change it so only id
algorithm: 'HS256',
expiresIn: 604800
}
)
}

const hashPassword = async password => {
if (!password) {
throw new Error('Password was not provided')
Expand Down Expand Up @@ -74,4 +88,4 @@ const getRedirectUrl = role => {
}
}

export { setup, signToken, hashPassword, verifyPassword, checkIsInRole, getRedirectUrl, whatIsRole }
export { setup, signToken, camundaToken, hashPassword, verifyPassword, checkIsInRole, getRedirectUrl, whatIsRole }
Loading

0 comments on commit f8b1cc1

Please sign in to comment.