PermissionEvaluator: rename query to authorizeConditional

Signed-off-by: Vincenzo Scamporlino <me@vinzscam.dev>
This commit is contained in:
Vincenzo Scamporlino
2022-04-07 20:25:53 +02:00
parent 3f41ada39d
commit 63902fcc17
21 changed files with 98 additions and 84 deletions
@@ -30,7 +30,7 @@ describe('AuthorizedEntitiesCatalog', () => {
};
const fakePermissionApi = {
authorize: jest.fn(),
query: jest.fn(),
authorizeConditional: jest.fn(),
};
const createCatalog = (...rules: CatalogPermissionRule[]) =>
@@ -46,7 +46,7 @@ describe('AuthorizedEntitiesCatalog', () => {
describe('entities', () => {
it('returns empty response on DENY', async () => {
fakePermissionApi.query.mockResolvedValue([
fakePermissionApi.authorizeConditional.mockResolvedValue([
{ result: AuthorizeResult.DENY },
]);
const catalog = createCatalog();
@@ -62,7 +62,7 @@ describe('AuthorizedEntitiesCatalog', () => {
});
it('calls underlying catalog method with correct filter on CONDITIONAL', async () => {
fakePermissionApi.query.mockResolvedValue([
fakePermissionApi.authorizeConditional.mockResolvedValue([
{
result: AuthorizeResult.CONDITIONAL,
conditions: { rule: 'IS_ENTITY_KIND', params: [['b']] },
@@ -79,7 +79,7 @@ describe('AuthorizedEntitiesCatalog', () => {
});
it('calls underlying catalog method on ALLOW', async () => {
fakePermissionApi.query.mockResolvedValue([
fakePermissionApi.authorizeConditional.mockResolvedValue([
{ result: AuthorizeResult.ALLOW },
]);
const catalog = createCatalog();
@@ -99,7 +99,7 @@ describe('AuthorizedEntitiesCatalog', () => {
{ kind: 'component', namespace: 'default', name: 'my-component' },
],
});
fakePermissionApi.query.mockResolvedValue([
fakePermissionApi.authorizeConditional.mockResolvedValue([
{ result: AuthorizeResult.DENY },
]);
const catalog = new AuthorizedEntitiesCatalog(
@@ -114,7 +114,7 @@ describe('AuthorizedEntitiesCatalog', () => {
});
it('throws error on CONDITIONAL authorization that evaluates to 0 entities', async () => {
fakePermissionApi.query.mockResolvedValue([
fakePermissionApi.authorizeConditional.mockResolvedValue([
{
result: AuthorizeResult.CONDITIONAL,
conditions: { rule: 'IS_ENTITY_KIND', params: [['b']] },
@@ -133,7 +133,7 @@ describe('AuthorizedEntitiesCatalog', () => {
});
it('calls underlying catalog method on CONDITIONAL authorization that evaluates to nonzero entities', async () => {
fakePermissionApi.query.mockResolvedValue([
fakePermissionApi.authorizeConditional.mockResolvedValue([
{
result: AuthorizeResult.CONDITIONAL,
conditions: { rule: 'IS_ENTITY_KIND', params: [['b']] },
@@ -159,7 +159,7 @@ describe('AuthorizedEntitiesCatalog', () => {
{ kind: 'component', namespace: 'default', name: 'my-component' },
],
});
fakePermissionApi.query.mockResolvedValue([
fakePermissionApi.authorizeConditional.mockResolvedValue([
{ result: AuthorizeResult.ALLOW },
]);
const catalog = new AuthorizedEntitiesCatalog(
@@ -253,7 +253,7 @@ describe('AuthorizedEntitiesCatalog', () => {
describe('facets', () => {
it('returns empty response on DENY', async () => {
fakePermissionApi.query.mockResolvedValue([
fakePermissionApi.authorizeConditional.mockResolvedValue([
{ result: AuthorizeResult.DENY },
]);
const catalog = createCatalog();
@@ -269,7 +269,7 @@ describe('AuthorizedEntitiesCatalog', () => {
});
it('calls underlying catalog method with correct filter on CONDITIONAL', async () => {
fakePermissionApi.query.mockResolvedValue([
fakePermissionApi.authorizeConditional.mockResolvedValue([
{
result: AuthorizeResult.CONDITIONAL,
conditions: { rule: 'IS_ENTITY_KIND', params: [['b']] },
@@ -287,7 +287,7 @@ describe('AuthorizedEntitiesCatalog', () => {
});
it('calls underlying catalog method on ALLOW', async () => {
fakePermissionApi.query.mockResolvedValue([
fakePermissionApi.authorizeConditional.mockResolvedValue([
{ result: AuthorizeResult.ALLOW },
]);
const catalog = createCatalog();
@@ -45,7 +45,7 @@ export class AuthorizedEntitiesCatalog implements EntitiesCatalog {
async entities(request?: EntitiesRequest): Promise<EntitiesResponse> {
const authorizeDecision = (
await this.permissionApi.query(
await this.permissionApi.authorizeConditional(
[{ permission: catalogEntityReadPermission }],
{ token: request?.authorizationToken },
)
@@ -78,7 +78,7 @@ export class AuthorizedEntitiesCatalog implements EntitiesCatalog {
options?: { authorizationToken?: string },
): Promise<void> {
const authorizeResponse = (
await this.permissionApi.query(
await this.permissionApi.authorizeConditional(
[{ permission: catalogEntityDeletePermission }],
{ token: options?.authorizationToken },
)
@@ -155,7 +155,7 @@ export class AuthorizedEntitiesCatalog implements EntitiesCatalog {
async facets(request: EntityFacetsRequest): Promise<EntityFacetsResponse> {
const authorizeDecision = (
await this.permissionApi.query(
await this.permissionApi.authorizeConditional(
[{ permission: catalogEntityReadPermission }],
{ token: request?.authorizationToken },
)
@@ -27,7 +27,7 @@ describe('AuthorizedLocationService', () => {
};
const fakePermissionApi = {
authorize: jest.fn(),
query: jest.fn(),
authorizeConditional: jest.fn(),
};
const mockAllow = () => {
@@ -49,7 +49,7 @@ const fakePermissionApi = {
result: AuthorizeResult.ALLOW,
},
]),
query: jest.fn(),
authorizeConditional: jest.fn(),
};
describe('JenkinsApi', () => {
+2 -2
View File
@@ -163,7 +163,7 @@ export class PermissionClient implements PermissionEvaluator {
requests: AuthorizePermissionRequest[],
options?: EvaluatorRequestOptions,
): Promise<AuthorizePermissionResponse[]>;
query(
authorizeConditional(
queries: QueryPermissionRequest[],
options?: EvaluatorRequestOptions,
): Promise<QueryPermissionResponse[]>;
@@ -192,7 +192,7 @@ export interface PermissionEvaluator {
requests: AuthorizePermissionRequest[],
options?: EvaluatorRequestOptions,
): Promise<AuthorizePermissionResponse[]>;
query(
authorizeConditional(
requests: QueryPermissionRequest[],
options?: EvaluatorRequestOptions,
): Promise<QueryPermissionResponse[]>;
@@ -53,7 +53,7 @@ describe('PermissionClient', () => {
afterEach(() => server.resetHandlers());
describe('authorize', () => {
const mockAuthorizeQuery = {
const mockAuthorizeConditional = {
permission: mockPermission,
resourceRef: 'foo:bar',
};
@@ -78,12 +78,12 @@ describe('PermissionClient', () => {
});
it('should fetch entities from correct endpoint', async () => {
await client.authorize([mockAuthorizeQuery]);
await client.authorize([mockAuthorizeConditional]);
expect(mockAuthorizeHandler).toHaveBeenCalled();
});
it('should include a request body', async () => {
await client.authorize([mockAuthorizeQuery]);
await client.authorize([mockAuthorizeConditional]);
const request = mockAuthorizeHandler.mock.calls[0][0];
@@ -98,21 +98,21 @@ describe('PermissionClient', () => {
});
it('should return the response from the fetch request', async () => {
const response = await client.authorize([mockAuthorizeQuery]);
const response = await client.authorize([mockAuthorizeConditional]);
expect(response[0]).toEqual(
expect.objectContaining({ result: AuthorizeResult.ALLOW }),
);
});
it('should not include authorization headers if no token is supplied', async () => {
await client.authorize([mockAuthorizeQuery]);
await client.authorize([mockAuthorizeConditional]);
const request = mockAuthorizeHandler.mock.calls[0][0];
expect(request.headers.has('authorization')).toEqual(false);
});
it('should include correctly-constructed authorization header if token is supplied', async () => {
await client.authorize([mockAuthorizeQuery], { token });
await client.authorize([mockAuthorizeConditional], { token });
const request = mockAuthorizeHandler.mock.calls[0][0];
expect(request.headers.get('authorization')).toEqual('Bearer fake-token');
@@ -125,7 +125,7 @@ describe('PermissionClient', () => {
},
);
await expect(
client.authorize([mockAuthorizeQuery], { token }),
client.authorize([mockAuthorizeConditional], { token }),
).rejects.toThrowError(/request failed with 401/i);
});
@@ -140,7 +140,7 @@ describe('PermissionClient', () => {
},
);
await expect(
client.authorize([mockAuthorizeQuery], { token }),
client.authorize([mockAuthorizeConditional], { token }),
).rejects.toThrowError(/items in response do not match request/i);
});
@@ -158,7 +158,7 @@ describe('PermissionClient', () => {
},
);
await expect(
client.authorize([mockAuthorizeQuery], { token }),
client.authorize([mockAuthorizeConditional], { token }),
).rejects.toThrowError(/invalid input/i);
});
@@ -179,7 +179,7 @@ describe('PermissionClient', () => {
discovery,
config: new ConfigReader({ permission: { enabled: false } }),
});
const response = await disabled.authorize([mockAuthorizeQuery]);
const response = await disabled.authorize([mockAuthorizeConditional]);
expect(response[0]).toEqual(
expect.objectContaining({ result: AuthorizeResult.ALLOW }),
);
@@ -203,7 +203,7 @@ describe('PermissionClient', () => {
discovery,
config: new ConfigReader({}),
});
const response = await disabled.authorize([mockAuthorizeQuery]);
const response = await disabled.authorize([mockAuthorizeConditional]);
expect(response[0]).toEqual(
expect.objectContaining({ result: AuthorizeResult.ALLOW }),
);
@@ -211,8 +211,8 @@ describe('PermissionClient', () => {
});
});
describe('query', () => {
const mockResourceAuthorizeQuery = {
describe('authorizeConditional', () => {
const mockResourceAuthorizeConditional = {
permission: mockPermission,
};
@@ -247,12 +247,12 @@ describe('PermissionClient', () => {
});
it('should fetch entities from correct endpoint', async () => {
await client.query([mockResourceAuthorizeQuery]);
await client.authorizeConditional([mockResourceAuthorizeConditional]);
expect(mockPolicyDecisionHandler).toHaveBeenCalled();
});
it('should include a request body', async () => {
await client.query([mockResourceAuthorizeQuery]);
await client.authorizeConditional([mockResourceAuthorizeConditional]);
const request = mockPolicyDecisionHandler.mock.calls[0][0];
@@ -266,7 +266,9 @@ describe('PermissionClient', () => {
});
it('should return the response from the fetch request', async () => {
const response = await client.query([mockResourceAuthorizeQuery]);
const response = await client.authorizeConditional([
mockResourceAuthorizeConditional,
]);
expect(response[0]).toEqual(
expect.objectContaining({
result: AuthorizeResult.CONDITIONAL,
@@ -280,14 +282,14 @@ describe('PermissionClient', () => {
});
it('should not include authorization headers if no token is supplied', async () => {
await client.query([mockResourceAuthorizeQuery]);
await client.authorizeConditional([mockResourceAuthorizeConditional]);
const request = mockPolicyDecisionHandler.mock.calls[0][0];
expect(request.headers.has('authorization')).toEqual(false);
});
it('should include correctly-constructed authorization header if token is supplied', async () => {
await client.query([mockResourceAuthorizeQuery], {
await client.authorizeConditional([mockResourceAuthorizeConditional], {
token,
});
@@ -302,7 +304,7 @@ describe('PermissionClient', () => {
},
);
await expect(
client.query([mockResourceAuthorizeQuery], {
client.authorizeConditional([mockResourceAuthorizeConditional], {
token,
}),
).rejects.toThrowError(/request failed with 401/i);
@@ -319,7 +321,7 @@ describe('PermissionClient', () => {
},
);
await expect(
client.query([mockResourceAuthorizeQuery], {
client.authorizeConditional([mockResourceAuthorizeConditional], {
token,
}),
).rejects.toThrowError(/items in response do not match request/i);
@@ -339,7 +341,7 @@ describe('PermissionClient', () => {
},
);
await expect(
client.query([mockResourceAuthorizeQuery], {
client.authorizeConditional([mockResourceAuthorizeConditional], {
token,
}),
).rejects.toThrowError(/invalid input/i);
@@ -362,9 +364,12 @@ describe('PermissionClient', () => {
discovery,
config: new ConfigReader({ permission: { enabled: false } }),
});
const response = await disabled.query([mockResourceAuthorizeQuery], {
token,
});
const response = await disabled.authorizeConditional(
[mockResourceAuthorizeConditional],
{
token,
},
);
expect(response[0]).toEqual(
expect.objectContaining({ result: AuthorizeResult.ALLOW }),
);
@@ -388,9 +393,12 @@ describe('PermissionClient', () => {
discovery,
config: new ConfigReader({}),
});
const response = await disabled.query([mockResourceAuthorizeQuery], {
token,
});
const response = await disabled.authorizeConditional(
[mockResourceAuthorizeConditional],
{
token,
},
);
expect(response[0]).toEqual(
expect.objectContaining({ result: AuthorizeResult.ALLOW }),
);
@@ -131,9 +131,9 @@ export class PermissionClient implements PermissionEvaluator {
}
/**
* {@inheritdoc PermissionEvaluator.query}
* {@inheritdoc PermissionEvaluator.authorizeConditional}
*/
async query(
async authorizeConditional(
queries: QueryPermissionRequest[],
options?: EvaluatorRequestOptions,
): Promise<QueryPermissionResponse[]> {
@@ -104,7 +104,7 @@ export function toPermissionEvaluator(
return response as DefinitivePolicyDecision[];
},
query(
authorizeConditional(
requests: QueryPermissionRequest[],
options?: EvaluatorRequestOptions,
): Promise<QueryPermissionResponse[]> {
+3 -3
View File
@@ -203,7 +203,7 @@ export type AuthorizePermissionRequest =
export type AuthorizePermissionResponse = DefinitivePolicyDecision;
/**
* Request object for {@link PermissionEvaluator.query}.
* Request object for {@link PermissionEvaluator.authorizeConditional}.
* @public
*/
export type QueryPermissionRequest = {
@@ -212,7 +212,7 @@ export type QueryPermissionRequest = {
};
/**
* Response object for {@link PermissionEvaluator.query}.
* Response object for {@link PermissionEvaluator.authorizeConditional}.
* @public
*/
export type QueryPermissionResponse = PolicyDecision;
@@ -239,7 +239,7 @@ export interface PermissionEvaluator {
* backend may want to use {@link PermissionCriteria | conditions} in a database query instead of
* evaluating each resource in memory.
*/
query(
authorizeConditional(
requests: QueryPermissionRequest[],
options?: EvaluatorRequestOptions,
): Promise<QueryPermissionResponse[]>;
+5 -5
View File
@@ -186,6 +186,11 @@ export class ServerPermissionClient implements PermissionEvaluator {
options?: EvaluatorRequestOptions,
): Promise<AuthorizePermissionResponse[]>;
// (undocumented)
authorizeConditional(
queries: QueryPermissionRequest[],
options?: EvaluatorRequestOptions,
): Promise<PolicyDecision[]>;
// (undocumented)
static fromConfig(
config: Config,
options: {
@@ -193,10 +198,5 @@ export class ServerPermissionClient implements PermissionEvaluator {
tokenManager: TokenManager;
},
): ServerPermissionClient;
// (undocumented)
query(
queries: QueryPermissionRequest[],
options?: EvaluatorRequestOptions,
): Promise<PolicyDecision[]>;
}
```
@@ -137,7 +137,7 @@ describe('ServerPermissionClient', () => {
});
});
describe('query', () => {
describe('authorizeConditional', () => {
let mockAuthorizeHandler: jest.Mock;
beforeEach(() => {
@@ -162,7 +162,9 @@ describe('ServerPermissionClient', () => {
tokenManager: ServerTokenManager.noop(),
});
await client.query([{ permission: testResourcePermission }]);
await client.authorizeConditional([
{ permission: testResourcePermission },
]);
expect(mockAuthorizeHandler).not.toHaveBeenCalled();
});
@@ -174,9 +176,12 @@ describe('ServerPermissionClient', () => {
tokenManager,
});
await client.query([{ permission: testResourcePermission }], {
token: (await tokenManager.getToken()).token,
});
await client.authorizeConditional(
[{ permission: testResourcePermission }],
{
token: (await tokenManager.getToken()).token,
},
);
expect(mockAuthorizeHandler).not.toHaveBeenCalled();
});
@@ -188,9 +193,12 @@ describe('ServerPermissionClient', () => {
tokenManager,
});
await client.query([{ permission: testResourcePermission }], {
token: 'a-user-token',
});
await client.authorizeConditional(
[{ permission: testResourcePermission }],
{
token: 'a-user-token',
},
);
expect(mockAuthorizeHandler).toHaveBeenCalled();
});
@@ -78,12 +78,13 @@ export class ServerPermissionClient implements PermissionEvaluator {
this.tokenManager = options.tokenManager;
this.permissionEnabled = options.permissionEnabled;
}
async query(
async authorizeConditional(
queries: QueryPermissionRequest[],
options?: EvaluatorRequestOptions,
): Promise<PolicyDecision[]> {
return (await this.isEnabled(options?.token))
? this.permissionClient.query(queries, options)
? this.permissionClient.authorizeConditional(queries, options)
: queries.map(_ => ({ result: AuthorizeResult.ALLOW }));
}
@@ -73,12 +73,12 @@ describe('AuthorizedSearchEngine', () => {
const mockedAuthorize: jest.MockedFunction<PermissionEvaluator['authorize']> =
jest.fn();
const mockedPermissionQuery: jest.MockedFunction<
PermissionEvaluator['query']
PermissionEvaluator['authorizeConditional']
> = jest.fn();
const permissionEvaluator: PermissionEvaluator = {
authorize: mockedAuthorize,
query: mockedPermissionQuery,
authorizeConditional: mockedPermissionQuery,
};
const defaultTypes: Record<string, DocumentTypeInfo> = {
@@ -122,7 +122,7 @@ describe('AuthorizedSearchEngine', () => {
const options = { token: 'token' };
const allowAll: PermissionEvaluator['authorize'] &
PermissionEvaluator['query'] = async queries => {
PermissionEvaluator['authorizeConditional'] = async queries => {
return queries.map(() => ({
result: AuthorizeResult.ALLOW,
}));
@@ -93,7 +93,7 @@ export class AuthorizedSearchEngine implements SearchEngine {
const conditionFetcher = new DataLoader(
(requests: readonly QueryPermissionRequest[]) =>
this.permissions.query(requests.slice(), options),
this.permissions.authorizeConditional(requests.slice(), options),
{
cacheKeyFn: ({ permission: { name } }) => name,
},
@@ -30,7 +30,7 @@ const mockPermissionEvaluator: PermissionEvaluator = {
authorize: () => {
throw new Error('Not implemented');
},
query: () => {
authorizeConditional: () => {
throw new Error('Not implemented');
},
};