Issues (1513)

lib/request/requestprocessor.php (6 issues)

Labels
Severity
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
It seems like Request::GetAuthUser() can also be of type boolean; however, parameter $string of strtolower() 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 ignore-type  annotation

38
		if (defined("CERTIFICATE_OWNER_PARAMETER") && isset($_SERVER[CERTIFICATE_OWNER_PARAMETER]) && strtolower($_SERVER[CERTIFICATE_OWNER_PARAMETER]) != strtolower(/** @scrutinizer ignore-type */ Request::GetAuthUser())) {
Loading history...
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 ignore-type  annotation

42
		if (Request::GetImpersonatedUser() && strcasecmp(Request::GetAuthUser(), /** @scrutinizer ignore-type */ Request::GetImpersonatedUser()) !== 0) {
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 ignore-type  annotation

42
		if (Request::GetImpersonatedUser() && strcasecmp(/** @scrutinizer ignore-type */ Request::GetAuthUser(), Request::GetImpersonatedUser()) !== 0) {
Loading history...
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 ignore-type  annotation

77
			self::$decoder = new WBXMLDecoder(/** @scrutinizer ignore-type */ Request::GetInputStream());
Loading history...
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 ignore-type  annotation

90
		$handler = GSync::GetRequestHandlerForCommand(/** @scrutinizer ignore-type */ Request::GetCommandCode());
Loading history...
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 ignore-type  annotation

94
			if (!$handler->Handle(/** @scrutinizer ignore-type */ Request::GetCommandCode())) {
Loading history...
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