Added authentication methods for simple and user based authentication

This commit is contained in:
Zi Xing 2022-01-05 22:22:44 -05:00
parent c05ec35556
commit 2a01bb433a
10 changed files with 317 additions and 4 deletions

View File

@ -0,0 +1,21 @@
<?php
namespace Methods\v1;
use KimchiAPI\Abstracts\Method;
use KimchiAPI\Exceptions\AccessKeyNotProvidedException;
use KimchiAPI\KimchiAPI;
use KimchiAPI\Objects\Response;
class AuthenticationTestMethod extends Method
{
/**
* @throws AccessKeyNotProvidedException
*/
public function execute(): Response
{
$response = new Response();
$response->ResultData = KimchiAPI::getAuthenticationToken();
return $response;
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace Methods\v1;
use KimchiAPI\Abstracts\Method;
use KimchiAPI\Exceptions\AccessKeyNotProvidedException;
use KimchiAPI\Exceptions\AuthenticationNotProvidedException;
use KimchiAPI\KimchiAPI;
use KimchiAPI\Objects\Response;
class UserAuthenticationTestMethod extends Method
{
/**
* @return Response
* @throws AuthenticationNotProvidedException
*/
public function execute(): Response
{
$response = new Response();
$response->ResultData = KimchiAPI::getUserAuthentication()->toArray();
return $response;
}
}

View File

@ -16,7 +16,9 @@
"enabled": true,
"methods": [
{"methods": ["GET", "POST"], "path": "ping", "class": "\\Methods\\v1\\PingMethod"},
{"methods": ["GET", "POST"], "path": "parameter_test", "class": "\\Methods\\v1\\ParameterTestMethod"}
{"methods": ["GET", "POST"], "path": "parameter_test", "class": "\\Methods\\v1\\ParameterTestMethod"},
{"methods": ["GET", "POST"], "path": "auth/simple", "class": "\\Methods\\v1\\AuthenticationTestMethod"},
{"methods": ["GET", "POST"], "path": "auth/user", "class": "\\Methods\\v1\\UserAuthenticationTestMethod"}
]
}
]

View File

@ -27,9 +27,17 @@
"required": true,
"file": "Methods/v1/ParameterTestMethod.php"
},
{
"required": true,
"file": "Methods/v1/UserAuthenticationTestMethod.php"
},
{
"required": true,
"file": "Methods/v1/PingMethod.php"
},
{
"required": true,
"file": "Methods/v1/AuthenticationTestMethod.php"
}
],
"files": [

View File

@ -74,6 +74,75 @@
return $_GET;
}
/**
* Returns a specified header otherwise null if not set
*
* @param string $value
* @return string|null
*/
public function getHeaderParameter(string $value): ?string
{
$headers = self::getHeaderParameters();
if(isset($headers[$value]))
return $headers[$value];
return null;
}
/**
* Returns an array of header parameters
*
* @return array
*/
public static function getHeaderParameters(): array
{
if(function_exists('getallheaders'))
return getallheaders();
$headers = [];
$copy_server = [
'CONTENT_TYPE' => 'Content-Type',
'CONTENT_LENGTH' => 'Content-Length',
'CONTENT_MD5' => 'Content-Md5',
];
foreach ($_SERVER as $key => $value)
{
if (substr($key, 0, 5) === 'HTTP_')
{
$key = substr($key, 5);
if (!isset($copy_server[$key]) || !isset($_SERVER[$key]))
{
$key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))));
$headers[$key] = $value;
}
}
elseif (isset($copy_server[$key]))
{
$headers[$copy_server[$key]] = $value;
}
}
if (!isset($headers['Authorization']))
{
if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
{
$headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
}
elseif (isset($_SERVER['PHP_AUTH_USER']))
{
$basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
$headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass);
}
elseif (isset($_SERVER['PHP_AUTH_DIGEST']))
{
$headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST'];
}
}
return $headers;
}
/**
* Returns a POST/GET Parameter
*
@ -104,6 +173,7 @@
public static function getParameters(): array
{
return array_merge(
self::getHeaderParameters(),
self::getGetParameters(),
self::getPostParameters(),
self::getDefinedDynamicParameters(),

View File

@ -0,0 +1,21 @@
<?php
namespace KimchiAPI\Exceptions;
use Exception;
use Throwable;
class AccessKeyNotProvidedException extends Exception
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->message = $message;
$this->code = $code;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace KimchiAPI\Exceptions;
use Exception;
use Throwable;
class AuthenticationNotProvidedException extends Exception
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->message = $message;
$this->code = $code;
}
}

View File

@ -9,8 +9,11 @@
use KimchiAPI\Abstracts\ResponseStandard;
use KimchiAPI\Abstracts\ResponseType;
use KimchiAPI\Classes\API;
use KimchiAPI\Classes\Request;
use KimchiAPI\Exceptions\AccessKeyNotProvidedException;
use KimchiAPI\Exceptions\ApiException;
use KimchiAPI\Exceptions\ApiMethodNotFoundException;
use KimchiAPI\Exceptions\AuthenticationNotProvidedException;
use KimchiAPI\Exceptions\IOException;
use KimchiAPI\Exceptions\MissingComponentsException;
use KimchiAPI\Exceptions\UnsupportedResponseStandardException;
@ -18,6 +21,7 @@
use KimchiAPI\Objects\ResponseStandards\GoogleAPI;
use KimchiAPI\Objects\ResponseStandards\IntellivoidAPI;
use KimchiAPI\Objects\ResponseStandards\JsonApiOrg;
use KimchiAPI\Objects\UserAuthentication;
use KimchiAPI\Utilities\Converter;
use ppm\Exceptions\AutoloaderException;
use ppm\Exceptions\InvalidComponentException;
@ -26,7 +30,6 @@
use ppm\Exceptions\VersionNotFoundException;
use ppm\ppm;
use RuntimeException;
use Symfony\Component\Uid\Uuid;
use VerboseAdventure\Abstracts\EventType;
use VerboseAdventure\VerboseAdventure;
@ -153,10 +156,14 @@
}
catch(ApiMethodNotFoundException $e)
{
unset($e);
self::handle404();
}
catch(AccessKeyNotProvidedException|AuthenticationNotProvidedException $e)
{
unset($e);
self::requireAuthentication(KIMCHI_API_NAME);
}
catch(Exception $e)
{
self::getVerboseAdventure()->logException($e, KIMCHI_API_REQUEST_ID);
@ -215,6 +222,31 @@
self::handleResponse($response);
}
/**
* Returns an authentication required header
*
* @param string $realm
* @param string $response_standard
* @param string $response_type
* @return void
* @throws ApiException
* @throws Exceptions\UnsupportedResponseTypeExceptions
* @throws UnsupportedResponseStandardException
*/
public static function requireAuthentication(string $realm, string $response_standard = ResponseStandard::KimchiAPI, string $response_type = ResponseType::Json)
{
$response = new Response();
$response->ResponseCode = 401;
$response->Success = false;
$response->ErrorCode = 401;
$response->ErrorMessage = 'Unauthorized';
$response->ResponseStandard = $response_standard;
$response->ResponseType = $response_type;
$response->Headers['WWW-Authenticate'] = 'Basic realm="' . $realm . '"';
self::handleResponse($response);
}
/**
* Returns the headers used for framework
*
@ -240,7 +272,6 @@
];
}
/**
* Handles the response handler and returns the response data to the client
*
@ -302,4 +333,56 @@
print($return_results);
exit();
}
/**
* Returns a username and password authentication
*
* @return UserAuthentication
* @throws AuthenticationNotProvidedException
*/
public static function getUserAuthentication(): UserAuthentication
{
if(isset($_SERVER['PHP_AUTH_USER']) == false)
{
$parameters = Request::getParameters();
if(isset($parameters['username']) && isset($parameters['password']))
{
$authentication_results = new UserAuthentication();
$authentication_results->Username = $parameters['username'];
$authentication_results->Password = $parameters['password'];
return $authentication_results;
}
throw new AuthenticationNotProvidedException('Authentication required, 401 unauthorized');
}
$authentication_results = new UserAuthentication();
$authentication_results->Username = $_SERVER['PHP_AUTH_USER'];
$authentication_results->Password = $_SERVER['PHP_AUTH_PW'];
return $authentication_results;
}
/**
* Attempts to fetch the authentication token
*
* @param string $parameter_name
* @return string
* @throws AccessKeyNotProvidedException
*/
public static function getAuthenticationToken(string $parameter_name='access_key'): string
{
if(isset($_SERVER['PHP_AUTH_USER']) == false)
{
$parameters = Request::getParameters();
if(isset($parameters[$parameter_name]) && is_string($parameters[$parameter_name]))
return (string)$parameters[$parameter_name];
throw new AccessKeyNotProvidedException('Authentication required, 401 unauthorized');
}
return $_SERVER['PHP_AUTH_PW'];
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace KimchiAPI\Objects;
class UserAuthentication
{
/**
* Returns a username representation of the object
*
* @var string
*/
public $Username;
/**
* The password representation of the object
*
* @var string
*/
public $Password;
/**
* Returns an array representation of the object
*
* @return array
*/
public function toArray(): array
{
return [
'username' => $this->Username,
'password' => $this->Password
];
}
/**
* Constructs object from an array representation
*
* @param array $data
* @return UserAuthentication
*/
public static function fromArray(array $data): UserAuthentication
{
$UserAuthenticationObject = new UserAuthentication();
if(isset($data['username']))
$UserAuthenticationObject->Username = $data['username'];
if(isset($data['password']))
$UserAuthenticationObject->Password = $data['password'];
return $UserAuthenticationObject;
}
}

View File

@ -87,6 +87,10 @@
"required": true,
"file": "Exceptions/BadEnvironmentException.php"
},
{
"required": true,
"file": "Exceptions/AuthenticationNotProvidedException.php"
},
{
"required": true,
"file": "Exceptions/MissingComponentsException.php"
@ -99,6 +103,10 @@
"required": true,
"file": "Exceptions/InternalServerException.php"
},
{
"required": true,
"file": "Exceptions/AccessKeyNotProvidedException.php"
},
{
"required": true,
"file": "Exceptions/ConnectionBlockedException.php"
@ -143,6 +151,10 @@
"required": true,
"file": "Interfaces/ResponseStandardInterface.php"
},
{
"required": true,
"file": "Objects/UserAuthentication.php"
},
{
"required": true,
"file": "Objects/Configuration/MethodConfiguration.php"