Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ This package provides an implementation for the `@aws-appsync/utils` package tha

## Changelog:

- v0.1.8: `util.authType()` now reports `Lambda Authorization` for the identity of a Lambda-authorized Event API request, which carries what the authorizer returned as `handlerContext` rather than the `resolverContext` a GraphQL API uses
- v0.1.7: complete the `@aws-appsync/utils/dynamodb` module with `query`, `sync`, the batch and transact helpers, the set helpers, `operations.remove` and `operations.updateListItem`, and the arguments the existing helpers dropped (`filter`, `projection`, `condition`, `consistentRead`, `_version` and the rest); add `util.transform.toSubscriptionFilter`; `util.dynamodb.fromS3ObjectJson` now parses instead of throwing
- v0.1.6: add `util.authType()`, derived from the identity of the request; a host installs the request through the new `setResolverContext` export. `util.transform.toDynamoDBFilterExpression` and `toDynamoDBConditionExpression` now cover every operator, including `between`, `in`, `size` and `attributeType`, and nested `and`/`or`/`not`; `util.dynamodb.toDynamoDB` accepts `null`
- v0.1.5: add `rds` `beginsWith`, `between` and `size` conditions, table aliases and `sql` template `where` clauses; invalid input now raises AWS's validation error instead of a raw `TypeError`, and the wildcard conditions require a string
Expand Down
28 changes: 28 additions & 0 deletions __tests__/authType.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ const COGNITO_CLAIMS = {

const LAMBDA_IDENTITY = { resolverContext: { userId: "alice", role: "admin" } };

// the same authorizer output on an Event API, which names the key `handlerContext`
const EVENT_LAMBDA_IDENTITY = { handlerContext: { userId: "alice", invocation: "inv-1" } };

const IAM_IDENTITY = {
accountId: "123456789012",
cognitoIdentityPoolId: null,
Expand Down Expand Up @@ -134,6 +137,31 @@ describe("util.authType", () => {
});
});

// NOT compared against AWS by this suite, unlike the blocks above: `EvaluateCode` validates its
// mock context against the GraphQL identity keys and rejects one carrying `handlerContext` ("The
// following properties in your mock context object failed validation: ctx.identity"), so
// `checkResolverValid` cannot reach this shape even with `TEST_TARGET=AWS_CLOUD`. The expected
// values were instead read off responses recorded from a real Lambda-authorized Event API on
// AWS, where `ctx.identity` is `{handlerContext: {...}}` and `util.authType()` is `Lambda
// Authorization`.
describe("the identity of an Event API request", () => {
afterEach(() => setResolverContext(null));

const authTypeForEventIdentity = (identity) => {
setResolverContext({ identity });
return util.authType();
};

test("an identity carrying a handler context comes from a Lambda authorizer", () => {
expect(authTypeForEventIdentity(EVENT_LAMBDA_IDENTITY)).toBe("Lambda Authorization");
});

// an authorizer that returns no context at all leaves the key holding an empty object
test("an identity whose handler context is empty comes from a Lambda authorizer", () => {
expect(authTypeForEventIdentity({ handlerContext: {} })).toBe("Lambda Authorization");
});
});

// NOT compared against AWS: `setResolverContext` is the seam a host uses to hand the request to
// the utils, so these pin our own contract with the runtime rather than any AWS behaviour. They
// also show that the module a test imports is the module the resolver code imports.
Expand Down
13 changes: 10 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,12 @@ const IDENTITY_SCHEMAS = [
required: ["sub", "issuer", "claims"],
},
{
// `resolverContext` is what the authorizer returned, and an authorizer may return nothing at
// all, so an identity with no keys whatsoever is a Lambda identity to AWS
// Both keys carry what the authorizer returned: a GraphQL API puts it under `resolverContext`
// and an Event API under `handlerContext`. An authorizer may return nothing at all, which
// leaves the key holding an empty object or the identity holding no keys whatsoever, so an
// empty identity is a Lambda identity to AWS rather than an absent one.
authType: AUTH_TYPE_LAMBDA,
keys: ["resolverContext"],
keys: ["resolverContext", "handlerContext"],
required: [],
},
];
Expand All @@ -181,6 +183,11 @@ const IDENTITY_SCHEMAS = [
// pool identity and not an OIDC one. The modes are mutually exclusive under those two rules, so
// the order below only makes the outcome deterministic. Anything unmatched, an absent identity
// included, is an API key request, which is the mode that populates no identity at all.
//
// The Event API identity, `{handlerContext}`, is the one shape not recorded that way:
// `EvaluateCode` validates its mock context against the GraphQL identity keys alone and rejects
// `handlerContext` before the resolver runs. It was read off the responses of a real
// Lambda-authorized Event API instead.
function authTypeFromIdentity(identity) {
if (identity === null || typeof identity !== "object" || Array.isArray(identity)) {
return AUTH_TYPE_API_KEY;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@localstack/appsync-utils",
"version": "0.1.7",
"version": "0.1.8",
"description": "Implementation of the AppSync utils helpers",
"type": "module",
"main": "index.js",
Expand Down
Loading