Skip to content

Commit

Permalink
Feature/58072 mtc closed guard (#2465)
Browse files Browse the repository at this point in the history
* basic working model

* hook into dfe signin process

* tests and implementation

---------

Co-authored-by: Mohsen Qureshi <[email protected]>
  • Loading branch information
GuyHarwood and activemq authored Mar 21, 2023
1 parent 588dcba commit 1c8a95a
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 0 deletions.
24 changes: 24 additions & 0 deletions admin/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const authModes = require('./lib/consts/auth-modes')
const dfeSignInStrategy = require('./authentication/dfe-signin-strategy')
const redisCacheService = require('./services/data-access/redis-cache.service')
const { CheckWindowPhaseService } = require('./services/check-window-phase/check-window-phase.service')
const checkWindowPhaseConsts = require('./lib/consts/check-window-phase')

const logger = require('./services/log.service').getLogger()
const sqlService = require('./services/data-access/sql.service')
Expand Down Expand Up @@ -124,6 +125,7 @@ const results = require('./routes/results')
const pupilStatus = require('./routes/pupil-status')
const websiteOffline = require('./routes/website-offline')
const techSupport = require('./routes/tech-support')
const roles = require('./lib/consts/roles')

setupBrowserSecurity(app)

Expand Down Expand Up @@ -341,6 +343,22 @@ if (WEBSITE_OFFLINE) {
app.use('/tech-support', techSupport)
}

app.use(async function (req, res, next) {
try {
if (req.isAuthenticated() === false) return next()
if (!req.user) {
return next()
}
// if user is a teacher and system is unavailable, short circuit to the unavailable page
if (global.checkWindowPhase === checkWindowPhaseConsts.unavailable && req.user.role === roles.teacher) {
res.locals.pageTitle = 'The service is currently closed'
return res.render('availability/admin-window-unavailable', {})
}
} catch (error) {
next(error)
}
})

// catch 404 and forward to error handler
app.use(function (req, res, next) {
const err = new Error('Not Found')
Expand All @@ -358,6 +376,12 @@ app.use(function (err, req, res, next) {
// catch CSRF errors and redirect to the previous location
if (err.code === 'EBADCSRFTOKEN') return res.redirect('back')

// catch system unavailable errors and redirect to the relevant page
if (err.code === 'SYSTEM_UNAVAILABLE') {
res.locals.pageTitle = 'The service is currently closed'
return res.render('availability/admin-window-unavailable', {})
}

// render the error page
res.locals.message = 'An error occurred'
res.locals.userMessage = err.userMessage
Expand Down
17 changes: 17 additions & 0 deletions admin/error-types/system-unavailable-error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict'

const { mtcError } = require('./mtc-error')

class SystemUnavailableError extends mtcError {
constructor () {
const message = 'The system is unavailable at this time'
super(message)
this.name = 'SystemUnavailableError'
this.userMessage = message
this.code = 'SYSTEM_UNAVAILABLE'
}
}

module.exports = {
SystemUnavailableError
}
6 changes: 6 additions & 0 deletions admin/services/dfe-signin.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const roles = require('../lib/consts/roles')
const dfeSigninDataService = require('./data-access/dfe-signin.data.service')
const adminLogonEventDataService = require('./data-access/admin-logon-event.data.service')
const { DsiSchoolNotFoundError } = require('../error-types/DsiSchoolNotFoundError')
const checkWindowPhaseConsts = require('../lib/consts/check-window-phase')
const { SystemUnavailableError } = require('../error-types/system-unavailable-error')

const service = {
/**
Expand All @@ -34,6 +36,10 @@ const service = {
let schoolRecord
// lookup school if in teacher or headteacher role
if (dfeUser.role === roles.teacher) {
// short circuit out of this if the check window is closed
if (global.checkWindowPhase === checkWindowPhaseConsts.unavailable) {
throw new SystemUnavailableError()
}
if (dfeUser.organisation && dfeUser.organisation.urn) {
schoolRecord = await schoolDataService.sqlFindOneByUrn(dfeUser.organisation.urn)
if (!schoolRecord) {
Expand Down
9 changes: 9 additions & 0 deletions admin/spec/back-end/service/dfe-signin.service.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ let sut, schoolDataService, userDataService, roleService, dfeDataService, adminL
const token = { id_token: 'the-token' }
const config = require('../../../config')
const roles = require('../../../lib/consts/roles')
const checkWindowPhaseConsts = require('../../../lib/consts/check-window-phase')

describe('dfe-signin.service', () => {
beforeEach(() => {
Expand All @@ -15,6 +16,7 @@ describe('dfe-signin.service', () => {
roleService = require('../../../services/role.service')
dfeDataService = require('../../../services/data-access/dfe-signin.data.service')
adminLogonEventDataService = require('../../../services/data-access/admin-logon-event.data.service')
global.checkWindowPhase = checkWindowPhaseConsts.officialCheck
})

afterEach(() => {
Expand Down Expand Up @@ -46,6 +48,13 @@ describe('dfe-signin.service', () => {
.toThrowError('user.organisation or user.organisation.urn not found on dfeUser object')
})

test('throws system unavailable error if teacher logging on when system is not available', async () => {
jest.spyOn(dfeDataService, 'getDfeRole').mockResolvedValue('mtc_teacher')
jest.spyOn(roleService, 'findByTitle').mockResolvedValue({ id: 3, title: roles.teacher })
global.checkWindowPhase = checkWindowPhaseConsts.unavailable
await expect(sut.initialiseUser({ organisation: { urn: 12345 } }, token)).rejects.toThrowError('The system is unavailable at this time')
})

test('does look up school if role is teacher', async () => {
jest.spyOn(dfeDataService, 'getDfeRole').mockResolvedValue('mtc_teacher')
jest.spyOn(roleService, 'findByTitle').mockResolvedValue({ id: 3, title: roles.teacher })
Expand Down

0 comments on commit 1c8a95a

Please sign in to comment.