langgenius / langgenius/dify

RBAC: per-resource access control is not initialized on most App/Dataset creation paths — team members get 403 on resources they didn't create

Open
#39,379 2 comments 1 reaction 0 assignees View on GitHub
💪 enhancement
Dominant language
TypeScript
Stars
156k
Forks
24.6k
Avg merge
22h 9m
Merged PRs (30d)
610

Description

### Self Checks

- [x] I have read the [Contributing Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) and [Language Policy](https://github.com/langgenius/dify/issues/1542).
- [x] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones.
- [x] I confirm that I am using English to submit this report, otherwise it will be closed.
- [x] Please do not modify this template :) and fill in all the required fields.

### 1. Is this request related to a challenge you're experiencing? Tell me about your story.

### Self Checks
- [x] Searched existing issues; this concerns the RBAC access path.

## Summary

When er-resource access is initialized on creation via
`AppAccess/DatasetAccess.replace_whitelist(scope=ALL)` +
`try_sync_creator_access_policy_member_bindings` + `initialize_created_app_rbac_access_task`.

This initialization is only wired into the **primary console create controllers**. Every other creation entry point constructs the `App`/`Dataset` object directly and **skips it**. Resources created via those paths therefore have **no RBAC access record**, and any non-maintainer team member gets **403** when opening them.

For datasets there is an additional layer: the legacy `check_dataset_permission` still runs unconditionally under RBAC and reads the legacy `dataset.permission` / `DatasetPermission` model, which the RBAC access-config UI does not update. A knowledge base created via the file-upload flow defaults to `permission=only_me` **and** has no RBAC whitelist, so it cannot be shared even after assigning "Partial team members" — the legacy gate rejects first with `You do not have permission to access this dataset.`

The maintainer/creator keeps access via the maintainer short-circuit, so this is **silent for the creator** and only breaks collaboration. Because RBAC is default-off, it appears to be largely unexercised.

## Environment
- `main` (verified on latest)

## Coverage matrix (verified on `main`)

### App creation
| Entry point | RBAC init on create? | Ref |
| --- | --- | --- |
| Console create app | ✅ | `controllers/console/app/app.py:676` (+ `app_service.py:540`) |
| DSL import (`import_app`) | ❌ | `services/app_dsl_service.py:442` |
| Agent duplicate | ❌ | `services/agent/roster_service.py:456` |
| Workflow convert | ❌ | `services/workflow/workflow_converter.py:94` |

`import_app` is reused by console / `inner_api/app/dsl.py` / `openapi/app_dsl.py`; none
initialize RBAC.

### Dataset creation
| Entry point | RBAC init on create? | Ref |
| --- | --- | --- |
| Console empty dataset | ✅ | `controllers/console/datasets/datasets.py:603,611` |
| Public API (`service_api`) | ✅ | `controllers/service_api/dataset/dataset.py:536,544` |
| **File upload** (`save_document_without_dataset_id`) | ❌ (also defaults `permission=only_me`) | `services/dataset_service.py:3007` |
| RAG pipeline empty dataset | ❌ | `services/dataset_service.py:532` |
| External knowledge base | ❌ | `services/external_knowledge_service.py:295` |
| RAG pipeline DSL import | ❌ | `services/rag_pipeline/rag_pipeline_dsl_service.py:281,414` |

Legacy gate: `check_dataset_permission` has no `RBAC_ENABLED` guard and is invoked on read paths (8 call sites in `controllers/console/datasets/datasets_document.py`).

## Reproduction — dataset (file upload)
1. User A creates a knowledge base by uploading a file.
2. Set it to "Partial team members" and add user B.
3. User B opens it → **403 `You do not have permission to access this dataset.`**
4. User B opens it → **403 `You do not have permission to access this dataset.`**

## Reproduction — app (DSL import)
1. User A imports an app from DSL.
2. User B (a member who can normally open A's console-created apps) → **403** on the imported app.

## Root cause
The RBAC-on-create logic is duplicated inline in two controllers rather than being a single shared step invoked by all creation paths, so each additional creation entry point silently omits it.

## Questions for maintainers (the reason for this issue)
1. Is RBAC-on-create initialization intended for **all** creation paths, or only console create? If all, would you accept a shared `apply__creation_rbac()` helper called by every path (App ×4, Dataset ×6)?
2. For datasets, is `check_dataset_permission` meant to stay active under RBAC? If yes, should non-console create paths force `permission=ALL_TEAM` (as console empty-create does) to keep it a pass-through — or should the check be gated behind `if not RBAC_ENABLED`? The two differ in rollback semantics.
3. Should the `inner_api` / `openapi` DSL-import endpoints also initialize RBAC?

Happy to open a PR once the intended direction is confirmed.

### 2. Additional context or comments

_No response_

### 3. Can you help us with this feature?

- [ ] I am interested in contributing to this feature.

Contributor guide

Open the contributing guide

Research direction

Start with the listed creation paths: services/app_dsl_service.py, services/agent/roster_service.py, services/workflow/workflow_converter.py, services/dataset_service.py, services/external_knowledge_service.py, and services/rag_pipeline/rag_pipeline_dsl_service.py. Compare them with the initialized console and service-API paths, then resolve the intended behavior for check_dataset_permission and inner_api/openapi imports. Done means every intended App and Dataset creation path gives non-creators the documented RBAC access without the legacy dataset gate causing an unexpected 403.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
authorization, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.