Skip to content

Commit 54a01a8

Browse files
authored
feat: add OAuth2 provider support to identity (#1856)
* feat: add OAuth2 provider support to identity * fix: mark provider config as sensitive + use modeled errors * fix: preserve existing provider config on update, and generalize config validation
1 parent 6a4900e commit 54a01a8

38 files changed

Lines changed: 1722 additions & 73 deletions

src/core/identity.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,31 @@
11
import {
22
CreateApiKeyCredentialProviderCommand,
3+
CreateOauth2CredentialProviderCommand,
34
DeleteApiKeyCredentialProviderCommand,
5+
DeleteOauth2CredentialProviderCommand,
46
GetApiKeyCredentialProviderCommand,
7+
GetOauth2CredentialProviderCommand,
58
ListApiKeyCredentialProvidersCommand,
9+
ListOauth2CredentialProvidersCommand,
610
UpdateApiKeyCredentialProviderCommand,
11+
UpdateOauth2CredentialProviderCommand,
712
type CreateApiKeyCredentialProviderResponse,
13+
type CreateOauth2CredentialProviderResponse,
814
type DeleteApiKeyCredentialProviderResponse,
15+
type DeleteOauth2CredentialProviderResponse,
916
type GetApiKeyCredentialProviderResponse,
17+
type GetOauth2CredentialProviderResponse,
1018
type ListApiKeyCredentialProvidersResponse,
19+
type ListOauth2CredentialProvidersResponse,
1120
type UpdateApiKeyCredentialProviderResponse,
21+
type UpdateOauth2CredentialProviderResponse,
1222
} from "@aws-sdk/client-bedrock-agentcore-control";
1323
import type {
1424
CoreIdentityClient,
1525
CreateApiKeyCredentialProviderInput,
26+
CreateOauth2CredentialProviderInput,
1627
UpdateApiKeyCredentialProviderInput,
28+
UpdateOauth2CredentialProviderInput,
1729
} from "../handlers/identity/types";
1830
import type { AwsClients, CoreOptions } from "./types";
1931
import { toClientConfig } from "./utils";
@@ -66,4 +78,50 @@ export class IdentityClient implements CoreIdentityClient {
6678
.control(toClientConfig(options))
6779
.send(new DeleteApiKeyCredentialProviderCommand({ name }));
6880
}
81+
82+
async createOauth2CredentialProvider(
83+
input: CreateOauth2CredentialProviderInput,
84+
options: CoreOptions,
85+
): Promise<CreateOauth2CredentialProviderResponse> {
86+
return this.clients
87+
.control(toClientConfig(options))
88+
.send(new CreateOauth2CredentialProviderCommand(input));
89+
}
90+
91+
async getOauth2CredentialProvider(
92+
name: string,
93+
options: CoreOptions,
94+
): Promise<GetOauth2CredentialProviderResponse> {
95+
return this.clients
96+
.control(toClientConfig(options))
97+
.send(new GetOauth2CredentialProviderCommand({ name }));
98+
}
99+
100+
async listOauth2CredentialProviders(
101+
nextToken: string | undefined,
102+
maxResults: number | undefined,
103+
options: CoreOptions,
104+
): Promise<ListOauth2CredentialProvidersResponse> {
105+
return this.clients
106+
.control(toClientConfig(options))
107+
.send(new ListOauth2CredentialProvidersCommand({ nextToken, maxResults }));
108+
}
109+
110+
async updateOauth2CredentialProvider(
111+
input: UpdateOauth2CredentialProviderInput,
112+
options: CoreOptions,
113+
): Promise<UpdateOauth2CredentialProviderResponse> {
114+
return this.clients
115+
.control(toClientConfig(options))
116+
.send(new UpdateOauth2CredentialProviderCommand(input));
117+
}
118+
119+
async deleteOauth2CredentialProvider(
120+
name: string,
121+
options: CoreOptions,
122+
): Promise<DeleteOauth2CredentialProviderResponse> {
123+
return this.clients
124+
.control(toClientConfig(options))
125+
.send(new DeleteOauth2CredentialProviderCommand({ name }));
126+
}
69127
}

src/handlers/identity/api-key-credential-provider/create/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { Core } from "../../../types";
66
import type { AppIO } from "../../../../io";
77
import { coreOptsFromCtx, parseTags } from "../../../utils";
88
import { SourceResolver } from "../../../../io";
9-
import { parseSecretReference } from "../parser";
9+
import { parseSecretReference } from "../../parser";
1010

1111
export const createCreateApiKeyCredentialProviderHandler = (core: Core, io: AppIO) =>
1212
createHandler({
@@ -46,7 +46,7 @@ export const createCreateApiKeyCredentialProviderHandler = (core: Core, io: AppI
4646
const resolver = new SourceResolver({ stdin: io.stdin });
4747
const apiKey = await resolver.resolveText("api-key", flags["api-key"]);
4848
const apiKeySecretConfig = hasSecretRef
49-
? parseSecretReference(flags["api-key-secret-reference"]!)
49+
? parseSecretReference("api-key-secret-reference", flags["api-key-secret-reference"]!)
5050
: undefined;
5151
const apiKeySecretSource = hasApiKey ? "MANAGED" : "EXTERNAL";
5252
const tags = parseTags(flags.tags);

src/handlers/identity/api-key-credential-provider/parser.tsx

Lines changed: 0 additions & 42 deletions
This file was deleted.

src/handlers/identity/api-key-credential-provider/update/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { Core } from "../../../types";
66
import type { AppIO } from "../../../../io";
77
import { coreOptsFromCtx } from "../../../utils";
88
import { SourceResolver } from "../../../../io";
9-
import { parseSecretReference } from "../parser";
9+
import { parseSecretReference } from "../../parser";
1010

1111
export const createUpdateApiKeyCredentialProviderHandler = (core: Core, io: AppIO) =>
1212
createHandler({
@@ -59,7 +59,7 @@ export const createUpdateApiKeyCredentialProviderHandler = (core: Core, io: AppI
5959
const resolver = new SourceResolver({ stdin: io.stdin });
6060
const apiKey = await resolver.resolveText("api-key", flags["api-key"]);
6161
const apiKeySecretConfig = hasSecretRef
62-
? parseSecretReference(flags["api-key-secret-reference"]!)
62+
? parseSecretReference("api-key-secret-reference", flags["api-key-secret-reference"]!)
6363
: undefined;
6464

6565
ctx.require(JsonRendererKey).renderJson(

src/handlers/identity/identity.test.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ describe("identity command hierarchy", () => {
5353

5454
expect(identity?.children().map((child) => child.name())).toEqual([
5555
"api-key-credential-provider",
56+
"oauth2-credential-provider",
5657
]);
5758
expect(
5859
identity
@@ -240,7 +241,7 @@ describe("api-key-credential-provider CRUDL", () => {
240241
"--api-key-secret-reference",
241242
'{"jsonKey":"apiKey"}',
242243
],
243-
/non-empty "secretId"/,
244+
/--api-key-secret-reference/,
244245
],
245246
[
246247
"create: --api-key-secret-reference with unexpected field",
@@ -253,7 +254,7 @@ describe("api-key-credential-provider CRUDL", () => {
253254
"--api-key-secret-reference",
254255
'{"secretId":"arn:aws:secretsmanager:us-west-2:123:secret:s","jsonKey":"apiKey","extra":"bad"}',
255256
],
256-
/unexpected fields/,
257+
/--api-key-secret-reference/,
257258
],
258259
[
259260
"update: --api-key with --api-key-secret-reference",

src/handlers/identity/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import { Router } from "../../router";
22
import type { AppIO } from "../../io";
33
import type { Core } from "../types";
44
import { createApiKeyCredentialProviderHandler } from "./api-key-credential-provider";
5+
import { createOauth2CredentialProviderHandler } from "./oauth2-credential-provider";
56
import { createHelpDefault } from "../help";
67

78
export function createIdentityHandler(core: Core, io: AppIO): Router {
89
return new Router("identity", "manage AgentCore Identity resources")
910
.default(createHelpDefault(io))
10-
.handler(createApiKeyCredentialProviderHandler(core, io));
11+
.handler(createApiKeyCredentialProviderHandler(core, io))
12+
.handler(createOauth2CredentialProviderHandler(core, io));
1113
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"clientSecretArn": {
3+
"secretArn": "arn:aws:secretsmanager:us-west-2:685197708687:secret:bedrock-agentcore-identity!default/oauth2/agentcore-cli-oauth2-fixture-2-7058dd32-VnfWeP"
4+
},
5+
"name": "agentcore-cli-oauth2-fixture-2",
6+
"credentialProviderArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:token-vault/default/oauth2credentialprovider/agentcore-cli-oauth2-fixture-2",
7+
"clientSecretSource": "MANAGED",
8+
"callbackUrl": "https://bedrock-agentcore.us-west-2.amazonaws.com/identities/oauth2/callback/b783b413-142f-4bbd-9f5d-6198ce095ee3",
9+
"oauth2ProviderConfigOutput": {
10+
"customOauth2ProviderConfig": {
11+
"oauthDiscovery": {
12+
"discoveryUrl": "https://example.com/.well-known/openid-configuration"
13+
},
14+
"clientId": "fixture-client-id-2"
15+
}
16+
},
17+
"status": "READY"
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"clientSecretArn": {
3+
"secretArn": "arn:aws:secretsmanager:us-west-2:685197708687:secret:bedrock-agentcore-identity!default/oauth2/agentcore-cli-oauth2-fixture-d172b1a9-dFOvOv"
4+
},
5+
"name": "agentcore-cli-oauth2-fixture",
6+
"credentialProviderArn": "arn:aws:bedrock-agentcore:us-west-2:685197708687:token-vault/default/oauth2credentialprovider/agentcore-cli-oauth2-fixture",
7+
"clientSecretSource": "MANAGED",
8+
"callbackUrl": "https://bedrock-agentcore.us-west-2.amazonaws.com/identities/oauth2/callback/2edfe7c4-4655-41a5-9722-767aa15e5b45",
9+
"oauth2ProviderConfigOutput": {
10+
"customOauth2ProviderConfig": {
11+
"oauthDiscovery": {
12+
"discoveryUrl": "https://example.com/.well-known/openid-configuration"
13+
},
14+
"clientId": "fixture-client-id"
15+
}
16+
},
17+
"status": "READY"
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

0 commit comments

Comments
 (0)