2021-11-03 16:11:21 +00:00
|
|
|
import * as Hawk from '@hapi/hawk';
|
2021-07-22 23:04:56 +00:00
|
|
|
import jwtAuthentication from 'jwt-authentication';
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
import {
|
|
|
|
AUTH_ASAP,
|
|
|
|
AUTH_BASIC,
|
|
|
|
AUTH_BEARER,
|
|
|
|
AUTH_HAWK,
|
|
|
|
AUTH_OAUTH_1,
|
2018-12-12 17:36:11 +00:00
|
|
|
AUTH_OAUTH_2,
|
2018-06-25 17:42:50 +00:00
|
|
|
} from '../common/constants';
|
2019-03-11 21:52:48 +00:00
|
|
|
import type { RenderedRequest } from '../common/render';
|
2018-06-25 17:42:50 +00:00
|
|
|
import { getBasicAuthHeader } from './basic-auth/get-header';
|
|
|
|
import { getBearerAuthHeader } from './bearer-auth/get-header';
|
2021-07-22 23:04:56 +00:00
|
|
|
import getOAuth1Token from './o-auth-1/get-token';
|
|
|
|
import getOAuth2Token from './o-auth-2/get-token';
|
2017-03-23 22:10:42 +00:00
|
|
|
|
2021-05-12 06:35:00 +00:00
|
|
|
interface Header {
|
|
|
|
name: string;
|
|
|
|
value: string;
|
|
|
|
}
|
2017-11-06 20:44:55 +00:00
|
|
|
|
2021-05-12 06:35:00 +00:00
|
|
|
export async function getAuthHeader(renderedRequest: RenderedRequest, url: string) {
|
2019-12-18 21:49:39 +00:00
|
|
|
const { method, authentication, body } = renderedRequest;
|
2019-03-11 21:52:48 +00:00
|
|
|
const requestId = renderedRequest._id;
|
|
|
|
|
2017-03-23 22:10:42 +00:00
|
|
|
if (authentication.disabled) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (authentication.type === AUTH_BASIC) {
|
2020-09-24 20:58:28 +00:00
|
|
|
const { username, password, useISO88591 } = authentication;
|
|
|
|
const encoding = useISO88591 ? 'latin1' : 'utf8';
|
|
|
|
return getBasicAuthHeader(username, password, encoding);
|
2017-03-23 22:10:42 +00:00
|
|
|
}
|
|
|
|
|
2017-06-01 13:18:42 +00:00
|
|
|
if (authentication.type === AUTH_BEARER) {
|
2018-06-25 17:42:50 +00:00
|
|
|
const { token, prefix } = authentication;
|
2018-03-30 12:52:02 +00:00
|
|
|
return getBearerAuthHeader(token, prefix);
|
2017-06-01 13:18:42 +00:00
|
|
|
}
|
|
|
|
|
2017-03-23 22:10:42 +00:00
|
|
|
if (authentication.type === AUTH_OAUTH_2) {
|
2018-03-29 02:32:09 +00:00
|
|
|
// HACK: GraphQL requests use a child request to fetch the schema with an
|
|
|
|
// ID of "{{request_id}}.graphql". Here we are removing the .graphql suffix and
|
|
|
|
// pretending we are fetching a token for the original request. This makes sure
|
|
|
|
// the same tokens are used for schema fetching. See issue #835 on GitHub.
|
2018-10-17 16:42:33 +00:00
|
|
|
const tokenId = requestId.match(/\.graphql$/) ? requestId.replace(/\.graphql$/, '') : requestId;
|
2018-03-29 02:32:09 +00:00
|
|
|
const oAuth2Token = await getOAuth2Token(tokenId, authentication);
|
2021-05-12 06:35:00 +00:00
|
|
|
|
2017-03-23 22:10:42 +00:00
|
|
|
if (oAuth2Token) {
|
2017-04-07 18:10:15 +00:00
|
|
|
const token = oAuth2Token.accessToken;
|
2017-08-10 19:34:33 +00:00
|
|
|
return _buildBearerHeader(token, authentication.tokenPrefix);
|
2017-03-23 22:10:42 +00:00
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-06 19:26:31 +00:00
|
|
|
if (authentication.type === AUTH_OAUTH_1) {
|
2019-12-18 21:49:39 +00:00
|
|
|
const oAuth1Token = await getOAuth1Token(url, method, authentication, body);
|
2021-05-12 06:35:00 +00:00
|
|
|
|
2017-11-06 19:26:31 +00:00
|
|
|
if (oAuth1Token) {
|
|
|
|
return {
|
|
|
|
name: 'Authorization',
|
2018-12-12 17:36:11 +00:00
|
|
|
value: oAuth1Token.Authorization,
|
2017-11-06 19:26:31 +00:00
|
|
|
};
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-21 17:43:12 +00:00
|
|
|
if (authentication.type === AUTH_HAWK) {
|
2019-03-11 21:52:48 +00:00
|
|
|
const { id, key, algorithm, ext, validatePayload } = authentication;
|
|
|
|
let headerOptions = {
|
2021-05-12 06:35:00 +00:00
|
|
|
credentials: {
|
|
|
|
id,
|
|
|
|
key,
|
|
|
|
algorithm,
|
|
|
|
},
|
2018-12-12 17:36:11 +00:00
|
|
|
ext: ext,
|
2019-03-11 21:52:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (validatePayload) {
|
|
|
|
const payloadValidationFields = {
|
|
|
|
payload: renderedRequest.body.text,
|
|
|
|
contentType: renderedRequest.body.mimeType,
|
|
|
|
};
|
|
|
|
headerOptions = Object.assign({}, payloadValidationFields, headerOptions);
|
|
|
|
}
|
|
|
|
|
2021-11-03 16:11:21 +00:00
|
|
|
const { header } = Hawk.client.header(url, method, headerOptions);
|
2017-08-21 17:43:12 +00:00
|
|
|
return {
|
|
|
|
name: 'Authorization',
|
2021-11-03 16:11:21 +00:00
|
|
|
value: header,
|
2017-08-21 17:43:12 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-11-07 18:14:08 +00:00
|
|
|
if (authentication.type === AUTH_ASAP) {
|
2018-10-17 16:42:33 +00:00
|
|
|
const { issuer, subject, audience, keyId, additionalClaims, privateKey } = authentication;
|
2017-11-07 18:14:08 +00:00
|
|
|
const generator = jwtAuthentication.client.create();
|
2021-05-12 06:35:00 +00:00
|
|
|
let claims = {
|
|
|
|
iss: issuer,
|
|
|
|
sub: subject,
|
|
|
|
aud: audience,
|
|
|
|
};
|
2018-03-28 23:27:21 +00:00
|
|
|
let parsedAdditionalClaims;
|
|
|
|
|
|
|
|
try {
|
2018-06-06 20:29:07 +00:00
|
|
|
parsedAdditionalClaims = JSON.parse(additionalClaims || '{}');
|
2018-03-28 23:27:21 +00:00
|
|
|
} catch (err) {
|
|
|
|
throw new Error(`Unable to parse additional-claims: ${err}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parsedAdditionalClaims) {
|
|
|
|
if (typeof parsedAdditionalClaims !== 'object') {
|
2018-06-25 17:42:50 +00:00
|
|
|
throw new Error(
|
2018-12-12 17:36:11 +00:00
|
|
|
`additional-claims must be an object received: '${typeof parsedAdditionalClaims}' instead`,
|
2018-06-25 17:42:50 +00:00
|
|
|
);
|
2018-03-28 23:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
claims = Object.assign(parsedAdditionalClaims, claims);
|
|
|
|
}
|
|
|
|
|
2017-11-07 18:14:08 +00:00
|
|
|
const options = {
|
|
|
|
privateKey,
|
2018-12-12 17:36:11 +00:00
|
|
|
kid: keyId,
|
2017-11-07 18:14:08 +00:00
|
|
|
};
|
2021-05-12 06:35:00 +00:00
|
|
|
return new Promise<Header>((resolve, reject) => {
|
2018-10-17 16:42:33 +00:00
|
|
|
generator.generateAuthorizationHeader(claims, options, (error, headerValue) => {
|
|
|
|
if (error) {
|
|
|
|
reject(error);
|
|
|
|
} else {
|
|
|
|
resolve({
|
|
|
|
name: 'Authorization',
|
2018-12-12 17:36:11 +00:00
|
|
|
value: headerValue,
|
2018-10-17 16:42:33 +00:00
|
|
|
});
|
2017-11-07 18:14:08 +00:00
|
|
|
}
|
2018-10-17 16:42:33 +00:00
|
|
|
});
|
2017-11-07 18:14:08 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-03-23 22:10:42 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2022-02-02 16:21:25 +00:00
|
|
|
export const _buildBearerHeader = (accessToken: string, prefix: string) => {
|
2017-03-23 22:10:42 +00:00
|
|
|
if (!accessToken) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2019-12-12 20:57:39 +00:00
|
|
|
const header = {
|
|
|
|
name: 'Authorization',
|
|
|
|
value: '',
|
|
|
|
};
|
2017-03-23 22:10:42 +00:00
|
|
|
|
2019-12-12 20:57:39 +00:00
|
|
|
if (prefix === 'NO_PREFIX') {
|
|
|
|
header.value = accessToken;
|
|
|
|
} else {
|
|
|
|
header.value = `${prefix || 'Bearer'} ${accessToken}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
return header;
|
2022-02-02 16:21:25 +00:00
|
|
|
};
|