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]

Reply via email to