Ratings | | Unique User Downloads | | Download Rankings |
Not yet rated by the users | | Total: 231 | | All time: 8,150 This week: 69 |
|
Description | | Author |
This package can HTTP authentication using PSR-7 interfaces.
It uses PSR-7 interface implementation for request and response classes that will read the authentication request values and generates the necessary responses.
Separate classes implement the authentication of users from a file based database of user and password records.
It provides classes to check if the user is already logged in an authenticate him in case he isn't. Innovation Award
August 2017
Number 13 |
PSR-7 is a PHP standards recommendation for abstracting information sent and received via HTTP requests.
This package implements a user authentication system that abstracts the way HTTP request and response headers are sent and received, so it can work with many different Web server architectures.
Manuel Lemos |
| |
|
|
Innovation award
Nominee: 2x |
|
Example
<?php
namespace Poirot\AuthSystem\Authenticate\Identifier\HttpDigest
{
use Poirot\Http\Interfaces\iHttpRequest;
/**
* Has Request Contains Authorization Header
*
* @param iHttpRequest $request
* @param bool $isProxy
*
* @return bool
*/
function hasAuthorizationHeader(iHttpRequest $request, $isProxy = false)
{
if ($isProxy)
$headerName = 'Proxy-Authorization';
else
$headerName = 'Authorization';
$hValue = false;
$headers = $request->headers();
if ($headers->has($headerName)) {
$h = $headers->get($headerName)->current();
$hValue = $h->renderValueLine();
}
return $hValue;
}
/**
* Parse Authorization Header
*
* Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
*
* - in case of basic extract given username/password
*
* @param string $headerValue
* @param null|string $clientScheme Basic|Digest, null detect from header
*
* @return array
* @throws \Exception
*/
function parseAuthorizationHeader($headerValue, $clientScheme = null)
{
if ($clientScheme === null) {
list($clientScheme) = explode(' ', trim($headerValue));
$clientScheme = strtolower($clientScheme);
}
if (!in_array($clientScheme, array('basic', 'digest')))
throw new \Exception(sprintf('Client Scheme (%s) Not Supported.', $clientScheme));
if ($clientScheme == 'basic')
$parsed = parseBasicAuthorizationHeader($headerValue);
else
$parsed = parseDigestAuthorizationHeader($headerValue);
return $parsed;
}
/**
* Parse Basic Authorization Header Value To It's
* Credential Values
*
* Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
*
* @param string $headerValue
*
* @return array [username=>'', 'password'=>'']
* @throws \Exception Invalid Header
*/
function parseBasicAuthorizationHeader($headerValue)
{
// Decode the Authorization header
$auth = substr($headerValue, strlen('Basic '));
$auth = base64_decode($auth);
if (!$auth)
throw new \RuntimeException('Unable to base64_decode Authorization header value');
if (!ctype_print($auth))
throw new \Exception('Invalid or Empty Authorization Credential.');
$creds = array_filter(explode(':', $auth));
if (count($creds) != 2)
throw new \Exception('Invalid Authorization Credential; Missing username or password.');
$credential = array('username' => $creds[0], 'password' => $creds[1], 0=>$creds[0], 1=>$creds[1]);
return $credential;
}
/**
* Parse Digest Authorization header
*
* credentials = "Digest" digest-response
* digest-response = 1#( username | realm | nonce | digest-uri
* | response | [ algorithm ] | [cnonce] | [opaque]
* | [message-qop] | [nonce-count] | [auth-param] )
*
* @param string $headerValue
*
* @return array
* @throws \Exception Invalid Header
*/
function parseDigestAuthorizationHeader($headerValue)
{
preg_match_all('@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', $headerValue, $matches, PREG_SET_ORDER);
$data = array();
foreach ($matches as $m) {
$key = $m[1];
$value = ($m[2]) ? $m[2] : $m[3];
switch ($key) {
case 'realm':
case 'username':
if (!ctype_print($value))
throw new \Exception('Invalid "realm" or "username"');
break;
case 'nonce':
if (!ctype_xdigit($value))
throw new \Exception('Invalid "nonce"');
break;
/*
* A string of 32 hex digits computed as defined below, which proves
* that the user knows a password
*/
case 'response':
if (32 != strlen($value) || !ctype_xdigit($value))
throw new \Exception('Invalid "response"');
break;
/*
* Indicates what "quality of protection" the client has applied to
* the message. If present, its value MUST be one of the alternatives
* the server indicated it supports in the WWW-Authenticate header.
*/
case 'qop':
break;
/*
* This MUST be specified if a qop directive is sent (see above), and
* MUST NOT be specified if the server did not send a qop directive in
* the WWW-Authenticate header field. The nc-value is the hexadecimal
* count of the number of requests (including the current request)
* that the client has sent with the nonce value in this request. For
* example, in the first request sent in response to a given nonce
* value, the client sends "nc=00000001". The purpose of this
* directive is to allow the server to detect request replays by
* maintaining its own copy of this count - if the same nc-value is
* seen twice, then the request is a replay.
*/
case 'nc':
if (8 != strlen($value) || !ctype_xdigit($value))
throw new \Exception('Invalid "nc"');
break;
}
$data[$key] = $value;
}
return $data;
## cnonce -----------------------------------------------------------------
/*
* Nonce-count. This a hexadecimal serial number for the request.
* The client should increase this number by one for every request.
*
* This MUST be specified if a qop directive is sent (see above), and
* MUST NOT be specified if the server did not send a qop directive in
* the WWW-Authenticate header field. The cnonce-value is an opaque
* quoted string value provided by the client and used by both client
* and server to avoid chosen plaintext attacks, to provide mutual
* authentication, and to provide some message integrity protection.
*/
}
}
|
Details
Poirot\AuthSystem
HTTP authentication using PSR-7 interfaces.
It uses PSR-7 interface implementation for request and response classes that will read the authentication request values and generates the necessary responses.
Separate classes implement the authentication of users from a file based database of user and password records.
It provides classes to check if the user is already logged in an authenticate him in case he isn't.
Overview usage sample
$request = new HttpRequest(new PhpServerRequestBuilder);
$response = new HttpResponse(new PhpServerResponseBuilder);
$lazyLoad = new LazyFulfillmentIdentity(['fulfillment_by' => 'username', 'data_provider' => new UserData]);
$auth = new Authenticator\HttpSessionAuth([
'identity' => $lazyLoad,
'request' => $request,
'response' => $response,
]);
try {
$credential = null;
## check user has authenticated
login_user:
$auth->authenticate($credential);
echo 'Continue ...';
if (!$auth->isSignIn()) {
$auth->signIn();
header('Location: '.$request->getUri()->getPath()->toString());
die();
}
} catch (WrongCredentialException $e) {
throw new \Exception('Invalid Username or Password.');
} catch (UserNotFoundException $e) {
throw new \Exception('Invalid Username or Password.');
} catch (AuthenticationException $e)
{
if ($e->getAuthenticator() instanceof Authenticator\HttpSessionAuth)
{
### handle login with satisfy request
if ($request->plg()->methodType()->isPost()) {
$credential = new UserPassCredential($request->plg()->phpServer()->getPost());
goto login_user;
}
### challenge user with login form, redirection or etc.
$response->setBody('
<form method="post" action="" enctype="application/x-www-form-urlencoded">
<input type="text" name="email">
<input type="password" name="password">
<input type="submit" value="send">
</form>
<p>Please Login ...</p>
');
}
}
## run rest of program
if ($auth->hasAuthenticated()) {
$response->setBody("<h1>Hello User {$auth->identity()->getEmail()}</h1>");
}
### send response
$response->flush();
TODO
-
Aggregate Authenticator
-
Aggregate Adapter
-
Write Authentication Service Layer On Top Of Adapters For Application Dispatching Control
|
Applications that use this package |
|
No pages of applications that use this class were specified.
If you know an application of this package, send a message to the author to add a link here.