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' ;
2017-03-23 22:10:42 +00:00
import getOAuth2Token from './o-auth-2/get-token' ;
2017-11-06 19:26:31 +00:00
import getOAuth1Token from './o-auth-1/get-token' ;
2017-08-21 17:43:12 +00:00
import * as Hawk from 'hawk' ;
2017-11-07 18:14:08 +00:00
import jwtAuthentication from 'jwt-authentication' ;
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' ;
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 ) ;
}
const header = Hawk . client . header ( url , method , headerOptions ) ;
2017-08-21 17:43:12 +00:00
return {
name : 'Authorization' ,
2021-05-12 06:35:00 +00:00
// @ts-expect-error -- TSCONVERSION need to update hawk, types only exist for the latest version (v9) and we need those types in order to successfully build
2018-12-12 17:36:11 +00:00
value : header.field ,
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 ;
}
2019-12-12 21:06:21 +00:00
export function _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 ;
2017-03-23 22:10:42 +00:00
}