Browse Source

REPORT-56220 数据连接越权漏洞修复

bugfix/11.0
Henry.Wang 3 years ago
parent
commit
69d6de2bcd
  1. 7
      designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
  2. 8
      designer-base/src/main/java/com/fr/design/mainframe/authority/DSColumnAuthorityChecker.java
  3. 25
      designer-base/src/main/java/com/fr/design/mainframe/authority/ElementAuthorityChecker.java
  4. 23
      designer-base/src/main/java/com/fr/design/mainframe/authority/FormulaAuthorityChecker.java
  5. 107
      designer-base/src/main/java/com/fr/design/mainframe/authority/JTemplateAuthorityChecker.java
  6. 7
      designer-base/src/main/java/com/fr/design/mainframe/authority/NameDatabaseConnectionAuthorityChecker.java
  7. 7
      designer-base/src/main/java/com/fr/design/mainframe/authority/NameTableDataAuthorityChecker.java

7
designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java

@ -1551,7 +1551,8 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
} }
private boolean saveRealFile() throws Exception { private boolean saveRealFile() throws Exception {
if (new JTemplateAuthorityChecker(this).isAuthority()) { JTemplateAuthorityChecker jTemplateAuthorityChecker = new JTemplateAuthorityChecker(this);
if (jTemplateAuthorityChecker.isAuthority()) {
FILE editingFILE = this.getEditingFILE(); FILE editingFILE = this.getEditingFILE();
if (editingFILE == null || editingFILE instanceof MemFILE) { if (editingFILE == null || editingFILE instanceof MemFILE) {
return false; return false;
@ -1559,9 +1560,11 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
this.getTarget().export(TemplateResourceManager.getResource().saveTemplate(editingFILE)); this.getTarget().export(TemplateResourceManager.getResource().saveTemplate(editingFILE));
this.editingFILE = editingFILE; this.editingFILE = editingFILE;
return true; return true;
} } else {
jTemplateAuthorityChecker.showAuthorityFailPromptDialog();
return false; return false;
} }
}
private CallbackSaveWorker saveAs(boolean showLoc) { private CallbackSaveWorker saveAs(boolean showLoc) {
FILE editingFILE = this.getEditingFILE(); FILE editingFILE = this.getEditingFILE();

8
designer-base/src/main/java/com/fr/design/mainframe/authority/DSColumnAuthorityChecker.java

@ -1,16 +1,18 @@
package com.fr.design.mainframe.authority; package com.fr.design.mainframe.authority;
import com.fr.report.cell.cellattr.core.group.DSColumn; import com.fr.report.cell.cellattr.core.group.DSColumn;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
public class DSColumnAuthorityChecker extends ElementAuthorityChecker<DSColumn> { public class DSColumnAuthorityChecker extends ElementAuthorityChecker<DSColumn> {
@Override @Override
String checkDatasetName(DSColumn dsColumn, Set<String> authDatasetNames) { Set<String> getNoAuthDatasetNames(DSColumn dsColumn, Set<String> authDatasetNames) {
if (!authDatasetNames.contains(dsColumn.getDSName())) { if (!authDatasetNames.contains(dsColumn.getDSName())) {
return dsColumn.getDSName(); return new HashSet<>(Arrays.asList(dsColumn.getDSName()));
} }
return null; return null;
} }
} }

25
designer-base/src/main/java/com/fr/design/mainframe/authority/ElementAuthorityChecker.java

@ -7,17 +7,34 @@ import java.util.Set;
public abstract class ElementAuthorityChecker<T> { public abstract class ElementAuthorityChecker<T> {
//检查是否有越权的数据连接,如果有返回名称,没有返回null
String checkConnectionName(T t, Set<String> authConnectionNames) {
/**
* @Description 获取越权的数据连接
* @param: t 待检查的对象
* @param: authConnectionNames 有权限的数据连接名
* @return 如果有返回名称没有返回null
*/
Set<String> getNoAuthConnectionNames(T t, Set<String> authConnectionNames) {
return null; return null;
} }
//检查是否有越权的服务器数据集,如果有返回名称,没有返回null //检查是否有越权的服务器数据集,如果有返回名称,没有返回null
String checkDatasetName(T t, Set<String> authDatasetNames) {
/**
* @Description 获取越权的服务器数据集
* @param: t 待检查的对象
* @param: authDatasetNames 有权限的服务器数据集名
* @return 如果有返回名称没有返回null
*/
Set<String> getNoAuthDatasetNames(T t, Set<String> authDatasetNames) {
return null; return null;
} }
//要检查对象的className /**
* @Description 要检查对象的className
* @return className
*/
String getCheckClassName() { String getCheckClassName() {
ParameterizedTypeImpl parameterizedType = (ParameterizedTypeImpl) this.getClass().getGenericSuperclass(); ParameterizedTypeImpl parameterizedType = (ParameterizedTypeImpl) this.getClass().getGenericSuperclass();
Type type = parameterizedType.getActualTypeArguments()[0]; Type type = parameterizedType.getActualTypeArguments()[0];

23
designer-base/src/main/java/com/fr/design/mainframe/authority/FormulaAuthorityChecker.java

@ -1,26 +1,23 @@
package com.fr.design.mainframe.authority; package com.fr.design.mainframe.authority;
import com.fr.base.Formula; import com.fr.base.Formula;
import com.fr.parser.FunctionCall;
import com.fr.parser.StringLiteral;
import com.fr.script.Calculator;
import java.lang.reflect.Field; import java.util.Arrays;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FormulaAuthorityChecker extends ElementAuthorityChecker<Formula> { public class FormulaAuthorityChecker extends ElementAuthorityChecker<Formula> {
@Override @Override
public String checkConnectionName(Formula formula, Set<String> authConnectionNames) { public Set<String> getNoAuthConnectionNames(Formula formula, Set<String> authConnectionNames) {
String content = formula.getContent(); String content = formula.getContent();
try { Pattern pattern = Pattern.compile("^=SQL\\(\"(.+?)\",");
FunctionCall functionCall = (FunctionCall) Calculator.createCalculator().parse(content).getConditionalExpression(); Matcher matcher = pattern.matcher(content);
StringLiteral stringLiteral = (StringLiteral) functionCall.getArguments()[0]; if (matcher.find()) {
String connectionName = (String) Calculator.createCalculator().evalValue(stringLiteral); if (!authConnectionNames.contains(matcher.group(1))) {
if (!authConnectionNames.contains(connectionName)) { return new HashSet<>(Arrays.asList(matcher.group(1)));
return connectionName;
} }
} catch (Exception ignore) {
} }
return null; return null;
} }

107
designer-base/src/main/java/com/fr/design/mainframe/authority/JTemplateAuthorityChecker.java

@ -6,9 +6,13 @@ import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.i18n.Toolkit; import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.JTemplate;
import com.fr.design.mod.ModClassFilter;
import com.fr.invoke.ClassHelper; import com.fr.invoke.ClassHelper;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.rpc.ExceptionHandler;
import com.fr.rpc.RPCInvokerExceptionInfo;
import com.fr.stable.Filter;
import com.fr.workspace.WorkContext; import com.fr.workspace.WorkContext;
import com.fr.workspace.server.authority.user.UserAuthority; import com.fr.workspace.server.authority.user.UserAuthority;
@ -42,17 +46,19 @@ public class JTemplateAuthorityChecker {
private void initAuthNames() { private void initAuthNames() {
UserAuthority templateAuthority = WorkContext.getCurrent().get(UserAuthority.class); UserAuthority templateAuthority = WorkContext.getCurrent().get(UserAuthority.class);
Map<String, Set<String>> allAuthNames = templateAuthority.getAuthServerDataSetAndConnectionNames(); Map<String, Set<String>> authNamesMap = templateAuthority.getAuthServerDataSetAndConnectionNames();
if (authNamesMap != null) {
//有权限的数据连接名称 //有权限的数据连接名称
authConnectionNames = allAuthNames.get(UserAuthority.AUTH_CONNECTION_NAMES); authConnectionNames = authNamesMap.get(UserAuthority.AUTH_CONNECTION_NAMES);
//有权限的数据集名称(模板数据集和服务器数据集) //有权限的数据集名称(模板数据集和服务器数据集)
authDatasetNames = allAuthNames.get(UserAuthority.AUTH_SERVER_DATASET_NAMES); authDatasetNames = authNamesMap.get(UserAuthority.AUTH_SERVER_DATASET_NAMES);
Iterator<String> iterator = jTemplate.getTarget().getTableDataNameIterator(); Iterator<String> iterator = jTemplate.getTarget().getTableDataNameIterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
String datasetName = iterator.next(); String datasetName = iterator.next();
authDatasetNames.add(datasetName); authDatasetNames.add(datasetName);
} }
} }
}
private void initChecker() { private void initChecker() {
registerChecker(new NameDatabaseConnectionAuthorityChecker()); registerChecker(new NameDatabaseConnectionAuthorityChecker());
@ -69,60 +75,57 @@ public class JTemplateAuthorityChecker {
public boolean isAuthority() { public boolean isAuthority() {
long s = System.currentTimeMillis(); long s = System.currentTimeMillis();
//遍历模板对象,根据checkerMap.keySet()把感兴趣的对象找出来 //遍历模板对象,根据checkerMap.keySet()把感兴趣的对象找出来
Map<String, Collection<Object>> targetObjects = ClassHelper.searchObject(jTemplate.getTarget(), checkerMap.keySet()); Map<String, Collection<Object>> targetObjects = ClassHelper.searchObject(jTemplate.getTarget(), checkerMap.keySet(), ClassFilter.getInstance());
//找到对应的checker,对对象进行检查 //找到对应的checker,对对象进行检查
for (String name : targetObjects.keySet()) { for (String name : targetObjects.keySet()) {
ElementAuthorityChecker checker = checkerMap.get(name); ElementAuthorityChecker checker = checkerMap.get(name);
for (Object object : targetObjects.get(name)) { for (Object object : targetObjects.get(name)) {
String authFailName = checker.checkConnectionName(object, authConnectionNames); if (authConnectionNames != null) {
if (authFailName != null) { Set<String> noAuthName = checker.getNoAuthConnectionNames(object, authConnectionNames);
authFailConnectionNames.add(authFailName); if (noAuthName != null) {
authFailConnectionNames.addAll(noAuthName);
}
}
if (authDatasetNames != null) {
Set<String> noAuthName = checker.getNoAuthDatasetNames(object, authDatasetNames);
if (noAuthName != null) {
authFailDatasetNames.addAll(noAuthName);
} }
authFailName = checker.checkDatasetName(object, authDatasetNames);
if (authFailName != null) {
authFailDatasetNames.add(authFailName);
} }
} }
} }
FineLoggerFactory.getLogger().info("JTemplateAuthorityChecker check time consume:" + (System.currentTimeMillis() - s)); FineLoggerFactory.getLogger().info("JTemplateAuthorityChecker check time consume:" + (System.currentTimeMillis() - s));
if (authFailConnectionNames.size() == 0 && authFailDatasetNames.size() == 0) { return authFailConnectionNames.size() == 0 && authFailDatasetNames.size() == 0;
return true;
} else {
//如果存在越权的,弹出弹框,并返回false
authorityFailPrompt();
return false;
}
} }
private void authorityFailPrompt() { public void showAuthorityFailPromptDialog() {
StringBuffer stringBuffer = new StringBuffer(); StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(Toolkit.i18nText("Fine-Design-Basic_Save_Failure")); stringBuffer.append(Toolkit.i18nText("Fine-Design-Basic_Save_Failure"));
stringBuffer.append("\n"); stringBuffer.append("\n");
if (authFailDatasetNames.size() > 0) { stringBuffer.append(getPromptInfo(authFailDatasetNames,
stringBuffer.append(Toolkit.i18nText("Fine-Design_Template_Authority_Check_Current_Operator_Miss")); Toolkit.i18nText("Fine-Design_Template_Authority_Check_Server_Dataset_Authority")));
stringBuffer.append(authFailDatasetNames.size()); stringBuffer.append(getPromptInfo(authFailConnectionNames,
stringBuffer.append(Toolkit.i18nText("Fine-Design_Report_Ge")); Toolkit.i18nText("Fine-Design_Template_Authority_Check_Data_Connection_Authority")));
stringBuffer.append(Toolkit.i18nText("Fine-Design_Template_Authority_Check_Server_Dataset_Authority")); FineJOptionPane.showMessageDialog(
stringBuffer.append("\n"); DesignerContext.getDesignerFrame(),
stringBuffer.append(getNoAuthNameSequence(authFailDatasetNames)); stringBuffer.toString(),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
} }
if (authFailConnectionNames.size() > 0) { private String getPromptInfo(Set<String> authFailNames, String message) {
StringBuffer stringBuffer = new StringBuffer();
if (authFailNames.size() > 0) {
stringBuffer.append(Toolkit.i18nText("Fine-Design_Template_Authority_Check_Current_Operator_Miss")); stringBuffer.append(Toolkit.i18nText("Fine-Design_Template_Authority_Check_Current_Operator_Miss"));
stringBuffer.append(authFailConnectionNames.size()); stringBuffer.append(authFailNames.size());
stringBuffer.append(Toolkit.i18nText("Fine-Design_Report_Ge")); stringBuffer.append(Toolkit.i18nText("Fine-Design_Report_Ge"));
stringBuffer.append(Toolkit.i18nText("Fine-Design_Template_Authority_Check_Data_Connection_Authority")); stringBuffer.append(message);
stringBuffer.append("\n"); stringBuffer.append("\n");
stringBuffer.append(getNoAuthNameSequence(authFailConnectionNames)); stringBuffer.append(getNoAuthNameSequence(authFailNames));
} }
return stringBuffer.toString();
FineJOptionPane.showMessageDialog(
DesignerContext.getDesignerFrame(),
stringBuffer.toString(),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
} }
private String getNoAuthNameSequence(Set<String> names) { private String getNoAuthNameSequence(Set<String> names) {
@ -143,5 +146,39 @@ public class JTemplateAuthorityChecker {
stringBuffer.append("\n"); stringBuffer.append("\n");
return stringBuffer.toString(); return stringBuffer.toString();
} }
static class ClassFilter implements Filter<String> {
private static final Set<String> FILTER_SET = new HashSet<>();
private static final Set<String> START_WITH_SET = new HashSet<>();
private static final Filter<String> INSTANCE = new ModClassFilter();
public static Filter<String> getInstance() {
return INSTANCE;
}
static {
FILTER_SET.add("java.awt.image.BufferedImage");
FILTER_SET.add("sun.awt.AppContext");
FILTER_SET.add("com.fr.poly.creator.ECBlockCreator");
FILTER_SET.add("io.netty.channel.nio.SelectedSelectionKeySet");
FILTER_SET.add("com.fr.form.ui.ElementCaseImage");
FILTER_SET.add("this$0");
START_WITH_SET.add("com.fr.design");
}
@Override
public boolean accept(String s) {
if (FILTER_SET.contains(s)) {
return true;
}
for (String start : START_WITH_SET) {
if (s.startsWith(start)) {
return true;
}
}
return false;
}
}
} }

7
designer-base/src/main/java/com/fr/design/mainframe/authority/NameDatabaseConnectionAuthorityChecker.java

@ -2,14 +2,17 @@ package com.fr.design.mainframe.authority;
import com.fr.data.impl.NameDatabaseConnection; import com.fr.data.impl.NameDatabaseConnection;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
public class NameDatabaseConnectionAuthorityChecker extends ElementAuthorityChecker<NameDatabaseConnection> { public class NameDatabaseConnectionAuthorityChecker extends ElementAuthorityChecker<NameDatabaseConnection> {
@Override @Override
String checkConnectionName(NameDatabaseConnection nameDatabaseConnection, Set<String> authConnectionNames) { Set<String> getNoAuthConnectionNames(NameDatabaseConnection nameDatabaseConnection, Set<String> authConnectionNames) {
String name = nameDatabaseConnection.getName(); String name = nameDatabaseConnection.getName();
if (!authConnectionNames.contains(name)) { if (!authConnectionNames.contains(name)) {
return name; return new HashSet<>(Arrays.asList(name));
} }
return null; return null;
} }

7
designer-base/src/main/java/com/fr/design/mainframe/authority/NameTableDataAuthorityChecker.java

@ -2,15 +2,16 @@ package com.fr.design.mainframe.authority;
import com.fr.data.impl.NameTableData; import com.fr.data.impl.NameTableData;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
public class NameTableDataAuthorityChecker extends ElementAuthorityChecker<NameTableData> { public class NameTableDataAuthorityChecker extends ElementAuthorityChecker<NameTableData> {
@Override @Override
String checkDatasetName(NameTableData nameTableData, Set<String> authDatasetNames) { Set<String> getNoAuthDatasetNames(NameTableData nameTableData, Set<String> authDatasetNames) {
if (!authDatasetNames.contains(nameTableData.getName())) { if (!authDatasetNames.contains(nameTableData.getName())) {
return nameTableData.getName(); return new HashSet<>(Arrays.asList(nameTableData.getName()));
} }
return null; return null;
} }
} }

Loading…
Cancel
Save