Add support for OAuth2 to OpenAPI3 importer (#2184)

Co-authored-by: Opender Singh <opender94@gmail.com>
This commit is contained in:
Sebastian Jonasson 2020-06-06 02:59:59 +02:00 committed by GitHub
parent 43e8429b21
commit 0356b8a082
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 260 additions and 8 deletions

View File

@ -37,6 +37,43 @@ components:
type: apiKey
name: another_key
in: query
OAuth2-AuthorizationCode:
type: oauth2
scheme: bearer
flows:
authorizationCode:
authorizationUrl: https://api.server.test/v1/auth
tokenUrl: https://api.server.test/v1/token
scopes:
read:something: Read all the data
write:something: Write all the data
OAuth2-Implicit:
type: oauth2
scheme: bearer
flows:
implicit:
authorizationUrl: https://api.server.test/v1/auth
scopes:
read:something: Read all the data
write:something: Write all the data
OAuth2-ClientCredentials:
type: oauth2
scheme: bearer
flows:
clientCredentials:
tokenUrl: https://api.server.test/v1/token
scopes:
read:something: Read all the data
write:something: Write all the data
OAuth2-Password:
type: oauth2
scheme: bearer
flows:
password:
tokenUrl: https://api.server.test/v1/token
scopes:
read:something: Read all the data
write:something: Write all the data
paths:
/none:
@ -91,6 +128,34 @@ paths:
responses:
'200':
description: OK
/oauth2/authorization-code:
get:
security:
- OAuth2-AuthorizationCode: []
responses:
'200':
description: OK
/oauth2/implicit:
get:
security:
- OAuth2-Implicit: []
responses:
'200':
description: OK
/oauth2/client-credentials:
get:
security:
- OAuth2-ClientCredentials: []
responses:
'200':
description: OK
/oauth2/password:
get:
security:
- OAuth2-Password: []
responses:
'200':
description: OK
/all:
get:
security:
@ -99,6 +164,10 @@ paths:
- Key-Query: []
- Key-Header: []
- Key-Cookie: []
- OAuth2-AuthorizationCode: []
- OAuth2-Implicit: []
- OAuth2-ClientCredentials: []
- OAuth2-Password: []
responses:
'200':
description: OK

View File

@ -32,6 +32,10 @@
"host": "api.server.test",
"httpPassword": "password",
"httpUsername": "username",
"oauth2ClientId": "clientId",
"oauth2ClientSecret": "clientSecret",
"oauth2Username": "username",
"oauth2Password": "password",
"key": "key",
"scheme": "https",
"xApiKey": "xApiKey",
@ -164,6 +168,84 @@
"parentId": "__WORKSPACE_ID__",
"url": "{{ base_url }}/key/query"
},
{
"_id": "req___WORKSPACE_ID__028b5fb7",
"_type": "request",
"authentication": {
"clientId": "{{ oauth2ClientId }}",
"clientSecret": "{{ oauth2ClientSecret }}",
"accessTokenUrl": "https://api.server.test/v1/token",
"authorizationUrl": "https://api.server.test/v1/auth",
"grantType": "authorization_code",
"scope": "read:something write:something",
"type": "oauth2"
},
"body": {},
"headers": [],
"method": "GET",
"name": "/oauth2/authorization-code",
"parameters": [],
"parentId": "__WORKSPACE_ID__",
"url": "{{ base_url }}/oauth2/authorization-code"
},
{
"_id": "req___WORKSPACE_ID__e5d224de",
"_type": "request",
"authentication": {
"clientId": "{{ oauth2ClientId }}",
"authorizationUrl": "https://api.server.test/v1/auth",
"grantType": "implicit",
"scope": "read:something write:something",
"type": "oauth2"
},
"body": {},
"headers": [],
"method": "GET",
"name": "/oauth2/implicit",
"parameters": [],
"parentId": "__WORKSPACE_ID__",
"url": "{{ base_url }}/oauth2/implicit"
},
{
"_id": "req___WORKSPACE_ID__ef33c6a4",
"_type": "request",
"authentication": {
"clientId": "{{ oauth2ClientId }}",
"clientSecret": "{{ oauth2ClientSecret }}",
"accessTokenUrl": "https://api.server.test/v1/token",
"grantType": "client_credentials",
"scope": "read:something write:something",
"type": "oauth2"
},
"body": {},
"headers": [],
"method": "GET",
"name": "/oauth2/client-credentials",
"parameters": [],
"parentId": "__WORKSPACE_ID__",
"url": "{{ base_url }}/oauth2/client-credentials"
},
{
"_id": "req___WORKSPACE_ID__06ba5946",
"_type": "request",
"authentication": {
"clientId": "{{ oauth2ClientId }}",
"clientSecret": "{{ oauth2ClientSecret }}",
"username": "{{ oauth2Username }}",
"password": "{{ oauth2Password }}",
"accessTokenUrl": "https://api.server.test/v1/token",
"grantType": "password",
"scope": "read:something write:something",
"type": "oauth2"
},
"body": {},
"headers": [],
"method": "GET",
"name": "/oauth2/password",
"parameters": [],
"parentId": "__WORKSPACE_ID__",
"url": "{{ base_url }}/oauth2/password"
},
{
"_id": "req___WORKSPACE_ID__e285189c",
"_type": "request",

View File

@ -22,7 +22,13 @@ const HTTP_AUTH_SCHEME = {
BASIC: 'basic',
BEARER: 'bearer',
};
const SUPPORTED_SECURITY_TYPES = [SECURITY_TYPE.HTTP, SECURITY_TYPE.API_KEY];
const OAUTH_FLOWS = {
AUTHORIZATION_CODE: 'authorizationCode',
CLIENT_CREDENTIALS: 'clientCredentials',
IMPLICIT: 'implicit',
PASSWORD: 'password',
};
const SUPPORTED_SECURITY_TYPES = [SECURITY_TYPE.HTTP, SECURITY_TYPE.API_KEY, SECURITY_TYPE.OAUTH];
const SUPPORTED_HTTP_AUTH_SCHEMES = [HTTP_AUTH_SCHEME.BASIC, HTTP_AUTH_SCHEME.BEARER];
let requestCounts = {};
@ -322,15 +328,29 @@ function parseSecurity(security, securitySchemes) {
apiKeyHeaders.push(apiKeyCookieHeader);
}
const httpAuthScheme = supportedSchemes.find(
scheme =>
scheme.type === SECURITY_TYPE.HTTP && SUPPORTED_HTTP_AUTH_SCHEMES.includes(scheme.scheme),
);
const authentication = (() => {
const authScheme = supportedSchemes.find(
scheme =>
[SECURITY_TYPE.HTTP, SECURITY_TYPE.OAUTH].includes(scheme.type) &&
SUPPORTED_HTTP_AUTH_SCHEMES.includes(scheme.scheme),
);
const httpAuth = httpAuthScheme ? parseHttpAuth(httpAuthScheme.scheme) : {};
if (!authScheme) {
return {};
}
switch (authScheme.type) {
case SECURITY_TYPE.HTTP:
return parseHttpAuth(authScheme.scheme);
case SECURITY_TYPE.OAUTH:
return parseOAuth2(authScheme);
default:
return {};
}
})();
return {
authentication: httpAuth,
authentication,
headers: apiKeyHeaders,
parameters: apiKeyParams,
};
@ -358,6 +378,20 @@ function getSecurityEnvVariables(securitySchemes) {
const hasHttpBearerScheme = securitySchemesArray.some(
scheme => scheme.type === SECURITY_TYPE.HTTP && scheme.scheme === 'bearer',
);
const oauth2Variables = securitySchemesArray.reduce((acc, scheme) => {
if (scheme.type === SECURITY_TYPE.OAUTH && scheme.scheme === 'bearer') {
acc.oauth2ClientId = 'clientId';
const flows = scheme.flows || {};
if (flows.authorizationCode || flows.clientCredentials || flows.password) {
acc.oauth2ClientSecret = 'clientSecret';
}
if (flows.password) {
acc.oauth2Username = 'username';
acc.oauth2Password = 'password';
}
}
return acc;
}, {});
Array.from(new Set(apiKeyVariableNames)).forEach(name => {
variables[name] = name;
@ -372,7 +406,7 @@ function getSecurityEnvVariables(securitySchemes) {
variables.bearerToken = 'bearerToken';
}
return variables;
return { ...variables, ...oauth2Variables };
}
/**
@ -546,6 +580,73 @@ function parseHttpAuth(scheme) {
}
}
function parseOAuth2Scopes(flow) {
const scopes = Object.keys(flow.scopes || {});
return scopes.join(' ');
}
function mapOAuth2GrantType(grantType) {
const types = {
[OAUTH_FLOWS.AUTHORIZATION_CODE]: 'authorization_code',
[OAUTH_FLOWS.CLIENT_CREDENTIALS]: 'client_credentials',
[OAUTH_FLOWS.IMPLICIT]: 'implicit',
[OAUTH_FLOWS.PASSWORD]: 'password',
};
return types[grantType];
}
function parseOAuth2(scheme) {
const flows = Object.keys(scheme.flows);
if (!flows.length) {
return {};
}
const grantType = flows[0];
const flow = scheme.flows[grantType];
if (!flow) {
return {};
}
const base = {
clientId: '{{ oauth2ClientId }}',
grantType: mapOAuth2GrantType(grantType),
scope: parseOAuth2Scopes(flow),
type: 'oauth2',
};
switch (grantType) {
case OAUTH_FLOWS.AUTHORIZATION_CODE:
return {
...base,
clientSecret: '{{ oauth2ClientSecret }}',
accessTokenUrl: flow.tokenUrl,
authorizationUrl: flow.authorizationUrl,
};
case OAUTH_FLOWS.CLIENT_CREDENTIALS:
return {
...base,
clientSecret: '{{ oauth2ClientSecret }}',
accessTokenUrl: flow.tokenUrl,
};
case OAUTH_FLOWS.IMPLICIT:
return {
...base,
authorizationUrl: flow.authorizationUrl,
};
case OAUTH_FLOWS.PASSWORD:
return {
...base,
clientSecret: '{{ oauth2ClientSecret }}',
username: '{{ oauth2Username }}',
password: '{{ oauth2Password }}',
accessTokenUrl: flow.tokenUrl,
};
}
}
function importBearerAuthentication() {
return {
type: 'bearer',