Skip to content

feat(bulk-import): add permissions support to the backend endpoints [RHIDP-1208] #1890

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/bulk-import-backend/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ permission:
```

When you run the previous command, a standalone server for the bulk-import backend is setup utilizing the root app configurations.
The server is available at `http://localhost:7007/api/bulk-import-backend`.
The server is available at `http://localhost:7007/api/bulk-import`.

Please refer to the [API documentation](./api-docs/README.md) for the API endpoints and their corresponding request and response formats.

Expand Down
117 changes: 63 additions & 54 deletions plugins/bulk-import-backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,65 +81,74 @@ export default async function createPlugin(
backend.start();
```

[//]: # '#### Permission Framework Support'
[//]: #
[//]: # "TODO: Update this section of the documentation as it doesn't work. Not sure how to setup the permission framework on vanilla backstage, but confirmed to work with the RBAC plugin."
[//]: #
[//]: # 'The bulk import backend plugin has support for the permission framework. A basic example permission policy is shown below to disallow access to the bulk import API for all users except those in the `backstage-admins` group. Please note that the This policy should be added to the `packages/backend/src/plugins/permissions.ts` file:'
[//]: #
[//]: # '```ts title="packages/backend/src/plugins/permissions.ts"'
[//]: # "import { createBackendModule } from '@backstage/backend-plugin-api';"
[//]: # "import { BackstageIdentityResponse } from '@backstage/plugin-auth-node';"
[//]: # 'import {'
[//]: # ' AuthorizeResult,'
[//]: # ' isPermission,'
[//]: # ' PolicyDecision,'
[//]: # "} from '@backstage/plugin-permission-common';"
[//]: # 'import {'
[//]: # ' PermissionPolicy,'
[//]: # ' PolicyQuery,'
[//]: # "} from '@backstage/plugin-permission-node';"
[//]: # "import { policyExtensionPoint } from '@backstage/plugin-permission-node/alpha';"
[//]: #
[//]: # "import { bulkImportPermission } from '@janus-idp/backstage-plugin-bulk-import-common';"
[//]: #
[//]: # 'class BulkImportPermissionPolicy implements PermissionPolicy {'
[//]: # ' async handle('
[//]: # ' request: PolicyQuery,'
[//]: # ' user?: BackstageIdentityResponse,'
[//]: # ' ): Promise<PolicyDecision> {'
[//]: # ' if (isPermission(request.permission, bulkImportPermission)) {'
[//]: # ' if ('
[//]: # ' user?.identity.ownershipEntityRefs.includes('
[//]: # " 'group:default/backstage-admins',"
[//]: # ' )'
[//]: # ' ) {'
[//]: # ' return { result: AuthorizeResult.ALLOW };'
[//]: # ' }'
[//]: # ' }'
[//]: # ' return { result: AuthorizeResult.DENY };'
[//]: # ' }'
[//]: # ' }'
[//]: #
[//]: # ' export const BulkImportPermissionBackendModule = createBackendModule({'
[//]: # " pluginId: 'permission',"
[//]: # " moduleId: 'custom-policy',"
[//]: # ' register(reg) {'
[//]: # ' reg.registerInit({'
[//]: # ' deps: { policy: policyExtensionPoint },'
[//]: # ' async init({ policy }) {'
[//]: # ' policy.setPolicy(new BulkImportPermissionPolicy());'
[//]: # ' },'
[//]: # ' });'
[//]: # ' },'
[//]: # ' });'
[//]: # '```'
#### Permission Framework Support

The Bulk Import Backend plugin has support for the permission framework. A basic example permission policy is shown below to disallow access to the bulk import API for all users except those in the `backstage-admins` group.

1. Create a backend module for the permission policy, under a `packages/backend/src/plugins/permissions.ts` file:

```ts title="packages/backend/src/plugins/permissions.ts"
import { createBackendModule } from '@backstage/backend-plugin-api';
import { BackstageIdentityResponse } from '@backstage/plugin-auth-node';
import {
AuthorizeResult,
isPermission,
PolicyDecision,
} from '@backstage/plugin-permission-common';
import {
PermissionPolicy,
PolicyQuery,
} from '@backstage/plugin-permission-node';
import { policyExtensionPoint } from '@backstage/plugin-permission-node/alpha';

import { bulkImportPermission } from '@janus-idp/backstage-plugin-bulk-import-common';

class BulkImportPermissionPolicy implements PermissionPolicy {
async handle(
request: PolicyQuery,
user?: BackstageIdentityResponse,
): Promise<PolicyDecision> {
if (isPermission(request.permission, bulkImportPermission)) {
if (
user?.identity.ownershipEntityRefs.includes(
'group:default/backstage-admins',
)
) {
return { result: AuthorizeResult.ALLOW };
}
}
return { result: AuthorizeResult.DENY };
}
}

export const BulkImportPermissionBackendModule = createBackendModule({
pluginId: 'permission',
moduleId: 'custom-policy',
register(reg) {
reg.registerInit({
deps: { policy: policyExtensionPoint },
async init({ policy }) {
policy.setPolicy(new BulkImportPermissionPolicy());
},
});
},
});
```

2. Import `@backstage/plugin-permission-backend/alpha` and add your permission module to the `packages/backend/src/index.ts` file:

```ts title="packages/backend/src/index.ts"
import { BulkImportPermissionBackendModule } from './plugins/permissions';

backend.add(BulkImportPermissionBackendModule);
backend.add(import('@backstage/plugin-permission-backend/alpha'));
```

## For Users

### Usage

The bulk import backend plugin provides a REST API to bulk import catalog entities into the catalog. The API is available at the `/api/bulk-import-backend` endpoint.
The bulk import backend plugin provides a REST API to bulk import catalog entities into the catalog. The API is available at the `/api/bulk-import` endpoint.

As a prerequisite, you need to add at least one GitHub Integration (using either a GitHub token or a GitHub App or both) in your app-config YAML file (or a local `app-config.local.yaml` file).
See https://backstage.io/docs/integrations/github/locations/#configuration and https://backstage.io/docs/integrations/github/github-apps/#including-in-integrations-config for more details.
Expand Down
2 changes: 1 addition & 1 deletion plugins/bulk-import-backend/api-docs/Apis/ImportApi.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion plugins/bulk-import-backend/api-docs/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion plugins/bulk-import-backend/dev/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export async function startStandaloneServer(
.enableCors({
origin: '*',
})
.addRouter('/api/bulk-import-backend', router)
.addRouter('/api/bulk-import', router)
.addRouter('/api/catalog', await catalog(catalogEnv));
if (options.enableCors) {
service = service.enableCors({ origin: 'http://localhost:3000' });
Expand Down
3 changes: 2 additions & 1 deletion plugins/bulk-import-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"backstage": {
"role": "backend-plugin",
"supported-versions": "1.28.4",
"pluginId": "bulk-import-backend",
"pluginId": "bulk-import",
"pluginPackages": [
"@janus-idp/backstage-plugin-bulk-import-backend"
]
Expand Down Expand Up @@ -57,6 +57,7 @@
"@backstage/plugin-catalog-node": "^1.12.4",
"@backstage/plugin-permission-common": "^0.8.0",
"@backstage/plugin-permission-node": "^0.8.0",
"@janus-idp/backstage-plugin-bulk-import-common": "0.2.0",
"@octokit/auth-app": "^6.0.3",
"@octokit/core": "^5.1.0",
"@octokit/rest": "^20.0.2",
Expand Down
36 changes: 35 additions & 1 deletion plugins/bulk-import-backend/src/helpers/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,41 @@
* limitations under the License.
*/

import { AuthService } from '@backstage/backend-plugin-api';
import {
AuthService,
BackstageCredentials,
PermissionsService,
} from '@backstage/backend-plugin-api';
import { NotAllowedError } from '@backstage/errors';
import { AuthorizeResult } from '@backstage/plugin-permission-common';

import { bulkImportPermission } from '@janus-idp/backstage-plugin-bulk-import-common';

/**
* This will resolve to { result: AuthorizeResult.ALLOW } if the permission framework is disabled
*/
export async function permissionCheck(
permissions: PermissionsService,
credentials: BackstageCredentials,
) {
const decision = (
await permissions.authorize(
[
{
permission: bulkImportPermission,
resourceRef: bulkImportPermission.resourceType,
},
],
{
credentials,
},
)
)[0];

if (decision.result === AuthorizeResult.DENY) {
throw new NotAllowedError('Unauthorized');
}
}

export async function getTokenForPlugin(
auth: AuthService,
Expand Down
2 changes: 1 addition & 1 deletion plugins/bulk-import-backend/src/openapidocument.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion plugins/bulk-import-backend/src/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('bulkImportPlugin test', () => {
],
});

const response = await request(server).get('/api/bulk-import-backend/ping');
const response = await request(server).get('/api/bulk-import/ping');
expect(response.status).toBe(200);
expect(response.body).toEqual({ status: 'ok' });
});
Expand Down
2 changes: 1 addition & 1 deletion plugins/bulk-import-backend/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { createRouter } from './service/router';
* @alpha
*/
export const bulkImportPlugin = createBackendPlugin({
pluginId: 'bulk-import-backend',
pluginId: 'bulk-import',
register(env) {
env.registerInit({
deps: {
Expand Down
2 changes: 1 addition & 1 deletion plugins/bulk-import-backend/src/schema/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ servers:
port:
default: '7007'
basePath:
default: 'api/bulk-import-backend'
default: 'api/bulk-import'
paths:
/ping:
get:
Expand Down
Loading