Commit a522c0b7 authored by FORESTIER Fabien's avatar FORESTIER Fabien
Browse files

Add middleware verifying xsrf Token

parent 65dddb9c
Pipeline #2371 passed with stages
in 5 minutes and 15 seconds
......@@ -5,6 +5,7 @@ stages:
variables:
GROUP_HEADER: x-consumer-groups
ADMIN_GROUP_NAME: admin
ACCESS_TOKEN_COOKIE_KEY: access_token
build_development:
stage: build
......
......@@ -15,6 +15,7 @@ services:
POSTGRES_PORT: 5432
GROUP_HEADER: ${GROUP_HEADER}
ADMIN_GROUP_NAME: ${ADMIN_GROUP_NAME}
ACCESS_TOKEN_COOKIE_KEY: ${ACCESS_TOKEN_COOKIE_KEY}
restart: unless-stopped
database-organizations:
......
This diff is collapsed.
......@@ -36,6 +36,7 @@
"class-validator": "^0.9.1",
"cross-env": "^5.2.0",
"dotenv": "^6.1.0",
"jsonwebtoken": "^8.5.1",
"pg": "^7.4.3",
"postgresql": "0.0.1",
"reflect-metadata": "^0.1.12",
......@@ -81,4 +82,4 @@
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
\ No newline at end of file
}
import { Module } from '@nestjs/common';
import { Module, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { OrganizationsModule } from './organizations/organizations.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LinksModule } from './links/links.module';
......@@ -7,6 +7,7 @@ import { ConfigModule } from './configuration/config.module';
import { APP_GUARD } from '@nestjs/core';
import { GroupsGuard } from './guards/groups.guards';
import { AppLogger } from './app-logger';
import { VerifyXsrfTokenAndDecodeJWTPayloadMiddleware } from './middlewares/decode-jwt-payload.middleware';
@Module({
imports: [
......@@ -24,4 +25,17 @@ import { AppLogger } from './app-logger';
},
],
})
export class AppModule { }
export class AppModule {
configure(consumer: MiddlewareConsumer) {
// Applying the middleware that takes the Authorization header jwt payload and put it in the request headers
consumer
.apply(VerifyXsrfTokenAndDecodeJWTPayloadMiddleware).forRoutes(
{ path: 'links', method: RequestMethod.POST },
{ path: 'links/:id', method: RequestMethod.PUT },
{ path: 'links/:id', method: RequestMethod.DELETE },
{ path: 'organizations', method: RequestMethod.POST },
{ path: 'organizations/:id', method: RequestMethod.PUT },
{ path: 'organizations/:id', method: RequestMethod.DELETE },
);
}
}
......@@ -11,6 +11,7 @@ export class ConfigService {
dotenv.config();
this._config.groupNames.admin = process.env.ADMIN_GROUP_NAME;
this._config.groupHeader = process.env.GROUP_HEADER;
this._config.accessTokenCookieKey = process.env.ACCESS_TOKEN_COOKIE_KEY;
}
get config() {
......
......@@ -3,4 +3,5 @@ export const config = {
admin: '',
},
groupHeader: '',
accessTokenCookieKey: '',
};
\ No newline at end of file
import { UnauthorizedException, Logger, NestMiddleware, MiddlewareFunction, Injectable } from '@nestjs/common';
import * as jwt from 'jsonwebtoken';
import { ConfigService } from '../configuration/config.service';
@Injectable()
export class VerifyXsrfTokenAndDecodeJWTPayloadMiddleware implements NestMiddleware {
private logger: Logger;
constructor(
private _configService: ConfigService,
) {
this.logger = new Logger(VerifyXsrfTokenAndDecodeJWTPayloadMiddleware.name);
}
resolve(): MiddlewareFunction {
return (req, res, next) => {
this.logger.log('Entering function', `${VerifyXsrfTokenAndDecodeJWTPayloadMiddleware.name} - ${this.resolve.name}`);
// Verifying that all the authentications part are set
// tslint:disable-next-line:max-line-length
if (req.headers['x-anonymous-consumer'] !== 'true' && req.cookies[this._configService.config.accessTokenCookieKey] && req.headers['x-xsrf-token']) {
let token = req.cookies[this._configService.config.accessTokenCookieKey];
const xsrfToken = req.headers['x-xsrf-token'];
token = jwt.decode(token);
// Make sure the token has correctly been decrypted
if (token) {
// Verify the wsrfToken from the header with the value of the corresponding in the JWT payload
if (token.xsrfToken === xsrfToken) {
req.headers.token = token;
next();
} else {
this.logger.log('Could\'t verify xsrf token.');
throw new UnauthorizedException('Could\'t verify xsrf token.');
}
} else {
this.logger.log('Invalid token provided');
throw new UnauthorizedException('Invalid token provided.');
}
} else {
this.logger.log('Missing credential information');
throw new UnauthorizedException('Missing credential information.');
}
};
}
}
......@@ -2,6 +2,7 @@ TAG=<version number>
ORGANIZATIONS_SERVICE_BIND_PORT=<service port>
GROUP_HEADER=<group header set by the api gateway>
ADMIN_GROUP_NAME=<name of the admin group>
ACCESS_TOKEN_COOKIE_KEY=<cookie key where the access token will be stored>
POSTGRES_USER=<postgres user>
POSTGRES_PASSWORD=<postgres password>
POSTGRES_HOST=<postgres database host>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment