From 25a69b236b682a056570aab52aa4086413457bee Mon Sep 17 00:00:00 2001 From: Mike Macgirvin Date: Sat, 29 Jul 2023 11:07:38 +1000 Subject: [PATCH] new auth work --- Code/Lib/Activity.php | 14 +++----------- Code/Module/Cdav.php | 32 +++++++++++--------------------- Code/Module/Dav.php | 34 ++++++++++------------------------ Code/Module/Getfile.php | 33 ++++++++++++--------------------- Code/Module/Owa.php | 16 +++------------- Code/Module/Token.php | 15 +++------------ Code/Web/HTTPHeaders.php | 26 +++++++++++++++++++++++++- include/api_auth.php | 24 ++++++++---------------- 8 files changed, 75 insertions(+), 119 deletions(-) diff --git a/Code/Lib/Activity.php b/Code/Lib/Activity.php index 4fead31d3..2b0e40233 100644 --- a/Code/Lib/Activity.php +++ b/Code/Lib/Activity.php @@ -8,6 +8,7 @@ use Code\ActivityStreams\Actor; use Code\ActivityStreams\ASObject; use Code\ActivityStreams\Link; use Code\Nomad\Profile; +use Code\Web\HTTPHeaders; use Code\Web\HTTPSig; use Code\Access\Permissions; use Code\Access\PermissionRoles; @@ -4596,23 +4597,14 @@ class Activity public static function token_from_request() { - - foreach (['REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION'] as $s) { - $auth = ((array_key_exists($s, $_SERVER) && str_starts_with($_SERVER[$s], 'Bearer ')) - ? str_replace('Bearer ', EMPTY_STR, $_SERVER[$s]) - : EMPTY_STR - ); - if ($auth) { - break; - } - } + $authHeader = (new HTTPHeaders())->getAuthHeader(); + $auth = ($authHeader && str_starts_with($authHeader, 'Bearer')); if (!$auth) { if (array_key_exists('token', $_REQUEST) && $_REQUEST['token']) { $auth = $_REQUEST['token']; } } - return $auth; } diff --git a/Code/Module/Cdav.php b/Code/Module/Cdav.php index 4a351def5..96b795fe4 100644 --- a/Code/Module/Cdav.php +++ b/Code/Module/Cdav.php @@ -3,6 +3,7 @@ namespace Code\Module; use App; +use Code\Web\HTTPHeaders; use DBA; use DateTime; use Sabre\CalDAV\CalendarRoot; @@ -63,29 +64,23 @@ class Cdav extends Controller $_SERVER['HTTP_AUTHORIZATION'] = 'Signature ' . $_SERVER['HTTP_SIGNATURE']; } + $authHeader = (new HTTPHeaders())->getAuthHeader(); + if ($authHeader) { - foreach (['REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION'] as $head) { /* Basic authentication */ - - if (array_key_exists($head, $_SERVER) && substr(trim($_SERVER[$head]), 0, 5) === 'Basic') { - $userpass = @base64_decode(substr(trim($_SERVER[$head]), 6)); + if (substr(trim($authHeader), 0, 5) === 'Basic') { + $userpass = @base64_decode(substr(trim($authHeader), 6)); if (strlen($userpass)) { list($name, $password) = explode(':', $userpass); $_SERVER['PHP_AUTH_USER'] = $name; $_SERVER['PHP_AUTH_PW'] = $password; } - break; } /* Signature authentication */ - if (array_key_exists($head, $_SERVER) && substr(trim($_SERVER[$head]), 0, 9) === 'Signature') { - if ($head !== 'HTTP_AUTHORIZATION') { - $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head]; - continue; - } - - $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]); + if (substr(trim($authHeader), 0, 9) === 'Signature') { + $sigblock = HTTPSig::parse_sigheader($authHeader); if ($sigblock) { $keyId = str_replace('acct:', '', $sigblock['keyId']); if ($keyId) { @@ -103,9 +98,10 @@ class Cdav extends Controller $channel_login = $c['channel_id']; } } - } - if (!$record) { - continue; + + if ($record) { + break; + } } if ($record) { @@ -119,17 +115,11 @@ class Cdav extends Controller change_channel($channel_login); } } - if ($verified && $verified['header_signed'] && $verified['header_valid'] && $record) { - break; - } } } } } } - if ($verified && $verified['header_signed'] && $verified['header_valid'] && $record['account']) { - break; - } } /** diff --git a/Code/Module/Dav.php b/Code/Module/Dav.php index a7dcbfda5..f2969c555 100644 --- a/Code/Module/Dav.php +++ b/Code/Module/Dav.php @@ -36,17 +36,13 @@ class Dav extends Controller */ public function init() { - if (isset($_SERVER['HTTP_SIGNATURE']) && - !isset($_SERVER['REDIRECT_REMOTE_USER']) && - !isset($_SERVER['HTTP_AUTHORIZATION'])) { - $_SERVER['HTTP_AUTHORIZATION'] = 'Signature ' . $_SERVER['HTTP_SIGNATURE']; - } + $authHeader = (new HTTPHeaders())->getAuthHeader(); + if ($authHeader) { - foreach (['REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION'] as $head) { /* Basic authentication */ - if (array_key_exists($head, $_SERVER) && str_starts_with(trim($_SERVER[$head]), 'Basic')) { - $userpass = @base64_decode(substr(trim($_SERVER[$head]), 6)); + if (str_starts_with(trim($authHeader), 'Basic')) { + $userpass = @base64_decode(substr(trim($authHeader), 6)); if (strlen($userpass)) { list($name, $password) = explode(':', $userpass); $_SERVER['PHP_AUTH_USER'] = $name; @@ -57,13 +53,8 @@ class Dav extends Controller /* Signature authentication */ - if (array_key_exists($head, $_SERVER) && str_starts_with(trim($_SERVER[$head]), 'Signature')) { - if ($head !== 'HTTP_AUTHORIZATION') { - $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head]; - continue; - } - - $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]); + if (str_starts_with(trim($authHeader), 'Signature')) { + $sigblock = HTTPSig::parse_sigheader($authHeader); if ($sigblock) { $keyId = str_replace('acct:', '', $sigblock['keyId']); if ($keyId) { @@ -81,10 +72,11 @@ class Dav extends Controller $channel_login = $c['channel_id']; } } + if ($record) { + break; + } } - if (!$record) { - continue; - } + if ($record) { $verified = HTTPSig::verify('', $record['channel']['channel_pubkey']); @@ -97,17 +89,11 @@ class Dav extends Controller change_channel($channel_login); } } - if ($verified && $verified['header_signed'] && $verified['header_valid'] && $record) { - break; - } } } } } } - if ($verified && $verified['header_signed'] && $verified['header_valid'] && $record['account']) { - break; - } } if (!is_dir('store')) { diff --git a/Code/Module/Getfile.php b/Code/Module/Getfile.php index 40e175992..98ee1518a 100644 --- a/Code/Module/Getfile.php +++ b/Code/Module/Getfile.php @@ -56,35 +56,26 @@ class Getfile extends Controller killme(); } - if (isset($_SERVER['HTTP_SIGNATURE']) && - !isset($_SERVER['REDIRECT_REMOTE_USER']) && - !isset($_SERVER['HTTP_AUTHORIZATION'])) { - $_SERVER['HTTP_AUTHORIZATION'] = 'Signature ' . $_SERVER['HTTP_SIGNATURE']; - } + $authHeader = (new HTTPHeaders())->getAuthHeader(); + if (($authHeader) && str_starts_with(trim($authHeader), 'Signature')) { + $_SERVER['HTTP_AUTHORIZATION'] = $authHeader; - foreach (['REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION'] as $head) { - if (array_key_exists($head, $_SERVER) && str_starts_with(trim($_SERVER[$head]), 'Signature')) { - if ($head !== 'HTTP_AUTHORIZATION') { - $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head]; - continue; - } - - $verified = HTTPSig::verify(''); - if ($verified && $verified['header_signed'] && $verified['header_valid']) { - $r = hubloc_id_addr_query($verified['signer']); - if ($r) { - foreach($r as $hub) { - if ($hub['hubloc_hash'] === $hash) { - $header_verified = true; - break; - } + $verified = HTTPSig::verify(''); + if ($verified && $verified['header_signed'] && $verified['header_valid']) { + $r = hubloc_id_addr_query($verified['signer']); + if ($r) { + foreach($r as $hub) { + if ($hub['hubloc_hash'] === $hash) { + $header_verified = true; + break; } } } } } + if (!$header_verified) { http_status_exit(403, 'Permission denied'); } diff --git a/Code/Module/Owa.php b/Code/Module/Owa.php index 972819f37..0fcd29990 100644 --- a/Code/Module/Owa.php +++ b/Code/Module/Owa.php @@ -21,20 +21,10 @@ class Owa extends Controller public function init() { $ret = ['success' => false]; + $authHeader = (new HTTPHeaders())->getAuthHeader(); - if (array_key_exists('REDIRECT_REMOTE_USER', $_SERVER) && (!array_key_exists('HTTP_AUTHORIZATION', $_SERVER))) { - $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_REMOTE_USER']; - } - - // Apache is now aggressively stripping authentication headers from reaching PHP. They aren't even available with the - // CGIPassAuth directive. So accept a Signature header in lieu of whatever Apache decides it isn't safe for your - // application to look at. - if (array_key_exists('HTTP_SIGNATURE', $_SERVER) && (!array_key_exists('HTTP_AUTHORIZATION', $_SERVER))) { - $_SERVER['HTTP_AUTHORIZATION'] = 'Signature ' . $_SERVER['HTTP_SIGNATURE']; - } - - if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER) && str_starts_with(trim($_SERVER['HTTP_AUTHORIZATION']), 'Signature')) { - $sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']); + if (str_starts_with(trim($authHeader), 'Signature')) { + $sigblock = HTTPSig::parse_sigheader($authHeader); if ($sigblock) { $keyId = $sigblock['keyId']; if ($keyId) { diff --git a/Code/Module/Token.php b/Code/Module/Token.php index c625d035c..f13eb0c72 100644 --- a/Code/Module/Token.php +++ b/Code/Module/Token.php @@ -18,19 +18,10 @@ class Token extends Controller { logger('args: ' . print_r($_REQUEST, true)); + $authHeader = (new HTTPHeaders())->getAuthHeader(); - // workaround for HTTP-auth in CGI mode - if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { - $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)); - if (strlen($userpass)) { - list($name, $password) = explode(':', $userpass); - $_SERVER['PHP_AUTH_USER'] = $name; - $_SERVER['PHP_AUTH_PW'] = $password; - } - } - - if (x($_SERVER, 'HTTP_AUTHORIZATION')) { - $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)); + if ($authHeader && str_starts_with($authHeader,'Basic')) { + $userpass = base64_decode(substr($authHeader, 6)); if (strlen($userpass)) { list($name, $password) = explode(':', $userpass); $_SERVER['PHP_AUTH_USER'] = $name; diff --git a/Code/Web/HTTPHeaders.php b/Code/Web/HTTPHeaders.php index 84a7abfe8..d0a194b16 100644 --- a/Code/Web/HTTPHeaders.php +++ b/Code/Web/HTTPHeaders.php @@ -8,8 +8,11 @@ class HTTPHeaders private $in_progress = []; private $parsed = []; - public function __construct($headers) + public function __construct($headers = null) { + if (!$headers) { + return; + } $lines = explode("\n", str_replace("\r", '', $headers)); if ($lines) { @@ -55,4 +58,25 @@ class HTTPHeaders } return $ret; } + + public function getAuthHeader() + { + $candidates = [ + 'HTTP_AUTHORIZATION', + 'REDIRECT_HTTP_AUTHORIZATION', + 'REDIRECT_REMOTE_USER', + 'HTTP_SIGNATURE', + 'HTTP_X_NOMAD_SIGNATURE' + ]; + + foreach ($candidates as $candidate) { + if (!empty($_SERVER[$candidate]) && in_array($candidate, ['HTTP_SIGNATURE', 'HTTP_X_NOMAD_SIGNATURE'])) { + return 'Signature ' . $_SERVER[$candidate]; + } + if (!empty($_SERVER[$candidate])) { + return $_SERVER[$candidate]; + } + } + return null; + } } diff --git a/include/api_auth.php b/include/api_auth.php index 50f6c3db9..1cd074e6d 100644 --- a/include/api_auth.php +++ b/include/api_auth.php @@ -1,5 +1,6 @@ getAuthHeader(); // login with oauth @@ -78,12 +71,12 @@ function api_login() } - if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER)) { - /* Basic authentication */ + if ($authHeader) { - if (str_starts_with(trim($_SERVER['HTTP_AUTHORIZATION']), 'Basic')) { + /* Basic authentication */ + if (str_starts_with(trim($authHeader), 'Basic')) { // ignore base64 decoding errors caused by tricksters - $userpass = @base64_decode(substr(trim($_SERVER['HTTP_AUTHORIZATION']), 6)) ; + $userpass = @base64_decode(substr(trim($authHeader), 6)) ; if (strlen($userpass)) { list($name, $password) = explode(':', $userpass); $_SERVER['PHP_AUTH_USER'] = $name; @@ -92,11 +85,10 @@ function api_login() } /* OpenWebAuth */ - - if (str_starts_with(trim($_SERVER['HTTP_AUTHORIZATION']), 'Signature')) { + if (str_starts_with(trim($authHeader), 'Signature')) { $record = null; - $sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']); + $sigblock = HTTPSig::parse_sigheader($authHeader); if ($sigblock) { $keyId = str_replace('acct:', '', $sigblock['keyId']); if ($keyId) {