Completed
Push — master ( 3845e2...5afe3b )
by Jean-Christophe
02:10
created

AuthController::fromCookie()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
namespace Ubiquity\controllers\auth;
3
4
use Ubiquity\utils\http\USession;
5
use Ubiquity\utils\http\URequest;
6
use Ubiquity\utils\flash\FlashMessage;
7
use Ubiquity\controllers\ControllerBase;
8
use Ubiquity\controllers\Auth\AuthFiles;
9
use Ubiquity\cache\ClassUtils;
10
use Ubiquity\utils\http\UResponse;
11
use Ubiquity\utils\base\UString;
12
use Ubiquity\controllers\Startup;
13
use Ubiquity\utils\http\UCookie;
14
15
 /**
16
 * Controller Auth
17
 * @property \Ajax\php\ubiquity\JsUtils $jquery
18
 **/
19
abstract class AuthController extends ControllerBase{
20
	/**
21
	 * @var AuthFiles
22
	 */
23
	protected $authFiles;
24
	protected $_controller;
25
	protected $_action;
26
	protected $_actionParams;
27
	protected $_noAccessMsg;
28
	protected $_loginCaption;
29
	protected $_attemptsSessionKey="_attempts";
30
	
31
	public function __construct(){
32
		parent::__construct();
33
		$this->_controller=Startup::getController();
34
		$this->_action=Startup::getAction();
35
		$this->_actionParams=Startup::getActionParams();
36
		$this->_noAccessMsg=new FlashMessage("You are not authorized to access the page <b>{url}</b> !","Forbidden access","error","warning circle");
37
		$this->_loginCaption="Log in";
38
	}
39
	
40
	public function index(){
41
		if(($nbAttempsMax=$this->attemptsNumber())!=null){
42
			$nb=USession::getTmp($this->_attemptsSessionKey,$nbAttempsMax);
43
			if($nb<=0){
44
				$this->badLogin();
45
				return;
46
			}
47
		}
48
		$this->authLoadView($this->_getFiles()->getViewIndex(),["action"=>$this->_getBaseRoute()."/connect",
49
				"loginInputName"=>$this->_getLoginInputName(),"loginLabel"=>$this->loginLabel(),
50
				"passwordInputName"=>$this->_getPasswordInputName(),"passwordLabel"=>$this->passwordLabel(),
51
				"rememberCaption"=>$this->rememberCaption()
52
		]);
53
	}
54
	
55
	/**
56
	 * To override
57
	 * Return the base route for this Auth controller
58
	 * @return string
59
	 */
60
	public function _getBaseRoute(){
61
		return ClassUtils::getClassSimpleName(get_class($this));
62
	}
63
	/**
64
	 * {@inheritDoc}
65
	 * @see \controllers\ControllerBase::isValid()
66
	 */
67
	public final function isValid($action) {
0 ignored issues
show
Coding Style introduced by
As per PSR2, final should precede the visibility keyword.
Loading history...
68
		return true;
69
	}
70
	
71
	/**
72
	 * Action called when the user does not have access rights to a requested resource
73
	 * @param array|string $urlParts
74
	 */
75
	public function noAccess($urlParts){
76
		if(!is_array($urlParts)){
77
			$urlParts=explode(".", $urlParts);
78
		}
79
		USession::set("urlParts", $urlParts);
80
		$fMessage=$this->_noAccessMsg;
81
		$this->noAccessMessage($fMessage);
82
		$message=$this->fMessage($fMessage->parseContent(["url"=>implode("/",$urlParts)]));		
83
		$this->authLoadView($this->_getFiles()->getViewNoAccess(),["_message"=>$message,"authURL"=>$this->_getBaseRoute(),"bodySelector"=>$this->_getBodySelector(),"_loginCaption"=>$this->_loginCaption]);
84
	}
85
	
86
	/**
87
	 * Override for modifying the noAccess message
88
	 * @param FlashMessage $fMessage
89
	 */
90
	protected function noAccessMessage(FlashMessage $fMessage){
91
		
92
	}
93
	
94
	/**
95
	 * Override for modifying attempts message
96
	 * You can use {_timer} and {_attemptsCount} variables in message content
97
	 * @param FlashMessage $fMessage
98
	 * @param int $attempsCount
99
	 */
100
	protected function attemptsNumberMessage(FlashMessage $fMessage,$attempsCount){
101
		
102
	}
103
	
104
	/**
105
	 * Override to implement the complete connection procedure 
106
	 */
107
	public function connect(){
108
		if(URequest::isPost()){
109
			if($connected=$this->_connect()){
110
				if(isset($_POST["ck-remember"])){
111
					$this->rememberMe($connected);
112
				}
113
				if(USession::exists($this->_attemptsSessionKey)){
114
					USession::delete($this->_attemptsSessionKey);
115
				}
116
				$this->onConnect($connected);
117
			}else{
118
				$this->onBadCreditentials();
119
			}
120
		}
121
	}
122
	
123
	/**
124
	 * Processes the data posted by the login form
125
	 * Have to return the connected user instance
126
	 */
127
	abstract protected function _connect();
128
	
129
	/**
130
	 * @param object $connected
131
	 */
132
	abstract protected function onConnect($connected);
133
	
134
	/**
135
	 * To override for defining a new action when creditentials are invalid
136
	 */
137
	protected function onBadCreditentials(){
138
		$this->badLogin();
139
	}
140
	
141
	/**
142
	 * Default Action for invalid creditentials
143
	 */
144
	public function badLogin(){
145
		$fMessage=new FlashMessage("Invalid creditentials!","Connection problem","warning","warning circle");
146
		$this->badLoginMessage($fMessage);
147
		$attemptsMessage="";
148
		if(($nbAttempsMax=$this->attemptsNumber())!=null){
149
			$nb=USession::getTmp($this->_attemptsSessionKey,$nbAttempsMax);
150
			$nb--;
151
			if($nb<0) $nb=0;
152
			if($nb==0){
153
				$fAttemptsNumberMessage=$this->noAttempts();
154
			}else{
155
				$fAttemptsNumberMessage=new FlashMessage("<i class='ui warning icon'></i> You still have {_attemptsCount} attempts to log in.",null,"bottom attached warning","");
156
			}
157
			USession::setTmp($this->_attemptsSessionKey, $nb,$this->attemptsTimeout());
158
			$this->attemptsNumberMessage($fAttemptsNumberMessage,$nb);
159
			$fAttemptsNumberMessage->parseContent(["_attemptsCount"=>$nb,"_timer"=>"<span id='timer'></span>"]);
160
			$attemptsMessage=$this->fMessage($fAttemptsNumberMessage,"timeout-message");
161
			$fMessage->addType("attached");
162
		}
163
		$message=$this->fMessage($fMessage,"bad-login").$attemptsMessage;
164
		$this->authLoadView($this->_getFiles()->getViewNoAccess(),["_message"=>$message,"authURL"=>$this->_getBaseRoute(),"bodySelector"=>$this->_getBodySelector(),"_loginCaption"=>$this->_loginCaption]);
165
	}
166
	
167
	protected function noAttempts(){
168
		$timeout=$this->attemptsTimeout();
169
		$plus="";
170
		if(is_numeric($timeout)){
171
			$this->jquery->exec("$('._login').addClass('disabled');",true);
172
			$plus=" You can try again {_timer}";
173
			$this->jquery->exec("var startTimer=function(duration, display) {var timer = duration, minutes, seconds;
174
    										var interval=setInterval(function () {
175
        										minutes = parseInt(timer / 60, 10);seconds = parseInt(timer % 60, 10);
176
										        minutes = minutes < 10 ? '0' + minutes : minutes;
177
        										seconds = seconds < 10 ? '0' + seconds : seconds;
178
										        display.html(minutes + ':' + seconds);
179
										        if (--timer < 0) {clearInterval(interval);$('#timeout-message').hide();$('#bad-login').removeClass('attached');$('._login').removeClass('disabled');}
180
    										}, 1000);
181
										}",true);
182
			$timeToLeft=USession::getTimeout($this->_attemptsSessionKey);
183
			$this->jquery->exec("startTimer({$timeToLeft},$('#timer'));",true);
184
			$this->jquery->compile($this->view);
185
		}
186
		return new FlashMessage("<i class='ui warning icon'></i> You have no more attempt of connection !".$plus,null,"bottom attached error","");
187
	}
188
	
189
	/**
190
	 * To override for modifying the bad login message
191
	 * @param FlashMessage $fMessage
192
	 */
193
	protected function badLoginMessage(FlashMessage $fMessage){
194
		
195
	}
196
	
197
	private function authLoadView($viewName,$vars=[]){
198
		$files=$this->_getFiles();
199
		$mainTemplate=$files->getBaseTemplate();
200
		if(isset($mainTemplate)){
201
			$vars["_viewname"]=$viewName;
202
			$vars["_base"]=$mainTemplate;
203
			$this->loadView($files->getViewBaseTemplate(),$vars);
204
		}else{
205
			$this->loadView($viewName,$vars);
206
		}
207
	}
208
	
209
	/**
210
	 * Logout action
211
	 * Terminate the session and display a logout message
212
	 */
213
	public function terminate(){
214
		USession::terminate();
215
		$fMessage=new FlashMessage("You have been properly disconnected!","Logout","success","checkmark");
216
		$this->terminateMessage($fMessage);
217
		$message=$this->fMessage($fMessage);
218
		$this->authLoadView($this->_getFiles()->getViewNoAccess(),["_message"=>$message,"authURL"=>$this->_getBaseRoute(),"bodySelector"=>$this->_getBodySelector(),"_loginCaption"=>$this->_loginCaption]);
219
	}
220
	
221
	public function _disConnected(){
222
		$fMessage=new FlashMessage("You have been disconnected from the application!","Logout","","sign out");
223
		$this->disconnectedMessage($fMessage);
224
		$message=$this->fMessage($fMessage);
225
		$this->jquery->getOnClick("._signin", $this->_getBaseRoute(),$this->_getBodySelector(),["stopPropagation"=>false,"preventDefault"=>false]);
226
		$this->jquery->execOn("click", "._close", "window.open(window.location,'_self').close();");
227
		$this->jquery->renderView($this->_getFiles()->getViewDisconnected(),["_title"=>"Session ended","_message"=>$message]);
228
	}
229
	
230
	/**
231
	 * To override for modifying the logout message
232
	 * @param FlashMessage $fMessage
233
	 */
234
	protected function terminateMessage(FlashMessage $fMessage){
235
		
236
	}
237
	
238
	/**
239
	 * To override for modifying the disconnect message
240
	 * @param FlashMessage $fMessage
241
	 */
242
	protected function disconnectedMessage(FlashMessage $fMessage){
243
		
244
	}
245
	
246
	/**
247
	 * Action displaying the logged user information 
248
	 * if _displayInfoAsString returns true, use _infoUser var in views to display user info
249
	 * @return string|null
250
	 */
251
	public function info(){
252
		return $this->loadView($this->_getFiles()->getViewInfo(),["connected"=>USession::get($this->_getUserSessionKey()),"authURL"=>$this->_getBaseRoute(),"bodySelector"=>$this->_getBodySelector()],$this->_displayInfoAsString());
253
	}
254
	
255
	protected function fMessage(FlashMessage $fMessage,$id=null){
256
		return $this->message($fMessage->getType(), $fMessage->getTitle(), $fMessage->getContent(),$fMessage->getIcon(),$id);
257
	}
258
	
259
	public function message($type,$header,$body,$icon="info",$id=null){
260
		return $this->loadView($this->_getFiles()->getViewMessage(),get_defined_vars(),true);
261
	}
262
	
263
	protected function getOriginalURL(){
264
		return USession::get("urlParts");
265
	}
266
	
267
	/**
268
	 * To override for defining user session key, default : "activeUser"
269
	 * @return string
270
	 */
271
	public function _getUserSessionKey(){
272
		return "activeUser";
273
	}
274
	
275
	/**
276
	 * To override for getting active user, default : USession::get("activeUser")
277
	 * @return string
278
	 */
279
	public function _getActiveUser(){
280
		return USession::get($this->_getUserSessionKey());
281
	}
282
	
283
	/**
284
	 * To override
285
	 * Returns the maximum number of allowed login attempts
286
	 */
287
	protected function attemptsNumber(){
288
		return;
289
	}
290
	
291
	/**
292
	 * To override
293
	 * Returns the time before trying to connect again
294
	 * Effective only if attemptsNumber return a number
295
	 * @return number
296
	 */
297
	protected function attemptsTimeout(){
298
		return 3*60;
299
	}
300
	
301
	public function _checkConnection(){
302
		UResponse::asJSON();
303
		echo "{\"valid\":".UString::getBooleanStr($this->_isValidUser())."}";
304
	}
305
	
306
	/**
307
	 * return boolean true if activeUser is valid
308
	 */
309
	abstract public function _isValidUser();
310
	
311
	/**
312
	 * To override for changing view files
313
	 * @return AuthFiles
314
	 */
315
	protected function getFiles ():AuthFiles{
316
		return new AuthFiles();
317
	}
318
	
319
	/**
320
	 * Override to define if info is displayed as string
321
	 * if set to true, use _infoUser var in views to display user info
322
	 */
323
	public function _displayInfoAsString(){
324
		return false;
325
	}
326
	
327
	public function _checkConnectionTimeout(){
328
		return;
329
	}
330
	
331
	private function _getFiles():AuthFiles{
332
		if(!isset($this->authFiles)){
333
			$this->authFiles=$this->getFiles();
334
		}
335
		return $this->authFiles;
336
	}
337
	
338
	public function _getLoginInputName(){
339
		return "email";
340
	}
341
342
	protected function loginLabel(){
343
		return ucfirst($this->_getLoginInputName());
344
	}
345
	
346
	public function _getPasswordInputName(){
347
		return "password";
348
	}
349
	
350
	protected function passwordLabel(){
351
		return ucfirst($this->_getPasswordInputName());
352
	}
353
	
354
	public function _getBodySelector(){
355
		return "body";
356
	}
357
	
358
	/**
359
	 * Sets the default noAccess message
360
	 * Default : "You are not authorized to access the page <b>{url}</b> !"
361
	 * @param string $content
362
	 * @param string $title
363
	 * @param string $type
364
	 * @param string $icon
365
	 */
366
	public function _setNoAccessMsg($content,$title=NULL,$type=NULL,$icon=null) {
367
		$this->_noAccessMsg->setValues($content,$title,$type,$icon);
368
	}
369
	/**
370
	 * @param string $_loginCaption
371
	 */
372
	public function _setLoginCaption($_loginCaption) {
373
		$this->_loginCaption = $_loginCaption;
374
	}
375
	
376
	protected function rememberCaption(){
377
		return "Remember me";
378
	}
379
	
380
	protected function getViewVars($viewname){
381
		return ["authURL"=>$this->_getBaseRoute(),"bodySelector"=>$this->_getBodySelector(),"_loginCaption"=>$this->_loginCaption];
382
	}
383
	
384
	/**
385
	 * Saves the connected user identifier in a cookie
386
	 * @param object $connected
387
	 */
388
	protected function rememberMe($connected){
389
		$id= $this->toCookie($connected);
390
		if(isset($id)){
391
			UCookie::set($this->_getUserSessionKey(),$id);
392
		}
393
	}
394
	
395
	/**
396
	 * Returns the cookie for auto connection
397
	 * @return NULL|string
398
	 */
399
	protected function getCookieUser(){
400
		return UCookie::get($this->_getUserSessionKey());
401
	}
402
	
403
	/**
404
	 * Returns the value from connected user to save it in the cookie for auto connection
405
	 * @param object $connected
406
	 */
407
	protected function toCookie($connected){
408
		return;
409
	}
410
	
411
	/**
412
	 * Loads the user from database using the cookie value
413
	 * @param string $cookie
414
	 */
415
	protected function fromCookie($cookie){
416
		return;
417
	}
418
	
419
	/**
420
	 * Auto connect the user
421
	 */
422
	public function _autoConnect() {
423
		$cookie=$this->getCookieUser();
424
		if(isset($cookie)){
425
			$user=$this->fromCookie($cookie);
426
			if(isset($user)){
427
				USession::set($this->_getUserSessionKey(), $user);
428
			}
429
		}
430
	}
431
	/**
432
	 * Deletes the cookie for auto connection and returns to index
433
	 */
434
	public function forgetConnection(){
435
		UCookie::delete($this->_getUserSessionKey());
436
		$this->index();
437
	}
438
}
439