{"record":{"id":"d92bb26215f988cf","repo":"apache/hadoop","slug":"can-t-replace-host-pattern-since-client-address-i","errorCode":null,"errorMessage":"Can't replace _HOST pattern since client address is null","messagePattern":"Can't replace _HOST pattern since client address is null","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/SecurityUtil.java","lineNumber":230,"sourceCode":"   * \n   * @param principalConfig\n   *          Kerberos principal name pattern to convert\n   * @param addr\n   *          InetAddress of the host used for substitution\n   * @return converted Kerberos principal name\n   * @throws IOException if the client address cannot be determined\n   */\n  @InterfaceAudience.Public\n  @InterfaceStability.Evolving\n  public static String getServerPrincipal(String principalConfig,\n      InetAddress addr) throws IOException {\n    String[] components = getComponents(principalConfig);\n    if (components == null || components.length != 3\n        || !components[1].equals(HOSTNAME_PATTERN)) {\n      return principalConfig;\n    } else {\n      if (addr == null) {\n        throw new IOException(\"Can't replace \" + HOSTNAME_PATTERN\n            + \" pattern since client address is null\");\n      }\n      return replacePattern(components, domainNameResolver.getHostnameByIP(addr));\n    }\n  }\n  \n  private static String[] getComponents(String principalConfig) {\n    if (principalConfig == null)\n      return null;\n    return principalConfig.split(\"[/@]\");\n  }\n  \n  private static String replacePattern(String[] components, String hostname)\n      throws IOException {\n    String fqdn = hostname;\n    if (fqdn == null || fqdn.isEmpty() || fqdn.equals(\"0.0.0.0\")) {\n      fqdn = getLocalHostName(null);\n    }","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/SecurityUtil.java#L212-L248","documentation":"SecurityUtil.getServerPrincipal(principalConfig, addr) replaces the _HOST placeholder (the second component of a principal like hdfs/_HOST@REALM) using a hostname derived from the supplied InetAddress. When the principal uses _HOST but addr is null, there is no way to derive the host, so an IOException is thrown rather than returning a broken principal.","triggerScenarios":"Calling getServerPrincipal(principalConfig, (InetAddress) null) or a wrapper that passes a null address while the configured principal contains _HOST; typically client-side code that has not yet opened a socket to the server, or unit tests passing null.","commonSituations":"Client code copied from server login paths that legitimately has no server address yet; refactors that dropped the address argument; tests exercising principal substitution with null inputs.","solutions":["Use the single-argument overload SecurityUtil.getServerPrincipal(principalConfig) when local-host substitution is intended","Use SecurityUtil.getServerPrincipal(principalConfig, hostname) with an explicit hostname string when no InetAddress is available","Otherwise pass the server's non-null address (commonly socket.getInetAddress()) before calling","Restrict _HOST usage to daemon-side principal configs; client-side configs should name the host explicitly"],"exampleFix":"// before\nString principal = SecurityUtil.getServerPrincipal(principalConfig, (InetAddress) null);\n\n// after\nString principal = SecurityUtil.getServerPrincipal(principalConfig, serverHostname); // String-hostname overload","handlingStrategy":"validation","validationCode":"String[] c = principalConfig.split(\"[/@]\");\nboolean usesHostPattern = c.length == 3 && \"_HOST\".equals(c[1]);\nif (usesHostPattern && addr == null) {\n  // pick an overload that does not need an address\n  return SecurityUtil.getServerPrincipal(principalConfig);\n}","typeGuard":"static boolean hostSubstitutable(String principalConfig, InetAddress addr) {\n  String[] c = principalConfig == null ? new String[0] : principalConfig.split(\"[/@]\");\n  boolean usesHost = c.length == 3 && \"_HOST\".equals(c[1]);\n  return !usesHost || addr != null;\n}","tryCatchPattern":null,"preventionTips":["Pass a hostname String or use the no-address overload when no InetAddress exists","Reserve _HOST placeholders for daemon-side principal configs","Unit-test principal substitution paths with null addresses"],"tags":["kerberos","principal","dns","client"],"backgroundTag":"kerberos-host-substitution-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}