From c2298a81f901d7110a8b1f9927d62e653a6b59c8 Mon Sep 17 00:00:00 2001 From: Sibidharan Nandhakumar <hello@sibidharan.me> Date: Sun, 16 May 2021 16:52:50 +0530 Subject: [PATCH] Auth done --- api/apis/auth/current.php | 26 ++++++++++++ api/apis/auth/login.php | 7 ++++ api/apis/auth/refresh.php | 11 +++-- api/index.php | 80 +++++++++++++++++++++++++++++------- api/lib/Auth.class.php | 24 +++++++++-- api/lib/OAuth.class.php | 85 +++++++++++++++++++++++++++++++++------ call.php | 7 +++- 7 files changed, 203 insertions(+), 37 deletions(-) create mode 100644 api/apis/auth/current.php diff --git a/api/apis/auth/current.php b/api/apis/auth/current.php new file mode 100644 index 0000000..a53c0fa --- /dev/null +++ b/api/apis/auth/current.php @@ -0,0 +1,26 @@ +<?php + +${basename(__FILE__, '.php')} = function(){ + if($this->get_request_method() == "POST" and $this->isAuthenticated()){ + try{ + $data = [ + "username" => $this->getUsername(), + ]; + $data = $this->json($data); + $this->response($data, 200); + } catch(Exception $e){ + $data = [ + "error" => $e->getMessage() + ]; + $data = $this->json($data); + $this->response($data, 403); + } + + } else { + $data = [ + "error" => "Bad request" + ]; + $data = $this->json($data); + $this->response($data, 400); + } +}; \ No newline at end of file diff --git a/api/apis/auth/login.php b/api/apis/auth/login.php index 7a4e345..4d4ea49 100644 --- a/api/apis/auth/login.php +++ b/api/apis/auth/login.php @@ -1,6 +1,13 @@ <?php ${basename(__FILE__, '.php')} = function(){ + if($this->isAuthenticated()){ + $data = [ + "error" => "Already logged in" + ]; + $data = $this->json($data); + $this->response($data, 400); + } if($this->get_request_method() == "POST" and isset($this->_request['username']) and isset($this->_request['password'])){ $username = $this->_request['username']; $password = $this->_request['password']; diff --git a/api/apis/auth/refresh.php b/api/apis/auth/refresh.php index 7a4e345..78ed561 100644 --- a/api/apis/auth/refresh.php +++ b/api/apis/auth/refresh.php @@ -1,14 +1,13 @@ <?php ${basename(__FILE__, '.php')} = function(){ - if($this->get_request_method() == "POST" and isset($this->_request['username']) and isset($this->_request['password'])){ - $username = $this->_request['username']; - $password = $this->_request['password']; + if($this->get_request_method() == "POST" and isset($this->_request['refresh_token'])){ + $refresh_token = $this->_request['refresh_token']; try { - $auth = new Auth($username, $password); + $auth = new OAuth($refresh_token); $data = [ - "message" => "Login success", - "tokens" => $auth->getAuthTokens() + "message" => "Refresh Success", + "tokens" => $auth->refreshAccess() ]; $data = $this->json($data); $this->response($data, 200); diff --git a/api/index.php b/api/index.php index 124689a..2990de0 100644 --- a/api/index.php +++ b/api/index.php @@ -12,6 +12,7 @@ class API extends REST { private $db = NULL; private $current_call; + private $auth = null; public function __construct(){ parent::__construct(); // Init parent contructor @@ -31,27 +32,70 @@ class API extends REST { else { if(isset($_GET['namespace'])){ $dir = $_SERVER['DOCUMENT_ROOT'].'/api/apis/'.$_GET['namespace']; - $methods = scandir($dir); - //var_dump($methods); - foreach($methods as $m){ - if($m == "." or $m == ".."){ - continue; - } - $basem = basename($m, '.php'); - //echo "Trying to call $basem() for $func()\n"; - if($basem == $func){ - include $dir."/".$m; - $this->current_call = Closure::bind(${$basem}, $this, get_class()); - $this->$basem(); - } + $file = $dir.'/'.$func.'.php'; + if(file_exists($file)){ + include $file; + $this->current_call = Closure::bind(${$func}, $this, get_class()); + $this->$func(); + } else { + $this->response($this->json(['error'=>'method_not_found']),404); } + + /** + * Use the following snippet if you want to include multiple files + */ + // $methods = scandir($dir); + // //var_dump($methods); + // foreach($methods as $m){ + // if($m == "." or $m == ".."){ + // continue; + // } + // $basem = basename($m, '.php'); + // //echo "Trying to call $basem() for $func()\n"; + // if($basem == $func){ + // include $dir."/".$m; + // $this->current_call = Closure::bind(${$basem}, $this, get_class()); + // $this->$basem(); + // } + // } } else { //we can even process functions without namespace here. - $this->response($this->json(['error'=>'methood_not_found']),404); + $this->response($this->json(['error'=>'method_not_found']),404); } } } + public function auth(){ + $headers = getallheaders(); + if(isset($headers['Authorization'])){ + $token = explode(' ', $headers['Authorization']); + $this->auth = new Auth($token[1]); + } + } + + public function isAuthenticated(){ + if($this->auth == null){ + return false; + } + if($this->auth->getOAuth()->authenticate() and isset($_SESSION['username'])){ + return true; + } else { + return false; + } + } + + public function getUsername(){ + return $_SESSION['username']; + } + + public function die($e){ + $data = [ + "error" => $e->getMessage() + ]; + $data = $this->json($data); + $this->response($data,400); + } + public function __call($method, $args){ if(is_callable($this->current_call)){ return call_user_func_array($this->current_call, $args); @@ -131,5 +175,11 @@ class API extends REST { // Initiiate Library $api = new API; -$api->processApi(); +try { + $api->auth(); + $api->processApi(); +} catch (Exception $e){ + $api->die($e); +} + ?> \ No newline at end of file diff --git a/api/lib/Auth.class.php b/api/lib/Auth.class.php index 6c964c2..84ed180 100644 --- a/api/lib/Auth.class.php +++ b/api/lib/Auth.class.php @@ -10,6 +10,7 @@ class Auth { private $db; private $isTokenAuth = false; private $loginTokens = null; + private $oauth; public function __construct($username, $password = NULL){ $this->db = Database::getConnection(); @@ -24,7 +25,8 @@ class Auth { } if($this->isTokenAuth){ - throw new Exception("Not Implemented"); + $this->oauth = new OAuth($this->token); + $this->oauth->authenticate(); } else { $user = new User($this->username); $hash = $user->getPasswordHash(); @@ -33,19 +35,35 @@ class Auth { if(!$user->isActive()){ throw new Exception("Please check your email and activate your account."); } - $this->loginTokens = $this->addSession(); + $this->loginTokens = $this->addSession(7200); } else { throw new Exception("Password Mismatch"); } } } + /** + * Returns the username of authenticated user + */ + public function getUsername(){ + if($this->oauth->authenticate()){ + return $this->oauth->getUsername(); + } else { + return "a"; + } + } + + public function getOAuth(){ + return $this->oauth; + } + public function getAuthTokens(){ return $this->loginTokens; } private function addSession(){ - $oauth = new OAuth($this->username); + $oauth = new OAuth(); + $oauth->setUsername($this->username); $session = $oauth->newSession(); return $session; } diff --git a/api/lib/OAuth.class.php b/api/lib/OAuth.class.php index 856bbc3..3bc8cc0 100644 --- a/api/lib/OAuth.class.php +++ b/api/lib/OAuth.class.php @@ -6,29 +6,82 @@ require_once($_SERVER['DOCUMENT_ROOT'].'/api/lib/User.class.php'); class OAuth { private $db; - private $refresh_token; - private $access_token; + private $refresh_token = null; + private $access_token = null; private $valid_for = 7200; private $username; + private $user; - public function __construct($username, $refresh_token = NULL){ - $this->refresh_token = $refresh_token; + /** + * Can construct without refresh token for new session + * Can construct with refresh token for refresh session + */ + public function __construct($token = NULL){ $this->db = Database::getConnection(); + if($token != NULL){ + if($this->startsWith($token, 'a.')){ + $this->access_token = $token; + } else if($this->startsWith($token, 'r.')){ + $this->refresh_token = $token; + } else { + $this->setUsername($token); + } + } + } + + public function setUsername($username){ $this->username = $username; - $u = new User($this->username); + $this->user = new User($this->username); + } + + public function getUsername(){ + return $this->username; } - public function newSession($valid_for = 7200){ + public function authenticate(){ + if($this->access_token != null){ + $query = "SELECT * FROM apis.session WHERE access_token = '$this->access_token';"; + $result = mysqli_query($this->db, $query); + if($result){ + $data = mysqli_fetch_assoc($result); + $created_at = strtotime($data['created_at']); + $expires_at = $created_at + $data['valid_for']; + + if(time() <= $expires_at){ + if (session_status() === PHP_SESSION_NONE) { + session_start(); + } + $this->username = $_SESSION['username'] = $data['username']; + $_SESSION['token'] = $this->access_token; + return true; + } else { + throw new Exception("Expired token"); + } + } else { + throw new Exception(mysqli_error($this->db)); + } + } + } + + public function newSession($valid_for = 7200, $reference_token = 'auth_grant'){ + if($this->username == NULL){ + throw new Exception("Username not set for OAuth"); + } $this->valid_for = $valid_for; - $this->access_token = Auth::generateRandomHash(32); - $this->refresh_token = Auth::generateRandomHash(32); + $this->access_token = 'a.'.Auth::generateRandomHash(32); + if($reference_token == 'auth_grant'){ + $this->refresh_token = 'r.'.Auth::generateRandomHash(32); + } else { + $this->refresh_token = 'd.'.Auth::generateRandomHash(16); + } $query = "INSERT INTO `apis`.`session` (`username`, `access_token`, `refresh_token`, `valid_for`, `reference_token`) - VALUES ('$this->username', '$this->access_token', '$this->refresh_token', $this->valid_for, 'auth_grant');"; + VALUES ('$this->username', '$this->access_token', '$this->refresh_token', $this->valid_for, '$reference_token');"; if(mysqli_query($this->db, $query)){ return array( "access_token" => $this->access_token, "valid_for" => $this->valid_for, "refresh_token" => $this->refresh_token, + "reference_token" => $reference_token, "type" => 'api' ); } else { @@ -37,19 +90,27 @@ class OAuth { } public function refreshAccess(){ - if($this->refresh_token){ + if($this->refresh_token != NULL and !$this->startsWith($this->refresh_token, 'd.')){ $query = "SELECT * FROM apis.session WHERE refresh_token = '$this->refresh_token';"; $result = mysqli_query($this->db, $query); if($result){ $data = mysqli_fetch_assoc($result); + $this->username = $data['username']; if($data['valid'] == 1){ - + return $this->newSession(7200, $this->refresh_token); } else { throw new Exception("Expired token"); } } else { - throw new Exception("Invalid request"); + throw new Exception("Error: "+mysqli_error($this->db)); } + } else { + throw new Exception("Invalid request"); } } + + private function startsWith ($string, $startString){ + $len = strlen($startString); + return (substr($string, 0, $len) === $startString); + } } \ No newline at end of file diff --git a/call.php b/call.php index 0a9707b..160a46c 100644 --- a/call.php +++ b/call.php @@ -46,10 +46,15 @@ class Superhero { } $hero = new Superhero("Batman"); +echo date_default_timezone_get(); +echo date("Y-m-d h:i:s a", time()); echo $hero->getName()."\n"; echo $hero->get_powers(); +//session_start(); +$_SESSION['hello'] = 'world'; +print_r($_SESSION); -var_dump($_SERVER); +//var_dump($_SERVER); ?> -- GitLab