diff --git a/OPTIONS.md b/OPTIONS.md index 22d2c3630..e08940b24 100644 --- a/OPTIONS.md +++ b/OPTIONS.md @@ -20,3 +20,4 @@ ignoreUnresolvedVariables|boolean|-|false|Whether to ignore mismatches resulting strictRequestMatching|boolean|-|false|Whether requests should be strictly matched with schema operations. Setting to true will not include any matches where the URL path segments don't match exactly.|VALIDATION disableOptionalParameters|boolean|-|false|Whether to set optional parameters as disabled|CONVERSION keepImplicitHeaders|boolean|-|false|Whether to keep implicit headers from the OpenAPI specification, which are removed by default.|CONVERSION +alwaysInheritAuthentication|boolean|-|false|Whether authentication details should be included on every request, or always inherited from the collection.|CONVERSION diff --git a/lib/options.js b/lib/options.js index d7b585669..ecad1487d 100644 --- a/lib/options.js +++ b/lib/options.js @@ -230,6 +230,16 @@ module.exports = { description: 'Whether to keep implicit headers from the OpenAPI specification, which are removed by default.', external: true, usage: ['CONVERSION'] + }, + { + name: 'Always inherit authentication', + id: 'alwaysInheritAuthentication', + type: 'boolean', + default: false, + description: 'Whether authentication details should be included on every request, or always inherited from ' + + 'the collection.', + external: true, + usage: ['CONVERSION'] } ]; diff --git a/lib/schemaUtils.js b/lib/schemaUtils.js index e8bfa061b..73cc2bd74 100644 --- a/lib/schemaUtils.js +++ b/lib/schemaUtils.js @@ -2321,7 +2321,12 @@ module.exports = { } // handling authentication here (for http type only) - authHelper = this.getAuthHelper(openapi, operation.security); + if (options.alwaysInheritAuthentication) { + authHelper = this.getAuthHelper(openapi, openapi.security); + } + else { + authHelper = this.getAuthHelper(openapi, operation.security); + } // creating the request object item = new sdk.Item({ @@ -2344,7 +2349,7 @@ module.exports = { thisAuthObject[authMap[authMeta.currentHelper]] = authMeta.helperAttributes; item.request.auth = new sdk.RequestAuth(thisAuthObject); } - else { + else if (!options.alwaysInheritAuthentication) { item.request.auth = authHelper; } diff --git a/test/data/valid_openapi/security-test-inheritance.yaml b/test/data/valid_openapi/security-test-inheritance.yaml new file mode 100644 index 000000000..191fd945a --- /dev/null +++ b/test/data/valid_openapi/security-test-inheritance.yaml @@ -0,0 +1,48 @@ +openapi: 3.0.0 +info: + title: "Reproduce Authorization issue" + version: 0.0.1 +security: + - MyAuth: [] + - BearerAuth: [] +paths: + /health: + get: + summary: "health" + description: "Health check - always returns OK" + operationId: "get_healthz" + security: + - BearerAuth: [] + responses: + '200': + description: "OK" + content: + text/plain: + schema: + type: "string" + default: "OK" + /status: + get: + summary: "status" + description: "Returns the service version" + operationId: "get_status" + security: + - MyAuth: [] + responses: + '200': + description: "Service info multi-line string" + content: + text/plain: + schema: + type: "string" +components: + securitySchemes: + BearerAuth: + type: http + scheme: bearer + bearerFormat: token + MyAuth: + type: apiKey + description: "This is my auth" + name: Mera-Auth + in: header \ No newline at end of file diff --git a/test/system/structure.test.js b/test/system/structure.test.js index 20699e779..1c42d0e65 100644 --- a/test/system/structure.test.js +++ b/test/system/structure.test.js @@ -23,7 +23,8 @@ const optionIds = [ 'optimizeConversion', 'strictRequestMatching', 'disableOptionalParameters', - 'keepImplicitHeaders' + 'keepImplicitHeaders', + 'alwaysInheritAuthentication' ], expectedOptions = { collapseFolders: { @@ -171,6 +172,15 @@ const optionIds = [ description: 'Whether to keep implicit headers from the OpenAPI specification, which are removed by default.', external: true, usage: ['CONVERSION'] + }, + alwaysInheritAuthentication: { + name: 'Always inherit authentication', + type: 'boolean', + default: false, + description: 'Whether authentication details should be included on every request, or always inherited from ' + + 'the collection.', + external: true, + usage: ['CONVERSION'] } }; diff --git a/test/unit/base.test.js b/test/unit/base.test.js index 92d36d55e..c974621e7 100644 --- a/test/unit/base.test.js +++ b/test/unit/base.test.js @@ -40,10 +40,38 @@ describe('CONVERT FUNCTION TESTS ', function() { tooManyRefs = path.join(__dirname, VALID_OPENAPI_PATH, '/too-many-refs.json'), tagsFolderSpec = path.join(__dirname, VALID_OPENAPI_PATH + '/petstore-detailed.yaml'), securityTestCases = path.join(__dirname, VALID_OPENAPI_PATH + '/security-test-cases.yaml'), + securityTestInheritance = path.join(__dirname, VALID_OPENAPI_PATH + '/security-test-inheritance.yaml'), emptySecurityTestCase = path.join(__dirname, VALID_OPENAPI_PATH + '/empty-security-test-case.yaml'), rootUrlServerWithVariables = path.join(__dirname, VALID_OPENAPI_PATH + '/root_url_server_with_variables.json'), parameterExamples = path.join(__dirname, VALID_OPENAPI_PATH + '/parameteres_with_examples.yaml'); + it('Should explicitly set auth when specified on a request ' + + securityTestInheritance, function(done) { + var openapi = fs.readFileSync(securityTestInheritance, 'utf8'); + Converter.convert({ type: 'string', data: openapi }, {}, (err, conversionResult) => { + + expect(err).to.be.null; + expect(conversionResult.output[0].data.auth.type).to.equal('apikey'); + expect(conversionResult.output[0].data.item[0].request.auth.type).to.equal('bearer'); + expect(conversionResult.output[0].data.item[1].request.auth.type).to.equal('apikey'); + done(); + }); + }); + + it('Should not explicitly set auth when specified on a request when passed alwaysInheritAuthentication ' + + securityTestInheritance, function(done) { + var openapi = fs.readFileSync(securityTestInheritance, 'utf8'); + Converter.convert( + { type: 'string', data: openapi }, + { alwaysInheritAuthentication: true }, (err, conversionResult) => { + + expect(err).to.be.null; + expect(conversionResult.output[0].data.auth.type).to.equal('apikey'); + expect(conversionResult.output[0].data.item[0].request.auth).to.be.undefined; + expect(conversionResult.output[0].data.item[1].request.auth).to.be.undefined; + done(); + }); + }); it('Should add collection level auth with type as `bearer`' + securityTestCases, function(done) {