diff --git a/.changeset/thirty-houses-juggle.md b/.changeset/thirty-houses-juggle.md new file mode 100644 index 0000000000..c54ab5526f --- /dev/null +++ b/.changeset/thirty-houses-juggle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Pass authorization token to location service inside location api routes diff --git a/plugins/catalog-backend/src/service/createRouter.test.ts b/plugins/catalog-backend/src/service/createRouter.test.ts index a747a4cf23..205be01b42 100644 --- a/plugins/catalog-backend/src/service/createRouter.test.ts +++ b/plugins/catalog-backend/src/service/createRouter.test.ts @@ -250,8 +250,14 @@ describe('createRouter readonly disabled', () => { ]; locationService.listLocations.mockResolvedValueOnce(locations); - const response = await request(app).get('/locations'); + const response = await request(app) + .get('/locations') + .set('authorization', 'Bearer someauthtoken'); + expect(locationService.listLocations).toHaveBeenCalledTimes(1); + expect(locationService.listLocations).toHaveBeenCalledWith({ + authorizationToken: 'someauthtoken', + }); expect(response.status).toEqual(200); expect(response.body).toEqual([ { data: { id: 'foo', target: 'example.com', type: 'url' } }, @@ -259,6 +265,33 @@ describe('createRouter readonly disabled', () => { }); }); + describe('GET /locations/:id', () => { + it('happy path: gets location by id', async () => { + const location: Location = { + id: 'foo', + type: 'url', + target: 'example.com', + }; + locationService.getLocation.mockResolvedValueOnce(location); + + const response = await request(app) + .get('/locations/foo') + .set('authorization', 'Bearer someauthtoken'); + + expect(locationService.getLocation).toHaveBeenCalledTimes(1); + expect(locationService.getLocation).toHaveBeenCalledWith('foo', { + authorizationToken: 'someauthtoken', + }); + + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + id: 'foo', + target: 'example.com', + type: 'url', + }); + }); + }); + describe('POST /locations', () => { it('rejects malformed locations', async () => { const spec = { @@ -266,7 +299,10 @@ describe('createRouter readonly disabled', () => { target: 'c', } as unknown as LocationSpec; - const response = await request(app).post('/locations').send(spec); + const response = await request(app) + .post('/locations') + .set('authorization', 'Bearer someauthtoken') + .send(spec); expect(locationService.createLocation).not.toHaveBeenCalled(); expect(response.status).toEqual(400); @@ -283,10 +319,15 @@ describe('createRouter readonly disabled', () => { entities: [], }); - const response = await request(app).post('/locations').send(spec); + const response = await request(app) + .post('/locations') + .set('authorization', 'Bearer someauthtoken') + .send(spec); expect(locationService.createLocation).toHaveBeenCalledTimes(1); - expect(locationService.createLocation).toHaveBeenCalledWith(spec, false); + expect(locationService.createLocation).toHaveBeenCalledWith(spec, false, { + authorizationToken: 'someauthtoken', + }); expect(response.status).toEqual(201); expect(response.body).toEqual( expect.objectContaining({ @@ -308,10 +349,13 @@ describe('createRouter readonly disabled', () => { const response = await request(app) .post('/locations?dryRun=true') + .set('authorization', 'Bearer someauthtoken') .send(spec); expect(locationService.createLocation).toHaveBeenCalledTimes(1); - expect(locationService.createLocation).toHaveBeenCalledWith(spec, true); + expect(locationService.createLocation).toHaveBeenCalledWith(spec, true, { + authorizationToken: 'someauthtoken', + }); expect(response.status).toEqual(201); expect(response.body).toEqual( expect.objectContaining({ @@ -320,6 +364,23 @@ describe('createRouter readonly disabled', () => { ); }); }); + + describe('DELETE /locations', () => { + it('deletes the location', async () => { + locationService.deleteLocation.mockResolvedValueOnce(undefined); + + const response = await request(app) + .delete('/locations/foo') + .set('authorization', 'Bearer someauthtoken'); + + expect(locationService.deleteLocation).toHaveBeenCalledTimes(1); + expect(locationService.deleteLocation).toHaveBeenCalledWith('foo', { + authorizationToken: 'someauthtoken', + }); + + expect(response.status).toEqual(204); + }); + }); }); describe('createRouter readonly enabled', () => { @@ -397,7 +458,14 @@ describe('createRouter readonly enabled', () => { ]; locationService.listLocations.mockResolvedValueOnce(locations); - const response = await request(app).get('/locations'); + const response = await request(app) + .get('/locations') + .set('authorization', 'Bearer someauthtoken'); + + expect(locationService.listLocations).toHaveBeenCalledTimes(1); + expect(locationService.listLocations).toHaveBeenCalledWith({ + authorizationToken: 'someauthtoken', + }); expect(response.status).toEqual(200); expect(response.body).toEqual([ @@ -406,6 +474,33 @@ describe('createRouter readonly enabled', () => { }); }); + describe('GET /locations/:id', () => { + it('happy path: gets location by id', async () => { + const location: Location = { + id: 'foo', + type: 'url', + target: 'example.com', + }; + locationService.getLocation.mockResolvedValueOnce(location); + + const response = await request(app) + .get('/locations/foo') + .set('authorization', 'Bearer someauthtoken'); + + expect(locationService.getLocation).toHaveBeenCalledTimes(1); + expect(locationService.getLocation).toHaveBeenCalledWith('foo', { + authorizationToken: 'someauthtoken', + }); + + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + id: 'foo', + target: 'example.com', + type: 'url', + }); + }); + }); + describe('POST /locations', () => { it('is not allowed', async () => { const spec: LocationSpec = { @@ -413,7 +508,10 @@ describe('createRouter readonly enabled', () => { target: 'c', }; - const response = await request(app).post('/locations').send(spec); + const response = await request(app) + .post('/locations') + .set('authorization', 'Bearer someauthtoken') + .send(spec); expect(locationService.createLocation).not.toHaveBeenCalled(); expect(response.status).toEqual(403); @@ -433,10 +531,13 @@ describe('createRouter readonly enabled', () => { const response = await request(app) .post('/locations?dryRun=true') + .set('authorization', 'Bearer someauthtoken') .send(spec); expect(locationService.createLocation).toHaveBeenCalledTimes(1); - expect(locationService.createLocation).toHaveBeenCalledWith(spec, true); + expect(locationService.createLocation).toHaveBeenCalledWith(spec, true, { + authorizationToken: 'someauthtoken', + }); expect(response.status).toEqual(201); expect(response.body).toEqual( expect.objectContaining({ @@ -445,6 +546,17 @@ describe('createRouter readonly enabled', () => { ); }); }); + + describe('DELETE /locations', () => { + it('is not allowed', async () => { + const response = await request(app) + .delete('/locations/foo') + .set('authorization', 'Bearer someauthtoken'); + + expect(locationService.deleteLocation).not.toHaveBeenCalled(); + expect(response.status).toEqual(403); + }); + }); }); describe('NextRouter permissioning', () => { diff --git a/plugins/catalog-backend/src/service/createRouter.ts b/plugins/catalog-backend/src/service/createRouter.ts index fc60577141..ab123238c7 100644 --- a/plugins/catalog-backend/src/service/createRouter.ts +++ b/plugins/catalog-backend/src/service/createRouter.ts @@ -174,24 +174,32 @@ export async function createRouter( disallowReadonlyMode(readonlyEnabled); } - const output = await locationService.createLocation(input, dryRun); + const output = await locationService.createLocation(input, dryRun, { + authorizationToken: getBearerToken(req.header('authorization')), + }); res.status(201).json(output); }) - .get('/locations', async (_req, res) => { - const locations = await locationService.listLocations(); + .get('/locations', async (req, res) => { + const locations = await locationService.listLocations({ + authorizationToken: getBearerToken(req.header('authorization')), + }); res.status(200).json(locations.map(l => ({ data: l }))); }) .get('/locations/:id', async (req, res) => { const { id } = req.params; - const output = await locationService.getLocation(id); + const output = await locationService.getLocation(id, { + authorizationToken: getBearerToken(req.header('authorization')), + }); res.status(200).json(output); }) .delete('/locations/:id', async (req, res) => { disallowReadonlyMode(readonlyEnabled); const { id } = req.params; - await locationService.deleteLocation(id); + await locationService.deleteLocation(id, { + authorizationToken: getBearerToken(req.header('authorization')), + }); res.status(204).end(); }); }