forked from fanruan/design
Browse Source
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
7 changed files with 332 additions and 7 deletions
@ -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; |
||||
} |
||||
} |
@ -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(); |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
||||
|
@ -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; |
||||
} |
||||
|
||||
} |
@ -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…
Reference in new issue