rzo1 opened a new issue, #2103:
URL: https://github.com/apache/stormcrawler/issues/2103

   
   ## What happens
   `OpenSearchConnection.getClient()` prefixes an address that has no scheme 
with `http://`. If `opensearch.<type>.user` and `opensearch.<type>.password` 
are set, the client sends Basic authentication over that plain connection with 
no complaint. The credentials are registered against `AuthScope.ANY`, so they 
are offered to any host, port and realm the client ends up talking to, 
including nodes discovered by the sniffer, which is on by default. 
`opensearch.disable.tls.validation` turns off certificate and hostname checking 
in one line and logs nothing when it is on.
   
   ## Where
   
`external/opensearch/src/main/java/org/apache/stormcrawler/opensearch/OpenSearchConnection.java:102-106`
 and `:151-153`. The same three things exist in 
`external/opensearch-java/src/main/java/org/apache/stormcrawler/opensearch/OpenSearchConnection.java:273-276`
 and `:356-362`, where the scope is `new AuthScope(null, -1)`.
   
   ```java
   String scheme = "http";
   // no scheme specified? use http
   if (!host.startsWith(scheme)) {
       host = "http://"; + host;
   }
   ```
   
   ```java
   credentialsProvider.setCredentials(
           AuthScope.ANY, new UsernamePasswordCredentials(user, password));
   ```
   
   Config keys: `opensearch.<type>.addresses`, `opensearch.<type>.user`, 
`opensearch.<type>.password`, `opensearch.<type>.sniff`, 
`opensearch.disable.tls.validation`.
   
   ## Why it matters
   The shipped `external/opensearch/opensearch-conf.yaml` puts 
`opensearch.user` and `opensearch.password` stubs directly under 
`opensearch.addresses: "http://localhost:9200"`, and 
`opensearch.indexer.addresses: "localhost"` has no scheme at all. An operator 
who fills in the credentials and moves the cluster to another host, without 
also editing the scheme, sends the password in cleartext on every bulk and 
status request. `AuthScope.ANY` widens that: the sniffer learns the node list 
over the same unauthenticated channel, and the credentials are then offered to 
whatever addresses come back. Every harmful case needs the operator to have 
left cleartext in place, and the shipped example is loopback, so this is about 
failing closed rather than about a default that is wrong on its own.
   
   ## Reproduction
   
   Save as 
`external/opensearch/src/test/java/org/apache/stormcrawler/opensearch/OpenSearchConnectionCredentialsTest.java`.
   
   ```java
   /*
    * Licensed to the Apache Software Foundation (ASF) under one or more
    * contributor license agreements.  See the NOTICE file distributed with
    * this work for additional information regarding copyright ownership.
    * The ASF licenses this file to you under the Apache License, Version 2.0
    * (the "License"); you may not use this file except in compliance with
    * the License.  You may obtain a copy of the License at
    *
    *      http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
   
   package org.apache.stormcrawler.opensearch;
   
   import static org.junit.jupiter.api.Assertions.assertNotEquals;
   
   import java.util.HashMap;
   import java.util.Map;
   import org.junit.jupiter.api.Test;
   import org.opensearch.client.Node;
   import org.opensearch.client.RestHighLevelClient;
   
   /**
    * An address without a scheme is turned into an http:// one. Combined with 
opensearch.*.user and
    * opensearch.*.password, that sends Basic credentials in the clear to a 
remote host.
    */
   class OpenSearchConnectionCredentialsTest {
   
       @Test
       void credentialsAreNotSentOverPlainHttp() throws Exception {
           Map<String, Object> conf = new HashMap<>();
           conf.put("opensearch.indexer.addresses", 
"opensearch1.example.org:9200");
           conf.put("opensearch.indexer.user", "crawler");
           conf.put("opensearch.indexer.password", "s3cret");
   
           try (RestHighLevelClient client = 
OpenSearchConnection.getClient(conf, "indexer")) {
               for (Node node : client.getLowLevelClient().getNodes()) {
                   System.out.println("node: " + node.getHost());
                   assertNotEquals(
                           "http",
                           node.getHost().getSchemeName(),
                           "credentials configured, so the connection must not 
default to plain http");
               }
           }
       }
   }
   ```
   
   Run it:
   
   ```
   mvn -pl external/opensearch test -Dtest=OpenSearchConnectionCredentialsTest
   ```
   
   It builds a client from a config with a scheme-less remote address plus user 
and password, and asserts the resulting node is not plain http. It fails on 
main. No server is contacted; the client is only constructed.
   
   ```
   node: http://opensearch1.example.org:9200
   [ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
   [ERROR]   
OpenSearchConnectionCredentialsTest.credentialsAreNotSentOverPlainHttp:44 
credentials configured, so the connection must not default to plain http ==> 
expected: not equal but was: <http>
   ```
   
   ## Suggested fix
   In both `OpenSearchConnection` classes, refuse to start when a user and 
password are configured and the resulting scheme is http, with an exemption for 
loopback addresses so local development keeps working. Scope the credentials to 
the configured hosts instead of `AuthScope.ANY`, so a node address that arrives 
from sniffing does not automatically receive them. Log a warning when 
`opensearch.disable.tls.validation` is on. Change the shipped 
`opensearch-conf.yaml` and the archetype copy to show `https://` next to the 
credential stubs, and give every address an explicit scheme. Refusing to start 
is a behaviour change for anyone running credentials over http today, so it 
needs a release note.
   


-- 
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