All files / src/plugins/validation/2and3/semantic-validators security-definitions-ibm.js

95% Statements 57/60
84.21% Branches 32/38
100% Functions 13/13
100% Lines 57/57

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129        29x 29x   29x 98x   98x   98x 98x       98x       98x 66x   66x 66x 66x     66x 38x 6x 6x 6x 6x 12x 12x 12x 12x         32x 31x 62x 62x 62x                   98x 3x       98x 98x 192x 192x 244x 244x 111x           114x 114x   114x   115x 111x   111x 111x   111x 107x 208x 208x                   98x 66x 24x     24x                 98x 74x 2x     2x                 98x    
// From swagger-tools -
// Assertation 1: Security requirements defined in securityDefinitions should be used in the spec
// Assertation 2: Each scope defined in an OAuth2 scheme should be used in the spec
 
const each = require('lodash/each');
const MessageCarrier = require('../../../utils/messageCarrier');
 
module.exports.validate = function({ resolvedSpec, isOAS3 }, config) {
  const messages = new MessageCarrier();
 
  config = config.security_definitions;
 
  const definedSchemes = {};
  const definedScopes = {};
 
  // collect the security requirements and all relevant scopes
 
  const securityDefinitions = isOAS3
    ? resolvedSpec.components && resolvedSpec.components.securitySchemes
    : resolvedSpec.securityDefinitions;
 
  each(securityDefinitions, (scheme, name) => {
    Iif (name.slice(0, 2) === 'x-') return;
 
    definedSchemes[name] = {};
    definedSchemes[name].used = false;
    definedSchemes[name].type = scheme.type;
 
    // collect scopes in oauth2 schemes
    if (scheme.type.toLowerCase() === 'oauth2') {
      if (isOAS3) {
        Eif (scheme.flows) {
          each(scheme.flows, (flow, flowType) => {
            Eif (flow.scopes) {
              Object.keys(flow.scopes).forEach(scope => {
                definedScopes[scope] = {};
                definedScopes[scope].used = false;
                definedScopes[scope].scheme = name;
                definedScopes[scope].flow = flowType;
              });
            }
          });
        }
      } else if (scheme.scopes) {
        Object.keys(scheme.scopes).forEach(scope => {
          definedScopes[scope] = {};
          definedScopes[scope].used = false;
          definedScopes[scope].scheme = name;
        });
      }
    }
  });
 
  // check all instances of 'security' objects
  // security objects can exist at either:
 
  // 1) the top level of the spec (global definition)
  if (resolvedSpec.security) {
    flagUsedDefinitions(resolvedSpec.security);
  }
 
  // 2) within operations objects
  const paths = resolvedSpec.paths;
  each(paths, (operations, pathName) => {
    Iif (pathName.slice(0, 2) === 'x-') return;
    each(operations, (operation, opName) => {
      Iif (opName.slice(0, 2) === 'x-') return;
      if (operation.security) {
        flagUsedDefinitions(operation.security);
      }
    });
  });
 
  function flagUsedDefinitions(security) {
    security.forEach(scheme => {
      const schemeNames = Object.keys(scheme);
 
      schemeNames.forEach(schemeName => {
        // make sure this scheme was in the security definitions, then label as used
        if (definedSchemes[schemeName]) {
          definedSchemes[schemeName].used = true;
 
          const type = definedSchemes[schemeName].type;
          const scopesArray = scheme[schemeName];
 
          if (type.toLowerCase() === 'oauth2') {
            scopesArray.forEach(scope => {
              Eif (definedScopes[scope]) {
                definedScopes[scope].used = true;
              }
            });
          }
        }
      });
    });
  }
 
  // check what has been used and what has not been
  each(definedSchemes, (info, name) => {
    if (info.used === false) {
      const location = isOAS3
        ? 'components.securitySchemes'
        : 'securityDefinitions';
      messages.addMessage(
        `${location}.${name}`,
        `A security scheme is defined but never used: ${name}`,
        config.unused_security_schemes,
        'unused_security_schemes'
      );
    }
  });
 
  each(definedScopes, (info, name) => {
    if (info.used === false) {
      const path = isOAS3
        ? `components.securitySchemes.${info.scheme}.flows.${info.flow}.scopes.${name}`
        : `securityDefinitions.${info.scheme}.scopes.${name}`;
      messages.addMessage(
        path,
        `A security scope is defined but never used: ${name}`,
        config.unused_security_scopes,
        'unused_security_scopes'
      );
    }
  });
 
  return messages;
};