Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed missing endpoints for feature Organizations for Client Credentials changes #1046

Merged
merged 6 commits into from
Nov 5, 2024
12 changes: 0 additions & 12 deletions src/auth/id-token-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,24 +102,12 @@ export class IDTokenValidator {
'Organization Id (org_id) claim must be a string present in the ID token'
);
}

if (payload.org_id !== organization) {
throw new Error(
`Organization Id (org_id) claim value mismatch in the ID token; expected "${organization}", found "${payload.org_id}"'`
);
}
} else {
if (!payload.org_name || typeof payload.org_name !== 'string') {
throw new Error(
'Organization Name (org_name) claim must be a string present in the ID token'
);
}

if (payload.org_name !== organization.toLowerCase()) {
throw new Error(
`Organization Name (org_name) claim value mismatch in the ID token; expected "${organization}", found "${payload.org_name}"'`
);
}
}
}

Expand Down
61 changes: 60 additions & 1 deletion src/management/__generated/managers/organizations-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
GetInvitations200ResponseOneOfInner,
GetMembers200Response,
GetOrganizationClientGrants200Response,
GetOrganizationClientGrants200ResponseOneOfInner,

Check warning on line 12 in src/management/__generated/managers/organizations-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/management/__generated/managers/organizations-manager.ts#L12

Added line #L12 was not covered by tests
GetOrganizationMemberRoles200Response,
GetOrganizations200Response,
GetOrganizations200ResponseOneOfInner,
Expand All @@ -17,6 +18,7 @@
PostEnabledConnectionsRequest,
PostInvitationsRequest,
PostMembersRequest,
PostOrganizationClientGrantsRequest,

Check warning on line 21 in src/management/__generated/managers/organizations-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/management/__generated/managers/organizations-manager.ts#L21

Added line #L21 was not covered by tests
PostOrganizationMemberRolesRequest,
PostOrganizations201Response,
PostOrganizationsRequest,
Expand All @@ -25,10 +27,10 @@
GetMembers200ResponseOneOf,
GetMembers200ResponseOneOfInner,
GetOrganizationClientGrants200ResponseOneOf,
GetOrganizationClientGrants200ResponseOneOfInner,
GetOrganizationMemberRoles200ResponseOneOf,
GetOrganizationMemberRoles200ResponseOneOfInner,
GetOrganizations200ResponseOneOf,
DeleteClientGrantsByGrantIdRequest,
DeleteEnabledConnectionsByConnectionIdRequest,
DeleteInvitationsByInvitationIdRequest,
DeleteMembersOperationRequest,
Expand All @@ -49,6 +51,7 @@
PostEnabledConnectionsOperationRequest,
PostInvitationsOperationRequest,
PostMembersOperationRequest,
PostOrganizationClientGrantsOperationRequest,
PostOrganizationMemberRolesOperationRequest,
} from '../models/index.js';

Expand All @@ -58,6 +61,30 @@
*
*/
export class OrganizationsManager extends BaseAPI {
/**
* Remove a client grant from an organization
*
* @throws {RequiredError}
*/
async deleteClientGrantsByGrantId(
requestParameters: DeleteClientGrantsByGrantIdRequest,
initOverrides?: InitOverride
): Promise<ApiResponse<void>> {
runtime.validateRequiredRequestParams(requestParameters, ['id', 'grant_id']);

const response = await this.request(
{
path: `/organizations/{id}/client-grants/{grant_id}`
.replace('{id}', encodeURIComponent(String(requestParameters.id)))
.replace('{grant_id}', encodeURIComponent(String(requestParameters.grant_id))),
method: 'DELETE',
},
initOverrides
);

return runtime.VoidApiResponse.fromResponse(response);
}

/**
* Delete connections from an organization
*
Expand Down Expand Up @@ -859,6 +886,38 @@
return runtime.VoidApiResponse.fromResponse(response);
}

/**
* Associate a client grant with an organization
*
* @throws {RequiredError}
*/
async postOrganizationClientGrants(
requestParameters: PostOrganizationClientGrantsOperationRequest,
bodyParameters: PostOrganizationClientGrantsRequest,
initOverrides?: InitOverride
): Promise<ApiResponse<GetOrganizationClientGrants200ResponseOneOfInner>> {
runtime.validateRequiredRequestParams(requestParameters, ['id']);

const headerParameters: runtime.HTTPHeaders = {};

headerParameters['Content-Type'] = 'application/json';

const response = await this.request(
{
path: `/organizations/{id}/client-grants`.replace(
'{id}',
encodeURIComponent(String(requestParameters.id))
),
method: 'POST',
headers: headerParameters,
body: bodyParameters,
},
initOverrides
);

return runtime.JSONApiResponse.fromResponse(response);
}

/**
* Assign one or more roles to a given user that will be applied in the context of the provided organization
*
Expand Down
35 changes: 35 additions & 0 deletions src/management/__generated/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10513,6 +10513,16 @@
*/
members: Array<string>;
}
/**
*
*/
export interface PostOrganizationClientGrantsRequest {
/**
* A Client Grant ID to add to the organization.
*
*/
grant_id: string;
}
/**
*
*/
Expand Down Expand Up @@ -12146,7 +12156,7 @@
/**
*
*/
export interface SsProfileList extends Array<SsProfile> {}

Check warning on line 12159 in src/management/__generated/models/index.ts

View workflow job for this annotation

GitHub Actions / Build and Test (18.17)

An interface declaring no members is equivalent to its supertype

Check warning on line 12159 in src/management/__generated/models/index.ts

View workflow job for this annotation

GitHub Actions / Build and Test (20.3)

An interface declaring no members is equivalent to its supertype
/**
*
*/
Expand Down Expand Up @@ -14924,6 +14934,21 @@
*/
id: string;
}
/**
*
*/
export interface DeleteClientGrantsByGrantIdRequest {
/**
* Organization identifier
*
*/
id: string;
/**
* The Client Grant ID to remove from the organization
*
*/
grant_id: string;
}
/**
*
*/
Expand Down Expand Up @@ -15319,6 +15344,16 @@
*/
id: string;
}
/**
*
*/
export interface PostOrganizationClientGrantsOperationRequest {
/**
* Organization identifier
*
*/
id: string;
}
/**
*
*/
Expand Down
56 changes: 0 additions & 56 deletions test/auth/id-token-validator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,60 +386,4 @@ describe('id-token-validator', () => {
'Organization Name (org_name) claim must be a string present in the ID token'
);
});

it('should throw when org id claim doesnt match org expected', async () => {
const idTokenValidator = new IDTokenValidator({
domain: DOMAIN,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
});

const jwt = await sign({ payload: { org_id: 'org_1234' } });

await expect(idTokenValidator.validate(jwt, { organization: 'org_123' })).rejects.toThrow(
'Organization Id (org_id) claim value mismatch in the ID token; expected "org_123", found "org_1234'
);
});

it('should throw when org name claim doesnt match org expected', async () => {
const idTokenValidator = new IDTokenValidator({
domain: DOMAIN,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
});

const jwt = await sign({ payload: { org_name: 'notExpectedOrg' } });

await expect(idTokenValidator.validate(jwt, { organization: 'testorg' })).rejects.toThrow(
'Organization Name (org_name) claim value mismatch in the ID token; expected "testorg", found "notExpectedOrg'
);
});

it('should NOT throw when org_id matches expected organization', async () => {
const idTokenValidator = new IDTokenValidator({
domain: DOMAIN,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
});

const jwt = await sign({ payload: { org_id: 'org_123' } });

await expect(
idTokenValidator.validate(jwt, { organization: 'org_123' })
).resolves.not.toThrow();
});

it('should NOT throw when org_name matches expected organization', async () => {
const idTokenValidator = new IDTokenValidator({
domain: DOMAIN,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
});

const jwt = await sign({ payload: { org_name: 'testorg' } });

await expect(
idTokenValidator.validate(jwt, { organization: 'testOrg' })
).resolves.not.toThrow();
});
});
34 changes: 0 additions & 34 deletions test/auth/oauth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,38 +409,4 @@ describe('OAuth (with ID Token validation)', () => {
);
nockDone();
});

it('should throw for invalid organization id', async () => {
const { nockDone } = await nockBack('auth/fixtures/oauth.json', {
before: await withIdToken({
...opts,
payload: { org_id: 'org_123' },
}),
});
const oauth = new OAuth(opts);
await expect(
oauth.refreshTokenGrant(
{ refresh_token: 'test-refresh-token' },
{ idTokenValidateOptions: { organization: 'org_1235' } }
)
).rejects.toThrowError(/\(org_id\) claim value mismatch in the ID token/);
nockDone();
});

it('should throw for invalid organization name', async () => {
const { nockDone } = await nockBack('auth/fixtures/oauth.json', {
before: await withIdToken({
...opts,
payload: { org_name: 'org123' },
}),
});
const oauth = new OAuth(opts);
await expect(
oauth.refreshTokenGrant(
{ refresh_token: 'test-refresh-token' },
{ idTokenValidateOptions: { organization: 'org1235' } }
)
).rejects.toThrowError(/\(org_name\) claim value mismatch in the ID token/);
nockDone();
});
});
Loading