Skip to content

Commit 57cdaa7

Browse files
JeanPierreNellLenbkrcshezi
authored
feat: add Auth (#95)
* feat: add Auth * refactor: assign privileges to endpoints * refactor: helper function refactorization * refactor: auth toggle variable name --------- Co-authored-by: Len Bekker <[email protected]> Co-authored-by: cshezi <[email protected]>
1 parent feea89c commit 57cdaa7

9 files changed

+196
-37
lines changed

.env.template

+3
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ VALKEY_IS_CLUSTER=false
2626
CACHE_TTL=1000
2727

2828
ACTIVE_CONDITIONS_ONLY=false
29+
30+
AUTHENTICATED=false
31+
CERT_PATH_PUBLIC=

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,6 @@ dist
131131
.pnp.*
132132

133133
build
134+
135+
#keys
136+
*.pem

Dockerfile

+3
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ ENV VALKEY_AUTH=
6767
ENV VALKEY_SERVERS=
6868
ENV VALKEY_IS_CLUSTER=
6969

70+
ENV AUTHENTICATED=false
71+
ENV CERT_PATH_PUBLIC=
72+
7073
ENV CACHE_TTL=1000
7174
ENV ACTIVE_CONDITIONS_ONLY=false
7275

package-lock.json

+97
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"@fastify/response-validation": "^2.6.0",
3636
"@fastify/swagger": "^8.8.0",
3737
"@fastify/swagger-ui": "^3.0.0",
38+
"@tazama-lf/auth-lib": "^0.0.9",
3839
"@tazama-lf/frms-coe-lib": "^4.2.0-rc.0",
3940
"ajv": "^8.16.0",
4041
"dotenv": "^16.0.3",

src/auth/authHandler.ts

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { validateTokenAndClaims } from '@tazama-lf/auth-lib';
2+
import { type FastifyReply, type FastifyRequest } from 'fastify';
3+
import { loggerService } from '..';
4+
5+
export const tokenHandler = (claim: string) => {
6+
return async (request: FastifyRequest, reply: FastifyReply): Promise<void> => {
7+
const logContext = 'tokenHandler()';
8+
const authHeader = request.headers.authorization;
9+
if (!authHeader?.startsWith('Bearer ') || !claim) {
10+
reply.code(401).send({ error: 'Unauthorized' });
11+
return;
12+
}
13+
14+
try {
15+
const token = authHeader.split(' ')[1];
16+
const validated = validateTokenAndClaims(token, [claim]);
17+
if (!validated[claim]) {
18+
reply.code(401).send({ error: 'Unauthorized' });
19+
}
20+
loggerService.log('Authenticated', logContext);
21+
} catch (error) {
22+
const err = error as Error;
23+
loggerService.error(`${err.name}: ${err.message}\n${err.stack}`, logContext);
24+
reply.code(401).send({ error: 'Unauthorized' });
25+
}
26+
};
27+
};

src/config.ts

+2
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ export interface IConfig {
2222
};
2323
db: Required<AppDatabaseServices>;
2424
cacheTTL: number;
25+
authentication: boolean;
2526
}
2627

2728
export const configuration: IConfig = {
2829
cacheTTL: parseInt(process.env.CACHE_TTL!, 10) || 1000,
2930
maxCPU: parseInt(process.env.MAX_CPU!, 10) || 1,
3031
env: process.env.NODE_ENV!,
3132
activeConditionsOnly: process.env.ACTIVE_CONDITIONS_ONLY === 'true',
33+
authentication: process.env.AUTHENTICATED === 'true',
3234
service: {
3335
port: parseInt(process.env.PORT!, 10) || 3000,
3436
host: process.env.HOST! || '127.0.0.1',

src/router.ts

+45-9
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,61 @@ import {
1111
updateAccountConditionExpiryDateHandler,
1212
updateEntityConditionExpiryDateHandler,
1313
} from './app.controller';
14-
import { SetOptionsBody, SetOptionsParams, SetOptionsBodyAndParams } from './utils/schema-utils';
14+
import { SetOptionsBodyAndParams } from './utils/schema-utils';
15+
16+
const routePrivilege = {
17+
getAccount: 'GET_V1_EVENT_FLOW_CONTROL_ACCOUNT',
18+
getEntity: 'GET_V1_EVENT_FLOW_CONTROL_ENTITY',
19+
putAccount: 'PUT_V1_EVENT_FLOW_CONTROL_ACCOUNT',
20+
putEntity: 'PUT_V1_EVENT_FLOW_CONTROL_ENTITY',
21+
postAccount: 'POST_V1_EVENT_FLOW_CONTROL_ACCOUNT',
22+
postEntity: 'POST_V1_EVENT_FLOW_CONTROL_ENTITY',
23+
putCache: 'PUT_V1_EVENT_FLOW_CONTROL_CACHE',
24+
getReport: 'GET_V1_GETREPORTBYMSGID',
25+
};
1526

1627
async function Routes(fastify: FastifyInstance): Promise<void> {
1728
fastify.get('/', handleHealthCheck);
1829
fastify.get('/health', handleHealthCheck);
19-
fastify.get('/v1/admin/reports/getreportbymsgid', SetOptionsParams(reportRequestHandler, 'messageIDSchema'));
20-
fastify.get('/v1/admin/event-flow-control/entity', SetOptionsParams(getConditionHandler, 'queryEntityConditionSchema'));
21-
fastify.get('/v1/admin/event-flow-control/account', SetOptionsParams(getAccountConditionsHandler, 'queryAccountConditionSchema'));
22-
fastify.post('/v1/admin/event-flow-control/entity', SetOptionsBody(postConditionHandlerEntity, 'entityConditionSchema'));
23-
fastify.post('/v1/admin/event-flow-control/account', SetOptionsBody(postConditionHandlerAccount, 'accountConditionSchema'));
30+
fastify.get(
31+
'/v1/admin/reports/getreportbymsgid',
32+
SetOptionsBodyAndParams(reportRequestHandler, routePrivilege.getReport, undefined, 'messageIDSchema'),
33+
);
34+
fastify.get(
35+
'/v1/admin/event-flow-control/entity',
36+
SetOptionsBodyAndParams(getConditionHandler, routePrivilege.getEntity, undefined, 'queryEntityConditionSchema'),
37+
);
38+
fastify.get(
39+
'/v1/admin/event-flow-control/account',
40+
SetOptionsBodyAndParams(getAccountConditionsHandler, routePrivilege.getAccount, undefined, 'queryAccountConditionSchema'),
41+
);
42+
fastify.post(
43+
'/v1/admin/event-flow-control/entity',
44+
SetOptionsBodyAndParams(postConditionHandlerEntity, routePrivilege.postEntity, 'entityConditionSchema'),
45+
);
46+
fastify.post(
47+
'/v1/admin/event-flow-control/account',
48+
SetOptionsBodyAndParams(postConditionHandlerAccount, routePrivilege.postAccount, 'accountConditionSchema'),
49+
);
2450
fastify.put(
2551
'/v1/admin/event-flow-control/entity',
26-
SetOptionsBodyAndParams(updateEntityConditionExpiryDateHandler, 'expireDateTimeSchema', 'expireEntityConditionSchema'),
52+
SetOptionsBodyAndParams(
53+
updateEntityConditionExpiryDateHandler,
54+
routePrivilege.putEntity,
55+
'expireDateTimeSchema',
56+
'expireEntityConditionSchema',
57+
),
2758
);
2859
fastify.put(
2960
'/v1/admin/event-flow-control/account',
30-
SetOptionsBodyAndParams(updateAccountConditionExpiryDateHandler, 'expireDateTimeSchema', 'expireAccountConditionSchema'),
61+
SetOptionsBodyAndParams(
62+
updateAccountConditionExpiryDateHandler,
63+
routePrivilege.putAccount,
64+
'expireDateTimeSchema',
65+
'expireAccountConditionSchema',
66+
),
3167
);
32-
fastify.put('/v1/admin/event-flow-control/cache', putRefreshCache);
68+
fastify.put('/v1/admin/event-flow-control/cache', SetOptionsBodyAndParams(putRefreshCache, routePrivilege.putCache));
3369
}
3470

3571
export default Routes;

src/utils/schema-utils.ts

+15-28
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,26 @@
11
// SPDX-License-Identifier: Apache-2.0
2-
import { type RouteHandlerMethod } from 'fastify';
2+
import { type FastifyReply, type FastifyRequest, type RouteHandlerMethod } from 'fastify';
33
import { type FastifySchema } from 'fastify/types/schema';
4+
import { loggerService } from '..';
5+
import { configuration } from '../config';
6+
import { tokenHandler } from '../auth/authHandler';
47

5-
export const SetOptionsBody = (
6-
handler: RouteHandlerMethod,
7-
bodySchemaName: string,
8-
): { handler: RouteHandlerMethod; schema: FastifySchema } => {
9-
const schema: FastifySchema = { body: { $ref: `${bodySchemaName}#` } };
10-
11-
return {
12-
handler,
13-
schema,
14-
};
15-
};
16-
17-
export const SetOptionsParams = (
18-
handler: RouteHandlerMethod,
19-
paramSchemaName: string,
20-
): { handler: RouteHandlerMethod; schema: FastifySchema } => {
21-
const schema: FastifySchema = { querystring: { $ref: `${paramSchemaName}#` } };
22-
23-
return {
24-
handler,
25-
schema,
26-
};
27-
};
8+
type preHandler = (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
289

2910
export const SetOptionsBodyAndParams = (
3011
handler: RouteHandlerMethod,
31-
bodySchemaName: string,
32-
paramSchemaName: string,
33-
): { handler: RouteHandlerMethod; schema: FastifySchema } => {
34-
const schema: FastifySchema = { querystring: { $ref: `${paramSchemaName}#` }, body: { $ref: `${bodySchemaName}#` } };
12+
claim: string,
13+
bodySchemaName?: string,
14+
paramSchemaName?: string,
15+
): { preHandler?: preHandler; handler: RouteHandlerMethod; schema: FastifySchema } => {
16+
loggerService.debug(`Authentication is ${configuration.authentication ? 'ENABLED' : 'DISABLED'} for ${handler.name}`);
17+
const preHandler = configuration.authentication ? tokenHandler(claim) : undefined;
18+
const querystring = paramSchemaName ? { querystring: { $ref: `${paramSchemaName}#` } } : undefined;
19+
const body = bodySchemaName ? { body: { $ref: `${bodySchemaName}#` } } : undefined;
20+
const schema: FastifySchema = { ...querystring, ...body };
3521

3622
return {
23+
preHandler,
3724
handler,
3825
schema,
3926
};

0 commit comments

Comments
 (0)