vyommani commented on code in PR #1266:
URL: https://github.com/apache/ranger/pull/1266#discussion_r4143852755
##########
security-admin/src/main/java/org/apache/ranger/biz/ServiceMgr.java:
##########
@@ -460,6 +444,82 @@ Long parseLong(String str) {
}
}
+ private void enforceSavedServiceEndpointConfigs(RangerService service)
throws Exception {
+ if
(!Boolean.parseBoolean(PropertiesUtil.getProperty(PROP_SERVICE_CONFIG_VALIDATE_REQUIRE_SAVED_SERVICE,
"false"))) {
+ return;
+ }
+
+ String serviceName = service.getName();
+ if (StringUtils.isBlank(serviceName)) {
+ return;
+ }
+
+ RangerService savedService = svcDBStore.getServiceByName(serviceName);
+ if (savedService == null) {
+ throw new Exception("Configuration validation requires a saved
service: " + serviceName);
+ }
+
+ if (StringUtils.isNotBlank(service.getType()) &&
StringUtils.isNotBlank(savedService.getType())
+ && !StringUtils.equals(service.getType(),
savedService.getType())) {
+ throw new Exception("Configuration validation service type does
not match saved service: " + serviceName);
+ }
+
+ Map<String, String> savedConfigs =
rangerSvcService.getConfigsWithDecryptedPassword(savedService);
+ if (savedConfigs == null) {
+ savedConfigs = Collections.emptyMap();
+ }
+
+ for (Map.Entry<String, String> entry :
service.getConfigs().entrySet()) {
+ String requestValue = entry.getValue();
+ if (requestValue == null || requestValue.trim().isEmpty()) {
+ continue;
+ }
+
+ String requestHost = extractHost(requestValue);
+ if (requestHost == null) {
+ continue;
+ }
+
+ String savedValue = savedConfigs.get(entry.getKey());
+ if (savedValue == null) {
+ throw new Exception("Invalid value for configuration " +
entry.getKey() + ": endpoint property is not present in saved service
configuration");
+ }
+
+ String savedHost = extractHost(savedValue);
+ if (savedHost == null || !requestHost.equalsIgnoreCase(savedHost))
{
Review Comment:
This does not pin the endpoint. extractHost returns only the URI host: the
port, user info, path, and query are dropped. With the flag on, a saved
https://knox.example.com:8443/gateway still accepts
https://knox.example.com:9/other and
https://[email protected]:8443/gateway.
A comma-separated JDBC authority is also cut at the first colon, so
jdbc:mysql://knox.example.com:3306,evil.example.com:3306/db matches
knox.example.com. Values for which extractHost returns null are skipped, and
the blocked-keyword check only rejects localhost, 127.0.0.1, 0.0.0.0, and ::1.
jdbc:mysql:loadbalance://evil.example.com:3306/db is an opaque URI and
jdbc:hive2:///default has no host, so both pass, and validateConfig still
connects with the request configs. The same helper treats a plain token as a
host (admin becomes http://admin), so changing a username is rejected while
these URL changes are not.
When the flag is on, compare scheme, user info, host, port, and path, and
compare every host in a comma-separated authority. Reject a connection URL
whose host cannot be parsed. Do not apply this pin to non-URL values such as
usernames.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]