FLPATH-3243 | [UI] Plugin skeleton - App shell and navigation#2425
FLPATH-3243 | [UI] Plugin skeleton - App shell and navigation#2425asmasarw wants to merge 6 commits intoredhat-developer:mainfrom
Conversation
Missing ChangesetsThe following package(s) are changed by this PR but do not have a changeset:
See CONTRIBUTING.md for more information about how to add changesets. Changed Packages
|
Review Summary by QodoImplement DCM backend API with RBAC and sidebar navigation
WalkthroughsDescription• Implement DCM backend API with token and access endpoints • Add RBAC permission integration and authorization checks • Create collapsible Administration sidebar menu with DCM and RBAC items • Configure permission system with RBAC backend plugin integration • Add SSO token management with caching and configuration support Diagramflowchart LR
A["Backend Plugin"] -->|"registers"| B["RBAC Backend"]
A -->|"registers"| C["DCM Backend"]
C -->|"provides"| D["/token endpoint"]
C -->|"provides"| E["/access endpoint"]
D -->|"fetches from"| F["Red Hat SSO"]
E -->|"checks"| G["RBAC Permissions"]
H["Frontend Root"] -->|"renders"| I["Administration Menu"]
I -->|"contains"| J["DCM Submenu"]
I -->|"contains"| K["RBAC Submenu"]
File Changes1. workspaces/dcm/packages/backend/src/index.ts
|
Code Review by Qodo
1. Guest RBAC superuser
|
| permission: | ||
| enabled: true | ||
| rbac: | ||
| policyFileReload: true | ||
| pluginsWithPermission: | ||
| - catalog | ||
| - scaffolder | ||
| - permission | ||
| - dcm | ||
| admin: | ||
| users: | ||
| - name: group:default/admins | ||
| - name: user:default/guest | ||
| superUsers: | ||
| - name: group:default/admins | ||
| - name: user:default/guest |
There was a problem hiding this comment.
1. Guest rbac superuser 🐞 Bug ⛨ Security
Guest auth is enabled and auto-sign-in is configured, but the guest user is also configured as an RBAC admin and superUser, effectively bypassing authorization for anyone who can access the app.
Agent Prompt
### Issue description
`user:default/guest` is configured as an RBAC admin and superUser while guest auth + auto sign-in is enabled, making the instance effectively admin-by-default.
### Issue Context
This is a configuration chain issue: guest provider + auto sign-in + guest listed in RBAC admin/superUsers.
### Fix Focus Areas
- workspaces/dcm/app-config.yaml[42-61]
- workspaces/dcm/packages/app/src/App.tsx[79-81]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| export const getToken = | ||
| (options: RouterOptions): RequestHandler => | ||
| async (_, response) => { | ||
| const { logger, config } = options; | ||
|
|
||
| assert(typeof config !== 'undefined', 'Config is undefined'); | ||
|
|
||
| logger.info('Requesting new access token'); | ||
|
|
||
| const ssoBaseUrl = | ||
| config.getOptionalString('dcm.ssoBaseUrl') ?? DEFAULT_SSO_BASE_URL; | ||
| const clientId = config.getString('dcm.clientId'); | ||
| const clientSecret = config.getString('dcm.clientSecret'); | ||
|
|
||
| const tokenUrl = `${ssoBaseUrl}/auth/realms/redhat-external/protocol/openid-connect/token`; | ||
| const body = new URLSearchParams({ | ||
| client_id: clientId, | ||
| client_secret: clientSecret, | ||
| scope: 'api.console', | ||
| grant_type: 'client_credentials', | ||
| }); | ||
|
|
||
| const rhSsoResponse = await fetch(tokenUrl, { | ||
| method: 'POST', | ||
| headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, | ||
| body: body.toString(), | ||
| }); | ||
|
|
||
| if (rhSsoResponse.ok) { | ||
| const json = (await rhSsoResponse.json()) as { | ||
| access_token: string; | ||
| expires_in: number; | ||
| }; | ||
| const bodyRes: GetTokenResponse = { | ||
| accessToken: json.access_token, | ||
| expiresAt: Date.now() + json.expires_in * 1000, | ||
| }; | ||
| response.json(bodyRes); |
There was a problem hiding this comment.
2. Un-gated token endpoint 🐞 Bug ⛨ Security
The DCM backend exposes GET /token that returns an RH SSO client_credentials access token to any user-cookie caller, without performing any permission check; combined with guest auto-sign-in this can hand out privileged external tokens to arbitrary visitors.
Agent Prompt
### Issue description
`GET /api/dcm/token` returns an RH SSO `client_credentials` access token to any authenticated user-cookie caller, without any RBAC/permission gate.
### Issue Context
- `/access` performs permission evaluation but `/token` does not.
- Guest auth is configured with auto sign-in, increasing exposure.
### Fix Focus Areas
- workspaces/dcm/plugins/dcm-backend/src/plugin.ts[48-59]
- workspaces/dcm/plugins/dcm-backend/src/routes/token.ts[23-64]
- workspaces/dcm/plugins/dcm-backend/src/routes/access.ts[22-50]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| export async function createRouter( | ||
| options: RouterOptions, | ||
| ): Promise<express.Router> { | ||
| const router = Router(); | ||
| router.use(express.json()); | ||
|
|
||
| // TEMPLATE NOTE: | ||
| // Zod is a powerful library for data validation and recommended in particular | ||
| // for user-defined schemas. In this case we use it for input validation too. | ||
| // | ||
| // If you want to define a schema for your API we recommend using Backstage's | ||
| // OpenAPI tooling: https://backstage.io/docs/next/openapi/01-getting-started | ||
| const todoSchema = z.object({ | ||
| title: z.string(), | ||
| entityRef: z.string().optional(), | ||
| }); | ||
|
|
||
| router.post('/todos', async (req, res) => { | ||
| const parsed = todoSchema.safeParse(req.body); | ||
| if (!parsed.success) { | ||
| throw new InputError(parsed.error.toString()); | ||
| } | ||
|
|
||
| const result = await todoList.createTodo(parsed.data, { | ||
| credentials: await httpAuth.credentials(req, { allow: ['user'] }), | ||
| }); | ||
| router.use(express.json()); | ||
|
|
||
| res.status(201).json(result); | ||
| const permissionsIntegrationRouter = createPermissionIntegrationRouter({ | ||
| permissions: dcmPluginPermissions, | ||
| }); | ||
| router.use(permissionsIntegrationRouter); | ||
|
|
||
| router.get('/todos', async (_req, res) => { | ||
| res.json(await todoList.listTodos()); | ||
| router.get('/health', (_req, res) => { | ||
| res.json({ status: 'ok' }); | ||
| }); | ||
|
|
||
| router.get('/todos/:id', async (req, res) => { | ||
| res.json(await todoList.getTodo({ id: req.params.id })); | ||
| }); | ||
| router.get('/token', getToken(options)); | ||
| router.get('/access', getAccess(options)); | ||
|
|
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
|



FLPATH-3243 | [UI] Plugin skeleton - App shell and navigation