UNPKG

aws-crt

Version:

NodeJS/browser bindings to the aws-c-* libraries

396 lines (346 loc) 13.7 kB
/* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ /** * Module for AWS Authentication logic - signing http requests, events, chunks, etc... * * @packageDocumentation * @module auth * @mergeTarget */ import * as auth from '../common/auth'; import crt_native from './binding'; import { CrtError } from './error'; import { HttpRequest, HttpProxyOptions } from './http'; import {ClientBootstrap, ClientTlsContext} from './io'; export {AwsSigningConfigBase} from "../common/auth"; /** * A pair defining an identity provider and a valid login token sourced from it. * * @category Auth */ export interface CognitoLoginTokenPair { /** * Name of an identity provider */ identityProviderName: string; /** * Valid login token source from the identity provider */ identityProviderToken: string; } /** * Definition for the configuration needed to create a Cognito-based Credentials Provider * * @category Auth */ export interface CognitoCredentialsProviderConfig { /** * Cognito service regional endpoint to source credentials from. */ endpoint: string; /** * Cognito identity to fetch credentials relative to. */ identity: string; /** * Optional set of identity provider token pairs to allow for authenticated identity access. */ logins?: Array<CognitoLoginTokenPair>; /** * Optional ARN of the role to be assumed when multiple roles were received in the token from the identity provider. */ customRoleArn?: string; /** * TLS context for secure socket connections. * If undefined, then a default tls context will be created and used. */ tlsContext?: ClientTlsContext; /** * Client bootstrap to use. In almost all cases, this can be left undefined. */ bootstrap?: ClientBootstrap; /** * Proxy configuration if connecting through an HTTP proxy is desired */ httpProxyOptions?: HttpProxyOptions; } /** * Definition for the configuration needed to create a X509-based Credentials Provider * * @category Auth */ export interface X509CredentialsConfig { /** * X509 service regional endpoint to source credentials from. * This is a per-account value that can be determined via the CLI: * `aws iot describe-endpoint --endpoint-type iot:CredentialProvider` */ endpoint: string; /** * The name of the IoT thing to use to fetch credentials. */ thingName: string; /** * The name of the role alias to fetch credentials through. */ roleAlias: string; /** * TLS context for secure socket connections. */ tlsContext: ClientTlsContext; /** * Proxy configuration if connecting through an HTTP proxy is desired */ httpProxyOptions?: HttpProxyOptions; } /** * Credentials providers source the AwsCredentials needed to sign an authenticated AWS request. * * We don't currently expose an interface for fetching credentials from Javascript. * * @category Auth */ /* Subclass for the purpose of exposing a non-NativeHandle based API */ export class AwsCredentialsProvider extends crt_native.AwsCredentialsProvider { /** * Creates a new default credentials provider to be used internally for AWS credentials resolution: * * The CRT's default provider chain currently sources in this order: * * 1. Environment * 2. Profile * 3. (conditional, off by default) ECS * 4. (conditional, on by default) EC2 Instance Metadata * * @param bootstrap (optional) client bootstrap to be used to establish any required network connections * * @returns a new credentials provider using default credentials resolution rules */ static newDefault(bootstrap: ClientBootstrap | undefined = undefined): AwsCredentialsProvider { return super.newDefault(bootstrap != null ? bootstrap.native_handle() : null); } /** * Creates a new credentials provider that returns a fixed set of credentials. * * @param access_key access key to use in the static credentials * @param secret_key secret key to use in the static credentials * @param session_token (optional) session token to use in the static credentials * * @returns a new credentials provider that will return a fixed set of AWS credentials */ static newStatic(access_key: crt_native.StringLike, secret_key: crt_native.StringLike, session_token?: crt_native.StringLike): AwsCredentialsProvider { return super.newStatic(access_key, secret_key, session_token); } /** * Creates a new credentials provider that sources credentials from the AWS Cognito Identity service via the * GetCredentialsForIdentity http API. * * @param config provider configuration necessary to make GetCredentialsForIdentity web requests * * @returns a new credentials provider that returns credentials sourced from the AWS Cognito Identity service */ static newCognito(config: CognitoCredentialsProviderConfig): AwsCredentialsProvider { if (config == null || config == undefined) { throw new CrtError("AwsCredentialsProvider newCognito: Cognito config not defined"); } return super.newCognito(config, config.tlsContext != null ? config.tlsContext.native_handle() : new ClientTlsContext().native_handle(), config.bootstrap != null ? config.bootstrap.native_handle() : null, config.httpProxyOptions ? config.httpProxyOptions.create_native_handle() : null); } /** * Creates a new credentials provider that sources credentials from the the X509 service on AWS IoT Core. * * @param config provider configuration necessary to source credentials via X509 * * @returns a new credentials provider that returns credentials sourced from the AWS X509 service */ static newX509(config : X509CredentialsConfig): AwsCredentialsProvider { if (config == null || config == undefined) { throw new CrtError("AwsCredentialsProvider newX509: X509 config not defined") } return super.newX509( config, config.tlsContext.native_handle(), config.httpProxyOptions ? config.httpProxyOptions.create_native_handle() : null); } } /** * AWS signing algorithm enumeration. * * @category Auth */ export enum AwsSigningAlgorithm { /** Use the Aws signature version 4 signing process to sign the request */ SigV4, /** Use the Aws signature version 4 Asymmetric signing process to sign the request */ SigV4Asymmetric } /** * AWS signature type enumeration. * * @category Auth */ export enum AwsSignatureType { /** Sign an http request and apply the signing results as headers */ HttpRequestViaHeaders, /** Sign an http request and apply the signing results as query params */ HttpRequestViaQueryParams, /** Sign an http request payload chunk */ HttpRequestChunk, /** Sign an event stream event */ HttpRequestEvent } /** * Values for use with {@link AwsSigningConfig.signed_body_value}. * * Some services use special values (e.g. 'UNSIGNED-PAYLOAD') when the body * is not being signed in the usual way. * * @category Auth */ export enum AwsSignedBodyValue { /** Use the SHA-256 of the empty string as the canonical request payload value */ EmptySha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", /** Use the literal string 'UNSIGNED-PAYLOAD' as the canonical request payload value */ UnsignedPayload = "UNSIGNED-PAYLOAD", /** Use the literal string 'STREAMING-AWS4-HMAC-SHA256-PAYLOAD' as the canonical request payload value */ StreamingAws4HmacSha256Payload = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD", /** Use the literal string 'STREAMING-AWS4-HMAC-SHA256-EVENTS' as the canonical request payload value */ StreamingAws4HmacSha256Events = "STREAMING-AWS4-HMAC-SHA256-EVENTS", } /** * AWS signed body header enumeration. * * @category Auth */ export enum AwsSignedBodyHeaderType { /** Do not add a header containing the canonical request payload value */ None, /** Add the X-Amz-Content-Sha256 header with the canonical request payload value */ XAmzContentSha256 } /** * Configuration for use in AWS-related signing. * AwsSigningConfig is immutable. * It is good practice to use a new config for each signature, or the date might get too old. * * @category Auth */ export interface AwsSigningConfig extends auth.AwsSigningConfigBase { /** Which signing process to invoke */ algorithm: AwsSigningAlgorithm; /** What kind of signature to compute */ signature_type: AwsSignatureType; /** Credentials provider to fetch signing credentials with */ provider: AwsCredentialsProvider; /** * Headers to skip when signing. * * Skipping auth-required headers will result in an unusable signature. * Headers injected by the signing process are not skippable. * This function does not override the internal check function * (x-amzn-trace-id, user-agent), but rather supplements it. * In particular, a header will get signed if and only if it returns * true to both the internal check (skips x-amzn-trace-id, user-agent) * and is found in this list (if defined) */ header_blacklist?: string[]; /** * Set true to double-encode the resource path when constructing the * canonical request. By default, all services except S3 use double encoding. */ use_double_uri_encode?: boolean; /** * Whether the resource paths are normalized when building the canonical request. */ should_normalize_uri_path?: boolean; /** * Should the session token be omitted from the signing process? This should only be * true when making a websocket handshake with IoT Core. */ omit_session_token?: boolean; /** * Value to use as the canonical request's body value. * * Typically, this is the SHA-256 of the payload, written as lowercase hex. * If this has been precalculated, it can be set here. * Special values used by certain services can also be set (see {@link AwsSignedBodyValue}). * If undefined (the default), the typical value will be calculated from the payload during signing. */ signed_body_value?: string; /** Controls what header, if any, should be added to the request, containing the body value */ signed_body_header?: AwsSignedBodyHeaderType; /** Query param signing only: how long the pre-signed URL is valid for */ expiration_in_seconds?: number; } /** * Perform AWS HTTP request signing. * * The {@link HttpRequest} is transformed asynchronously, * according to the {@link AwsSigningConfig}. * * When signing: * 1. It is good practice to use a new config for each signature, * or the date might get too old. * * 2. Do not add the following headers to requests before signing, they may be added by the signer: * x-amz-content-sha256, * X-Amz-Date, * Authorization * * 3. Do not add the following query params to requests before signing, they may be added by the signer: * X-Amz-Signature, * X-Amz-Date, * X-Amz-Credential, * X-Amz-Algorithm, * X-Amz-SignedHeaders * @param request The HTTP request to sign. * @param config Configuration for signing. * @returns A promise whose result will be the signed * {@link HttpRequest}. The future will contain an exception * if the signing process fails. * * @category Auth */ export async function aws_sign_request(request: HttpRequest, config: AwsSigningConfig): Promise<HttpRequest> { return new Promise((resolve, reject) => { try { /* Note: if the body of request has not fully loaded, it will lead to an endless loop. * User should set the signed_body_value of config to prevent this endless loop in this case */ crt_native.aws_sign_request(request, config, (error_code) => { if (error_code == 0) { resolve(request); } else { reject(new CrtError(error_code)); } }); } catch (error) { reject(error); } }); } /** * * @internal * * Test only. * Verifies: * (1) The canonical request generated during sigv4a signing of the request matches what is passed in * (2) The signature passed in is a valid ECDSA signature of the hashed string-to-sign derived from the * canonical request * * @param request The HTTP request to sign. * @param config Configuration for signing. * @param expected_canonical_request String type of expected canonical request. Refer to XXX(link to doc?) * @param signature The generated signature string from {@link aws_sign_request}, which is verified here. * @param ecc_key_pub_x the x coordinate of the public part of the ecc key to verify the signature. * @param ecc_key_pub_y the y coordinate of the public part of the ecc key to verify the signature * @returns True, if the verification succeed. Otherwise, false. */ export function aws_verify_sigv4a_signing(request: HttpRequest, config: AwsSigningConfig, expected_canonical_request: crt_native.StringLike, signature: crt_native.StringLike, ecc_key_pub_x: crt_native.StringLike, ecc_key_pub_y: crt_native.StringLike): boolean { return crt_native.aws_verify_sigv4a_signing(request, config, expected_canonical_request, signature, ecc_key_pub_x, ecc_key_pub_y); }