From 68928b9d5ee92b07b8c3da958941dc8c6c1b07b8 Mon Sep 17 00:00:00 2001 From: Steve Bauman Date: Wed, 13 Aug 2025 11:28:11 -0400 Subject: [PATCH 1/3] Require PHP 8.2 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 97e84cd5..e504a01d 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ } ], "require": { - "php": ">=8.1", + "php": ">=8.2", "ext-ldap": "*", "ext-json": "*", "ext-iconv": "*", From fa542fe1fe888616e54f4ef40b79f37deaf2bb03 Mon Sep 17 00:00:00 2001 From: Steve Bauman Date: Wed, 13 Aug 2025 11:29:43 -0400 Subject: [PATCH 2/3] Add SensitiveParameter annotations to password parameters --- src/Auth/Guard.php | 7 +++--- src/Connection.php | 3 ++- src/Ldap.php | 5 +++-- src/LdapInterface.php | 5 +++-- src/Models/Attributes/Password.php | 35 +++++++++++++++-------------- src/Models/Concerns/HasPassword.php | 11 ++++----- 6 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index a77cf632..91765c04 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -6,6 +6,7 @@ use LdapRecord\Configuration\DomainConfiguration; use LdapRecord\Events\DispatcherInterface; use LdapRecord\LdapInterface; +use SensitiveParameter; class Guard { @@ -39,7 +40,7 @@ public function __construct(LdapInterface $connection, DomainConfiguration $conf * @throws UsernameRequiredException * @throws PasswordRequiredException */ - public function attempt(string $username, string $password, bool $stayBound = false): bool + public function attempt(string $username, #[SensitiveParameter] string $password, bool $stayBound = false): bool { switch (true) { case empty($username): @@ -73,7 +74,7 @@ public function attempt(string $username, string $password, bool $stayBound = fa * @throws BindException * @throws \LdapRecord\ConnectionException */ - public function bind(?string $username = null, ?string $password = null): void + public function bind(?string $username = null, #[SensitiveParameter] ?string $password = null): void { $this->fireAuthEvent('binding', $username, $password); @@ -104,7 +105,7 @@ public function bind(?string $username = null, ?string $password = null): void * * @throws \LdapRecord\ConnectionException */ - protected function authenticate(?string $username = null, ?string $password = null): bool + protected function authenticate(?string $username = null, #[SensitiveParameter] ?string $password = null): bool { if ($this->configuration->get('use_sasl') ?? false) { return $this->connection->saslBind( diff --git a/src/Connection.php b/src/Connection.php index ea96c1e0..a2adb869 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -11,6 +11,7 @@ use LdapRecord\Query\Builder; use LdapRecord\Query\Cache; use Psr\SimpleCache\CacheInterface; +use SensitiveParameter; class Connection { @@ -211,7 +212,7 @@ public function setGuardResolver(Closure $callback): void * @throws Auth\BindException * @throws LdapRecordException */ - public function connect(?string $username = null, ?string $password = null): void + public function connect(?string $username = null, #[SensitiveParameter] ?string $password = null): void { $attempt = function () use ($username, $password) { $this->dispatch(new Events\Connecting($this)); diff --git a/src/Ldap.php b/src/Ldap.php index 1002565e..b65a1f27 100644 --- a/src/Ldap.php +++ b/src/Ldap.php @@ -3,6 +3,7 @@ namespace LdapRecord; use LDAP\Connection as RawLdapConnection; +use SensitiveParameter; class Ldap implements LdapInterface { @@ -270,7 +271,7 @@ public function parseResult(mixed $result, int &$errorCode = 0, ?string &$dn = n /** * {@inheritdoc} */ - public function bind(?string $dn = null, ?string $password = null, ?array $controls = null): LdapResultResponse + public function bind(?string $dn = null, #[SensitiveParameter] ?string $password = null, ?array $controls = null): LdapResultResponse { /** @var \LDAP\Result $result */ $result = $this->executeFailableOperation(function () use ($dn, $password, $controls) { @@ -287,7 +288,7 @@ public function bind(?string $dn = null, ?string $password = null, ?array $contr /** * {@inheritDoc} */ - public function saslBind(?string $dn = null, ?string $password = null, array $options = []): bool + public function saslBind(?string $dn = null, #[SensitiveParameter] ?string $password = null, array $options = []): bool { return $this->executeFailableOperation(function () use ($dn, $password, $options) { $options = array_merge([ diff --git a/src/LdapInterface.php b/src/LdapInterface.php index 307e8f81..ff99b8ee 100644 --- a/src/LdapInterface.php +++ b/src/LdapInterface.php @@ -3,6 +3,7 @@ namespace LdapRecord; use LDAP\Connection; +use SensitiveParameter; /** * @see https://ldap.com/ldap-oid-reference-guide @@ -501,7 +502,7 @@ public function parseResult(mixed $result, int &$errorCode = 0, ?string &$dn = n * * @throws LdapRecordException */ - public function bind(?string $dn = null, ?string $password = null, ?array $controls = null): LdapResultResponse; + public function bind(?string $dn = null, #[SensitiveParameter] ?string $password = null, ?array $controls = null): LdapResultResponse; /** * Bind to the LDAP directory using SASL. @@ -516,7 +517,7 @@ public function bind(?string $dn = null, ?string $password = null, ?array $contr * @see https://php.net/manual/en/function.ldap-sasl-bind.php * @see https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml */ - public function saslBind(?string $dn = null, ?string $password = null, array $options = []): bool; + public function saslBind(?string $dn = null, #[SensitiveParameter] ?string $password = null, array $options = []): bool; /** * Adds an entry to the current connection. diff --git a/src/Models/Attributes/Password.php b/src/Models/Attributes/Password.php index 71f4d06e..62975733 100644 --- a/src/Models/Attributes/Password.php +++ b/src/Models/Attributes/Password.php @@ -5,6 +5,7 @@ use InvalidArgumentException; use LdapRecord\LdapRecordException; use ReflectionMethod; +use SensitiveParameter; class Password { @@ -17,7 +18,7 @@ class Password /** * Make an encoded password for transmission over LDAP. */ - public static function encode(string $password): string + public static function encode(#[SensitiveParameter] string $password): string { return iconv('UTF-8', 'UTF-16LE', '"'.$password.'"'); } @@ -25,7 +26,7 @@ public static function encode(string $password): string /** * Make a salted md5 password. */ - public static function smd5(string $password, ?string $salt = null): string + public static function smd5(#[SensitiveParameter] string $password, ?string $salt = null): string { return '{SMD5}'.static::makeHash($password, 'md5', null, $salt ?? random_bytes(4)); } @@ -33,7 +34,7 @@ public static function smd5(string $password, ?string $salt = null): string /** * Make a salted SHA password. */ - public static function ssha(string $password, ?string $salt = null): string + public static function ssha(#[SensitiveParameter] string $password, ?string $salt = null): string { return '{SSHA}'.static::makeHash($password, 'sha1', null, $salt ?? random_bytes(4)); } @@ -41,7 +42,7 @@ public static function ssha(string $password, ?string $salt = null): string /** * Make a salted SSHA256 password. */ - public static function ssha256(string $password, ?string $salt = null): string + public static function ssha256(#[SensitiveParameter] string $password, ?string $salt = null): string { return '{SSHA256}'.static::makeHash($password, 'hash', 'sha256', $salt ?? random_bytes(4)); } @@ -49,7 +50,7 @@ public static function ssha256(string $password, ?string $salt = null): string /** * Make a salted SSHA384 password. */ - public static function ssha384(string $password, ?string $salt = null): string + public static function ssha384(#[SensitiveParameter] string $password, ?string $salt = null): string { return '{SSHA384}'.static::makeHash($password, 'hash', 'sha384', $salt ?? random_bytes(4)); } @@ -57,7 +58,7 @@ public static function ssha384(string $password, ?string $salt = null): string /** * Make a salted SSHA512 password. */ - public static function ssha512(string $password, ?string $salt = null): string + public static function ssha512(#[SensitiveParameter] string $password, ?string $salt = null): string { return '{SSHA512}'.static::makeHash($password, 'hash', 'sha512', $salt ?? random_bytes(4)); } @@ -65,7 +66,7 @@ public static function ssha512(string $password, ?string $salt = null): string /** * Make a non-salted SHA password. */ - public static function sha(string $password): string + public static function sha(#[SensitiveParameter] string $password): string { return '{SHA}'.static::makeHash($password, 'sha1'); } @@ -73,7 +74,7 @@ public static function sha(string $password): string /** * Make a non-salted SHA256 password. */ - public static function sha256(string $password): string + public static function sha256(#[SensitiveParameter] string $password): string { return '{SHA256}'.static::makeHash($password, 'hash', 'sha256'); } @@ -81,7 +82,7 @@ public static function sha256(string $password): string /** * Make a non-salted SHA384 password. */ - public static function sha384(string $password): string + public static function sha384(#[SensitiveParameter] string $password): string { return '{SHA384}'.static::makeHash($password, 'hash', 'sha384'); } @@ -89,7 +90,7 @@ public static function sha384(string $password): string /** * Make a non-salted SHA512 password. */ - public static function sha512(string $password): string + public static function sha512(#[SensitiveParameter] string $password): string { return '{SHA512}'.static::makeHash($password, 'hash', 'sha512'); } @@ -97,7 +98,7 @@ public static function sha512(string $password): string /** * Make a non-salted md5 password. */ - public static function md5(string $password): string + public static function md5(#[SensitiveParameter] string $password): string { return '{MD5}'.static::makeHash($password, 'md5'); } @@ -105,7 +106,7 @@ public static function md5(string $password): string /** * Make a non-salted NThash password. */ - public static function nthash(string $password): string + public static function nthash(#[SensitiveParameter] string $password): string { return '{NTHASH}'.strtoupper(hash('md4', iconv('UTF-8', 'UTF-16LE', $password))); } @@ -113,7 +114,7 @@ public static function nthash(string $password): string /** * Crypt password with an MD5 salt. */ - public static function md5Crypt(string $password, ?string $salt = null): string + public static function md5Crypt(#[SensitiveParameter] string $password, ?string $salt = null): string { return '{CRYPT}'.static::makeCrypt($password, static::CRYPT_SALT_TYPE_MD5, $salt); } @@ -121,7 +122,7 @@ public static function md5Crypt(string $password, ?string $salt = null): string /** * Crypt password with a SHA256 salt. */ - public static function sha256Crypt(string $password, ?string $salt = null): string + public static function sha256Crypt(#[SensitiveParameter] string $password, ?string $salt = null): string { return '{CRYPT}'.static::makeCrypt($password, static::CRYPT_SALT_TYPE_SHA256, $salt); } @@ -129,7 +130,7 @@ public static function sha256Crypt(string $password, ?string $salt = null): stri /** * Crypt a password with a SHA512 salt. */ - public static function sha512Crypt(string $password, ?string $salt = null): string + public static function sha512Crypt(#[SensitiveParameter] string $password, ?string $salt = null): string { return '{CRYPT}'.static::makeCrypt($password, static::CRYPT_SALT_TYPE_SHA512, $salt); } @@ -137,7 +138,7 @@ public static function sha512Crypt(string $password, ?string $salt = null): stri /** * Make a new password hash. */ - protected static function makeHash(string $password, string $method, ?string $algo = null, ?string $salt = null): string + protected static function makeHash(#[SensitiveParameter] string $password, string $method, ?string $algo = null, ?string $salt = null): string { $params = $algo ? [$algo, $password.$salt] : [$password.$salt]; @@ -147,7 +148,7 @@ protected static function makeHash(string $password, string $method, ?string $al /** * Make a hashed password. */ - protected static function makeCrypt(string $password, int $type, ?string $salt = null): string + protected static function makeCrypt(#[SensitiveParameter] string $password, int $type, ?string $salt = null): string { return crypt($password, $salt ?? static::makeCryptSalt($type)); } diff --git a/src/Models/Concerns/HasPassword.php b/src/Models/Concerns/HasPassword.php index dcbaf87d..0f2b17ff 100644 --- a/src/Models/Concerns/HasPassword.php +++ b/src/Models/Concerns/HasPassword.php @@ -5,6 +5,7 @@ use LdapRecord\ConnectionException; use LdapRecord\LdapRecordException; use LdapRecord\Models\Attributes\Password; +use SensitiveParameter; /** @mixin \LdapRecord\Models\Model */ trait HasPassword @@ -14,7 +15,7 @@ trait HasPassword * * @throws ConnectionException */ - public function setPasswordAttribute(array|string $password): void + public function setPasswordAttribute(#[SensitiveParameter] array|string $password): void { $this->assertSecureConnection(); @@ -49,7 +50,7 @@ public function setPasswordAttribute(array|string $password): void * * @throws ConnectionException */ - public function setUnicodepwdAttribute(array|string $password): void + public function setUnicodepwdAttribute(#[SensitiveParameter] array|string $password): void { $this->setPasswordAttribute($password); } @@ -97,7 +98,7 @@ public function getPasswordHashMethod(): string /** * Set the changed password. */ - protected function setChangedPassword(string $oldPassword, string $newPassword, string $attribute): void + protected function setChangedPassword(#[SensitiveParameter] string $oldPassword, #[SensitiveParameter] string $newPassword, string $attribute): void { // Create batch modification for removing the old password. $this->addModification( @@ -121,7 +122,7 @@ protected function setChangedPassword(string $oldPassword, string $newPassword, /** * Set the password on the model. */ - protected function setPassword(string $password, string $attribute): void + protected function setPassword(#[SensitiveParameter] string $password, string $attribute): void { if (! $this->exists) { $this->setRawAttribute($attribute, $password); @@ -143,7 +144,7 @@ protected function setPassword(string $password, string $attribute): void * * @throws LdapRecordException */ - protected function getHashedPassword(string $method, string $password, ?string $salt = null): string + protected function getHashedPassword(string $method, #[SensitiveParameter] string $password, ?string $salt = null): string { if (! method_exists(Password::class, $method)) { throw new LdapRecordException("Password hashing method [{$method}] does not exist."); From 4f93f89627b840489809ab169f8b80cc13e034fb Mon Sep 17 00:00:00 2001 From: Steve Bauman Date: Wed, 13 Aug 2025 11:30:49 -0400 Subject: [PATCH 3/3] Update workflows --- .github/workflows/run-integration-tests.yml | 2 +- .github/workflows/run-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-integration-tests.yml b/.github/workflows/run-integration-tests.yml index de67e91c..6b0d603f 100644 --- a/.github/workflows/run-integration-tests.yml +++ b/.github/workflows/run-integration-tests.yml @@ -28,7 +28,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - php: [8.1, 8.2, 8.3] + php: [8.2, 8.3, 8.4] name: ${{ matrix.os }} - P${{ matrix.php }} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 8781e918..47613b29 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -15,7 +15,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - php: [8.1, 8.2, 8.3, 8.4] + php: [8.2, 8.3, 8.4] steps: - name: Checkout code