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