sulu / SuluArticleBundle

Bundle for managing localized content-rich entities like blog-posts in the Sulu content management system
MIT License
52 stars 77 forks source link

How to pass specific characters password to ElasticSearch through Sulu/ArticleBundle #659

Closed Braskalyne closed 3 weeks ago

Braskalyne commented 4 months ago
Q A
Bug? yes
New Feature? no
SuluArticleBundle Version 2.5.2
Sulu Version 2.4.15

Actual Behavior

I'm working on a project using Sulu 2.4.15 - php 8.2 - Symfony 5.5 - Sulu/Article-bundle 2.5.2

I usually use ElasticSearch with Sulu, which is recommended as standard. But until now, I've never secured the ElasticSearch connection via login/password. For this project, our customer is imposing a password made up of special characters, but I can't get in. For my example, I have an elastic 7.17 image:

cat docker-compose.yml 
version: '3,7'

services:
  elasticsearch:
   image: docker.elastic.co/elasticsearch/elasticsearch:7.17.17
   ports:
     - 9200:9200
   environment:
     - discovery.type=single-node
     - ELASTIC_PASSWORD=toto?
     - xpack.security.enabled=true

The password is "toto?" When I access my ES via Curl I have no problem:


curl -u "elastic:toto?" http://localhost:9200
{
  "name" : "131fb8b51258",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "Ht_U5OURSvSD0NyCIRNXDw",
  "version" : {
    "number" : "7.17.17",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "aba4da413a368e296dfc64fb20897334d0340aa1",
    "build_date" : "2024-01-18T10:05:03.821431920Z",
    "build_snapshot" : false,
    "lucene_version" : "8.11.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

Same if i encode my password :

curl -X GET "http://elastic:toto%3F@localhost:9200/_cluster/health?pretty"
{
  "cluster_name" : "docker-cluster",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  "active_primary_shards" : 4,
  "active_shards" : 4,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 100.0
}

But when I try to run a command that requires connecting to ElasticSearch from Sulu/ArticleBundle, like a sulu:article:reindex , I can't authenticate : (log of my docker-compose) :

elasticsearch-elasticsearch-1 | {"type": "server", "timestamp": "2024-02-06T09:52:35,577Z", "level": "INFO", "component": "o.e.x.s.a.RealmsAuthenticator", "cluster.name": "docker-cluster", "node.name": "131fb8b51258", "message": "Authentication of [elastic] was terminated by realm [reserved] - failed to authenticate user [elastic]", "cluster.uuid": "Ht_U5OURSvSD0NyCIRNXDw", "node.id": "xE6rXeH3SPW5YB6yvB-hmQ" }

However, if I set the password in my ES docker to "toto" and remove %3F from my .env url, I don't have any connection problems. The problem comes from the special character "?

Digging through the error messages, I came across this file : vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/Connection.php

And I realized that just before the query, the string was not decoded. If I modify it manually at this point, either by using an urldecode function or by hard-coding it, then I'm able to connect & do my reindex : (both lines work operate) :

            $request['client']['curl'][10005] = urldecode($request['client']['curl'][10005]);
            $request['client']['curl'][10005] = "elastic:toto?";

But I don't understand why I need to manually "urldecode" my string, and this solution isn't viable since it's in the vendor/ folder.

I feel like I've searched in multiple places, but I can't find any answer for what seems to be a very basic concern.

I've already tried it in my .env :

ELASTICSEARCH_HOST=http://elastic:toto%3F@127.0.0.1:9200
ELASTICSEARCH_HOST="http://elastic:toto%3F@127.0.0.1:9200"
ELASTICSEARCH_HOST=http://elastic:toto?@127.0.0.1:9200
ELASTICSEARCH_HOST=http://elastic:toto\%3F@127.0.0.1:9200
ELASTICSEARCH_HOST=http://elastic:toto\?@127.0.0.1:9200
ELASTICSEARCH_HOST=http://elastic:toto%%3F@127.0.0.1:9200

etc...

Expected Behavior

I should be able to pass : ELASTICSEARCH_HOST="http://elastic:toto%3F@127.0.0.1:9200/" in my .env to make the connection to ElasticSearch

Steps to Reproduce

Install ES 7.17 :

cat docker-compose.yml 
version: '3,7'

services:
  elasticsearch:
   image: docker.elastic.co/elasticsearch/elasticsearch:7.17.17
   ports:
     - 9200:9200
   environment:
     - discovery.type=single-node
     - ELASTIC_PASSWORD=toto?
     - xpack.security.enabled=true

Install a 2.5 Sulu project : https://docs.sulu.io/en/2.5/

Install Sulu/ArticleBundle 2.5 : https://github.com/sulu/SuluArticleBundle

Try a command like

bin/console sulu:article:reindex

Possible Solutions

if i modify the file vendor/elasticsearch/elasticsearch/src/Elasticsearch>Connections>Connection.php ligne 262 and i add either this one :

$request['client']['curl'][10005] = "elastic:toto?"; or this one

$request['client']['curl'][10005] = urldecode($request['client']['curl'][10005]); Then it works !

But well, i cannot modify and push a vendor folder, so i don't really know what to do

mamazu commented 4 months ago

Thanks for reporting that issue. However this is an issue with the elastic search package. You can find the repository https://github.com/elastic/elasticsearch-php

The problem: parsing_urls is hard

This is the correct hostname: ELASTICSEARCH_HOST=http://elastic:toto?@127.0.0.1:9200 not escaped. However this will not work because Elasticsearch tries to extract out all the relevant information with parse_url and hits an error. Because it interprets the "?" as the start of the query string.

php > var_dump(parse_url('http://elastic:toto?@127.0.0.1:9200'));
bool(false)

// How it should look like:
php > var_dump(parse_url('http://elastic:toto@127.0.0.1:9200'));
array(5) {
  ["scheme"]=>
  string(4) "http"
  ["host"]=>
  string(9) "127.0.0.1"
  ["port"]=>
  int(9200)
  ["user"]=>
  string(7) "elastic"
  ["pass"]=>
  string(4) "toto"
}

z

The options

  1. Don't use valid url characters in your passwords. (Not the best solution)
  2. Create a vendor patch. If you want to modify vendor code you can do that with the vendor patches package.
  3. Suggest your patch to the Elasticsearch people. (The best solution.) However adding url decoding to the process will be a BC break for some passwords.
alexander-schranz commented 3 weeks ago

Closing this as the issue seems to be in elasticsearch package not in article bundle.