diff --git a/.travis.yml b/.travis.yml index b4d533f4a5..6899dfd5cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,6 +34,7 @@ jobs: - time npm run test_services - time CYPRESS_baseUrl=http://localhost:1337/staging/ npm run cypress:record - docker ps -a + - if [[ $(docker ps --all | grep -Eo '(Exited|Restarting) \([0-9]+\)' | grep -Eo '[0-9]+' | awk '{ sum += $1 } END { print sum }') != '0' ]]; then echo 'Some process had nonzero exit code'; exit 1; fi deploy: # deploy is always skipped for PR provider: script skip_cleanup: true @@ -54,10 +55,11 @@ jobs: - time npm run test_services - time CYPRESS_baseUrl=http://localhost:1337/ npm run cypress:record - docker ps -a + - if [[ $(docker ps --all | grep -Eo '(Exited|Restarting) \([0-9]+\)' | grep -Eo '[0-9]+' | awk '{ sum += $1 } END { print sum }') != '0' ]]; then echo 'Some process had nonzero exit code'; exit 1; fi deploy: # deploy is always skipped for PR provider: script skip_cleanup: true - script: "docker-compose -f docker-compose.lateste2e.production.yml push && curl -X POST -H 'Content-type: application/json' --data \"{\\\"text\\\":\\\"${TRAVIS_TAG} release waiting for manual deployment!\\\"}\" ${SLACKBOT_URL}" + script: "docker-compose -f docker-compose.lateste2e.production.yml push && curl -X POST -H 'Content-type: application/json' --data \"{\\\"text\\\":\\\"${TRAVIS_TAG} release started auto deployment!\\\"}\" ${SLACKBOT_URL}" on: tags: true diff --git a/cypress/integration/Users.js b/cypress/integration/Users.js new file mode 100644 index 0000000000..15e8d45e99 --- /dev/null +++ b/cypress/integration/Users.js @@ -0,0 +1,39 @@ + +describe('Users tests', () => { + beforeEach(() => { + cy.server({ + onAnyRequest: function (route, proxy) { + if (Cypress.config().baseUrl.includes("http://localhost:1337/")) { + proxy.xhr.setRequestHeader('uid', 'admink') + proxy.xhr.setRequestHeader('shib-session-id', 'mock-shibboleth') + proxy.xhr.setRequestHeader('hygroupcn', 'grp-oodikone-users') + proxy.xhr.setRequestHeader('edupersonaffiliation', 'asdasd') + } + } + }) + console.log(Cypress.config().baseUrl) + cy.visit(Cypress.config().baseUrl) + cy.reload() + cy.contains("Users").click() + cy.contains("Enable or disable access to Oodikone") + }) + + it("Admin mocking normal user shows only the mocked user's programmes", () => { + cy.contains("mocking").should('not.exist') + cy.contains("tr", "Normaalikäyttäjä").within(($row) => { + cy.contains('button', 'Edit').click() + }) + cy.contains("Access rights").siblings().within(($row) => { + cy.get("div[role='listitem']").should('have.length', 1).contains("Tietojenkäsittelytieteen kandiohjelma") + }) + + cy.get('i.spy').click() + cy.contains("mocking as normk") + cy.contains("Study programme").click().siblings().contains("Search by class").click() + cy.contains("label", "Study programme") + cy.contains("label", "Study programme").siblings().within(($row) => { + cy.get("div[role='option']").should('have.length', 1).contains("Tietojenkäsittelytieteen kandiohjelma") + }) + }) + +}) diff --git a/package.json b/package.json index 0ac6ceecb9..9d6a044dff 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "cypress:open": "CYPRESS_baseUrl=http://localhost:8081 cypress open", "cypress:run": "CYPRESS_baseUrl=http://localhost:8081 cypress run --config video=false -P ./", - "cypress:record": "cypress run --config videoUploadOnPasses=false -P ./", + "cypress:record": "cypress run --config videoUploadOnPasses=false --record -P ./", "concurrently": "concurrently", "test": "./run_all_tests.sh", "test_services": "./run_service_tests.sh" diff --git a/scripts.sh b/scripts.sh index a781775ce0..77fbe13c06 100644 --- a/scripts.sh +++ b/scripts.sh @@ -57,7 +57,7 @@ get_anon_oodikone() { } unpack_oodikone_server_backup() { - bunzip2 -d -v ./$BACKUP_DIR/*.bz2 + bunzip2 --force --decompress --verbose ./$BACKUP_DIR/*.bz2 } restore_psql_from_backup () { diff --git a/services/backend/oodikone2-backend/src/routes.js b/services/backend/oodikone2-backend/src/routes.js index f3294bdf0e..6f416c840a 100644 --- a/services/backend/oodikone2-backend/src/routes.js +++ b/services/backend/oodikone2-backend/src/routes.js @@ -4,6 +4,7 @@ const courses = require('./routes/courses') const students = require('./routes/students') const population = require('./routes/population') const login = require('./routes/login') +const superlogin = require('./routes/superlogin') const language = require('./routes/language') const users = require('./routes/users') const elementdetails = require('./routes/elementdetails') @@ -25,6 +26,7 @@ module.exports = (app, url) => { app.use(url, login) app.use(url, ping) app.use(auth.checkAuth, auth.checkRequiredGroup, auth.checkUserBlacklisting, accessLogger) + app.use(`${url}/superlogin`, auth.roles(['admin']), superlogin) app.use(url, elementdetails) app.use(url, courses) app.use(url, students) diff --git a/services/backend/oodikone2-backend/src/routes/elementdetails.js b/services/backend/oodikone2-backend/src/routes/elementdetails.js index b4545ac281..3bc2c75a7b 100644 --- a/services/backend/oodikone2-backend/src/routes/elementdetails.js +++ b/services/backend/oodikone2-backend/src/routes/elementdetails.js @@ -21,7 +21,7 @@ router.get('/v2/studyprogrammes/:id/mandatory_courses', async (req, res) => { const codes = await MandatoryCourses.byStudyprogramme(req.params.id) res.json(codes) } else { - res.status(422) + res.status(422).end() } }) @@ -30,7 +30,7 @@ router.get('/v2/studyprogrammes/ping', async (req, res) => { const result = await ping() res.json(result) } catch (e) { - res.status(500) + res.status(500).end() } }) @@ -54,7 +54,7 @@ router.get('/v2/studyprogrammes/:id/productivity', async (req, res) => { } return res.json(data) } else { - res.status(422) + res.status(422).end() } }) @@ -118,7 +118,7 @@ router.get('/v2/studyprogrammes/:id/throughput', async (req, res) => { } return res.json({ ...data, thesis: await thesisPromise }) } else { - res.status(422) + res.status(422).end() } }) @@ -162,7 +162,7 @@ router.get('/v2/studyprogrammes/:id/thesis', async (req, res) => { const thesis = await findProgrammeTheses(id) res.json(thesis) } else { - res.status(422) + res.status(422).end() } }) @@ -173,7 +173,7 @@ router.post('/v2/studyprogrammes/:id/thesis', async (req, res) => { const thesis = await createThesisCourse(id, course, thesisType) res.status(201).json(thesis) } else { - res.status(422) + res.status(422).end() } }) @@ -183,8 +183,8 @@ router.delete('/v2/studyprogrammes/:id/thesis/:course', async (req, res) => { const deleted = await deleteThesisCourse(id, course) res.status(204).json(deleted) } else { - res.status(422) + res.status(422).end() } }) -module.exports = router \ No newline at end of file +module.exports = router diff --git a/services/backend/oodikone2-backend/src/routes/login.js b/services/backend/oodikone2-backend/src/routes/login.js index 3f03d8f30b..faf1464d39 100644 --- a/services/backend/oodikone2-backend/src/routes/login.js +++ b/services/backend/oodikone2-backend/src/routes/login.js @@ -27,7 +27,7 @@ router.post('/login', async (req, res) => { const mail = req.headers.mail || '' const hyGroups = parseHyGroups(req.headers['hygroupcn']) const affiliations = parseHyGroups(req.headers['edupersonaffiliation']) - + console.log(uid, 'trying to login, referring to userservice.') let { token, isNew } = await userService.login(uid, full_name, hyGroups, affiliations, mail) isNew && sendEmail(uid) @@ -44,26 +44,6 @@ router.post('/login', async (req, res) => { } }) -router.post('/superlogin/:uid', async (req, res) => { - try { - const asUser = req.params.uid - const uid = req.headers['uid'] - if (req.headers['shib-session-id'] && uid) { - console.log('super') - const token = await userService.superlogin(uid, asUser) - res.status(200).json({ token }) - } else { - res.status(401).json({ - message: `Not enough headers login, uid: - ${req.headers.uid} session-id ${req.headers['shib-session-id']}` - }).end() - } - } catch (err) { - console.log(err) - res.status(401).json({ message: 'problem with login', err }) - } -}) - router.delete('/logout', async (req, res) => { try { const logoutUrl = req.headers.shib_logout_url diff --git a/services/backend/oodikone2-backend/src/routes/population.js b/services/backend/oodikone2-backend/src/routes/population.js index 9a6d6ac4c3..0364145e5d 100644 --- a/services/backend/oodikone2-backend/src/routes/population.js +++ b/services/backend/oodikone2-backend/src/routes/population.js @@ -62,7 +62,7 @@ router.get('/v3/populationstatistics', async (req, res) => { if (result.error) { console.log(result.error) - res.status(400) + res.status(400).end() return } diff --git a/services/backend/oodikone2-backend/src/routes/superlogin.js b/services/backend/oodikone2-backend/src/routes/superlogin.js new file mode 100644 index 0000000000..574a314cc2 --- /dev/null +++ b/services/backend/oodikone2-backend/src/routes/superlogin.js @@ -0,0 +1,24 @@ +const router = require('express').Router() +const userService = require('../services/userService') + +router.post('/:uid', async (req, res) => { + try { + const asUser = req.params.uid + const uid = req.decodedToken.mockedBy == null ? req.headers['uid'] : req.decodedToken.mockedBy + if (req.headers['shib-session-id'] && uid) { + console.log('super') + const token = await userService.superlogin(uid, asUser) + res.status(200).json({ token }) + } else { + res.status(401).json({ + message: `Not enough headers login, uid: + ${req.headers.uid} session-id ${req.headers['shib-session-id']}` + }).end() + } + } catch (err) { + console.log(err.message) + res.status(401).json({ message: 'problem with login', err: err.message }) + } +}) + +module.exports = router diff --git a/services/oodikone2-frontend/src/apiConnection/index.js b/services/oodikone2-frontend/src/apiConnection/index.js index ac8ee96dc2..74a8d4a6a8 100644 --- a/services/oodikone2-frontend/src/apiConnection/index.js +++ b/services/oodikone2-frontend/src/apiConnection/index.js @@ -72,19 +72,6 @@ export const login = async () => { return response.data.token } -export const superLogin = async (uid) => { - let options = null - if (isDevEnv) { - options = devOptions - } - if (isTestEnv) { - options = testOptions - } - const response = await getAxios().post(`/superlogin/${uid}`, null, options) - console.log(`Setting new token ${response.data.token}`) - await setToken(response.data.token) -} - export const returnToSelf = async () => { const token = await login() await setToken(token) @@ -115,6 +102,12 @@ export const callApi = async (url, method = 'get', data, params, timeout = 0) => } } +export const superLogin = async (uid) => { + const response = await callApi(`/superlogin/${uid}`, 'post') + console.log(`Setting new token ${response.data.token}`) + await setToken(response.data.token) +} + export const callController = (route, prefix, data, method = 'get', query, params) => { const requestSettings = { route, diff --git a/services/oodikone2-frontend/src/components/EnableUsers/index.jsx b/services/oodikone2-frontend/src/components/EnableUsers/index.jsx index c60f610f03..f0b0c76ba9 100644 --- a/services/oodikone2-frontend/src/components/EnableUsers/index.jsx +++ b/services/oodikone2-frontend/src/components/EnableUsers/index.jsx @@ -158,11 +158,8 @@ class EnableUsers extends Component { title: '', getRowVal: user => ( - ), diff --git a/services/oodikone2-frontend/src/components/UserPage/index.jsx b/services/oodikone2-frontend/src/components/UserPage/index.jsx index 8aa8b061a5..c294515663 100644 --- a/services/oodikone2-frontend/src/components/UserPage/index.jsx +++ b/services/oodikone2-frontend/src/components/UserPage/index.jsx @@ -153,7 +153,7 @@ class UserPage extends Component { { this.props.isAdmin && user.is_enabled && ( } + trigger={