Spring Boot 4.1.2 修了 spring.elasticsearch.uris 里密码带冒号会被截断的问题。URI 写成 http://elastic:pass:with:colons@127.0.0.1:19200 时,4.1.1 解析出的密码是 pass,4.1.2 才是完整的 pass:with:colons。下面用同一份配置对照跑了这两个版本。

官方 Release Notes 对应条目是 Authentication fails when password configured in spring.elasticsearch.uris contains a colon(#52166)。根因是 PropertiesElasticsearchConnectionDetails 以前把 userinfo 按每个冒号切开,只留前两段;密码里再出现冒号就会被截掉。4.1.2 改成只在第一个冒号处切开,后面整段当密码,和同文件里的 createUserInfoCredentials 以及 RFC 3986 对 userinfo 的拆法一致。

实验项目

两个最小工程,分别钉 Spring Boot 4.1.1 和 4.1.2,依赖是 spring-boot-starter-data-elasticsearch 和 spring-boot-elasticsearch,运行在 JDK 21.0.12.1。不启 Elasticsearch 进程,只把解析后的 ElasticsearchConnectionDetails 打出来就退出:

@SpringBootApplication
public class App {
  public static void main(String[] args) {
    SpringApplication.run(App.class, args).close();
  }

  @Bean
  ApplicationRunner dump(ElasticsearchConnectionDetails details) {
    return args -> {
      System.out.println("BOOT_VERSION=...");
      System.out.println("ES_USERNAME=" + details.getUsername());
      System.out.println("ES_PASSWORD=" + details.getPassword());
      details.getNodes().forEach(n -> {
        System.out.println("NODE=" + n.hostname() + ":" + n.port()
            + " user=" + n.username() + " password=" + n.password()
            + " proto=" + n.protocol());
      });
    };
  }
}
spring.main.web-application-type=none
spring.main.banner-mode=off
logging.level.root=WARN
spring.elasticsearch.uris=http://elastic:pass:with:colons@127.0.0.1:19200

密码故意写成 pass:with:colons,里面有两个冒号。

4.1.1:密码停在第一个片段

===== Boot 4.1.1: parse spring.elasticsearch.uris =====
+ java -jar target/es-uri-colon-4.1.1-0.0.1-SNAPSHOT.jar
BOOT_VERSION=4.1.1
ES_USERNAME=null
ES_PASSWORD=null
NODE=127.0.0.1:19200 user=elastic password=pass proto=HTTP

节点上的 user 是 elastic,password 只剩 pass。后面的 :with:colons 被吃掉了。顶层的 getUsername() / getPassword() 是 null,凭证落在 node 上,REST 客户端认证用的就是这份被截断的密码。

4.1.2:整段密码保留

===== Boot 4.1.2: parse spring.elasticsearch.uris =====
+ java -jar target/es-uri-colon-4.1.2-0.0.1-SNAPSHOT.jar
BOOT_VERSION=4.1.2
ES_USERNAME=null
ES_PASSWORD=null
NODE=127.0.0.1:19200 user=elastic password=pass:with:colons proto=HTTP

同一条 URI,password 变成 pass:with:colons。主机和端口没变。Release Notes 里说的认证失败,就是旧版把密码截成 pass 之后去连集群。

无密码(user@)和空密码(user:@)的行为官方说明保持不变。密码里没有冒号时,两个版本结果一样,这篇不再展开。

和拆开写的属性的关系

如果用户名密码写在 spring.elasticsearch.username / spring.elasticsearch.password,不走 URI userinfo,本来就不会被这套按冒号切片的逻辑碰到。这次修的是把账号密码嵌进 spring.elasticsearch.uris 的写法。

参考来源

— 感谢阅读 —
广告

一起交流

分享你的思考,让讨论更进一步。