Skip to content

Commit

Permalink
Add ability to configure basic auth and request headers
Browse files Browse the repository at this point in the history
  • Loading branch information
Fabian Schneider committed Oct 6, 2017
1 parent f1e51b0 commit e780126
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 22 deletions.
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,56 @@ Security can be specified per path using the `paths.security` field.
}
```

### Authentication & Request Headers

To retrieve Swagger schemas that are access protected, basic auth information (username and password) or any headers to be sent with the http request can be specified:

```json
{
"swagger": "2.0",
"info": {
"title": "Swagger Combine Authentication Example",
"version": "1.0.0"
},
"apis": [
{
"url": "http://petstore.swagger.io/v2/swagger.json",
"resolve": {
"http": {
"auth": {
"username": "admin",
"password": "secret12345"
}
}
}
},
{
"url": "https://api.apis.guru/v2/specs/medium.com/1.0.0/swagger.yaml",
"resolve": {
"http": {
"headers": {
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWV9.44lJS0jlltzcglq7vgjXMXYRTecBxseN3Dec_LO_osI"
}
}
}
},
{
"url": "https://api.apis.guru/v2/specs/deutschebahn.com/betriebsstellen/v1/swagger.json",
"resolve": {
"http": {
"headers": {
"authorization": "Basic YWRtaW46c2VjcmV0MTIz"
}
}
}
}
]
}
```

For all possible resolve options have a look at the [documentation of json-schema-ref-parser](https://github.com/BigstickCarpet/json-schema-ref-parser/blob/master/docs/options.md#resolve-options).


## API

### swaggerCombine(config, [options], [callback])
Expand Down
49 changes: 49 additions & 0 deletions examples/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const swaggerCombine = require('../src');

const config = (module.exports = {
swagger: '2.0',
info: {
title: 'Swagger Combine Authentication Example',
version: {
$ref: './package.json#/version',
},
},
apis: [
{
url: 'http://petstore.swagger.io/v2/swagger.json',
resolve: {
http: {
auth: {
username: 'admin',
password: 'secret12345'
}
}
}
},
{
url: 'https://api.apis.guru/v2/specs/medium.com/1.0.0/swagger.yaml',
resolve: {
http: {
headers: {
authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWV9.44lJS0jlltzcglq7vgjXMXYRTecBxseN3Dec_LO_osI'
}
}
}
},
{
url: 'https://api.apis.guru/v2/specs/deutschebahn.com/betriebsstellen/v1/swagger.json',
resolve: {
http: {
headers: {
authorization: 'Basic YWRtaW46c2VjcmV0MTIz'
}
}
}
},
]
});

if (!module.parent) {
swaggerCombine(config).then(res => console.log(JSON.stringify(res, false, 2))).catch(err => console.error(err));

}
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@
"url-join": "^2.0.2"
},
"devDependencies": {
"@maxdome/prettier": "^1.2.1",
"@maxdome/prettier": "^1.3.2",
"chai": "^4.1.2",
"chai-http": "^3.0.0",
"chai-somewhere": "^1.0.2",
"express": "^4.15.4",
"express": "^4.16.1",
"mocha": "^3.5.0",
"nock": "^9.0.14",
"nock": "^9.0.22",
"sinon": "^4.0.0",
"sinon-chai": "^2.13.0"
"sinon-chai": "^2.14.0"
},
"directories": {
"example": "examples"
Expand Down
29 changes: 21 additions & 8 deletions src/SwaggerCombine.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,28 @@ class SwaggerCombine {
this.combinedSchema = _.omit(configSchema, 'apis');

return Promise.all(
this.apis.map((api, idx) =>
SwaggerParser.dereference(api.url, this.opts).catch(err => {
if (this.opts.continueOnError) {
return;
}
this.apis.map((api, idx) => {
const opts = _.cloneDeep(this.opts);
opts.resolve = Object.assign({}, opts.resolve, api.resolve);

if (_.has(opts, 'resolve.http.auth.username') && _.has(opts, 'resolve.http.auth.password')) {
const basicAuth =
'Basic ' +
new Buffer(`${opts.resolve.http.auth.username}:${opts.resolve.http.auth.password}`).toString('base64');
_.set(opts, 'resolve.http.headers.authorization', basicAuth);
}

throw err;
})
)
return $RefParser
.dereference(api.url, opts)
.then(res => SwaggerParser.dereference(res, opts))
.catch(err => {
if (this.opts.continueOnError) {
return;
}

throw err;
});
})
);
})
.then(apis => {
Expand Down
18 changes: 8 additions & 10 deletions src/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@ exports.middleware = (config, opts = {}) => {
};

exports.middlewareAsync = (config, opts = {}) => {
return new SwaggerCombine(config, opts)
.combine()
.then(sc => {
return function (req, res, next) {
if (opts && (opts.format === 'yaml' || opts.format === 'yml')) {
return res.type('yaml').send(sc.toString());
}

res.json(sc.combinedSchema);
return new SwaggerCombine(config, opts).combine().then(sc => {
return function(req, res, next) {
if (opts && (opts.format === 'yaml' || opts.format === 'yml')) {
return res.type('yaml').send(sc.toString());
}
});

res.json(sc.combinedSchema);
};
});
};
76 changes: 76 additions & 0 deletions test/unit.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const chai = require('chai');
const http = require('http');
const sinon = require('sinon');
chai.use(require('sinon-chai'));

Expand Down Expand Up @@ -125,6 +126,81 @@ describe('[Unit] SwaggerCombine.js', () => {
});
});

describe('load()', () => {
beforeEach(() => {
sandbox.stub(http, 'get');
});

it('transforms auth to authorization header and sends it on http request', () => {
instance.config = {
apis: [
{
url: 'http://test/swagger.json',
resolve: {
http: {
auth: {
username: 'admin',
password: 'secret12345',
},
},
},
},
],
};

return instance
.load()
.then(() => {
throw new Error('Should fail');
})
.catch(err => {
expect(http.get).to.have.been.calledWithMatch(
sinon.match({
headers: {
authorization: sinon.match.string,
},
})
);
});
});

it('sets authorization headers on http request', () => {
const token =
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWV9.44lJS0jlltzcglq7vgjXMXYRTecBxseN3Dec_LO_osI';
instance.config = {
apis: [
{
url: 'http://test/swagger.json',
resolve: {
http: {
headers: {
authorization: token,
},
},
},
},
],
};

return instance
.load()
.then(() => {
throw new Error('Should fail');
})
.catch(err => {
expect(http.get).to.have.been.calledWithMatch(
sinon.match({
headers: {
authorization: token,
},
})
);
});
});

afterEach(() => sandbox.restore());
});

describe('filterPaths()', () => {
it('filters included path', () => {
instance.apis = [
Expand Down

0 comments on commit e780126

Please sign in to comment.