CodeBiting / onion-cargo-loading-service

Servei per determinar quin contenidor fer servir i com s'han de disposar els elements a dins
MIT License
1 stars 4 forks source link

Implementació de control d'autorització i autenticació #40

Open jordidh opened 1 year ago

jordidh commented 1 year ago

Objectiu

Validar l'autenticació i l'autorització de la petició. Per totes les crides rebudes hem d'assegurar-nos que el client que la crida és qui diu ser i que té permís per accedir a la url que demana. Per això s'ha de:

  1. Autenticació: Comprovar que el token coincideixen en el mateix client. El rebrem en el header com a 'x-api-key'
  2. Autorització: Comprovar que el client té accés a la URL que demana. Nota: mirarem si el client és superusuari o no. Si és superusuari pot accedir a tots els clients, sinó només al les seves.

Solució

Es proposa refactoritzar la funció del middleware que genera el requestId per realitzar l'autenticació i l'autorització de manera que només si es passen les dues es generarà el requestId i es continuará. Si no es superen es deixarà un error en consola per detectar els intents d'accés no permès i poder actuar davant d'aquests errors/atacs.

Per exemple, com a idea de com fer-ho es proposa modificar la funció de la següent manera:

Ara tenim en el app.js:

/**
 * Generate one uniqueid everytime API is called, to trace the client call
 */
app.use((req, res, next) => {
  // Get the requestId if its provided in the heather
  let requestId = req.headers["x-request-id"];
  // Save the requestId or create a new one if not exists
  req.requestId = requestId || uniqid();
  // Call the next function in the middleware
  next();
});

Modificar-ho de la següent manera:


const clientService = require(`${__base}api/v1/clientService`);

const BAD_REQUEST = 400;
const UNAUTHORIZED = 401;
const FORBIDDEN = 403;

/**
 * Autenticate and autorize the requests
 * Generate one uniqueid everytime API is called, to trace the client call
 */
app.use(async (req, res, next) => {
  if (req.url && !req.url.startsWith('/v1/api-docs')) {

    let token = req.headers["x-api-key"];

    // Autenticate and autorize the requests
    if (!req.query || !token) {
      logger.error(`Authentication error, missing clientId or token: [${req.method}] ${req.originalUrl}`);
      // En la resposta no indiquem el motiu de l'error per no ajudar a possibles atacants
      let error = new ApiError('GENERIC-ERROR-001', 'Bad request', '', `${req.protocol}://${req.get('host')}${HELP_BASE_URL}/GENERIC-ERROR-001`);
      return res.status(BAD_REQUEST).json(new ApiResult("ERROR", null, [ error ]));
    }

    // Check the authorization data provided is correct
    if (await clientService.isAuthenticacionValid(req.query.clientId, token) !== true) {
      logger.error(`Authentication error, incorrect clientId or token: [${req.method}] ${req.originalUrl}`);
      // En la resposta no indiquem el motiu de l'error per no ajudar a possibles atacants
      let error = new ApiError('AUTHORIZATION-ERROR-001', 'Authorization error', '', `${req.protocol}://${req.get('host')}${HELP_BASE_URL}/AUTHORIZATION-ERROR-001`);
      return res.status(UNAUTHORIZED).json(new ApiResult("ERROR", null, [ error ]));
    }

    // Check the client has access to the resource requested
    if (await clientService.hasAccessToTheResource(req.query.clientId, req.originalUrl) !== true) {
      logger.error(`Authorization error, clientId ${req.query.clientId} don't have access to the resource ${req.originalUrl}: [${req.method}] ${req.originalUrl}`);
      // En la resposta no indiquem el motiu de l'error per no ajudar a possibles atacants
      let error = new ApiError('AUTHORIZATION-ERROR-001', 'Authorization error', '', `${req.protocol}://${req.get('host')}${HELP_BASE_URL}/AUTHORIZATION-ERROR-001`);
      return res.status(FORBIDDEN).json(new ApiResult("ERROR", null, [ error ]));
    }
  }

  // Get the requestId if its provided in the heather
  let requestId = req.headers["x-request-id"];
  // Save the requestId or create a new one if not exists
  req.requestId = requestId || uniqid();
  // Call the next function in the middleware

  next();
});

TODO: Modificar la documentació swagger per indicar que en la crida s'ha de proporcionar el id de client i el token