packages/aws-cdk-lib/aws-events/lib/connection.ts (194 lines of code) (raw):

import { Construct } from 'constructs'; import { CfnConnection } from './events.generated'; import { IResource, Resource, Stack, SecretValue, UnscopedValidationError } from '../../core'; import { addConstructMetadata } from '../../core/lib/metadata-resource'; /** * An API Destination Connection * * A connection defines the authorization type and credentials to use for authorization with an API destination HTTP endpoint. */ export interface ConnectionProps { /** * The name of the connection. * * @default - A name is automatically generated */ readonly connectionName?: string; /** * The name of the connection. * * @default - none */ readonly description?: string; /** * The authorization type for the connection. */ readonly authorization: Authorization; /** * Additional string parameters to add to the invocation bodies * * @default - No additional parameters */ readonly bodyParameters?: Record<string, HttpParameter>; /** * Additional string parameters to add to the invocation headers * * @default - No additional parameters */ readonly headerParameters?: Record<string, HttpParameter>; /** * Additional string parameters to add to the invocation query strings * * @default - No additional parameters */ readonly queryStringParameters?: Record<string, HttpParameter>; } /** * Authorization type for an API Destination Connection */ export abstract class Authorization { /** * Use API key authorization * * API key authorization has two components: an API key name and an API key value. * What these are depends on the target of your connection. */ public static apiKey(apiKeyName: string, apiKeyValue: SecretValue): Authorization { return new class extends Authorization { public _bind() { return { authorizationType: AuthorizationType.API_KEY, authParameters: { apiKeyAuthParameters: { apiKeyName: apiKeyName, apiKeyValue: apiKeyValue.unsafeUnwrap(), // Safe usage }, } as CfnConnection.AuthParametersProperty, }; } }(); } /** * Use username and password authorization */ public static basic(username: string, password: SecretValue): Authorization { return new class extends Authorization { public _bind() { return { authorizationType: AuthorizationType.BASIC, authParameters: { basicAuthParameters: { username: username, password: password.unsafeUnwrap(), // Safe usage }, } as CfnConnection.AuthParametersProperty, }; } }(); } /** * Use OAuth authorization */ public static oauth(props: OAuthAuthorizationProps): Authorization { if (![HttpMethod.POST, HttpMethod.GET, HttpMethod.PUT].includes(props.httpMethod)) { throw new UnscopedValidationError('httpMethod must be one of GET, POST, PUT'); } return new class extends Authorization { public _bind() { return { authorizationType: AuthorizationType.OAUTH_CLIENT_CREDENTIALS, authParameters: { oAuthParameters: { authorizationEndpoint: props.authorizationEndpoint, clientParameters: { clientId: props.clientId, clientSecret: props.clientSecret.unsafeUnwrap(), // Safe usage }, httpMethod: props.httpMethod, oAuthHttpParameters: { bodyParameters: renderHttpParameters(props.bodyParameters), headerParameters: renderHttpParameters(props.headerParameters), queryStringParameters: renderHttpParameters(props.queryStringParameters), }, }, } as CfnConnection.AuthParametersProperty, }; } }(); } /** * Bind the authorization to the construct and return the authorization properties * * @internal */ public abstract _bind(): AuthorizationBindResult; } /** * Properties for `Authorization.oauth()` */ export interface OAuthAuthorizationProps { /** * The URL to the authorization endpoint */ readonly authorizationEndpoint: string; /** * The method to use for the authorization request. * * (Can only choose POST, GET or PUT). */ readonly httpMethod: HttpMethod; /** * The client ID to use for OAuth authorization for the connection. */ readonly clientId: string; /** * The client secret associated with the client ID to use for OAuth authorization for the connection. */ readonly clientSecret: SecretValue; /** * Additional string parameters to add to the OAuth request body * * @default - No additional parameters */ readonly bodyParameters?: Record<string, HttpParameter>; /** * Additional string parameters to add to the OAuth request header * * @default - No additional parameters */ readonly headerParameters?: Record<string, HttpParameter>; /** * Additional string parameters to add to the OAuth request query string * * @default - No additional parameters */ readonly queryStringParameters?: Record<string, HttpParameter>; } /** * An additional HTTP parameter to send along with the OAuth request */ export abstract class HttpParameter { /** * Make an OAuthParameter from a string value * * The value is not treated as a secret. */ public static fromString(value: string): HttpParameter { return new class extends HttpParameter { public _render(name: string) { return { key: name, value, isValueSecret: false, } as CfnConnection.ParameterProperty; } }(); } /** * Make an OAuthParameter from a secret */ public static fromSecret(value: SecretValue): HttpParameter { return new class extends HttpParameter { public _render(name: string) { return { key: name, value: value.unsafeUnwrap(), // Safe usage isValueSecret: true, } as CfnConnection.ParameterProperty; } }(); } /** * Render the paramter value * * @internal */ public abstract _render(name: string): any; } /** * Result of the 'bind' operation of the 'Authorization' class * * @internal */ export interface AuthorizationBindResult { /** * The authorization type */ readonly authorizationType: AuthorizationType; /** * The authorization parameters (depends on the type) */ readonly authParameters: any; } /** * Interface for EventBus Connections */ export interface IConnection extends IResource { /** * The Name for the connection. * @attribute */ readonly connectionName: string; /** * The ARN of the connection created. * @attribute */ readonly connectionArn: string; /** * The ARN for the secret created for the connection. * @attribute */ readonly connectionSecretArn: string; } /** * Interface with properties necessary to import a reusable Connection */ export interface ConnectionAttributes { /** * The Name for the connection. */ readonly connectionName: string; /** * The ARN of the connection created. */ readonly connectionArn: string; /** * The ARN for the secret created for the connection. */ readonly connectionSecretArn: string; } /** * Define an EventBridge Connection * * @resource AWS::Events::Connection */ export class Connection extends Resource implements IConnection { /** * Import an existing connection resource * @param scope Parent construct * @param id Construct ID * @param connectionArn ARN of imported connection */ public static fromEventBusArn(scope: Construct, id: string, connectionArn: string, connectionSecretArn: string): IConnection { const parts = Stack.of(scope).parseArn(connectionArn); return new ImportedConnection(scope, id, { connectionArn: connectionArn, connectionName: parts.resourceName || '', connectionSecretArn: connectionSecretArn, }); } /** * Import an existing connection resource * @param scope Parent construct * @param id Construct ID * @param attrs Imported connection properties */ public static fromConnectionAttributes(scope: Construct, id: string, attrs: ConnectionAttributes): IConnection { return new ImportedConnection(scope, id, attrs); } /** * The Name for the connection. * @attribute */ public readonly connectionName: string; /** * The ARN of the connection created. * @attribute */ public readonly connectionArn: string; /** * The ARN for the secret created for the connection. * @attribute */ public readonly connectionSecretArn: string; constructor(scope: Construct, id: string, props: ConnectionProps) { super(scope, id, { physicalName: props.connectionName, }); // Enhanced CDK Analytics Telemetry addConstructMetadata(this, props); const authBind = props.authorization._bind(); const invocationHttpParameters = !!props.headerParameters || !!props.queryStringParameters || !!props.bodyParameters ? { bodyParameters: renderHttpParameters(props.bodyParameters), headerParameters: renderHttpParameters(props.headerParameters), queryStringParameters: renderHttpParameters(props.queryStringParameters), } : undefined; let connection = new CfnConnection(this, 'Connection', { authorizationType: authBind.authorizationType, authParameters: { ...authBind.authParameters, invocationHttpParameters: invocationHttpParameters, }, description: props.description, name: this.physicalName, }); this.connectionName = this.getResourceNameAttribute(connection.ref); this.connectionArn = connection.attrArn; this.connectionSecretArn = connection.attrSecretArn; } } class ImportedConnection extends Resource { public readonly connectionArn: string; public readonly connectionName: string; public readonly connectionSecretArn: string; constructor(scope: Construct, id: string, attrs: ConnectionAttributes) { const arnParts = Stack.of(scope).parseArn(attrs.connectionArn); super(scope, id, { account: arnParts.account, region: arnParts.region, }); // Enhanced CDK Analytics Telemetry addConstructMetadata(this, attrs); this.connectionArn = attrs.connectionArn; this.connectionName = attrs.connectionName; this.connectionSecretArn = attrs.connectionSecretArn; } } /** * Supported HTTP operations. */ export enum HttpMethod { /** POST */ POST = 'POST', /** GET */ GET = 'GET', /** HEAD */ HEAD = 'HEAD', /** OPTIONS */ OPTIONS = 'OPTIONS', /** PUT */ PUT = 'PUT', /** PATCH */ PATCH = 'PATCH', /** DELETE */ DELETE = 'DELETE', } /** * Supported Authorization Types. */ enum AuthorizationType { /** API_KEY */ API_KEY = 'API_KEY', /** BASIC */ BASIC = 'BASIC', /** OAUTH_CLIENT_CREDENTIALS */ OAUTH_CLIENT_CREDENTIALS = 'OAUTH_CLIENT_CREDENTIALS', } function renderHttpParameters(ps?: Record<string, HttpParameter>): CfnConnection.ParameterProperty[] | undefined { if (!ps || Object.keys(ps).length === 0) { return undefined; } return Object.entries(ps).map(([name, p]) => p._render(name)); }