Browse Source

Pull request #5893: REPORT-56220 数据连接越权漏洞修复

Merge in DESIGN/design from ~HENRY.WANG/design:release/11.0 to release/11.0

* commit '83aa0647da69837fb1bf688599d99a0a840b2ef2':
  REPORT-56220 数据连接越权漏洞修复
  REPORT-56220 数据连接越权漏洞修复
  REPORT-56220 数据连接越权漏洞修复
  REPORT-56220 数据连接越权漏洞修复
bugfix/11.0
Henry.Wang 3 years ago
parent
commit
a8916acc65
  1. 10
      designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
  2. 20
      designer-base/src/main/java/com/fr/design/mainframe/authority/DSColumnAuthorityChecker.java
  3. 45
      designer-base/src/main/java/com/fr/design/mainframe/authority/ElementAuthorityChecker.java
  4. 27
      designer-base/src/main/java/com/fr/design/mainframe/authority/FormulaAuthorityChecker.java
  5. 184
      designer-base/src/main/java/com/fr/design/mainframe/authority/JTemplateAuthorityChecker.java
  6. 22
      designer-base/src/main/java/com/fr/design/mainframe/authority/NameDatabaseConnectionAuthorityChecker.java
  7. 19
      designer-base/src/main/java/com/fr/design/mainframe/authority/NameTableDataAuthorityChecker.java

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

@ -43,6 +43,7 @@ import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.imenu.UIMenuItem; import com.fr.design.gui.imenu.UIMenuItem;
import com.fr.design.i18n.Toolkit; import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.authority.JTemplateAuthorityChecker;
import com.fr.design.mainframe.chart.info.ChartInfoCollector; import com.fr.design.mainframe.chart.info.ChartInfoCollector;
import com.fr.design.mainframe.check.CheckButton; import com.fr.design.mainframe.check.CheckButton;
import com.fr.design.mainframe.template.info.TemplateProcessInfo; import com.fr.design.mainframe.template.info.TemplateProcessInfo;
@ -247,6 +248,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
} }
} }
} }
private void stopListenThemeConfig() { private void stopListenThemeConfig() {
if (themeConfigChangeListener != null) { if (themeConfigChangeListener != null) {
TemplateThemeConfig<? extends TemplateTheme> config = getUsingTemplateThemeConfig(); TemplateThemeConfig<? extends TemplateTheme> config = getUsingTemplateThemeConfig();
@ -1404,7 +1406,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
* @return 按钮组 * @return 按钮组
*/ */
public UIButton[] createExtraButtons() { public UIButton[] createExtraButtons() {
UIButton[] uiButtons = new UIButton[] { UIButton[] uiButtons = new UIButton[]{
(UIButton) new CompileAction().createToolBarComponent() (UIButton) new CompileAction().createToolBarComponent()
}; };
Set<DesignerFrameUpButtonProvider> providers = ExtraDesignClassManager.getInstance().getArray(DesignerFrameUpButtonProvider.XML_TAG); Set<DesignerFrameUpButtonProvider> providers = ExtraDesignClassManager.getInstance().getArray(DesignerFrameUpButtonProvider.XML_TAG);
@ -1549,6 +1551,8 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
} }
private boolean saveRealFile() throws Exception { private boolean saveRealFile() throws Exception {
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;
@ -1556,6 +1560,10 @@ 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;
}
} }
private CallbackSaveWorker saveAs(boolean showLoc) { private CallbackSaveWorker saveAs(boolean showLoc) {

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

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

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

@ -0,0 +1,45 @@
package com.fr.design.mainframe.authority;
import org.jetbrains.annotations.Nullable;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
import java.lang.reflect.Type;
import java.util.Set;
public abstract class ElementAuthorityChecker<T> {
/**
* @Description 获取越权的数据连接
* @param: t 待检查的对象
* @param: authConnectionNames 有权限的数据连接名
* @return 如果有返回名称没有返回null
*/
@Nullable
Set<String> getNoAuthConnectionNames(T t, Set<String> authConnectionNames) {
return null;
}
/**
* @Description 获取越权的服务器数据集
* @param: t 待检查的对象
* @param: authDatasetNames 有权限的服务器数据集名
* @return 如果有返回名称没有返回null
*/
@Nullable
Set<String> getNoAuthDatasetNames(T t, Set<String> authDatasetNames) {
return null;
}
/**
* @Description 要检查对象的className
* @return className
*/
String getCheckClassName() {
ParameterizedTypeImpl parameterizedType = (ParameterizedTypeImpl) this.getClass().getGenericSuperclass();
Type type = parameterizedType.getActualTypeArguments()[0];
return type.getTypeName();
}
}

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

@ -0,0 +1,27 @@
package com.fr.design.mainframe.authority;
import com.fr.base.Formula;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FormulaAuthorityChecker extends ElementAuthorityChecker<Formula> {
private static final Pattern FORMULA_PATTERN = Pattern.compile("^=SQL\\(\"(.+?)\",");
@Override
@Nullable
public Set<String> getNoAuthConnectionNames(Formula formula, Set<String> authConnectionNames) {
String content = formula.getContent();
Matcher matcher = FORMULA_PATTERN.matcher(content);
if (matcher.find()) {
if (!authConnectionNames.contains(matcher.group(1))) {
return new HashSet<>(Arrays.asList(matcher.group(1)));
}
}
return null;
}
}

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

@ -0,0 +1,184 @@
package com.fr.design.mainframe.authority;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mod.ModClassFilter;
import com.fr.invoke.ClassHelper;
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.server.authority.user.UserAuthority;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
public class JTemplateAuthorityChecker {
JTemplate<?, ?> jTemplate;
Set<String> authConnectionNames;
Set<String> authDatasetNames;
Map<String, ElementAuthorityChecker> checkerMap = new HashMap<>();
Set<String> authFailConnectionNames = new HashSet<>();
Set<String> authFailDatasetNames = new HashSet<>();
public JTemplateAuthorityChecker(JTemplate<?, ?> jTemplate) {
long s = System.currentTimeMillis();
this.jTemplate = jTemplate;
this.initAuthNames();
this.initChecker();
FineLoggerFactory.getLogger().info("JTemplateAuthorityChecker init time consume:" + (System.currentTimeMillis() - s));
}
private void initAuthNames() {
UserAuthority templateAuthority = WorkContext.getCurrent().get(UserAuthority.class);
Map<String, Set<String>> authNamesMap = templateAuthority.getAuthServerDataSetAndConnectionNames();
if (authNamesMap != null) {
//有权限的数据连接名称
authConnectionNames = authNamesMap.get(UserAuthority.AUTH_CONNECTION_NAMES);
//有权限的数据集名称(模板数据集和服务器数据集)
authDatasetNames = authNamesMap.get(UserAuthority.AUTH_SERVER_DATASET_NAMES);
Iterator<String> iterator = jTemplate.getTarget().getTableDataNameIterator();
while (iterator.hasNext()) {
String datasetName = iterator.next();
authDatasetNames.add(datasetName);
}
}
}
private void initChecker() {
registerChecker(new NameDatabaseConnectionAuthorityChecker());
registerChecker(new DSColumnAuthorityChecker());
registerChecker(new FormulaAuthorityChecker());
registerChecker(new NameTableDataAuthorityChecker());
}
private void registerChecker(ElementAuthorityChecker checker) {
checkerMap.put(checker.getCheckClassName(), checker);
}
public boolean isAuthority() {
long s = System.currentTimeMillis();
//遍历模板对象,根据checkerMap.keySet()把感兴趣的对象找出来
Map<String, Collection<Object>> targetObjects = ClassHelper.searchObject(jTemplate.getTarget(), checkerMap.keySet(), ClassFilter.getInstance());
//找到对应的checker,对对象进行检查
for (String name : targetObjects.keySet()) {
ElementAuthorityChecker checker = checkerMap.get(name);
for (Object object : targetObjects.get(name)) {
if (authConnectionNames != null) {
Set<String> noAuthName = checker.getNoAuthConnectionNames(object, authConnectionNames);
if (noAuthName != null) {
authFailConnectionNames.addAll(noAuthName);
}
}
if (authDatasetNames != null) {
Set<String> noAuthName = checker.getNoAuthDatasetNames(object, authDatasetNames);
if (noAuthName != null) {
authFailDatasetNames.addAll(noAuthName);
}
}
}
}
FineLoggerFactory.getLogger().info("JTemplateAuthorityChecker check time consume:" + (System.currentTimeMillis() - s));
return authFailConnectionNames.size() == 0 && authFailDatasetNames.size() == 0;
}
public void showAuthorityFailPromptDialog() {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(Toolkit.i18nText("Fine-Design-Basic_Save_Failure"));
stringBuffer.append("\n");
stringBuffer.append(getPromptInfo(authFailDatasetNames,
Toolkit.i18nText("Fine-Design_Template_Authority_Check_Server_Dataset_Authority")));
stringBuffer.append(getPromptInfo(authFailConnectionNames,
Toolkit.i18nText("Fine-Design_Template_Authority_Check_Data_Connection_Authority")));
FineJOptionPane.showMessageDialog(
DesignerContext.getDesignerFrame(),
stringBuffer.toString(),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
}
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(authFailNames.size());
stringBuffer.append(Toolkit.i18nText("Fine-Design_Report_Ge"));
stringBuffer.append(message);
stringBuffer.append("\n");
stringBuffer.append(getNoAuthNameSequence(authFailNames));
}
return stringBuffer.toString();
}
private String getNoAuthNameSequence(Set<String> names) {
StringBuffer stringBuffer = new StringBuffer();
int showMaxCount = 3;
int count = 0;
for (String name : names) {
if (count == showMaxCount) {
stringBuffer.append(Toolkit.i18nText("Fine-Design_Template_Authority_Check_Etc"));
break;
}
stringBuffer.append(name);
if (count != names.size() - 1 && count != showMaxCount - 1) {
stringBuffer.append(";");
}
count++;
}
stringBuffer.append("\n");
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;
}
}
}

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

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

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

@ -0,0 +1,19 @@
package com.fr.design.mainframe.authority;
import com.fr.data.impl.NameTableData;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class NameTableDataAuthorityChecker extends ElementAuthorityChecker<NameTableData> {
@Override
@Nullable
Set<String> getNoAuthDatasetNames(NameTableData nameTableData, Set<String> authDatasetNames) {
if (!authDatasetNames.contains(nameTableData.getName())) {
return new HashSet<>(Arrays.asList(nameTableData.getName()));
}
return null;
}
}
Loading…
Cancel
Save