Skip to content
Draft
45 changes: 36 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,48 @@
ARG PHP_VERSION
ARG PHP_VERSION=8.4.7

FROM php:${PHP_VERSION}-cli

# Set environment variables
ENV PATH="/usr/local/go/bin:${PATH}" \
COMPOSER_ALLOW_SUPERUSER=1 \
DEBIAN_FRONTEND=noninteractive

# Install dependencies, Go, PHP extensions, Python venv and tools
RUN apt-get update \
&& apt-get install -y \
&& apt-get install -y --no-install-recommends \
libzip-dev \
unzip \
git \
wget \
curl \
tar \
gcc \
make \
ca-certificates \
build-essential \
pkg-config \
software-properties-common \
python3-venv \
python3-pip \
python3-setuptools \
# Install Go 1.22.0
&& curl -LO https://golang.org/dl/go1.22.0.linux-amd64.tar.gz \
&& tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz \
&& rm go1.22.0.linux-amd64.tar.gz \
&& ln -s /usr/local/go/bin/go /usr/bin/go \
# Install PHP extensions
&& docker-php-ext-install -j$(nproc) bcmath sockets \
&& wget https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 \
&& mv test-reporter-latest-linux-amd64 /usr/bin/cc-test-reporter \
# Install CodeClimate Test Reporter
&& wget -O /usr/bin/cc-test-reporter https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 \
&& chmod +x /usr/bin/cc-test-reporter \
# Install and enable Xdebug
&& pecl install xdebug \
&& docker-php-ext-enable xdebug && \
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
&& docker-php-ext-enable xdebug \
# Install Composer
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
# Cleanup
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# Set working directory
WORKDIR /opt/project



12 changes: 6 additions & 6 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ x-definitions:
PHP_VERSION: "${PHP_VERSION-8.1}"
volumes:
- .:/opt/project

x-common-cluster:
&common-cluster
<<: *common
Expand All @@ -51,9 +52,10 @@ services:
- .:/opt/project
env_file:
- .env

neo4j:
<<: *common
image: neo4j:5.23-community
image: neo4j:5-enterprise
hostname: neo4j
networks:
- neo4j
Expand All @@ -62,11 +64,10 @@ services:
- "11474:7474"
environment:
<<: *common-env
NEO4J_ACCEPT_LICENSE_AGREEMENT: 'yes'
NEO4J_server_bolt_advertised__address: neo4j:7687
NEO4J_server_http_advertised__address: neo4j:7474



server1:
<<: *common-cluster
hostname: server1
Expand Down Expand Up @@ -117,9 +118,7 @@ services:
NEO4J_server_http_advertised__address: server4:7474

testkit:
image: python:3.13
volumes:
- .:/opt/project
<<: *common-php
working_dir: /opt/project/testkit-backend
networks:
- neo4j
Expand All @@ -140,6 +139,7 @@ services:
- neo4j
extra_hosts:
- "host.docker.internal:host-gateway"
- "thehost:host-gateway"
depends_on:
- neo4j
ports:
Expand Down
36 changes: 11 additions & 25 deletions src/Authentication/BasicAuth.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,10 @@

namespace Laudis\Neo4j\Authentication;

use Bolt\protocol\V4_4;
use Bolt\protocol\V5;
use Bolt\protocol\V5_1;
use Bolt\protocol\V5_2;
use Bolt\protocol\V5_3;
use Bolt\protocol\V5_4;
use Exception;
use Laudis\Neo4j\Bolt\BoltConnection;
use Laudis\Neo4j\Bolt\BoltMessageFactory;
use Laudis\Neo4j\Common\Neo4jLogger;
use Laudis\Neo4j\Common\ResponseHelper;
use Laudis\Neo4j\Contracts\AuthenticateInterface;
use Psr\Http\Message\UriInterface;

Expand All @@ -43,27 +37,26 @@ public function __construct(
*
* @return array{server: string, connection_id: string, hints: list}
*/
public function authenticateBolt(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol, string $userAgent): array
public function authenticateBolt(BoltConnection $connection, string $userAgent): array
{
$factory = $this->createMessageFactory($protocol);
$factory = $this->createMessageFactory($connection);

$protocol = $connection->protocol();
if (method_exists($protocol, 'logon')) {
$helloMetadata = ['user_agent' => $userAgent];

$factory->createHelloMessage($helloMetadata)->send();
$response = ResponseHelper::getResponse($protocol);
$responseHello = $factory->createHelloMessage($helloMetadata)->send()->getResponse();

$credentials = [
'scheme' => 'basic',
'principal' => $this->username,
'credentials' => $this->password,
];

$factory->createLogonMessage($credentials)->send();
ResponseHelper::getResponse($protocol);
$response = $factory->createLogonMessage($credentials)->send()->getResponse();

/** @var array{server: string, connection_id: string, hints: list} */
return $response->content;
return array_merge($responseHello->content, $response->content);
}

$helloMetadata = [
Expand All @@ -73,22 +66,15 @@ public function authenticateBolt(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol, string $
'credentials' => $this->password,
];

$factory->createHelloMessage($helloMetadata)->send();
$response = $factory->createHelloMessage($helloMetadata)->send()->getResponse();

/** @var array{server: string, connection_id: string, hints: list} */
return ResponseHelper::getResponse($protocol)->content;
return $response->content;
}

/**
* @throws Exception
*/
public function logoff(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol): void
{
$factory = $this->createMessageFactory($protocol);
$factory->createLogoffMessage()->send();
ResponseHelper::getResponse($protocol);
}

public function toString(UriInterface $uri): string
{
return sprintf('Basic %s:%s@%s:%s', $this->username, '######', $uri->getHost(), $uri->getPort() ?? '');
Expand All @@ -97,8 +83,8 @@ public function toString(UriInterface $uri): string
/**
* Helper to create message factory.
*/
private function createMessageFactory(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol): BoltMessageFactory
private function createMessageFactory(BoltConnection $connection): BoltMessageFactory
{
return new BoltMessageFactory($protocol, $this->logger);
return new BoltMessageFactory($connection, $this->logger);
}
}
35 changes: 8 additions & 27 deletions src/Authentication/KerberosAuth.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,11 @@

namespace Laudis\Neo4j\Authentication;

use Bolt\protocol\V4_4;
use Bolt\protocol\V5;
use Bolt\protocol\V5_1;
use Bolt\protocol\V5_2;
use Bolt\protocol\V5_3;
use Bolt\protocol\V5_4;
use Exception;
use Laudis\Neo4j\Bolt\BoltConnection;
use Laudis\Neo4j\Bolt\BoltMessageFactory;
use Laudis\Neo4j\Common\Neo4jLogger;
use Laudis\Neo4j\Common\ResponseHelper;
use Laudis\Neo4j\Contracts\AuthenticateInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\UriInterface;
use Psr\Log\LogLevel;

Expand All @@ -41,38 +34,26 @@ public function __construct(
) {
}

public function authenticateHttp(RequestInterface $request, UriInterface $uri, string $userAgent): RequestInterface
{
$this->logger?->log(LogLevel::DEBUG, 'Authenticating using KerberosAuth');

return $request->withHeader('Authorization', 'Kerberos '.$this->token)
->withHeader('User-Agent', $userAgent);
}

/**
* @throws Exception
*
* @return array{server: string, connection_id: string, hints: list}
*/
public function authenticateBolt(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol, string $userAgent): array
public function authenticateBolt(BoltConnection $connection, string $userAgent): array
{
$factory = $this->createMessageFactory($protocol);
$factory = $this->createMessageFactory($connection);

$this->logger?->log(LogLevel::DEBUG, 'HELLO', ['user_agent' => $userAgent]);

$factory->createHelloMessage(['user_agent' => $userAgent])->send();

$response = ResponseHelper::getResponse($protocol);
$factory->createHelloMessage(['user_agent' => $userAgent])->send()->getResponse();

$this->logger?->log(LogLevel::DEBUG, 'LOGON', ['scheme' => 'kerberos', 'principal' => '']);

$factory->createLogonMessage([
$response = $factory->createLogonMessage([
'scheme' => 'kerberos',
'principal' => '',
'credentials' => $this->token,
])->send();

ResponseHelper::getResponse($protocol);
])->send()->getResponse();

/**
* @var array{server: string, connection_id: string, hints: list}
Expand All @@ -88,8 +69,8 @@ public function toString(UriInterface $uri): string
/**
* Helper to create the message factory.
*/
private function createMessageFactory(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol): BoltMessageFactory
private function createMessageFactory(BoltConnection $connection): BoltMessageFactory
{
return new BoltMessageFactory($protocol, $this->logger);
return new BoltMessageFactory($connection, $this->logger);
}
}
45 changes: 11 additions & 34 deletions src/Authentication/NoAuth.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,13 @@

namespace Laudis\Neo4j\Authentication;

use Bolt\protocol\V4_4;
use Bolt\protocol\V5;
use Bolt\protocol\V5_1;
use Bolt\protocol\V5_2;
use Bolt\protocol\V5_3;
use Bolt\protocol\V5_4;
use Exception;
use Laudis\Neo4j\Bolt\BoltConnection;
use Laudis\Neo4j\Bolt\BoltMessageFactory;
use Laudis\Neo4j\Common\Neo4jLogger;
use Laudis\Neo4j\Common\ResponseHelper;
use Laudis\Neo4j\Contracts\AuthenticateInterface;
use Psr\Http\Message\RequestInterface;
use Laudis\Neo4j\Enum\ConnectionProtocol;
use Psr\Http\Message\UriInterface;
use Psr\Log\LogLevel;

use function sprintf;

Expand All @@ -37,30 +30,21 @@ public function __construct(
) {
}

public function authenticateHttp(RequestInterface $request, UriInterface $uri, string $userAgent): RequestInterface
{
$this->logger?->log(LogLevel::DEBUG, 'Authentication disabled');

return $request->withHeader('User-Agent', $userAgent);
}

/**
* @throws Exception
*
* @return array{server: string, connection_id: string, hints: list}
*/
public function authenticateBolt(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol, string $userAgent): array
public function authenticateBolt(BoltConnection $connection, string $userAgent): array
{
$factory = $this->createMessageFactory($protocol);
$factory = $this->createMessageFactory($connection);

if (method_exists($protocol, 'logon')) {
if ($connection->getProtocol()->compare(ConnectionProtocol::BOLT_V5_1()) >= 0) {
$helloMetadata = ['user_agent' => $userAgent];

$factory->createHelloMessage($helloMetadata)->send();
$response = ResponseHelper::getResponse($protocol);
$factory->createHelloMessage($helloMetadata)->send()->getResponse();

$factory->createLogonMessage(['scheme' => 'none'])->send();
ResponseHelper::getResponse($protocol);
$response = $factory->createLogonMessage(['scheme' => 'none'])->send()->getResponse();

/** @var array{server: string, connection_id: string, hints: list} */
return $response->content;
Expand All @@ -71,26 +55,19 @@ public function authenticateBolt(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol, string $
'scheme' => 'none',
];

$factory->createHelloMessage($helloMetadata)->send();
$response = $factory->createHelloMessage($helloMetadata)->send()->getResponse();

/** @var array{server: string, connection_id: string, hints: list} */
return ResponseHelper::getResponse($protocol)->content;
}

public function logoff(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol): void
{
$factory = $this->createMessageFactory($protocol);
$factory->createLogoffMessage()->send();
ResponseHelper::getResponse($protocol);
return $response->content;
}

public function toString(UriInterface $uri): string
{
return sprintf('No Auth %s:%s', $uri->getHost(), $uri->getPort() ?? '');
}

private function createMessageFactory(V4_4|V5|V5_1|V5_2|V5_3|V5_4 $protocol): BoltMessageFactory
private function createMessageFactory(BoltConnection $connection): BoltMessageFactory
{
return new BoltMessageFactory($protocol, $this->logger);
return new BoltMessageFactory($connection, $this->logger);
}
}
Loading