Add authentication mecanisme and secure database.

This commit is contained in:
2020-09-26 20:48:29 +02:00
parent 54495c0689
commit 8a4463cbc5
14 changed files with 93 additions and 43 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
**/node_modules **/node_modules
docker/mongodb/data

View File

@@ -5,3 +5,10 @@ services:
image: "mongo:latest" image: "mongo:latest"
ports: ports:
- "27017:27017" - "27017:27017"
environment:
- "MONGO_INITDB_DATABASE=express-test"
- "MONGO_INITDB_ROOT_USERNAME=god"
- "MONGO_INITDB_ROOT_PASSWORD=P@ssword"
volumes:
- "./mongodb/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d/:ro"
- "./mongodb/data:/data/db"

View File

@@ -0,0 +1,12 @@
db.test.insert({id: 'test'});
db.createUser(
{
user: "application_user",
pwd: "Password1",
roles:
[
{ role: "readWrite", db: "db_application" }
]
}
)

View File

@@ -1,6 +1,8 @@
const Repository = require('../repository/repository'); const Repository = require('../repository/repository');
const router = require('express').Router(); const authenticationFilter = require('../filter/authenticationFilter');
const express = require('express');
const router = express.Router();
const applicationRepository = new Repository('applications'); const applicationRepository = new Repository('applications');
router.get('/', (request, response) => { router.get('/', (request, response) => {
@@ -36,7 +38,7 @@ router.put('/:applicationId', (request, response) => {
}); });
}); });
router.delete('/:applicationId', (request, response) => { router.delete('/:applicationId', authenticationFilter, (request, response) => {
const applicationId = request.params.applicationId; const applicationId = request.params.applicationId;
applicationRepository.find({_id: applicationId}, entity => { applicationRepository.find({_id: applicationId}, entity => {
if (entity.length === 0) { if (entity.length === 0) {

View File

@@ -1,4 +1,3 @@
const Repository = require('../repository/repository');
const router = require('express').Router(); const router = require('express').Router();
// Develop routes here // Develop routes here

View File

@@ -8,10 +8,12 @@ router.post('/login', (request, response) => {
if (!loginRequest) { if (!loginRequest) {
response.status(403).send(); response.status(403).send();
} else { } else {
userService.checkCredentials(loginRequest.login, loginRequest.password, () => { userService.checkCredentials(loginRequest.login, loginRequest.password,
() => {
const tokenPayload = { login: loginRequest.login }; const tokenPayload = { login: loginRequest.login };
response.json(tokenService.build(tokenPayload)); response.json(tokenService.build(tokenPayload));
}, () => response.status(403).send()); },
() => response.status(403).send());
} }
}); });

View File

@@ -0,0 +1,17 @@
const tokenService = require('../service/tokenService');
module.exports = (request, response, next) => {
const authenticationHeader = request.headers.authorization;
if (authenticationHeader) {
const token = authenticationHeader.split(' ')[1];
if (tokenService.isValid(token)) {
next();
} else {
response.status(403).send();
}
} else {
response.status(401).send();
}
};

View File

@@ -2,9 +2,18 @@ const mongodb = require('mongodb');
const configuration = require('../configuration'); const configuration = require('../configuration');
const mongoConfig = configuration.mongodb; const mongoConfig = configuration.mongodb;
function buildDatabaseUrl() {
const username = mongoConfig.username;
const password = encodeURIComponent(mongoConfig.password);
const url = `${mongoConfig.url}:${mongoConfig.port}`;
const test = `mongodb://${username}:${password}@${url}`;
console.log(test);
return test;
}
class MongoClient { class MongoClient {
constructor() { constructor() {
mongodb.MongoClient.connect(mongoConfig.url, (error, client) => { mongodb.MongoClient.connect(buildDatabaseUrl(), (error, client) => {
if (error !== null) { if (error !== null) {
throw new Error(`Unable de connect to Mongo database: ${error}`); throw new Error(`Unable de connect to Mongo database: ${error}`);
} }
@@ -61,6 +70,5 @@ class MongoClient {
} }
} }
// Define a singleton of class "MongoClient". const singleton = new MongoClient();
const mongoClient = new MongoClient(); module.exports = singleton;
module.exports = mongoClient;

View File

@@ -13,7 +13,7 @@ function convertIdToMongodbFormat(entity) {
module.exports = class Repository { module.exports = class Repository {
/** /**
* Creates a new repository which read and write into the {@code collectionName} collection in database. * Creates a new repository which read and write into the {@code collectionName} collection in database.
* @param {*} collectionName * @param {String} collectionName
*/ */
constructor(collectionName) { constructor(collectionName) {
this.collectionName = collectionName; this.collectionName = collectionName;
@@ -22,8 +22,9 @@ module.exports = class Repository {
/** /**
* Returns the entities that matches criteria in {@code query}. * Returns the entities that matches criteria in {@code query}.
* @param {*} query The query which contains criteria to find some entities. * @param {Object} query The query which contains criteria to find some entities.
* @param {*} onSuccess The function to execute after getting entities. * @param {Function} onSuccess The function to execute after getting entities.
* @param {Function} onError The function to execute if entity finding failed.
*/ */
find(query, onSuccess, onError) { find(query, onSuccess, onError) {
convertIdToMongodbFormat(query); convertIdToMongodbFormat(query);

View File

@@ -2,11 +2,22 @@ const bcrypt = require('bcrypt');
const saltRounds = 10; const saltRounds = 10;
class PasswordService { class PasswordService {
/**
* Hashes the password in parameters.
* @param {String} password The plain text password.
* @returns The hashed password.
*/
hashPassword(password) { hashPassword(password) {
const salt = bcrypt.genSaltSync(saltRounds); const salt = bcrypt.genSaltSync(saltRounds);
return bcrypt.hashSync(password, salt); return bcrypt.hashSync(password, salt);
} }
/**
* Checks if the {@code plainTextPassword} matches the hashed password.
* @param {String} plainTextPassword The plain text password.
* @param {String} hashedPassword The hashed password.
* @returns A boolean.
*/
areSamePasswords(plainTextPassword, hashedPassword) { areSamePasswords(plainTextPassword, hashedPassword) {
return bcrypt.compareSync(plainTextPassword, hashedPassword); return bcrypt.compareSync(plainTextPassword, hashedPassword);
} }

View File

@@ -3,10 +3,20 @@ const configuration = require('../configuration');
const securityConfig = configuration.security; const securityConfig = configuration.security;
class TokenService { class TokenService {
/**
* Builds a JWT token.
* @param {Object} tokenPayload The JWT payload.
* @returns {String} The JWT token.
*/
build(tokenPayload) { build(tokenPayload) {
return jwt.sign(tokenPayload, securityConfig.jwt.secret, {expiresIn: securityConfig.jwt.validity}); return jwt.sign(tokenPayload, securityConfig.jwt.secret, {expiresIn: securityConfig.jwt.validity});
} }
/**
* Checks if the given token is valid, and provides from this application or not.
* @param {String} token The JWT token to check.
* @returns A boolean.
*/
isValid(token) { isValid(token) {
try { try {
jwt.verify(token, securityConfig.jwt.secret); jwt.verify(token, securityConfig.jwt.secret);
@@ -17,5 +27,5 @@ class TokenService {
} }
} }
const jwtInstance = new TokenService(); const singleton = new TokenService();
module.exports = jwtInstance; module.exports = singleton;

View File

@@ -15,14 +15,7 @@ class UserService {
} }
/** /**
* * Checks if credentials matches to an existing user, that have this password.
*/
isAuthenticated() {
return false;
}
/**
*
* @param {String} login User login. * @param {String} login User login.
* @param {String} password User password, in plain text. * @param {String} password User password, in plain text.
* @param {Function} onSuccess Callback function to execute if a user exists with this login. * @param {Function} onSuccess Callback function to execute if a user exists with this login.

View File

@@ -1,14 +0,0 @@
use express-test;
db.collection.test.insert({id: 'test'});
db.createUser(
{
user: "express-user",
pwd: "P@ssword1",
roles:
[
{ role: "readWrite", db: "express-test" }
]
}
)

View File

@@ -1,8 +1,9 @@
mongodb: mongodb:
url: 'mongodb://localhost:27017' url: 'localhost'
username: 'express-user' port: 27017
password: 'P@ssword1' username: 'application_user'
database: 'express-test' password: 'Password1'
database: 'db_application'
security: security:
jwt: jwt:
secret: 5ubtcCCo7hWBqjNGtzzVKnLT1KxN9uS4D6kRZowCunZAYPmxtKy6mvgoxANe4WqLVfiVI7AZSVqZCtvlSWFwIsnXGH6lxeKG0U8Wu7Kw0jwfFOGLvlO8bXaB secret: 5ubtcCCo7hWBqjNGtzzVKnLT1KxN9uS4D6kRZowCunZAYPmxtKy6mvgoxANe4WqLVfiVI7AZSVqZCtvlSWFwIsnXGH6lxeKG0U8Wu7Kw0jwfFOGLvlO8bXaB