105 lines
3.1 KiB
PHP
105 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace Ulmus\User\Authorize\Header;
|
|
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
use Ulmus\User\Entity\DigestAuthUserInterface;
|
|
use Ulmus\User\Lib\Authenticate;
|
|
|
|
class DigestMethod implements MethodInterface
|
|
{
|
|
public function __construct(
|
|
protected Authenticate $authorize,
|
|
protected DigestAuthUserInterface $user,
|
|
protected string|array $arguments
|
|
) {}
|
|
|
|
public function execute(ServerRequestInterface $request) : bool
|
|
{
|
|
$arguments = $this->parseDigestArguments($this->arguments);
|
|
|
|
if (empty($arguments['username'])) {
|
|
throw new \InvalidArgumentException("A 'username' key is required to authenticate using Digest");
|
|
}
|
|
|
|
$isSess = stripos($arguments['algorithm'] ?? "", "-SESS") !== false;
|
|
|
|
$hashMethod = $this->getDigestAlgorithmHash($arguments);
|
|
|
|
$arguments['nc'] = str_pad($arguments['nc'] ?? "1", 8, '0', STR_PAD_LEFT);
|
|
|
|
$ha1 = $this->getSecretHash();
|
|
|
|
if ($isSess) {
|
|
$ha1 = hash($hashMethod, implode(':', [
|
|
$ha1, $arguments['nonce'] , $arguments['cnonce']
|
|
]));
|
|
}
|
|
|
|
switch($arguments['qop'] ?? 'auth') {
|
|
case 'auth-int':
|
|
$ha2 = hash($hashMethod, implode(':', [
|
|
strtoupper($request->getMethod()), $arguments['uri'], hash($hashMethod, $body ?? "")
|
|
]));
|
|
break;
|
|
|
|
case 'auth':
|
|
default:
|
|
$ha2 = hash($hashMethod, implode(':', [
|
|
strtoupper($request->getMethod()), $arguments['uri']
|
|
]));
|
|
break;
|
|
}
|
|
|
|
if (isset($arguments['qop'])) {
|
|
$response = hash($hashMethod, implode(':', [
|
|
$ha1, $arguments['nonce'], $arguments['nc'], $arguments['cnonce'], $arguments['qop'], $ha2
|
|
]));
|
|
}
|
|
else {
|
|
$response = hash($hashMethod, implode(':', [
|
|
$ha1, $arguments['nonce'], $ha2
|
|
]));
|
|
}
|
|
|
|
return $response === $arguments['response'];
|
|
}
|
|
|
|
|
|
protected function parseDigestArguments(string|array $arguments) : array
|
|
{
|
|
if (is_string($arguments)) {
|
|
$keys = [ 'nonce', 'nc', 'cnonce', 'qop', 'username', 'uri', 'realm', 'response', 'opaque', 'algorithm' ];
|
|
|
|
# From https://www.php.net/manual/en/features.http-auth.php
|
|
preg_match_all('@(' . implode('|', $keys) . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $arguments, $matches, PREG_SET_ORDER);
|
|
|
|
$arguments = [];
|
|
|
|
foreach ($matches as $match) {
|
|
$arguments[$match[1]] = $match[3] ?: $match[4];
|
|
}
|
|
}
|
|
|
|
return $arguments;
|
|
}
|
|
|
|
protected function getDigestAlgorithmHash(array $arguments) : string
|
|
{
|
|
switch(strtoupper($arguments['algorithm'] ?? "")) {
|
|
case "SHA-512-256":
|
|
case "SHA-512-256-SESS":
|
|
return "sha512/256";
|
|
|
|
case "SHA-256":
|
|
case "SHA-256-SESS":
|
|
return "sha256";
|
|
|
|
default:
|
|
case 'MD5-SESS':
|
|
case 'MD5':
|
|
return "md5";
|
|
}
|
|
}
|
|
|
|
} |