grommunio /
grommunio-sync
| 1 | <?php |
||||||
| 2 | |||||||
| 3 | /* |
||||||
| 4 | * SPDX-License-Identifier: AGPL-3.0-only |
||||||
| 5 | * SPDX-FileCopyrightText: Copyright 2007-2016 Zarafa Deutschland GmbH |
||||||
| 6 | * SPDX-FileCopyrightText: Copyright 2020-2022 grommunio GmbH |
||||||
| 7 | * |
||||||
| 8 | * This file provides/loads the handlers for the different commands. The |
||||||
| 9 | * request handlers are optimised so that as little as possible data is |
||||||
| 10 | * kept-in-memory, and all output data is directly streamed to the client, |
||||||
| 11 | * while also streaming input data from the client. |
||||||
| 12 | */ |
||||||
| 13 | |||||||
| 14 | abstract class RequestProcessor { |
||||||
| 15 | protected static $backend; |
||||||
| 16 | protected static $deviceManager; |
||||||
| 17 | protected static $topCollector; |
||||||
| 18 | protected static $decoder; |
||||||
| 19 | protected static $encoder; |
||||||
| 20 | protected static $userIsAuthenticated; |
||||||
| 21 | protected static $specialHeaders; |
||||||
| 22 | protected static $waitTime = 0; |
||||||
| 23 | |||||||
| 24 | /** |
||||||
| 25 | * Authenticates the remote user |
||||||
| 26 | * The sent HTTP authentication information is used to on Backend->Logon(). |
||||||
| 27 | * As second step the GET-User verified by Backend->Setup() for permission check |
||||||
| 28 | * Request::GetGETUser() is usually the same as the Request::GetAuthUser(). |
||||||
| 29 | * If the GETUser is different from the AuthUser, the AuthUser MUST HAVE admin |
||||||
| 30 | * permissions on GETUsers data store. Only then the Setup() will be successful. |
||||||
| 31 | * This allows the user 'john' to do operations as user 'joe' if he has sufficient privileges. |
||||||
| 32 | * |
||||||
| 33 | * @throws AuthenticationRequiredException |
||||||
| 34 | */ |
||||||
| 35 | public static function Authenticate() { |
||||||
| 36 | self::$userIsAuthenticated = false; |
||||||
| 37 | |||||||
| 38 | // when a certificate is sent, allow authentication only as the certificate owner |
||||||
| 39 | if (defined("CERTIFICATE_OWNER_PARAMETER") && isset($_SERVER[CERTIFICATE_OWNER_PARAMETER]) && strtolower((string) $_SERVER[CERTIFICATE_OWNER_PARAMETER]) != strtolower(Request::GetAuthUser())) { |
||||||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||||
| 40 | throw new AuthenticationRequiredException(sprintf("Access denied. Access is allowed only for the certificate owner '%s'", $_SERVER[CERTIFICATE_OWNER_PARAMETER])); |
||||||
| 41 | } |
||||||
| 42 | |||||||
| 43 | if (Request::GetImpersonatedUser() && strcasecmp(Request::GetAuthUser(), Request::GetImpersonatedUser()) !== 0) { |
||||||
|
0 ignored issues
–
show
It seems like
Request::GetImpersonatedUser() can also be of type boolean; however, parameter $string2 of strcasecmp() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
It seems like
Request::GetAuthUser() can also be of type boolean; however, parameter $string1 of strcasecmp() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 44 | SLog::Write(LOGLEVEL_DEBUG, sprintf("RequestProcessor->Authenticate(): Impersonation active - authenticating: '%s' - impersonating '%s'", Request::GetAuthUser(), Request::GetImpersonatedUser())); |
||||||
| 45 | } |
||||||
| 46 | |||||||
| 47 | $backend = GSync::GetBackend(); |
||||||
| 48 | if ($backend->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword()) == false) { |
||||||
| 49 | throw new AuthenticationRequiredException("Access denied. Username or password incorrect"); |
||||||
| 50 | } |
||||||
| 51 | |||||||
| 52 | // mark this request as "authenticated" |
||||||
| 53 | self::$userIsAuthenticated = true; |
||||||
| 54 | } |
||||||
| 55 | |||||||
| 56 | /** |
||||||
| 57 | * Indicates if the user was "authenticated". |
||||||
| 58 | * |
||||||
| 59 | * @return bool |
||||||
| 60 | */ |
||||||
| 61 | public static function isUserAuthenticated() { |
||||||
| 62 | if (!isset(self::$userIsAuthenticated)) { |
||||||
| 63 | return false; |
||||||
| 64 | } |
||||||
| 65 | |||||||
| 66 | return self::$userIsAuthenticated; |
||||||
| 67 | } |
||||||
| 68 | |||||||
| 69 | /** |
||||||
| 70 | * Initialize the RequestProcessor. |
||||||
| 71 | */ |
||||||
| 72 | public static function Initialize() { |
||||||
| 73 | self::$backend = GSync::GetBackend(); |
||||||
| 74 | self::$deviceManager = GSync::GetDeviceManager(false); |
||||||
| 75 | self::$topCollector = GSync::GetTopCollector(); |
||||||
| 76 | |||||||
| 77 | if (!GSync::CommandNeedsPlainInput(Request::GetCommandCode())) { |
||||||
| 78 | self::$decoder = new WBXMLDecoder(Request::GetInputStream()); |
||||||
|
0 ignored issues
–
show
It seems like
Request::GetInputStream() can also be of type boolean; however, parameter $input of WBXMLDecoder::__construct() does only seem to accept stream, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 79 | } |
||||||
| 80 | |||||||
| 81 | self::$encoder = new WBXMLEncoder(Request::GetOutputStream(), Request::GetGETAcceptMultipart()); |
||||||
| 82 | self::$waitTime = 0; |
||||||
| 83 | } |
||||||
| 84 | |||||||
| 85 | /** |
||||||
| 86 | * Loads the command handler and processes a command sent from the mobile. |
||||||
| 87 | * |
||||||
| 88 | * @return bool |
||||||
| 89 | */ |
||||||
| 90 | public static function HandleRequest() { |
||||||
| 91 | $handler = GSync::GetRequestHandlerForCommand(Request::GetCommandCode()); |
||||||
|
0 ignored issues
–
show
Request::GetCommandCode() of type boolean|string is incompatible with the type integer expected by parameter $commandCode of GSync::GetRequestHandlerForCommand().
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 92 | |||||||
| 93 | // if there is an error decoding wbxml, consume remaining data and include it in the WBXMLException |
||||||
| 94 | try { |
||||||
| 95 | if (!$handler->Handle(Request::GetCommandCode())) { |
||||||
|
0 ignored issues
–
show
Request::GetCommandCode() of type boolean|string is incompatible with the type integer expected by parameter $commandCode of RequestProcessor::Handle().
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 96 | throw new WBXMLException(sprintf("Unknown error in %s->Handle()", $handler::class)); |
||||||
| 97 | } |
||||||
| 98 | } |
||||||
| 99 | catch (Exception $ex) { |
||||||
| 100 | // Log 10 KB of the WBXML data |
||||||
| 101 | SLog::Write(LOGLEVEL_FATAL, "WBXML 10K debug data: " . Request::GetInputAsBase64(10240), false); |
||||||
| 102 | |||||||
| 103 | throw $ex; |
||||||
| 104 | } |
||||||
| 105 | |||||||
| 106 | // also log WBXML in happy case |
||||||
| 107 | if (SLog::IsWbxmlDebugEnabled()) { |
||||||
| 108 | // Log 4 KB in the happy case |
||||||
| 109 | SLog::Write(LOGLEVEL_WBXML, "WBXML-IN : " . Request::GetInputAsBase64(4096), false); |
||||||
| 110 | } |
||||||
| 111 | |||||||
| 112 | return true; |
||||||
| 113 | } |
||||||
| 114 | |||||||
| 115 | /** |
||||||
| 116 | * Returns any additional headers which should be sent to the mobile. |
||||||
| 117 | * |
||||||
| 118 | * @return array |
||||||
| 119 | */ |
||||||
| 120 | public static function GetSpecialHeaders() { |
||||||
| 121 | if (!isset(self::$specialHeaders) || !is_array(self::$specialHeaders)) { |
||||||
| 122 | return []; |
||||||
| 123 | } |
||||||
| 124 | |||||||
| 125 | return self::$specialHeaders; |
||||||
| 126 | } |
||||||
| 127 | |||||||
| 128 | /** |
||||||
| 129 | * Returns the amount of seconds RequestProcessor waited e.g. during Ping. |
||||||
| 130 | * |
||||||
| 131 | * @return int |
||||||
| 132 | */ |
||||||
| 133 | public static function GetWaitTime() { |
||||||
| 134 | return self::$waitTime; |
||||||
| 135 | } |
||||||
| 136 | |||||||
| 137 | /** |
||||||
| 138 | * Handles a command. |
||||||
| 139 | * |
||||||
| 140 | * @param int $commandCode |
||||||
| 141 | * |
||||||
| 142 | * @return bool |
||||||
| 143 | */ |
||||||
| 144 | abstract public function Handle($commandCode); |
||||||
| 145 | } |
||||||
| 146 |