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

chore: amend gateway changes with scopes #7899

Merged
merged 8 commits into from
Nov 11, 2024
Merged
8 changes: 7 additions & 1 deletion packages/gateway/src/config/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from '@gateway/features/eventNotification/eventNotificationHandler'
import { ServerRoute } from '@hapi/hapi'
import { authProxy, catchAllProxy, rateLimitedAuthProxy } from './proxies'
import { SCOPES } from '@opencrvs/commons/authentication'
import sendVerifyCodeHandler, {
requestSchema,
responseSchema
Expand Down Expand Up @@ -51,7 +52,12 @@ export const getRoutes = () => {
tags: ['api'],
description: 'Create a health notification',
auth: {
scope: ['declare', 'notification-api']
scope: [
SCOPES.RECORD_DECLARE_BIRTH,
SCOPES.RECORD_DECLARE_DEATH,
SCOPES.RECORD_DECLARE_MARRIAGE,
SCOPES.NOTIFICATION_API
]
},
validate: {
payload: fhirBundleSchema,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import fetch from '@gateway/fetch'
import { inScope } from '@gateway/features/user/utils'
import { GQLResolver } from '@gateway/graphql/schema'
import { USER_MANAGEMENT_URL } from '@gateway/constants'
import { SCOPES } from '@gateway/../../commons/build/dist/scopes'

export const resolvers: GQLResolver = {
Mutation: {
Expand All @@ -21,7 +22,12 @@ export const resolvers: GQLResolver = {
{ headers: authHeader }
) {
// Only registrar or registration agent should be able to search user
if (!inScope(authHeader, ['register', 'validate'])) {
if (
!inScope(authHeader, [
SCOPES.RECORD_REGISTER,
SCOPES.RECORD_SUBMIT_FOR_APPROVAL
])
) {
return await Promise.reject(
new Error(
'Advanced search is only allowed for registrar or registration agent'
Expand Down Expand Up @@ -54,7 +60,12 @@ export const resolvers: GQLResolver = {
{ headers: authHeader }
) {
// Only registrar or registration agent should be able to search user
if (!inScope(authHeader, ['register', 'validate'])) {
if (
!inScope(authHeader, [
SCOPES.RECORD_REGISTER,
SCOPES.RECORD_SUBMIT_FOR_APPROVAL
])
) {
return await Promise.reject(
new Error(
'Advanced search is only allowed for registrar or registration agent'
Expand Down
22 changes: 14 additions & 8 deletions packages/gateway/src/features/correction/root-resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
requestRegistrationCorrection
} from '@gateway/workflow'
import { UserInputError } from 'apollo-server-hapi'
import { SCOPES } from '@gateway/../../commons/build/dist/scopes'

export const resolvers: GQLResolver = {
Mutation: {
Expand All @@ -39,7 +40,12 @@ export const resolvers: GQLResolver = {
{ id, details },
{ headers: authHeader }
) {
if (inScope(authHeader, ['register', 'validate'])) {
if (
inScope(authHeader, [
SCOPES.RECORD_REGISTER,
SCOPES.RECORD_SUBMIT_FOR_APPROVAL
])
) {
const hasAssignedToThisUser = await checkUserAssignment(id, authHeader)
if (!hasAssignedToThisUser) {
throw new UnassignError('User has been unassigned')
Expand All @@ -56,7 +62,7 @@ export const resolvers: GQLResolver = {
{ id, details },
{ headers: authHeader }
) {
if (inScope(authHeader, ['register'])) {
if (inScope(authHeader, [SCOPES.RECORD_REGISTER])) {
const hasAssignedToThisUser = await checkUserAssignment(id, authHeader)
if (!hasAssignedToThisUser) {
throw new UnassignError('User has been unassigned')
Expand All @@ -72,7 +78,7 @@ export const resolvers: GQLResolver = {
{ id, details },
{ headers: authHeader }
) {
if (inScope(authHeader, ['register'])) {
if (inScope(authHeader, [SCOPES.RECORD_REGISTER])) {
const hasAssignedToThisUser = await checkUserAssignment(id, authHeader)
if (!hasAssignedToThisUser) {
throw new UnassignError('User has been unassigned')
Expand All @@ -92,7 +98,7 @@ export const resolvers: GQLResolver = {
{ id, details },
{ headers: authHeader }
) {
if (inScope(authHeader, ['register'])) {
if (inScope(authHeader, [SCOPES.RECORD_REGISTER])) {
const hasAssignedToThisUser = await checkUserAssignment(id, authHeader)
if (!hasAssignedToThisUser) {
throw new UnassignError('User has been unassigned')
Expand All @@ -112,7 +118,7 @@ export const resolvers: GQLResolver = {
{ id, details },
{ headers: authHeader }
) {
if (inScope(authHeader, ['register'])) {
if (inScope(authHeader, [SCOPES.RECORD_REGISTER])) {
const hasAssignedToThisUser = await checkUserAssignment(id, authHeader)
if (!hasAssignedToThisUser) {
throw new UnassignError('User has been unassigned')
Expand All @@ -132,7 +138,7 @@ export const resolvers: GQLResolver = {
{ id, details },
{ headers: authHeader }
) {
if (inScope(authHeader, ['register'])) {
if (inScope(authHeader, [SCOPES.RECORD_REGISTER])) {
const hasAssignedToThisUser = await checkUserAssignment(id, authHeader)
if (!hasAssignedToThisUser) {
throw new UnassignError('User has been unassigned')
Expand All @@ -152,7 +158,7 @@ export const resolvers: GQLResolver = {
{ id, details },
{ headers: authHeader }
) {
if (inScope(authHeader, ['register'])) {
if (inScope(authHeader, [SCOPES.RECORD_REGISTER])) {
const hasAssignedToThisUser = await checkUserAssignment(id, authHeader)
if (!hasAssignedToThisUser) {
throw new UnassignError('User has been unassigned')
Expand All @@ -172,7 +178,7 @@ export const resolvers: GQLResolver = {
{ id, details },
{ headers: authHeader }
) {
if (inScope(authHeader, ['register'])) {
if (inScope(authHeader, [SCOPES.RECORD_REGISTER])) {
const hasAssignedToThisUser = await checkUserAssignment(id, authHeader)
if (!hasAssignedToThisUser) {
throw new UnassignError('User has been unassigned')
Expand Down
5 changes: 4 additions & 1 deletion packages/gateway/src/features/metrics/root-resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { GQLResolver } from '@gateway/graphql/schema'

import { inScope } from '@gateway/features/user/utils'
import { getMetrics } from './service'
import { SCOPES } from '@opencrvs/commons/authentication'

export interface IMetricsParam {
timeStart?: string
Expand Down Expand Up @@ -61,7 +62,9 @@ export const resolvers: GQLResolver = {
},
async getVSExports(_, variables, { headers: authHeader }) {
let results
if (inScope(authHeader, ['natlsysadmin', 'performance'])) {
if (
inScope(authHeader, [SCOPES.CONFIG_UPDATE_ALL, SCOPES.PERFORMANCE_READ])
) {
results = await getMetrics('/fetchVSExport', variables, authHeader)
return {
results
Expand Down
14 changes: 8 additions & 6 deletions packages/gateway/src/features/notification/root-resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
import { GQLNotificationType, GQLResolver } from '@gateway/graphql/schema'
import { inScope } from '@gateway/features/user/utils'
import { sendEmailToAllUsers } from './service'
import { unauthorized } from '@hapi/boom'

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
Expand All @@ -13,14 +8,21 @@ import { unauthorized } from '@hapi/boom'
*
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/

import { GQLNotificationType, GQLResolver } from '@gateway/graphql/schema'
import { inScope } from '@gateway/features/user/utils'
import { sendEmailToAllUsers } from './service'
import { unauthorized } from '@hapi/boom'
import { SCOPES } from '@opencrvs/commons/authentication'

export const resolvers: GQLResolver = {
Query: {
async sendNotificationToAllUsers(
_: any,
{ subject, body, type, locale },
{ headers: authHeader }
) {
if (!inScope(authHeader, ['natlsysadmin'])) {
if (!inScope(authHeader, [SCOPES.CONFIG_UPDATE_ALL])) {
throw unauthorized(
'Sending mass notification is only allowed for national system admin'
)
Expand Down
160 changes: 0 additions & 160 deletions packages/gateway/src/features/registration/root-resolvers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,6 @@ const certifyToken = jwt.sign(
}
)

const sysAdminToken = jwt.sign(
{ scope: ['sysadmin'] },
readFileSync('./test/cert.key'),
{
algorithm: 'RS256',
issuer: 'opencrvs:auth-service',
audience: 'opencrvs:gateway-user'
}
)

const authHeaderRegCert = {
Authorization: `Bearer ${registerCertifyToken}`
}
Expand All @@ -88,14 +78,6 @@ const authHeaderNotRegCert = {
Authorization: `Bearer ${declareToken}`
}

const authHeaderSysAdmin = {
Authorization: `Bearer ${sysAdminToken}`
}

const authHeaderNotSysAdmin = {
Authorization: `Bearer ${declareToken}`
}

const mockUserDetails = {
_id: 'ba7022f0ff4822',
name: [
Expand Down Expand Up @@ -177,148 +159,6 @@ beforeEach(() => {
})

describe('Registration root resolvers', () => {
describe('searchBirthRegistrations()', () => {
it('throws an error if the user does not have sysadmin scope', async () => {
return expect(
resolvers.Query!.searchBirthRegistrations(
{},
{
fromDate: new Date('05 October 2011 14:48 UTC'),
toDate: new Date('05 October 2012 14:48 UTC')
},
authHeaderNotSysAdmin
)
).rejects.toThrowError('User does not have a sysadmin scope')
})

it('returns an array of records', async () => {
fetch.mockResponses(
[
JSON.stringify({
entry: [
{
resource: {
id: '0411ff3d-78a4-4348-8eb7-b023a0ee6dce',
type: {
coding: [
{
code: 'birth-declaration'
}
]
}
}
}
]
}),
{ status: 200 }
],
[
JSON.stringify({
entry: [
{
resource: {
id: '0411ff3d-78a4-4348-8eb7-b023a0ee6dce',
type: {
coding: [
{
code: 'birth-declaration'
}
]
}
}
}
]
}),
{ status: 200 }
]
)

const compositions = await resolvers.Query!.searchBirthRegistrations(
{},
{
fromDate: new Date('05 October 2011 14:48 UTC'),
toDate: new Date('05 October 2012 14:48 UTC')
},
{ headers: authHeaderSysAdmin }
)

expect(compositions[0].entry[0].resource.id).toBe(
'0411ff3d-78a4-4348-8eb7-b023a0ee6dce'
)
})
})

describe('searchDeathRegistrations()', () => {
it('throws an error if the user does not have sysadmin scope', async () => {
return expect(
resolvers.Query!.searchDeathRegistrations(
{},
{
fromDate: new Date('05 October 2011 14:48 UTC'),
toDate: new Date('05 October 2012 14:48 UTC')
},
authHeaderNotSysAdmin
)
).rejects.toThrowError('User does not have a sysadmin scope')
})

it('returns an array of records', async () => {
fetch.mockResponses(
[
JSON.stringify({
entry: [
{
resource: {
id: '0411ff3d-78a4-4348-8eb7-b023a0ee6dce',
type: {
coding: [
{
code: 'death-declaration'
}
]
}
}
}
]
}),
{ status: 200 }
],
[
JSON.stringify({
entry: [
{
resource: {
id: '0411ff3d-78a4-4348-8eb7-b023a0ee6dce',
type: {
coding: [
{
code: 'death-declaration'
}
]
}
}
}
]
}),
{ status: 200 }
]
)

const compositions = await resolvers.Query!.searchDeathRegistrations(
{},
{
fromDate: new Date('05 October 2011 14:48 UTC'),
toDate: new Date('05 October 2012 14:48 UTC')
},
{ headers: authHeaderSysAdmin }
)

expect(compositions[0].entry[0].resource.id).toBe(
'0411ff3d-78a4-4348-8eb7-b023a0ee6dce'
)
})
})

describe('fetchBirthRegistration()', () => {
it('returns the record in the OpenCRVS format', async () => {
const mockTaskOfComposition = JSON.stringify({
Expand Down
Loading
Loading