Skip to content

Commit 5896264

Browse files
authored
feat(core): resolve auth schemes based on the preference list (#1571)
1 parent 063c14b commit 5896264

File tree

4 files changed

+95
-1
lines changed

4 files changed

+95
-1
lines changed

.changeset/fluffy-ducks-grin.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@smithy/core": minor
3+
---
4+
5+
Resolve auth schemes based on the preference list

packages/core/src/middleware-http-auth-scheme/httpAuthSchemeMiddleware.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
HttpAuthSchemeParametersProvider,
77
HttpAuthSchemeProvider,
88
IdentityProviderConfig,
9+
Provider,
910
SelectedHttpAuthScheme,
1011
SerializeHandler,
1112
SerializeHandlerArguments,
@@ -15,10 +16,13 @@ import {
1516
} from "@smithy/types";
1617
import { getSmithyContext } from "@smithy/util-middleware";
1718

19+
import { resolveAuthOptions } from "./resolveAuthOptions";
20+
1821
/**
1922
* @internal
2023
*/
2124
export interface PreviouslyResolved<TParameters extends HttpAuthSchemeParameters> {
25+
authSchemePreference?: Provider<string[]>;
2226
httpAuthSchemes: HttpAuthScheme[];
2327
httpAuthSchemeProvider: HttpAuthSchemeProvider<TParameters>;
2428
}
@@ -84,10 +88,14 @@ export const httpAuthSchemeMiddleware =
8488
const options = config.httpAuthSchemeProvider(
8589
await mwOptions.httpAuthSchemeParametersProvider(config, context as TContext, args.input)
8690
);
91+
92+
const authSchemePreference = config.authSchemePreference ? await config.authSchemePreference() : [];
93+
const resolvedOptions = resolveAuthOptions(options, authSchemePreference);
94+
8795
const authSchemes = convertHttpAuthSchemesToMap(config.httpAuthSchemes);
8896
const smithyContext: HttpAuthSchemeMiddlewareSmithyContext = getSmithyContext(context);
8997
const failureReasons = [];
90-
for (const option of options) {
98+
for (const option of resolvedOptions) {
9199
const scheme = authSchemes.get(option.schemeId);
92100
if (!scheme) {
93101
failureReasons.push(`HttpAuthScheme \`${option.schemeId}\` was not enabled for this service.`);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { HttpAuthOption } from "@smithy/types";
2+
import { describe, expect, it } from "vitest";
3+
4+
import { resolveAuthOptions } from "./resolveAuthOptions";
5+
6+
describe("resolveAuthSchemes", () => {
7+
const sigv4 = "sigv4";
8+
const sigv4a = "sigv4a";
9+
10+
const mockSigV4AuthScheme = { schemeId: `aws.auth#${sigv4}` } as HttpAuthOption;
11+
const mockSigV4aAuthScheme = { schemeId: `aws.auth#${sigv4a}` } as HttpAuthOption;
12+
13+
it("should return candidate auth schemes is preference list is not available", () => {
14+
const candidateAuthSchemes = [mockSigV4AuthScheme, mockSigV4aAuthScheme];
15+
expect(resolveAuthOptions(candidateAuthSchemes, [])).toEqual(candidateAuthSchemes);
16+
17+
// @ts-expect-error case where callee incorrectly passes undefined
18+
expect(resolveAuthOptions(candidateAuthSchemes)).toEqual(candidateAuthSchemes);
19+
});
20+
21+
it("should return auth scheme from preference if it's available", () => {
22+
expect(resolveAuthOptions([mockSigV4AuthScheme, mockSigV4aAuthScheme], [sigv4a])).toEqual([
23+
mockSigV4aAuthScheme,
24+
mockSigV4AuthScheme,
25+
]);
26+
27+
expect(resolveAuthOptions([mockSigV4AuthScheme, mockSigV4aAuthScheme], [sigv4a, sigv4])).toEqual([
28+
mockSigV4aAuthScheme,
29+
mockSigV4AuthScheme,
30+
]);
31+
32+
expect(resolveAuthOptions([mockSigV4AuthScheme, mockSigV4aAuthScheme], [sigv4, sigv4a])).toEqual([
33+
mockSigV4AuthScheme,
34+
mockSigV4aAuthScheme,
35+
]);
36+
});
37+
38+
it("should ignore auth scheme from preference if it's not available", () => {
39+
expect(resolveAuthOptions([mockSigV4AuthScheme], [sigv4a])).toEqual([mockSigV4AuthScheme]);
40+
expect(resolveAuthOptions([mockSigV4AuthScheme], ["sigv3"])).toEqual([mockSigV4AuthScheme]);
41+
});
42+
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { HttpAuthOption } from "@smithy/types";
2+
3+
/**
4+
* Resolves list of auth options based on the supported ones, vs the preference list.
5+
*
6+
* @param candidateAuthOptions list of supported auth options selected by the standard
7+
* resolution process (model-based, endpoints 2.0, etc.)
8+
* @param authSchemePreference list of auth schemes preferred by user.
9+
* @returns
10+
*/
11+
export const resolveAuthOptions = (
12+
candidateAuthOptions: HttpAuthOption[],
13+
authSchemePreference: string[]
14+
): HttpAuthOption[] => {
15+
if (!authSchemePreference || authSchemePreference.length === 0) {
16+
return candidateAuthOptions;
17+
}
18+
19+
// reprioritize candidates based on user's preference
20+
const preferredAuthOptions = [];
21+
22+
for (const preferredSchemeName of authSchemePreference) {
23+
for (const candidateAuthOption of candidateAuthOptions) {
24+
const candidateAuthSchemeName = candidateAuthOption.schemeId.split("#")[1];
25+
if (candidateAuthSchemeName === preferredSchemeName) {
26+
preferredAuthOptions.push(candidateAuthOption);
27+
}
28+
}
29+
}
30+
31+
// add any remaining candidates that weren't in the preference list
32+
for (const candidateAuthOption of candidateAuthOptions) {
33+
if (!preferredAuthOptions.find(({ schemeId }) => schemeId === candidateAuthOption.schemeId)) {
34+
preferredAuthOptions.push(candidateAuthOption);
35+
}
36+
}
37+
38+
return preferredAuthOptions;
39+
};

0 commit comments

Comments
 (0)