Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"docs": "https://book.cakephp.org/authentication/4/en/"
},
"require": {
"php": ">=8.1",
"php": ">=8.2",
"cakephp/http": "^5.0",
"cakephp/utility": "^5.0",
"laminas/laminas-diactoros": "^3.0",
Expand Down
33 changes: 33 additions & 0 deletions src/AuthenticationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -555,4 +555,37 @@ protected function getImpersonationProvider(): ImpersonationInterface

return $provider;
}

/**
* Debug info.
*
* Nested authenticator configuration can contain secrets such as the
* JWT `secretKey`, the digest `secret` or a string `salt` HMAC key.
* Those keys are redacted so debug output never contains them.
*
* @return array<string, mixed>
*/
public function __debugInfo(): array
{
$config = $this->_config;
if (isset($config['authenticators']) && is_array($config['authenticators'])) {
foreach ($config['authenticators'] as $name => $authenticatorConfig) {
if (!is_array($authenticatorConfig)) {
continue;
}
foreach (['secretKey', 'secret', 'salt'] as $secretKey) {
if (isset($authenticatorConfig[$secretKey])) {
$config['authenticators'][$name][$secretKey] = '*****';
}
}
}
}

return [
'config' => $config,
'authenticators' => $this->_authenticators,
'successfulAuthenticator' => $this->_successfulAuthenticator,
'result' => $this->_result,
];
}
}
31 changes: 27 additions & 4 deletions src/Authenticator/CookieAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
use InvalidArgumentException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use SensitiveParameter;
use UnexpectedValueException;

/**
Expand Down Expand Up @@ -151,7 +152,7 @@ public function authenticate(ServerRequestInterface $request): ResultInterface
* @param array $token The decoded token parts.
* @return \Authentication\Authenticator\ResultInterface
*/
protected function _authenticateToken(array $token): ResultInterface
protected function _authenticateToken(#[SensitiveParameter] array $token): ResultInterface
{
[$username, $expires, $tokenHash] = $token;
if (!is_string($username) || !is_numeric($expires) || !is_string($tokenHash)) {
Expand Down Expand Up @@ -198,7 +199,7 @@ protected function _authenticateToken(array $token): ResultInterface
* @param array $token The decoded token parts.
* @return \Authentication\Authenticator\ResultInterface
*/
protected function _authenticateLegacyToken(array $token): ResultInterface
protected function _authenticateLegacyToken(#[SensitiveParameter] array $token): ResultInterface
{
[$username, $tokenHash] = $token;
if (!is_string($username) || !is_string($tokenHash)) {
Expand Down Expand Up @@ -267,7 +268,7 @@ protected function _legacyHashWithinLimits(array $info): bool
* @param \ArrayAccess<string, mixed>|array<string, mixed> $identity Identity data.
* @return string
*/
protected function _createLegacyPlainToken(ArrayAccess|array $identity): string
protected function _createLegacyPlainToken(#[SensitiveParameter] ArrayAccess|array $identity): string
{
$usernameField = $this->getConfig('fields.username');
$passwordField = $this->getConfig('fields.password');
Expand Down Expand Up @@ -348,7 +349,7 @@ public function persistIdentity(
* @return string
* @throws \JsonException
*/
protected function _createToken(ArrayAccess|array $identity): string
protected function _createToken(#[SensitiveParameter] ArrayAccess|array $identity): string
{
$usernameField = $this->getConfig('fields.username');
$passwordField = $this->getConfig('fields.password');
Expand Down Expand Up @@ -448,4 +449,26 @@ protected function _createCookie(mixed $value): CookieInterface
$options,
);
}

/**
* Debug info.
*
* Redacts the `salt` configuration value when it is a string as a
* string salt is used as the HMAC key for remember-me tokens.
*
* @return array<string, mixed>
*/
public function __debugInfo(): array
{
$config = $this->_config;
if (isset($config['salt']) && is_string($config['salt'])) {
$config['salt'] = '*****';
}

return [
'config' => $config,
'identifier' => $this->_identifier,
'passwordHasher' => $this->_passwordHasher,
];
}
}
38 changes: 33 additions & 5 deletions src/Authenticator/HttpDigestAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Cake\Utility\Security;
use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use SensitiveParameter;

/**
* HttpDigest Authenticator
Expand Down Expand Up @@ -149,7 +150,7 @@ protected function _getDigest(ServerRequestInterface $request): ?array
* @param string $digest The raw digest authentication headers.
* @return array<string>|null An array of digest authentication headers
*/
public function parseAuthData(string $digest): ?array
public function parseAuthData(#[SensitiveParameter] string $digest): ?array
{
if (str_starts_with($digest, 'Digest ')) {
$digest = substr($digest, 7);
Expand Down Expand Up @@ -178,8 +179,11 @@ public function parseAuthData(string $digest): ?array
* @param string $method Request method
* @return string Response hash
*/
public function generateResponseHash(array $digest, string $password, string $method): string
{
public function generateResponseHash(
#[SensitiveParameter] array $digest,
#[SensitiveParameter] string $password,
string $method,
): string {
return md5(
$password .
':' . $digest['nonce'] . ':' . $digest['nc'] . ':' . $digest['cnonce'] . ':' . $digest['qop'] . ':' .
Expand All @@ -195,8 +199,11 @@ public function generateResponseHash(array $digest, string $password, string $me
* @param string $realm The realm the password is for.
* @return string the hashed password that can later be used with Digest authentication.
*/
public static function password(string $username, string $password, string $realm): string
{
public static function password(
string $username,
#[SensitiveParameter] string $password,
string $realm,
): string {
return md5($username . ':' . $realm . ':' . $password);
}

Expand Down Expand Up @@ -277,4 +284,25 @@ protected function validNonce(string $nonce): bool

return hash_equals($check, $checksum);
}

/**
* Debug info.
*
* Redacts the `secret` configuration value so that debug output
* never contains the nonce signing secret.
*
* @return array<string, mixed>
*/
public function __debugInfo(): array
{
$config = $this->_config;
if (isset($config['secret'])) {
$config['secret'] = '*****';
}

return [
'config' => $config,
'identifier' => $this->_identifier,
];
}
}
25 changes: 24 additions & 1 deletion src/Authenticator/JwtAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use Firebase\JWT\Key;
use Psr\Http\Message\ServerRequestInterface;
use RuntimeException;
use SensitiveParameter;
use stdClass;

class JwtAuthenticator extends TokenAuthenticator
Expand Down Expand Up @@ -158,7 +159,7 @@ public function getPayload(?ServerRequestInterface $request = null): ?object
* @param string $token JWT token to decode.
* @return object|null The JWT's payload as a PHP object, null on failure.
*/
protected function decodeToken(string $token): ?object
protected function decodeToken(#[SensitiveParameter] string $token): ?object
{
$jsonWebKeySet = $this->getConfig('jwks');
if ($jsonWebKeySet) {
Expand All @@ -174,4 +175,26 @@ protected function decodeToken(string $token): ?object

return JWT::decode($token, $key);
}

/**
* Debug info.
*
* Redacts the `secretKey` configuration value so that debug output
* never contains the signing secret.
*
* @return array<string, mixed>
*/
public function __debugInfo(): array
{
$config = $this->_config;
if (isset($config['secretKey'])) {
$config['secretKey'] = '*****';
}

return [
'config' => $config,
'identifier' => $this->_identifier,
'payload' => $this->payload,
];
}
}
3 changes: 2 additions & 1 deletion src/Authenticator/TokenAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Authentication\Identifier\IdentifierInterface;
use Authentication\Identifier\TokenIdentifier;
use Psr\Http\Message\ServerRequestInterface;
use SensitiveParameter;

/**
* Token Authenticator
Expand Down Expand Up @@ -75,7 +76,7 @@ protected function getToken(ServerRequestInterface $request): ?string
* @param string $prefix Prefix to strip
* @return string
*/
protected function stripTokenPrefix(string $token, string $prefix): string
protected function stripTokenPrefix(#[SensitiveParameter] string $token, string $prefix): string
{
$prefixLength = mb_strlen($prefix);
if (mb_substr(mb_strtolower($token), 0, $prefixLength) === mb_strtolower($prefix)) {
Expand Down
3 changes: 2 additions & 1 deletion src/Identifier/CallbackIdentifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Authentication\Authenticator\Result;
use InvalidArgumentException;
use RuntimeException;
use SensitiveParameter;

/**
* Callback Identifier
Expand Down Expand Up @@ -66,7 +67,7 @@ protected function checkCallable(): void
/**
* @inheritDoc
*/
public function identify(array $credentials): ArrayAccess|array|null
public function identify(#[SensitiveParameter] array $credentials): ArrayAccess|array|null
{
$callback = $this->getConfig('callback');

Expand Down
3 changes: 2 additions & 1 deletion src/Identifier/IdentifierInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
namespace Authentication\Identifier;

use ArrayAccess;
use SensitiveParameter;

interface IdentifierInterface
{
Expand All @@ -26,7 +27,7 @@ interface IdentifierInterface
* @param array<string, mixed> $credentials Authentication credentials
* @return \ArrayAccess<string, mixed>|array<string, mixed>|null
*/
public function identify(array $credentials): ArrayAccess|array|null;
public function identify(#[SensitiveParameter] array $credentials): ArrayAccess|array|null;

/**
* Gets a list of errors happened in the identification process
Expand Down
4 changes: 3 additions & 1 deletion src/Identifier/Ldap/AdapterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
namespace Authentication\Identifier\Ldap;

use SensitiveParameter;

interface AdapterInterface
{
/**
Expand All @@ -25,7 +27,7 @@ interface AdapterInterface
* @param string $password Bind password
* @return bool
*/
public function bind(string $bind, string $password): bool;
public function bind(string $bind, #[SensitiveParameter] string $password): bool;

/**
* Connect to an LDAP server
Expand Down
3 changes: 2 additions & 1 deletion src/Identifier/Ldap/ExtensionAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use ErrorException;
use LDAP\Connection;
use RuntimeException;
use SensitiveParameter;

/**
* Provides a very thin OOP wrapper around the ldap_* functions.
Expand Down Expand Up @@ -58,7 +59,7 @@ public function __construct()
* @param string $password Bind password
* @return bool
*/
public function bind(string $bind, string $password): bool
public function bind(string $bind, #[SensitiveParameter] string $password): bool
{
$this->_setErrorHandler();
$result = ldap_bind($this->getConnection(), $bind, $password);
Expand Down
9 changes: 6 additions & 3 deletions src/Identifier/LdapIdentifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use ErrorException;
use InvalidArgumentException;
use RuntimeException;
use SensitiveParameter;

/**
* LDAP Identifier
Expand Down Expand Up @@ -145,7 +146,7 @@ protected function _buildLdapObject(): void
/**
* @inheritDoc
*/
public function identify(array $credentials): ArrayAccess|array|null
public function identify(#[SensitiveParameter] array $credentials): ArrayAccess|array|null
{
$this->_connectLdap();
$fields = $this->getConfig('fields');
Expand Down Expand Up @@ -195,8 +196,10 @@ protected function _connectLdap(): void
* @param string $password The password
* @return \ArrayAccess|null
*/
protected function _bindUser(string $username, string $password): ?ArrayAccess
{
protected function _bindUser(
string $username,
#[SensitiveParameter] string $password,
): ?ArrayAccess {
$config = $this->getConfig();
try {
$ldapBind = $this->_ldap->bind($config['bindDN']($username), $password);
Expand Down
9 changes: 6 additions & 3 deletions src/Identifier/PasswordIdentifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Authentication\PasswordHasher\PasswordHasherFactory;
use Authentication\PasswordHasher\PasswordHasherInterface;
use Authentication\PasswordHasher\PasswordHasherTrait;
use SensitiveParameter;

/**
* Password Identifier
Expand Down Expand Up @@ -95,7 +96,7 @@ public function getPasswordHasher(): PasswordHasherInterface
/**
* @inheritDoc
*/
public function identify(array $credentials): ArrayAccess|array|null
public function identify(#[SensitiveParameter] array $credentials): ArrayAccess|array|null
{
if (!isset($credentials[self::CREDENTIAL_USERNAME])) {
return null;
Expand All @@ -121,8 +122,10 @@ public function identify(array $credentials): ArrayAccess|array|null
* @param string|null $password The password.
* @return bool
*/
protected function _checkPassword(ArrayAccess|array|null $identity, ?string $password): bool
{
protected function _checkPassword(
#[SensitiveParameter] ArrayAccess|array|null $identity,
#[SensitiveParameter] ?string $password,
): bool {
$passwordField = $this->getConfig('fields.' . self::CREDENTIAL_PASSWORD);

$identity ??= [
Expand Down
3 changes: 2 additions & 1 deletion src/Identifier/TokenIdentifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use ArrayAccess;
use Authentication\Identifier\Resolver\ResolverAwareTrait;
use Cake\Utility\Security;
use SensitiveParameter;

/**
* Token Identifier
Expand All @@ -44,7 +45,7 @@ class TokenIdentifier extends AbstractIdentifier
/**
* @inheritDoc
*/
public function identify(array $credentials): ArrayAccess|array|null
public function identify(#[SensitiveParameter] array $credentials): ArrayAccess|array|null
{
$dataField = $this->getConfig('dataField');
if (!isset($credentials[$dataField])) {
Expand Down
Loading
Loading