Skip to content

Commit 58dd84b

Browse files
authored
Merge pull request #3172 from artbear/PrivilegedModuleMethodCall
Правило "Обращение к методам привилегированных модулей"
2 parents 4c20e63 + e6b2d8e commit 58dd84b

File tree

16 files changed

+765
-0
lines changed

16 files changed

+765
-0
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Обращение к методам привилегированных модулей (PrivilegedModuleMethodCall)
2+
3+
<!-- Блоки выше заполняются автоматически, не трогать -->
4+
## Описание диагностики
5+
<!-- Описание диагностики заполняется вручную. Необходимо понятным языком описать смысл и схему работу -->
6+
При обращении к публичным процедурам и функциям привилегированных общих модулей могут нарушаться ограничения конфигурации по правам и ролям конфигурации, решения 1С.
7+
Необходимо провалидировать подобные обращения для исключения обхода ограничений.
8+
9+
## Примеры
10+
<!-- В данном разделе приводятся примеры, на которые диагностика срабатывает, а также можно привести пример, как можно исправить ситуацию -->
11+
Например, в конфигурации существует привилегированный модуль выполнения заданий с именем `Задания`.
12+
В этом модуле есть публичная функция `Функция ДобавитьЗадание(Знач ИмяМетода, Знач Параметры) Экспорт`.
13+
Какой-то код конфигурации или расширения обращается к этому методу `Задания.ДобавитьЗадание("МетодДляВыполнения", Параметры);`
14+
15+
Необходимо проанализировать код и убедиться в том, что:
16+
- указан правильный метод для выполнения задания - `МетодДляВыполнения`
17+
- метод `МетодДляВыполнения` для выполнения задания не выполняет деструктивных действий
18+
- и не выдает пользователям данные, запрещенные ограничениями конфигурации
19+
20+
## Источники
21+
<!-- Необходимо указывать ссылки на все источники, из которых почерпнута информация для создания диагностики -->
22+
<!-- Примеры источников
23+
24+
* Источник: [Стандарт: Тексты модулей](https://its.1c.ru/db/v8std#content:456:hdoc)
25+
* Полезная информация: [Отказ от использования модальных окон](https://its.1c.ru/db/metod8dev#content:5272:hdoc)
26+
* Источник: [Cognitive complexity, ver. 1.4](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) -->
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Accessing privileged module methods (PrivilegedModuleMethodCall)
2+
3+
<!-- Блоки выше заполняются автоматически, не трогать -->
4+
## Description
5+
<!-- Описание диагностики заполняется вручную. Необходимо понятным языком описать смысл и схему работу -->
6+
7+
## Examples
8+
<!-- В данном разделе приводятся примеры, на которые диагностика срабатывает, а также можно привести пример, как можно исправить ситуацию -->
9+
10+
## Sources
11+
<!-- Необходимо указывать ссылки на все источники, из которых почерпнута информация для создания диагностики -->
12+
<!-- Примеры источников
13+
14+
* Источник: [Стандарт: Тексты модулей](https://its.1c.ru/db/v8std#content:456:hdoc)
15+
* Полезная информация: [Отказ от использования модальных окон](https://its.1c.ru/db/metod8dev#content:5272:hdoc)
16+
* Источник: [Cognitive complexity, ver. 1.4](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* This file is a part of BSL Language Server.
3+
*
4+
* Copyright (c) 2018-2023
5+
* Alexey Sosnoviy <labotamy@gmail.com>, Nikita Fedkin <nixel2007@gmail.com> and contributors
6+
*
7+
* SPDX-License-Identifier: LGPL-3.0-or-later
8+
*
9+
* BSL Language Server is free software; you can redistribute it and/or
10+
* modify it under the terms of the GNU Lesser General Public
11+
* License as published by the Free Software Foundation; either
12+
* version 3.0 of the License, or (at your option) any later version.
13+
*
14+
* BSL Language Server is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
* Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with BSL Language Server.
21+
*/
22+
package com.github._1c_syntax.bsl.languageserver.diagnostics;
23+
24+
import com.github._1c_syntax.bsl.languageserver.context.symbol.ModuleSymbol;
25+
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
26+
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticParameter;
27+
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
28+
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
29+
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
30+
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
31+
import com.github._1c_syntax.bsl.languageserver.references.ReferenceIndex;
32+
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
33+
import com.github._1c_syntax.bsl.types.ModuleType;
34+
import com.github._1c_syntax.mdclasses.mdo.MDCommonModule;
35+
import lombok.RequiredArgsConstructor;
36+
import org.eclipse.lsp4j.SymbolKind;
37+
38+
import java.util.ArrayList;
39+
import java.util.List;
40+
import java.util.Optional;
41+
42+
@DiagnosticMetadata(
43+
type = DiagnosticType.SECURITY_HOTSPOT,
44+
severity = DiagnosticSeverity.MAJOR,
45+
minutesToFix = 60,
46+
tags = {
47+
DiagnosticTag.SUSPICIOUS
48+
},
49+
scope = DiagnosticScope.BSL
50+
)
51+
@RequiredArgsConstructor
52+
public class PrivilegedModuleMethodCallDiagnostic extends AbstractDiagnostic {
53+
54+
private static final boolean VALIDATE_NESTED_CALLS = true;
55+
56+
@DiagnosticParameter(
57+
type = Boolean.class,
58+
defaultValue = "" + VALIDATE_NESTED_CALLS
59+
)
60+
private boolean validateNestedCalls = VALIDATE_NESTED_CALLS;
61+
62+
private final ReferenceIndex referenceIndex;
63+
private List<ModuleSymbol> privilegedModuleSymbols = new ArrayList<>();
64+
65+
@Override
66+
protected void check() {
67+
if (privilegedModuleSymbols.isEmpty()){
68+
privilegedModuleSymbols = getPrivilegedModuleSymbols();
69+
}
70+
if (privilegedModuleSymbols.isEmpty()){
71+
return;
72+
}
73+
74+
referenceIndex.getReferencesFrom(documentContext.getUri(), SymbolKind.Method).stream()
75+
.filter(this::isReferenceToModules)
76+
.forEach(this::fireIssue);
77+
}
78+
79+
private List<ModuleSymbol> getPrivilegedModuleSymbols() {
80+
return documentContext.getServerContext().getConfiguration().getCommonModules()
81+
.values().stream()
82+
.filter(MDCommonModule::isPrivileged)
83+
.flatMap(mdCommonModule -> getPrivilegedModuleSymbol(mdCommonModule).stream())
84+
.toList();
85+
}
86+
87+
private Optional<ModuleSymbol> getPrivilegedModuleSymbol(MDCommonModule mdCommonModule) {
88+
return documentContext.getServerContext().getDocument(
89+
mdCommonModule.getMdoReference().getMdoRef(), ModuleType.CommonModule)
90+
.map(documentContext1 -> documentContext1.getSymbolTree().getModule());
91+
}
92+
93+
private boolean isReferenceToModules(Reference reference) {
94+
if (!validateNestedCalls && reference.getUri().equals(documentContext.getUri())){
95+
return false;
96+
}
97+
return reference.getSourceDefinedSymbol()
98+
.flatMap(sourceDefinedSymbol -> sourceDefinedSymbol.getRootParent(SymbolKind.Module))
99+
.filter(ModuleSymbol.class::isInstance)
100+
.map(ModuleSymbol.class::cast)
101+
.filter(privilegedModuleSymbols::contains)
102+
.isPresent();
103+
}
104+
105+
private void fireIssue(Reference reference) {
106+
diagnosticStorage.addDiagnostic(reference.getSelectionRange(),
107+
info.getMessage(reference.getSymbol().getName()));
108+
}
109+
}

src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/parameters-schema.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,24 @@
14961496
"title": "Source code parse error",
14971497
"$id": "#/definitions/ParseError"
14981498
},
1499+
"PrivilegedModuleMethodCall": {
1500+
"description": "Accessing privileged module methods",
1501+
"default": true,
1502+
"type": [
1503+
"boolean",
1504+
"object"
1505+
],
1506+
"title": "Accessing privileged module methods",
1507+
"properties": {
1508+
"validateNestedCalls": {
1509+
"description": "Validate nested method calls from privileged modules",
1510+
"default": true,
1511+
"type": "boolean",
1512+
"title": "Validate nested method calls from privileged modules"
1513+
}
1514+
},
1515+
"$id": "#/definitions/PrivilegedModuleMethodCall"
1516+
},
14991517
"ProcedureReturnsValue": {
15001518
"description": "Procedure should not return Value",
15011519
"default": true,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
diagnosticMessage=Check the %s method access of the privileged module
2+
diagnosticName=Accessing privileged module methods
3+
validateNestedCalls=Validate nested method calls from privileged modules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
diagnosticMessage=Проверьте обращение к методу %s привилегированного модуля
2+
diagnosticName=Обращение к методам привилегированных модулей
3+
validateNestedCalls=Проверять вложенные вызовы методов из привилегированных модулей
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* This file is a part of BSL Language Server.
3+
*
4+
* Copyright (c) 2018-2023
5+
* Alexey Sosnoviy <labotamy@gmail.com>, Nikita Fedkin <nixel2007@gmail.com> and contributors
6+
*
7+
* SPDX-License-Identifier: LGPL-3.0-or-later
8+
*
9+
* BSL Language Server is free software; you can redistribute it and/or
10+
* modify it under the terms of the GNU Lesser General Public
11+
* License as published by the Free Software Foundation; either
12+
* version 3.0 of the License, or (at your option) any later version.
13+
*
14+
* BSL Language Server is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
* Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with BSL Language Server.
21+
*/
22+
package com.github._1c_syntax.bsl.languageserver.diagnostics;
23+
24+
import org.eclipse.lsp4j.Diagnostic;
25+
import org.junit.jupiter.api.Test;
26+
27+
import java.nio.file.Path;
28+
import java.nio.file.Paths;
29+
import java.util.List;
30+
import java.util.Map;
31+
32+
import static com.github._1c_syntax.bsl.languageserver.util.Assertions.assertThat;
33+
import static org.mockito.Mockito.spy;
34+
import static org.mockito.Mockito.when;
35+
36+
class PrivilegedModuleMethodCallDiagnosticTest extends AbstractDiagnosticTest<PrivilegedModuleMethodCallDiagnostic> {
37+
private static final String PATH_TO_METADATA = "src/test/resources/metadata/privilegedModules";
38+
private static final String PATH_TO_MODULE_FILE = PATH_TO_METADATA + "/CommonModules/ПривилегированныйМодуль1/Ext/Module.bsl";
39+
40+
PrivilegedModuleMethodCallDiagnosticTest() {
41+
super(PrivilegedModuleMethodCallDiagnostic.class);
42+
}
43+
44+
@Test
45+
void testWithoutMetadata() {
46+
var diagnostics = getDiagnostics();
47+
assertThat(diagnostics).isEmpty();
48+
}
49+
50+
@Test
51+
void test() {
52+
initServerContext(PATH_TO_METADATA);
53+
54+
var diagnostics = getDiagnostics();
55+
56+
assertThat(diagnostics).hasSize(2);
57+
assertThat(diagnostics, true)
58+
.hasMessageOnRange("Проверьте обращение к методу ПубличнаяФункция привилегированного модуля", 3, 40, 56)
59+
.hasMessageOnRange("Проверьте обращение к методу ПубличнаяПроцедура привилегированного модуля", 4, 29, 47);
60+
}
61+
62+
@Test
63+
void getNestedCalls() {
64+
var diagnostics = getDiagnosticsAsCommonModule();
65+
assertThat(diagnostics).hasSize(2);
66+
assertThat(diagnostics, true)
67+
.hasMessageOnRange("Проверьте обращение к методу ПубличнаяФункция привилегированного модуля", 15, 15, 31)
68+
.hasMessageOnRange("Проверьте обращение к методу ПубличнаяПроцедура привилегированного модуля", 19, 4, 22);
69+
}
70+
71+
@Test
72+
void testParameterValidateNestedCalls() {
73+
Map<String, Object> configuration = diagnosticInstance.getInfo().getDefaultConfiguration();
74+
configuration.put("validateNestedCalls", false);
75+
diagnosticInstance.configure(configuration);
76+
77+
var diagnostics = getDiagnosticsAsCommonModule();
78+
assertThat(diagnostics).isEmpty();
79+
}
80+
81+
private List<Diagnostic> getDiagnosticsAsCommonModule() {
82+
Path moduleFile = Paths.get(PATH_TO_MODULE_FILE).toAbsolutePath();
83+
84+
initServerContext(PATH_TO_METADATA);
85+
86+
var documentContext = spy(getDocumentContext(diagnosticInstance.getClass().getSimpleName()));
87+
when(documentContext.getUri()).thenReturn(moduleFile.toUri());
88+
89+
return getDiagnostics(documentContext);
90+
}
91+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#Область ПрограммныйИнтерфейс
2+
3+
Функция Тест1()
4+
Значение = ПривилегированныйМодуль1.ПубличнаяФункция(); // ошибка
5+
ПривилегированныйМодуль1.ПубличнаяПроцедура(); // ошибка
6+
КонецФункции
7+
8+
Процедура Тест2()
9+
Значение = ПривилегированныйМодуль1.ПриватнаяФункция(); // не ошибка в данном правиле
10+
ПривилегированныйМодуль1.ПриватнаяПроцедура(); // не ошибка в данном правиле
11+
КонецПроцедуры
12+
13+
#КонецОбласти
14+
15+
#Область СлужебныеПроцедурыИФункции
16+
17+
#КонецОбласти
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.11">
3+
<CommonModule uuid="8bec7488-90ab-484a-bdc9-ce1584d95925">
4+
<Properties>
5+
<Name>ОбщийМодуль2</Name>
6+
<Synonym/>
7+
<Comment/>
8+
<Global>false</Global>
9+
<ClientManagedApplication>false</ClientManagedApplication>
10+
<Server>true</Server>
11+
<ExternalConnection>false</ExternalConnection>
12+
<ClientOrdinaryApplication>false</ClientOrdinaryApplication>
13+
<ServerCall>false</ServerCall>
14+
<Privileged>false</Privileged>
15+
<ReturnValuesReuse>DontUse</ReturnValuesReuse>
16+
</Properties>
17+
</CommonModule>
18+
</MetaDataObject>

0 commit comments

Comments
 (0)