Skip to content

Commit b099101

Browse files
authored
feat: support limit M2M usage - EA (#1093)
* feat: add token quota schema for client credentials in clients and organizations * feat: add token quota configuration schema for clients and organizations * feat: allow token quota to be null in clients and organizations schemas * test: add token_quota property validation for clients, organizations, and tenants * chore: update dependencies to latest versions
1 parent 9aaeaa0 commit b099101

File tree

8 files changed

+258
-24
lines changed

8 files changed

+258
-24
lines changed

package-lock.json

Lines changed: 22 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"homepage": "https://github.com/auth0/auth0-deploy-cli#readme",
3434
"dependencies": {
3535
"ajv": "^6.12.6",
36-
"auth0": "^4.23.1",
36+
"auth0": "^4.24.0",
3737
"dot-prop": "^5.3.0",
3838
"fs-extra": "^10.1.0",
3939
"js-yaml": "^4.1.0",
@@ -42,13 +42,13 @@
4242
"nconf": "^0.13.0",
4343
"promise-pool-executor": "^1.1.1",
4444
"sanitize-filename": "^1.6.3",
45-
"undici": "^7.8.0",
45+
"undici": "^7.10.0",
4646
"winston": "^3.17.0",
4747
"yargs": "^15.4.1"
4848
},
4949
"devDependencies": {
5050
"@types/fs-extra": "^9.0.13",
51-
"@types/lodash": "^4.17.16",
51+
"@types/lodash": "^4.17.17",
5252
"@types/mocha": "^10.0.10",
5353
"@types/nconf": "^0.10.7",
5454
"@typescript-eslint/parser": "^5.62.0",

src/tools/auth0/handlers/clients.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,31 @@ export const schema = {
8282
policies: multiResourceRefreshTokenPolicies,
8383
},
8484
},
85+
token_quota: {
86+
type: ['object', 'null'],
87+
properties: {
88+
client_credentials: {
89+
type: 'object',
90+
properties: {
91+
enforce: {
92+
type: 'boolean',
93+
default: true,
94+
},
95+
per_day: {
96+
type: 'integer',
97+
minimum: 1,
98+
},
99+
per_hour: {
100+
type: 'integer',
101+
minimum: 1,
102+
},
103+
},
104+
additionalProperties: false,
105+
minProperties: 1,
106+
},
107+
},
108+
required: ['client_credentials'],
109+
},
85110
},
86111
required: ['name'],
87112
},

src/tools/auth0/handlers/organizations.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,31 @@ export const schema = {
4545
},
4646
default: [],
4747
},
48+
token_quota: {
49+
type: ['object', 'null'],
50+
properties: {
51+
client_credentials: {
52+
type: 'object',
53+
properties: {
54+
enforce: {
55+
type: 'boolean',
56+
default: true,
57+
},
58+
per_day: {
59+
type: 'integer',
60+
minimum: 1,
61+
},
62+
per_hour: {
63+
type: 'integer',
64+
minimum: 1,
65+
},
66+
},
67+
additionalProperties: false,
68+
minProperties: 1,
69+
},
70+
},
71+
required: ['client_credentials'],
72+
},
4873
},
4974
required: ['name'],
5075
},

src/tools/auth0/handlers/tenant.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,45 @@ import { convertJsonToString } from '../../utils';
1111
import { Asset, Assets } from '../../../types';
1212
import log from '../../../logger';
1313

14+
const tokenQuotaConfigurationSchema = {
15+
type: 'object',
16+
properties: {
17+
client_credentials: {
18+
type: 'object',
19+
properties: {
20+
enforce: {
21+
type: 'boolean',
22+
default: true,
23+
},
24+
per_day: {
25+
type: 'integer',
26+
minimum: 1,
27+
},
28+
per_hour: {
29+
type: 'integer',
30+
minimum: 1,
31+
},
32+
},
33+
additionalProperties: false,
34+
minProperties: 1,
35+
},
36+
},
37+
required: ['client_credentials'],
38+
};
39+
1440
export const schema = {
1541
type: 'object',
42+
properties: {
43+
default_token_quota: {
44+
type: 'object',
45+
properties: {
46+
clients: tokenQuotaConfigurationSchema,
47+
organizations: tokenQuotaConfigurationSchema,
48+
},
49+
additionalProperties: false,
50+
minProperties: 1,
51+
},
52+
},
1653
};
1754

1855
export type Tenant = TenantSettings;

test/tools/auth0/handlers/clients.tests.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,46 @@ describe('#clients handler', () => {
184184
await stageFn.apply(handler, [{ clients: [clientWithRefreshTokenPolicies] }]);
185185
});
186186

187+
it('should allow valid token_quota property in client', async () => {
188+
const clientWithTokenQuota = {
189+
name: 'clientWithTokenQuota',
190+
token_quota: {
191+
client_credentials: {
192+
enforce: true,
193+
per_day: 1000,
194+
per_hour: 100,
195+
},
196+
},
197+
};
198+
let wasCreateCalled = false;
199+
const auth0 = {
200+
clients: {
201+
create: function (data) {
202+
wasCreateCalled = true;
203+
expect(data).to.be.an('object');
204+
expect(data.name).to.equal('clientWithTokenQuota');
205+
expect(data.token_quota).to.deep.equal({
206+
client_credentials: {
207+
enforce: true,
208+
per_day: 1000,
209+
per_hour: 100,
210+
},
211+
});
212+
return Promise.resolve({ data });
213+
},
214+
update: () => Promise.resolve({ data: [] }),
215+
delete: () => Promise.resolve({ data: [] }),
216+
getAll: (params) => mockPagedData(params, 'clients', []),
217+
},
218+
pool,
219+
};
220+
const handler = new clients.default({ client: pageClient(auth0), config });
221+
const stageFn = Object.getPrototypeOf(handler).processChanges;
222+
await stageFn.apply(handler, [{ clients: [clientWithTokenQuota] }]);
223+
// eslint-disable-next-line no-unused-expressions
224+
expect(wasCreateCalled).to.be.true;
225+
});
226+
187227
it('should get clients', async () => {
188228
const auth0 = {
189229
clients: {

test/tools/auth0/handlers/organizations.tests.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,58 @@ describe('#organizations handler', () => {
218218
]);
219219
});
220220

221+
it('should allow valid token_quota property in organization', async () => {
222+
const orgWithTokenQuota = {
223+
name: 'orgWithTokenQuota',
224+
token_quota: {
225+
client_credentials: {
226+
enforce: false,
227+
per_day: 500,
228+
per_hour: 50,
229+
},
230+
},
231+
};
232+
let wasCreateCalled = false;
233+
const auth0 = {
234+
organizations: {
235+
create: function (data) {
236+
wasCreateCalled = true;
237+
expect(data).to.be.an('object');
238+
expect(data.name).to.equal('orgWithTokenQuota');
239+
expect(data.token_quota).to.deep.equal({
240+
client_credentials: {
241+
enforce: false,
242+
per_day: 500,
243+
per_hour: 50,
244+
},
245+
});
246+
data.id = 'fake';
247+
return Promise.resolve({ data });
248+
},
249+
update: () => Promise.resolve({ data: [] }),
250+
delete: () => Promise.resolve({ data: [] }),
251+
getAll: (params) => Promise.resolve(mockPagedData(params, 'organizations', [sampleOrg])),
252+
getEnabledConnections: () => Promise.resolve({ data: [] }),
253+
getOrganizationClientGrants: () => ({ data: [] }),
254+
},
255+
connections: {
256+
getAll: (params) => mockPagedData(params, 'connections', []),
257+
},
258+
clients: {
259+
getAll: (params) => mockPagedData(params, 'clients', sampleClients),
260+
},
261+
clientGrants: {
262+
getAll: (params) => mockPagedData(params, 'client_grants', [sampleClientGrant]),
263+
},
264+
pool,
265+
};
266+
const handler = new organizations.default({ client: pageClient(auth0), config });
267+
const stageFn = Object.getPrototypeOf(handler).processChanges;
268+
await stageFn.apply(handler, [{ organizations: [orgWithTokenQuota] }]);
269+
// eslint-disable-next-line no-unused-expressions
270+
expect(wasCreateCalled).to.be.true;
271+
});
272+
221273
it('should get organizations', async () => {
222274
const auth0 = {
223275
organizations: {

0 commit comments

Comments
 (0)