Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Personal access token middleware (#2069)
* Middleware first version * Middleware tests * Add tests * Finish middleware tests * Add type for request * Add flagresolver * Fix snapshot * Update flags and tests * Put it back as default * Update snapshot
- Loading branch information
Showing
14 changed files
with
296 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import getLogger from '../../test/fixtures/no-logger'; | ||
import { createTestConfig } from '../../test/config/test-config'; | ||
import patMiddleware from './pat-middleware'; | ||
import User from '../types/user'; | ||
|
||
let config: any; | ||
|
||
beforeEach(() => { | ||
config = { | ||
getLogger, | ||
flagResolver: { | ||
isEnabled: jest.fn().mockReturnValue(true), | ||
}, | ||
}; | ||
}); | ||
|
||
test('should not set user if unknown token', async () => { | ||
const userService = { | ||
getUserByPersonalAccessToken: jest.fn(), | ||
}; | ||
|
||
const func = patMiddleware(config, { userService }); | ||
|
||
const cb = jest.fn(); | ||
|
||
const req = { | ||
header: jest.fn().mockReturnValue('user:some-token'), | ||
user: undefined, | ||
}; | ||
|
||
await func(req, undefined, cb); | ||
|
||
expect(cb).toHaveBeenCalled(); | ||
expect(req.header).toHaveBeenCalled(); | ||
expect(req.user).toBeFalsy(); | ||
}); | ||
|
||
test('should not set user if token wrong format', async () => { | ||
const userService = { | ||
getUserByPersonalAccessToken: jest.fn(), | ||
}; | ||
|
||
const func = patMiddleware(config, { userService }); | ||
|
||
const cb = jest.fn(); | ||
|
||
const req = { | ||
header: jest.fn().mockReturnValue('token-not-starting-with-user'), | ||
user: undefined, | ||
}; | ||
|
||
await func(req, undefined, cb); | ||
|
||
expect(userService.getUserByPersonalAccessToken).not.toHaveBeenCalled(); | ||
expect(cb).toHaveBeenCalled(); | ||
expect(req.header).toHaveBeenCalled(); | ||
expect(req.user).toBeFalsy(); | ||
}); | ||
|
||
test('should add user if known token', async () => { | ||
const apiUser = new User({ | ||
id: 44, | ||
username: 'my-user', | ||
}); | ||
const userService = { | ||
getUserByPersonalAccessToken: jest.fn().mockReturnValue(apiUser), | ||
}; | ||
|
||
const func = patMiddleware(config, { userService }); | ||
|
||
const cb = jest.fn(); | ||
|
||
const req = { | ||
header: jest.fn().mockReturnValue('user:some-known-token'), | ||
user: undefined, | ||
path: '/api/client', | ||
}; | ||
|
||
await func(req, undefined, cb); | ||
|
||
expect(cb).toHaveBeenCalled(); | ||
expect(req.header).toHaveBeenCalled(); | ||
expect(req.user).toBe(apiUser); | ||
}); | ||
|
||
test('should not add user if disabled', async () => { | ||
const apiUser = new User({ | ||
id: 44, | ||
username: 'my-user', | ||
}); | ||
const userService = { | ||
getUserByPersonalAccessToken: jest.fn().mockReturnValue(apiUser), | ||
}; | ||
|
||
const disabledConfig = createTestConfig({ | ||
getLogger, | ||
experimental: { | ||
flags: { | ||
personalAccessTokens: false, | ||
}, | ||
}, | ||
}); | ||
|
||
const func = patMiddleware(disabledConfig, { userService }); | ||
|
||
const cb = jest.fn(); | ||
|
||
const req = { | ||
header: jest.fn().mockReturnValue('user:some-known-token'), | ||
user: undefined, | ||
}; | ||
|
||
await func(req, undefined, cb); | ||
|
||
expect(cb).toHaveBeenCalled(); | ||
expect(req.user).toBeFalsy(); | ||
}); | ||
|
||
test('should call next if userService throws exception', async () => { | ||
getLogger.setMuteError(true); | ||
const userService = { | ||
getUserByPersonalAccessToken: () => { | ||
throw new Error('Error occurred'); | ||
}, | ||
}; | ||
|
||
const func = patMiddleware(config, { userService }); | ||
|
||
const cb = jest.fn(); | ||
|
||
const req = { | ||
header: jest.fn().mockReturnValue('user:some-token'), | ||
user: undefined, | ||
}; | ||
|
||
await func(req, undefined, cb); | ||
|
||
expect(cb).toHaveBeenCalled(); | ||
getLogger.setMuteError(false); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { IUnleashConfig } from '../types'; | ||
import { IAuthRequest } from '../routes/unleash-types'; | ||
|
||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ | ||
const patMiddleware = ( | ||
{ | ||
getLogger, | ||
flagResolver, | ||
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>, | ||
{ userService }: any, | ||
): any => { | ||
const logger = getLogger('/middleware/pat-middleware.ts'); | ||
logger.debug('Enabling PAT middleware'); | ||
|
||
if (!flagResolver.isEnabled('personalAccessTokens')) { | ||
return (req, res, next) => next(); | ||
} | ||
|
||
return async (req: IAuthRequest, res, next) => { | ||
try { | ||
const apiToken = req.header('authorization'); | ||
if (apiToken?.startsWith('user:')) { | ||
const user = await userService.getUserByPersonalAccessToken( | ||
apiToken, | ||
); | ||
req.user = user; | ||
} | ||
} catch (error) { | ||
logger.error(error); | ||
} | ||
next(); | ||
}; | ||
}; | ||
|
||
export default patMiddleware; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.