fix(auth): scope-фильтр на writer-side endpoints (Phase 2c security gap)
ScopeContext.canAccess(DataScope) — единая точка проверки доступа,
использует DataScope.visibleTo (PUBLIC видит PUBLIC, INTERNAL видит
PUBLIC+INTERNAL, RESTRICTED видит всё).
DictionaryRecordController:
- requireReadAccess на GET /{businessKey} и /{businessKey}/history
→ 404 dictionary_not_found если scope словаря недоступен (намеренно
скрываем существование INTERNAL/RESTRICTED данных, защита от
enumeration)
- requireWriteAccess на POST/PUT/DELETE
→ 403 scope_insufficient если scope недостаточен для записи
DictionaryDefinitionController:
- list() фильтрует список по canAccess (PUBLIC-юзер не видит INTERNAL
словари в каталоге)
- get() → 404 если недоступен
- create()/update() → 403 если новый scope выше доступа юзера
(защита от scope escalation через PUT)
AuthE2ETest.publicUser_cannotSeeInternalRecords: TODO snять, expectation
обновлён на isNotFound() (раньше было isOk + комментарий о gap).
До этого fix: PUBLIC-юзер мог GET /api/v1/dictionaries/{n}/records/{k}
INTERNAL-словарь на writer-side. Read-api (отдельный модуль) фильтровал
корректно. Issue найден через AuthE2ETest в Phase 2c.
Все 6 AuthE2ETest и 24 unit-теста rest-api зелёные.
This commit is contained in:
@@ -49,6 +49,19 @@ public class ScopeContext {
|
||||
return EnumSet.of(DataScope.PUBLIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* True если пользовательский scope видит данные {@code dataScope}.
|
||||
* Использует {@link DataScope#visibleTo(DataScope)}: PUBLIC видит PUBLIC,
|
||||
* INTERNAL видит PUBLIC+INTERNAL, RESTRICTED видит всё.
|
||||
*/
|
||||
public boolean canAccess(DataScope dataScope) {
|
||||
if (dataScope == null) return true;
|
||||
for (DataScope userScope : currentScopes()) {
|
||||
if (dataScope.visibleTo(userScope)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Set<DataScope> resolveForRead(String queryAsScope) {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (auth instanceof JwtAuthenticationToken jwtAuth) {
|
||||
|
||||
Reference in New Issue
Block a user