Add permission-node package
Signed-off-by: Tim Hansen <timbonicus@gmail.com> Co-authored-by: Mike Lewis <mtlewis@users.noreply.github.com> Co-authored-by: Himanshu Mishra <himanshu@orkohunter.net> Co-authored-by: Joe Porpeglia <joeporpeglia@users.noreply.github.com> Co-authored-by: Vincenzo Scamporlino <vinzscam@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: [require.resolve('@backstage/cli/config/eslint.backend')],
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
# @backstage/plugin-permission-node
|
||||
|
||||
> NOTE: THIS PACKAGE IS EXPERIMENTAL, HERE BE DRAGONS
|
||||
|
||||
Common permission and authorization utilities for backend plugins. For more
|
||||
information, see the [authorization
|
||||
PRFC](https://github.com/backstage/backstage/pull/7761).
|
||||
@@ -0,0 +1,126 @@
|
||||
## API Report File for "@backstage/plugin-permission-node"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { AuthorizeResult } from '@backstage/permission-common';
|
||||
import { BackstageIdentity } from '@backstage/plugin-auth-backend';
|
||||
import { DefinitiveAuthorizeResult } from '@backstage/permission-common';
|
||||
import { OpaqueAuthorizeRequest } from '@backstage/permission-common';
|
||||
import { PermissionCondition } from '@backstage/permission-common';
|
||||
import { PermissionCriteria } from '@backstage/permission-common';
|
||||
import { Router } from 'express';
|
||||
|
||||
// Warning: (ae-missing-release-tag) "AllowAllPermissionPolicy" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export class AllowAllPermissionPolicy implements PermissionPolicy {
|
||||
// (undocumented)
|
||||
handle(
|
||||
_request: OpaqueAuthorizeRequest,
|
||||
_user?: BackstageIdentity,
|
||||
): Promise<PolicyResult>;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ApplyConditionsRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type ApplyConditionsRequest = {
|
||||
resourceRef: string;
|
||||
resourceType: string;
|
||||
conditions: PermissionCriteria<PermissionCondition<unknown[]>>;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ConditionalPolicyResult" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type ConditionalPolicyResult = {
|
||||
result: AuthorizeResult.MAYBE;
|
||||
conditions: {
|
||||
pluginId: string;
|
||||
resourceType: string;
|
||||
conditions: PermissionCriteria<PermissionCondition>;
|
||||
};
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "conditionFor" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const conditionFor: <TParams extends any[]>(
|
||||
rule: PermissionRule<any, any, TParams>,
|
||||
) => (...params: TParams) => {
|
||||
rule: string;
|
||||
params: TParams;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "createPermissionIntegration" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const createPermissionIntegration: <
|
||||
TResource,
|
||||
TRules extends {
|
||||
[key: string]: PermissionRule<TResource, any, any>;
|
||||
},
|
||||
TGetResourceParams extends any[] = [],
|
||||
>({
|
||||
pluginId,
|
||||
resourceType,
|
||||
rules,
|
||||
getResource,
|
||||
}: {
|
||||
pluginId: string;
|
||||
resourceType: string;
|
||||
rules: TRules;
|
||||
getResource: (
|
||||
resourceRef: string,
|
||||
...params: TGetResourceParams
|
||||
) => Promise<TResource | undefined>;
|
||||
}) => {
|
||||
createPermissionIntegrationRouter: (...params: TGetResourceParams) => Router;
|
||||
toQuery: (
|
||||
conditions: PermissionCriteria<PermissionCondition>,
|
||||
) => PermissionCriteria<QueryType<TRules>>;
|
||||
conditions: Conditions<TRules>;
|
||||
createConditions: (conditions: PermissionCriteria<PermissionCondition>) => {
|
||||
pluginId: string;
|
||||
resourceType: string;
|
||||
conditions: PermissionCriteria<PermissionCondition>;
|
||||
};
|
||||
registerPermissionRule: (
|
||||
rule: PermissionRule<TResource, QueryType<TRules>, any>,
|
||||
) => void;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PermissionPolicy" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export interface PermissionPolicy {
|
||||
// (undocumented)
|
||||
handle(
|
||||
request: OpaqueAuthorizeRequest,
|
||||
user?: BackstageIdentity,
|
||||
): Promise<PolicyResult>;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PermissionRule" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type PermissionRule<TResource, TQuery, TParams extends any[] = any> = {
|
||||
name: string;
|
||||
description: string;
|
||||
apply(resource: TResource, ...params: TParams): boolean;
|
||||
toQuery(...params: TParams): TQuery | PermissionCriteria<TQuery>;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PolicyResult" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type PolicyResult = DefinitiveAuthorizeResult | ConditionalPolicyResult;
|
||||
|
||||
// Warnings were encountered during analysis:
|
||||
//
|
||||
// src/integration/createPermissionIntegration.d.ts:23:5 - (ae-forgotten-export) The symbol "QueryType" needs to be exported by the entry point index.d.ts
|
||||
// src/integration/createPermissionIntegration.d.ts:24:5 - (ae-forgotten-export) The symbol "Conditions" needs to be exported by the entry point index.d.ts
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "@backstage/plugin-permission-node",
|
||||
"description": "Common permission and authorization utilities for backend plugins",
|
||||
"version": "0.1.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "backstage-cli backend:build",
|
||||
"lint": "backstage-cli lint",
|
||||
"test": "backstage-cli test",
|
||||
"prepack": "backstage-cli prepack",
|
||||
"postpack": "backstage-cli postpack",
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/permission-common": "^0.1.0",
|
||||
"@backstage/plugin-auth-backend": "^0.4.6",
|
||||
"@types/express": "*",
|
||||
"express": "^4.17.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.8.1"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Common permission and authorization utilities for backend plugins
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export * from './integration';
|
||||
export * from './policy';
|
||||
export * from './types';
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { PermissionRule } from '../types';
|
||||
|
||||
export const conditionFor =
|
||||
<TParams extends any[]>(rule: PermissionRule<any, any, TParams>) =>
|
||||
(...params: TParams) => ({
|
||||
rule: rule.name,
|
||||
params,
|
||||
});
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
AuthorizeResult,
|
||||
PermissionCondition,
|
||||
PermissionCriteria,
|
||||
} from '@backstage/permission-common';
|
||||
import express, { Response, Router } from 'express';
|
||||
import { PermissionRule } from '../types';
|
||||
import { conditionFor } from './conditionFor';
|
||||
|
||||
/**
|
||||
* A request to load the referenced resource and apply conditions, to finalize a conditional
|
||||
* authorization response.
|
||||
* @public
|
||||
*/
|
||||
export type ApplyConditionsRequest = {
|
||||
resourceRef: string;
|
||||
resourceType: string;
|
||||
conditions: PermissionCriteria<PermissionCondition<unknown>>;
|
||||
};
|
||||
|
||||
type Condition<TRule> = TRule extends PermissionRule<any, any, infer TParams>
|
||||
? (...params: TParams) => PermissionCondition<TParams>
|
||||
: never;
|
||||
|
||||
type Conditions<TRules extends Record<string, PermissionRule<any, any>>> = {
|
||||
[Name in keyof TRules]: Condition<TRules[Name]>;
|
||||
};
|
||||
|
||||
type QueryType<TRules> = TRules extends Record<
|
||||
string,
|
||||
PermissionRule<any, infer TQuery, any>
|
||||
>
|
||||
? TQuery
|
||||
: never;
|
||||
|
||||
// TODO(permission-node): this is no longer correct
|
||||
function isPermissionCriteria(
|
||||
criteria: unknown,
|
||||
): criteria is PermissionCriteria<unknown> {
|
||||
return Object.prototype.hasOwnProperty.call(criteria, 'anyOf');
|
||||
}
|
||||
|
||||
export const createPermissionIntegration = <
|
||||
TResource,
|
||||
TRules extends { [key: string]: PermissionRule<TResource, any> },
|
||||
TGetResourceParams extends any[] = [],
|
||||
>({
|
||||
pluginId,
|
||||
resourceType,
|
||||
rules,
|
||||
getResource,
|
||||
}: {
|
||||
pluginId: string;
|
||||
resourceType: string;
|
||||
rules: TRules;
|
||||
getResource: (
|
||||
resourceRef: string,
|
||||
...params: TGetResourceParams
|
||||
) => Promise<TResource | undefined>;
|
||||
}): {
|
||||
createPermissionIntegrationRouter: (...params: TGetResourceParams) => Router;
|
||||
toQuery: (
|
||||
conditions: PermissionCriteria<PermissionCondition<QueryType<TRules>>>,
|
||||
) => PermissionCriteria<QueryType<TRules>>;
|
||||
conditions: Conditions<TRules>;
|
||||
createConditions: (
|
||||
conditions: PermissionCriteria<PermissionCondition<QueryType<TRules>>>,
|
||||
) => {
|
||||
pluginId: string;
|
||||
resourceType: string;
|
||||
conditions: PermissionCriteria<PermissionCondition<QueryType<TRules>>>;
|
||||
};
|
||||
registerPermissionRule: (
|
||||
rule: PermissionRule<TResource, QueryType<TRules>>,
|
||||
) => void;
|
||||
} => {
|
||||
const rulesMap = new Map(Object.values(rules).map(rule => [rule.name, rule]));
|
||||
|
||||
const getRule = (
|
||||
name: string,
|
||||
): PermissionRule<TResource, QueryType<TRules>> => {
|
||||
const rule = rulesMap.get(name);
|
||||
|
||||
if (!rule) {
|
||||
throw new Error(`Unexpected permission rule: ${name}`);
|
||||
}
|
||||
|
||||
return rule;
|
||||
};
|
||||
|
||||
return {
|
||||
createPermissionIntegrationRouter: (
|
||||
...getResourceParams: TGetResourceParams
|
||||
) => {
|
||||
const router = Router();
|
||||
|
||||
router.use('/permissions/', express.json());
|
||||
|
||||
router.post(
|
||||
'/permissions/apply-conditions',
|
||||
async (
|
||||
req,
|
||||
res: Response<Omit<AuthorizeResult, AuthorizeResult.CONDITIONAL>>,
|
||||
) => {
|
||||
// TODO(authorization-framework): validate input
|
||||
const body = req.body as ApplyConditionsRequest;
|
||||
|
||||
if (body.resourceType !== resourceType) {
|
||||
throw new Error(`Unexpected resource type: ${body.resourceType}`);
|
||||
}
|
||||
|
||||
const resource = await getResource(
|
||||
body.resourceRef,
|
||||
...getResourceParams,
|
||||
);
|
||||
|
||||
if (!resource) {
|
||||
return res.status(400).end();
|
||||
}
|
||||
|
||||
const resolveCriteria = (
|
||||
criteria: PermissionCriteria<
|
||||
PermissionCondition<QueryType<TRules>>
|
||||
>,
|
||||
): boolean => {
|
||||
return criteria.anyOf.some(({ allOf }) =>
|
||||
allOf.every(child =>
|
||||
isPermissionCriteria(child)
|
||||
? resolveCriteria(child)
|
||||
: getRule(child.rule).apply(resource, ...child.params),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
return res.status(200).json({
|
||||
result: resolveCriteria(body.conditions)
|
||||
? AuthorizeResult.ALLOW
|
||||
: AuthorizeResult.DENY,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return router;
|
||||
},
|
||||
toQuery: (
|
||||
conditions: PermissionCriteria<PermissionCondition<QueryType<TRules>>>,
|
||||
): PermissionCriteria<QueryType<TRules>> => {
|
||||
const mapCriteria = (
|
||||
criteria: PermissionCriteria<PermissionCondition<QueryType<TRules>>>,
|
||||
mapFn: (
|
||||
condition: PermissionCondition<QueryType<TRules>>,
|
||||
) => QueryType<TRules> | PermissionCriteria<QueryType<TRules>>,
|
||||
): PermissionCriteria<QueryType<TRules>> => {
|
||||
return {
|
||||
anyOf: criteria.anyOf.map(({ allOf }) => ({
|
||||
allOf: allOf.map(child =>
|
||||
isPermissionCriteria(child)
|
||||
? mapCriteria(child, mapFn)
|
||||
: mapFn(child),
|
||||
),
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
||||
return mapCriteria(conditions, condition =>
|
||||
getRule(condition.rule).toQuery(...condition.params),
|
||||
);
|
||||
},
|
||||
conditions: Object.entries(rules).reduce(
|
||||
(acc, [key, rule]) => ({
|
||||
...acc,
|
||||
[key]: conditionFor(rule),
|
||||
}),
|
||||
{} as Conditions<TRules>,
|
||||
),
|
||||
createConditions: (
|
||||
conditions: PermissionCriteria<PermissionCondition<QueryType<TRules>>>,
|
||||
) => ({
|
||||
pluginId,
|
||||
resourceType,
|
||||
conditions,
|
||||
}),
|
||||
registerPermissionRule: rule => {
|
||||
rulesMap.set(rule.name, rule);
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './conditionFor';
|
||||
export * from './createPermissionIntegration';
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export type {
|
||||
ConditionalPolicyResult,
|
||||
PermissionPolicy,
|
||||
PolicyResult,
|
||||
} from './types';
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
AuthorizeRequest,
|
||||
AuthorizeResult,
|
||||
PermissionCondition,
|
||||
PermissionCriteria,
|
||||
} from '@backstage/permission-common';
|
||||
import { BackstageIdentity } from '@backstage/plugin-auth-backend';
|
||||
|
||||
/**
|
||||
* An authorization request to be evaluated by the {@link PermissionPolicy}.
|
||||
*
|
||||
* This differs from {@link AuthorizeRequest} in that `resourceRef` should never be provided. This
|
||||
* forces policies to be written in a way that's compatible with filtering collections of resources
|
||||
* at data load time.
|
||||
* @public
|
||||
*/
|
||||
export type PolicyAuthorizeRequest = Omit<AuthorizeRequest, 'resourceRef'>;
|
||||
|
||||
/**
|
||||
* A conditional result to an authorization request, returned by the {@link PermissionPolicy}.
|
||||
*
|
||||
* This indicates that the policy allows authorization for the request, given that the returned
|
||||
* conditions hold when evaluated. The conditions will be evaluated by the corresponding plugin
|
||||
* which knows about the referenced permission rules.
|
||||
*
|
||||
* Similar to {@link AuthorizeResult}, but with the plugin and resource identifiers needed to
|
||||
* evaluate the returned conditions.
|
||||
* @public
|
||||
*/
|
||||
export type ConditionalPolicyResult = {
|
||||
result: AuthorizeResult.CONDITIONAL;
|
||||
conditions: {
|
||||
pluginId: string;
|
||||
resourceType: string;
|
||||
conditions: PermissionCriteria<PermissionCondition<unknown>>;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* The result of evaluating an authorization request with a {@link PermissionPolicy}.
|
||||
* @public
|
||||
*/
|
||||
export type PolicyResult =
|
||||
| { result: AuthorizeResult.ALLOW | AuthorizeResult.DENY }
|
||||
| ConditionalPolicyResult;
|
||||
|
||||
/**
|
||||
* A policy to evaluate authorization requests for any permissioned action performed in Backstage.
|
||||
*
|
||||
* This takes as input a permission and an optional Backstage identity, and should return ALLOW if
|
||||
* the user is permitted to execute that action; otherwise DENY. For permissions relating to
|
||||
* resources, such a catalog entities, a conditional response can also be returned. This states
|
||||
* that the action is allowed if the conditions provided hold true.
|
||||
*
|
||||
* Conditions are a rule, and parameters to evaluate against that rule. For example, the rule might
|
||||
* be `isOwner` and the parameters a collection of entityRefs; if one of the entityRefs matches
|
||||
* the `owner` field on a catalog entity, this would resolve to ALLOW.
|
||||
* @public
|
||||
*/
|
||||
export interface PermissionPolicy {
|
||||
handle(
|
||||
request: PolicyAuthorizeRequest,
|
||||
user?: BackstageIdentity,
|
||||
): Promise<PolicyResult>;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { PermissionCriteria } from '@backstage/permission-common';
|
||||
|
||||
/**
|
||||
* A conditional rule that can be provided in an {@link AuthorizeResult} response to an
|
||||
* authorization request.
|
||||
*
|
||||
* Rules can either be evaluated against a resource loaded in memory, or used as filters when
|
||||
* loading a collection of resources from a data source. The `apply` and `toQuery` methods implement
|
||||
* these two concepts.
|
||||
*
|
||||
* The two operations should always have the same logical result. If they don’t, the effective
|
||||
* outcome of an authorization operation will sometimes differ depending on how the authorization
|
||||
* check was performed.
|
||||
* @public
|
||||
*/
|
||||
export type PermissionRule<TResource, TQuery, TParams extends any[] = any> = {
|
||||
name: string;
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* Apply this rule to a resource already loaded from a backing data source. The params are
|
||||
* arguments supplied for the rule; for example, a rule could be `isOwner` with entityRefs as the
|
||||
* params.
|
||||
*/
|
||||
apply(resource: TResource, ...params: TParams): boolean;
|
||||
|
||||
/**
|
||||
* Translate this rule to criteria suitable for use in querying a backing data store. The criteria
|
||||
* can be used for loading a collection of resources efficiently with conditional criteria already
|
||||
* applied.
|
||||
*/
|
||||
toQuery(...params: TParams): TQuery | PermissionCriteria<TQuery>;
|
||||
};
|
||||
Reference in New Issue
Block a user