2019-02-27 21:39:31 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								< ? php  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								$configurationFile  =  '../lucidAuth.config.php' ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								if  ( ! file_exists ( $configurationFile ))  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									throw  new  Exception ( sprintf ( 'Missing config file. Please rename \'%1$s.example\' to \'%1$s\' and edit it to reflect your setup.' ,  explode ( '../' ,  $configurationFile )[ 1 ])); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								$settings  =  include_once ( $configurationFile );  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								try  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#	switch ($settings->Database['Driver']) {
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#		case 'sqlite':
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#			$database = new PDO('sqlite:' . $settings->Database['Path']);
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( is_writable ( $settings -> Sqlite [ 'Path' ]))  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										$pdoDB  =  new  PDO ( 'sqlite:'  .  $settings -> Sqlite [ 'Path' ]); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										throw  new  Exception ( sprintf ( 'Database file \'%1$s\' is not writable' ,  $settings -> Sqlite [ 'Path' ])); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#	}
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								catch  ( Exception  $e )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									throw  new  Exception ( sprintf ( 'Unable to connect to database \'%1$s\'' ,  $settings -> Sqlite [ 'Path' ])); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function  authenticateLDAP  ( string  $username ,  string  $password )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									global  $settings ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! empty ( $username )  &&  ! empty ( $password ))  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Handle login requests
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										$ds  =  ldap_connect ( $settings -> LDAP [ 'Server' ],  $settings -> LDAP [ 'Port' ]); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Strict namingconvention: only allow alphabetic characters
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										$sanitizedUsername  =  preg_replace ( '([^a-zA-Z]*)' ,  '' ,  $_POST [ 'username' ]); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										$qualifiedUsername  =  $settings -> LDAP [ 'Domain' ]  .  '\\'  .  $sanitizedUsername ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( @ ldap_bind ( $ds ,  $qualifiedUsername ,  utf8_encode ( $_POST [ 'password' ])))  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Successful authentication; get additional userdetails from authenticationsource
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											$ldapSearchResults  =  ldap_search ( $ds ,  $settings -> LDAP [ 'BaseDN' ],  " sAMAccountName= $sanitizedUsername " ); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											$commonName  =  ldap_get_entries ( $ds ,  $ldapSearchResults )[ 0 ][ 'cn' ][ 0 ]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Create JWT-payload
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											$jwtPayload  =  [ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												'iat' 	=>  time (), 					// Issued at: time when the token was generated
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												'iss' 	=>  $_SERVER [ 'SERVER_NAME' ], 	// Issuer
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												'sub' 	=>  $qualifiedUsername , 		// Subject (ie. username)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												'name' 	=>  $commonName 				// Common name (as retrieved from AD)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											$secureToken  =  JWT :: encode ( $jwtPayload ,  base64_decode ( $settings -> JWT [ 'PrivateKey_base64' ])); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  [ 'status'  =>  'Success' ,  'token'  =>  $secureToken ]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// LDAP authentication failed!
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  [ 'status'  =>  'Fail' ,  'reason'  =>  '1' ]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Empty username or passwords not allowed!
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  [ 'status'  =>  'Fail' ,  'reason'  =>  '1' ]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function  storeToken  ( string  $secureToken ,  string  $qualifiedUsername ,  string  $httpHost )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									global  $settings ,  $pdoDB ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Save authentication token in database serverside
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										$pdoQuery  =  $pdoDB -> prepare ( ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											INSERT  INTO  SecureToken  ( UserId ,  Value ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											SELECT  User . Id ,  : securetoken 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											FROM  User 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-07 19:50:04 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											WHERE  LOWER ( User . Username )  =  : qualifiedusername 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-27 21:39:31 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										' ); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										$pdoQuery -> execute ([ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											':securetoken' 			=> 	$secureToken , 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-07 19:50:04 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											':qualifiedusername' 	=> 	strtolower ( $qualifiedUsername ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-27 21:39:31 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										]); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									catch  ( Exception  $e )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  [ 'status'  =>  'Fail' ,  'reason'  =>  $e ]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-06 14:21:47 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-02-27 21:39:31 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Save authentication token in cookie clientside
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									$cookieDomain  =  array_values ( array_filter ( $settings -> Session [ 'CookieDomains' ],  function  ( $value )  use  ( $httpHost )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Check if $_SERVER['HTTP_HOST'] matches any of the configured domains (either explicitly or as a subdomain)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										//   This might seem backwards, but relying on $_SERVER directly allows spoofed values with potential security risks
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  ( strlen ( $value )  >  strlen ( $httpHost ))  ?  false  :  ( 0  ===  substr_compare ( $httpHost ,  $value ,  - strlen ( $value ))); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}))[ 0 ]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( $cookieDomain  &&  setcookie ( 'JWT' ,  $secureToken ,  ( time ()  +  $settings -> Session [ 'Duration' ]),  '/' ,  '.'  .  $cookieDomain ))  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  [ 'status'  =>  'Success' ]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  [ 'status'  =>  'Fail' ,  'reason'  =>  'Unable to store cookie(s)' ]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function  validateToken  ( string  $secureToken )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									global  $settings ,  $pdoDB ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Decode provided authentication token
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										$jwtPayload  =  JWT :: decode ( $secureToken ,  base64_decode ( $settings -> JWT [ 'PrivateKey_base64' ]),  $settings -> JWT [ 'Algorithm' ]); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  catch  ( Exception  $e )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Invalid token
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( $settings -> Debug [ 'LogToFile' ])  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											file_put_contents ( '../validateToken.log' ,  ( new  DateTime ()) -> format ( 'Y-m-d\TH:i:s.u' )  .  ' --- Provided token could not be decoded'  .  PHP_EOL ,  FILE_APPEND ); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  [ 'status'  =>  'Fail' ,  'reason'  =>  '1' ]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  (( int ) $jwtPayload -> iat  <  ( time ()  -  ( int ) $settings -> Session [ 'Duration' ]))  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Expired token
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( $settings -> Debug [ 'LogToFile' ])  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											file_put_contents ( '../validateToken.log' ,  ( new  DateTime ()) -> format ( 'Y-m-d\TH:i:s.u' )  .  ' --- Provided token has expired'  .  PHP_EOL ,  FILE_APPEND ); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  [ 'status'  =>  'Fail' ,  'reason'  =>  '3' ]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Retrieve all authentication tokens from database matching username
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									$pdoQuery  =  $pdoDB -> prepare ( ' 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-06 14:21:47 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										SELECT  User . Id ,  SecureToken . Value 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-27 21:39:31 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										FROM  SecureToken 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-06 14:21:47 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										LEFT  JOIN  User 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-27 21:39:31 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ON  ( User . Id = SecureToken . UserId ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-07 19:50:04 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										WHERE  LOWER ( User . Username )  =  : username 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-27 21:39:31 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									' ); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									$pdoQuery -> execute ([ 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-07 19:50:04 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											':username' 	=> 	( string )  strtolower ( $jwtPayload -> sub ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-27 21:39:31 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										]); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									foreach ( $pdoQuery -> fetchAll ( PDO :: FETCH_ASSOC )  as  $row )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											$storedTokens []  =  JWT :: decode ( $row [ 'Value' ],  base64_decode ( $settings -> JWT [ 'PrivateKey_base64' ]),  $settings -> JWT [ 'Algorithm' ]); 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-06 14:21:47 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            $currentUserId  =  $row [ 'Id' ]; 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-27 21:39:31 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  catch  ( Exception  $e )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Compare provided authentication token to all stored tokens in database
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! empty ( $storedTokens )  &&  sizeof ( array_filter ( $storedTokens ,  function  ( $value )  use  ( $jwtPayload )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  $value -> iat  ===  $jwtPayload -> iat ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}))  ===  1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  [ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											'status' 	=>  'Success' , 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-06 14:21:47 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											'name' 		=>  $jwtPayload -> name , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            'uid'        =>  $currentUserId 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-27 21:39:31 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( $settings -> Debug [ 'LogToFile' ])  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											file_put_contents ( '../validateToken.log' ,  ( new  DateTime ()) -> format ( 'Y-m-d\TH:i:s.u' )  .  ' --- Either no matching token or multiple matching tokens found in database'  .  PHP_EOL ,  FILE_APPEND ); 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  [ 'status'  =>  'Fail' ,  'reason'  =>  '2' ]; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-16 11:37:35 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								?>