fix #557: guide permission-driven VPD flow
This commit is contained in:
@@ -20,6 +20,8 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -32,6 +34,9 @@ public class VpdPolicyService {
|
||||
private static final long CATALOG_CACHE_MILLIS = 60_000L;
|
||||
private static final String COMMON_POLICY_NAME = "CB_PERMISSION_SELECT_POLICY";
|
||||
private static final String DEFAULT_PERMISSION_FILTER_FUNCTION = "CB_AGENT_DOC_VPD_FILTER";
|
||||
private static final Pattern RETURN_LITERAL = Pattern.compile(
|
||||
"(?is)\\bRETURN\\s+'((?:''|[^'])*)'\\s*;"
|
||||
);
|
||||
|
||||
private final VpdPolicyMapper mapper;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
@@ -94,6 +99,10 @@ public class VpdPolicyService {
|
||||
);
|
||||
}
|
||||
|
||||
public String currentUser() {
|
||||
return jdbcTemplate.queryForObject("SELECT USER FROM dual", String.class);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void saveFilterFunction(String functionOwnerValue, String functionNameValue, String filterPredicateValue) {
|
||||
String functionName = requiredIdentifier(functionNameValue, "Function name");
|
||||
@@ -275,6 +284,75 @@ public class VpdPolicyService {
|
||||
return new VpdPolicyDetail(policy, buildAddPolicyBlock(policy));
|
||||
}
|
||||
|
||||
public String findPolicyDescription(String objectOwner, String objectName, String policyName) {
|
||||
String description;
|
||||
try {
|
||||
description = mapper.findPolicyDescription(objectOwner, objectName, policyName);
|
||||
} catch (DataAccessException ignored) {
|
||||
description = null;
|
||||
}
|
||||
return description == null || description.isBlank()
|
||||
? objectOwner + "." + objectName + "에 요청마다 현재 권한체계의 행 접근 조건을 적용하는 " + policyName + " policy입니다."
|
||||
: description;
|
||||
}
|
||||
|
||||
public String findFilterDescription(String functionOwner, String functionName) {
|
||||
String description;
|
||||
try {
|
||||
description = mapper.findFilterDescription(functionOwner, functionName);
|
||||
} catch (DataAccessException ignored) {
|
||||
description = null;
|
||||
}
|
||||
return description == null || description.isBlank()
|
||||
? (DEFAULT_PERMISSION_FILTER_FUNCTION.equalsIgnoreCase(functionName)
|
||||
? "사용자·그룹·역할·TAG 권한을 동적으로 합쳐 VPD predicate를 반환합니다."
|
||||
: "이 Filter function이 반환하는 predicate로 조회 행을 제한합니다.")
|
||||
: description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the literal predicate used by a simple standalone Filter function created by this UI.
|
||||
* Packaged or system-managed functions intentionally return an empty string because their
|
||||
* source is not a single editable literal.
|
||||
*/
|
||||
public String findFilterPredicate(String owner, String packageName, String functionName) {
|
||||
if (packageName != null && !packageName.isBlank()
|
||||
|| DEFAULT_PERMISSION_FILTER_FUNCTION.equalsIgnoreCase(functionName)) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
VpdFunctionSource source = findFunctionSource(owner, null, functionName);
|
||||
if (source.source() == null) {
|
||||
return "";
|
||||
}
|
||||
Matcher matcher = RETURN_LITERAL.matcher(source.source());
|
||||
return matcher.find() ? matcher.group(1).replace("''", "'") : "";
|
||||
} catch (DataAccessException | AppException ignored) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void savePolicyDescription(String objectOwner, String objectName, String policyName, String description) {
|
||||
String normalized = normalizeDescription(description);
|
||||
mapper.upsertPolicyDescription(
|
||||
requiredIdentifier(objectOwner, "Object owner"),
|
||||
requiredIdentifier(objectName, "Object name"),
|
||||
requiredIdentifier(policyName, "Policy name"),
|
||||
normalized
|
||||
);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void saveFilterDescription(String functionOwner, String functionName, String description) {
|
||||
String normalized = normalizeDescription(description);
|
||||
mapper.upsertFilterDescription(
|
||||
requiredIdentifier(functionOwner, "Function owner"),
|
||||
requiredIdentifier(functionName, "Function name"),
|
||||
normalized
|
||||
);
|
||||
}
|
||||
|
||||
public VpdObjectFilterDetail findObjectFilterDetail(String objectOwner, String objectName) {
|
||||
String normalizedOwner = requiredIdentifier(objectOwner, "Object owner");
|
||||
String normalizedObject = requiredIdentifier(objectName, "Object name");
|
||||
@@ -611,6 +689,17 @@ public class VpdPolicyService {
|
||||
return String.join(",", statements);
|
||||
}
|
||||
|
||||
private String normalizeDescription(String value) {
|
||||
String normalized = value == null ? "" : value.trim();
|
||||
if (normalized.isBlank()) {
|
||||
throw new AppException("정책/필터 설명은 필수입니다.");
|
||||
}
|
||||
if (normalized.length() > 500) {
|
||||
throw new AppException("정책/필터 설명은 500자 이내여야 합니다.");
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private String escapeSqlLiteral(String value) {
|
||||
return value.replace("'", "''");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user