Completed
Branch newinternal (6027bd)
by Simon
06:03
created

InternalPageBase::getSecurityManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
namespace Waca\Tasks;
3
4
use Exception;
5
use PDO;
6
use Waca\DataObjects\User;
7
use Waca\Exceptions\AccessDeniedException;
8
use Waca\Exceptions\NotIdentifiedException;
9
use Waca\IdentificationVerifier;
10
use Waca\Helpers\Interfaces\ITypeAheadHelper;
11
use Waca\Security\SecurityConfiguration;
12
use Waca\Security\SecurityManager;
13
use Waca\WebRequest;
14
15
abstract class InternalPageBase extends PageBase
16
{
17
	/** @var IdentificationVerifier */
18
	private $identificationVerifier;
19
	/** @var ITypeAheadHelper */
20
	private $typeAheadHelper;
21
	/** @var SecurityManager */
22
	private $securityManager;
23
24
	/**
25
	 * @return ITypeAheadHelper
26
	 */
27
	public function getTypeAheadHelper()
28
	{
29
		return $this->typeAheadHelper;
30
	}
31
32
	/**
33
	 * Sets up the internal IdentificationVerifier instance.  Intended to be called from WebStart::setupHelpers().
34
	 *
35
	 * @param IdentificationVerifier $identificationVerifier
36
	 * @return void
37
	 */
38
	public function setIdentificationVerifier(IdentificationVerifier $identificationVerifier)
39
	{
40
		$this->identificationVerifier = $identificationVerifier;
41
	}
42
43
	/**
44
	 * @param ITypeAheadHelper $typeAheadHelper
45
	 */
46
	public function setTypeAheadHelper(ITypeAheadHelper $typeAheadHelper)
47
	{
48
		$this->typeAheadHelper = $typeAheadHelper;
49
	}
50
51
	/**
52
	 * Runs the page code
53
	 *
54
	 * @throws Exception
55
	 * @category Security-Critical
56
	 */
57
	final public function execute()
58
	{
59
		if ($this->getRouteName() === null) {
60
			throw new Exception("Request is unrouted.");
61
		}
62
63
		if ($this->getSiteConfiguration() === null) {
64
			throw new Exception("Page has no configuration!");
65
		}
66
67
		$this->setupPage();
68
69
		$this->touchUserLastActive();
70
71
		// Get the current security configuration
72
		$securityConfiguration = $this->getSecurityConfiguration();
73
		if ($securityConfiguration === null) {
74
			// page hasn't been written properly.
75
			throw new AccessDeniedException();
76
		}
77
78
		$currentUser = User::getCurrent($this->getDatabase());
79
80
		// Security barrier.
81
		//
82
		// This code essentially doesn't care if the user is logged in or not, as the
83
		if ($this->getSecurityManager()->allows($securityConfiguration, $currentUser)) {
84
			// We're allowed to run the page, so let's run it.
85
			$this->runPage();
86
		}
87
		else {
88
			$this->handleAccessDenied();
89
90
			// Send the headers
91
			foreach ($this->headerQueue as $item) {
92
				header($item);
93
			}
94
		}
95
	}
96
97
	/**
98
	 * Performs final tasks needed before rendering the page.
99
	 */
100
	final public function finalisePage()
101
	{
102
		parent::finalisePage();
103
104
		$this->assign('typeAheadBlock', $this->getTypeAheadHelper()->getTypeAheadScriptBlock());
105
106
		$database = $this->getDatabase();
107
108
		if (!User::getCurrent($database)->isCommunityUser()) {
109
			$sql = 'SELECT * FROM user WHERE lastactive > DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL 5 MINUTE);';
110
			$statement = $database->query($sql);
111
			$activeUsers = $statement->fetchAll(PDO::FETCH_CLASS, User::class);
112
			$this->assign('onlineusers', $activeUsers);
113
		}
114
	}
115
116
	/**
117
	 * Sets up the security for this page. If certain actions have different permissions, this should be reflected in
118
	 * the return value from this function.
119
	 *
120
	 * If this page even supports actions, you will need to check the route
121
	 *
122
	 * @return SecurityConfiguration
123
	 * @category Security-Critical
124
	 */
125
	abstract protected function getSecurityConfiguration();
126
127
	protected function handleAccessDenied()
128
	{
129
		$currentUser = User::getCurrent($this->getDatabase());
130
131
		// Not allowed to access this resource.
132
		// Firstly, let's check if we're even logged in.
133
		if ($currentUser->isCommunityUser()) {
134
			// Not logged in, redirect to login page
135
136
			// TODO: return to current page? Possibly as a session var?
137
			$this->redirect("login");
138
139
			return;
140
		}
141
		else {
142
			// Decide whether this was a rights failure, or an identification failure.
143
144
			if ($this->getSiteConfiguration()->getForceIdentification()
145
				&& $currentUser->isIdentified($this->identificationVerifier) !== true
146
			) {
147
				// Not identified
148
				throw new NotIdentifiedException();
149
			}
150
			else {
151
				// Nope, plain old access denied
152
				throw new AccessDeniedException();
153
			}
154
		}
155
	}
156
157
	/**
158
	 * Tests the security barrier for a specified action.
159
	 *
160
	 * Intended to be used from within templates
161
	 *
162
	 * @param string $action
163
	 *
164
	 * @return boolean
165
	 * @category Security-Critical
166
	 */
167
	final public function barrierTest($action)
168
	{
169
		$tmpRouteName = $this->getRouteName();
170
171
		try {
172
			$this->setRoute($action);
173
174
			$securityConfiguration = $this->getSecurityConfiguration();
175
			$currentUser = User::getCurrent($this->getDatabase());
176
177
			$allowed = $this->getSecurityManager()->allows($securityConfiguration, $currentUser);
178
179
			return $allowed;
180
		}
181
		finally {
182
			$this->setRoute($tmpRouteName);
183
		}
184
	}
185
186
	/**
187
	 * Updates the lastactive timestamp
188
	 */
189
	private function touchUserLastActive()
190
	{
191
		if (WebRequest::getSessionUserId() !== null) {
192
			$query = 'UPDATE user SET lastactive = CURRENT_TIMESTAMP() WHERE id = :id;';
193
			$this->getDatabase()->prepare($query)->execute(array(":id" => WebRequest::getSessionUserId()));
194
		}
195
	}
196
197
	/**
198
	 * @return SecurityManager
199
	 */
200
	public function getSecurityManager()
201
	{
202
		return $this->securityManager;
203
	}
204
205
	/**
206
	 * @param SecurityManager $securityManager
207
	 */
208
	public function setSecurityManager($securityManager)
209
	{
210
		$this->securityManager = $securityManager;
211
	}
212
}