Add authentication mecanisme and secure database.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
|
docker/mongodb/data
|
||||||
@@ -4,4 +4,11 @@ services:
|
|||||||
container_name: "mongo"
|
container_name: "mongo"
|
||||||
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"
|
||||||
12
docker/mongodb/docker-entrypoint-initdb.d/initDatabase.js
Normal file
12
docker/mongodb/docker-entrypoint-initdb.d/initDatabase.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
db.test.insert({id: 'test'});
|
||||||
|
|
||||||
|
db.createUser(
|
||||||
|
{
|
||||||
|
user: "application_user",
|
||||||
|
pwd: "Password1",
|
||||||
|
roles:
|
||||||
|
[
|
||||||
|
{ role: "readWrite", db: "db_application" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 };
|
() => {
|
||||||
response.json(tokenService.build(tokenPayload));
|
const tokenPayload = { login: loginRequest.login };
|
||||||
}, () => response.status(403).send());
|
response.json(tokenService.build(tokenPayload));
|
||||||
|
},
|
||||||
|
() => response.status(403).send());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
17
src/js/filter/authenticationFilter.js
Normal file
17
src/js/filter/authenticationFilter.js
Normal 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();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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;
|
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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.
|
||||||
|
|||||||
@@ -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" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user