Completed
Push — master ( d5f109...3a301a )
by Charles
03:33
created

AbstractAuthentication::process()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 31
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 19
dl 0
loc 31
rs 9.3222
c 0
b 0
f 0
cc 5
nc 8
nop 2
1
<?php declare(strict_types=1);
2
3
namespace ncryptf\middleware;
4
5
use DateTime;
6
use Exception;
7
8
use ncryptf\Authorization;
9
use ncryptf\Token;
10
11
use Psr\Http\Message\ResponseInterface;
12
use Psr\Http\Message\ServerRequestInterface;
13
use Psr\Http\Server\MiddlewareInterface;
14
use Psr\Http\Server\RequestHandlerInterface;
15
16
/**
17
 * PSR-15 Authentication middleware for handling ncryptf Authorization requests
18
 * Abstract class should be extended and implement `getTokenFromAccessToken` and `getRequestBody`
19
 */
20
abstract class AbstractAuthentication implements MiddlewareInterface
21
{
22
    use \Middlewares\Utils\Traits\HasResponseFactory;
23
24
    // The date header
25
    const DATE_HEADER = 'X-DATE';
26
    
27
    // The authorization header
28
    const AUTHORIZATION_HEADER = 'Authorization';
29
    
30
    // The amount of the seconds the request is permitted to differ from the server time
31
    const DRIFT_TIME_ALLOWANCE = 90;
32
33
    /**
34
     * Process a request
35
     * @param ServerRequestInterface $request
36
     * @param RequestHandlerInterface $handler
37
     * @return ResponseInterface
38
     */
39
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
40
    {
41
        $params = Authorization::extractParamsFromHeaderString(
42
            $request->getHeaderLine(self::AUTHORIZATION_HEADER)
43
        );
44
45
        if ($params) {
46
            if ($token = $this->getTokenFromAccessToken($params['access_token'])) {
47
                try {
48
                    $date = new DateTime($params['date'] ?? $request->getHeaderLine(self::DATE_HEADER));
49
                    
50
                    $auth = new Authorization(
51
                        $request->getMethod(),
52
                        $this->getRequestUri($request),
53
                        $token,
54
                        $date,
55
                        $this->getRequestBody($request),
56
                        $params['v'],
57
                        \base64_decode($params['salt'])
58
                    );
59
60
                    if ($auth->verify(\base64_decode($params['hmac']), $auth, static::DRIFT_TIME_ALLOWANCE)) {
61
                        return $handler->handle($request->withAttribute('ncryptf-token', $token));
62
                    }
63
                } catch (Exception $e) {
64
                    throw $e;
65
                }
66
            }
67
        }
68
69
        return $this->createResponse(401);
70
    }
71
72
    private function getRequestUri(ServerRequestInterface $request) : string
73
    {
74
        $uri = $request->getUri()->getPath();
75
        $query = $request->getUri()->getQuery();
76
77
        if (!empty($query)) {
78
            return $uri . '?' . \urldecode($query);
79
        }
80
81
        return $uri;
82
    }
83
84
    /**
85
     * Returns the \ncryptf\Token associated to the given access token.
86
     * If the access token is not found, `NULL` should be returned
87
     * 
88
     * @param string $accessToken
89
     * @return \ncryptf\Token
90
     */
91
    abstract protected function getTokenFromAccessToken(string $accessToken) :? Token;
92
93
    /**
94
     * Returns the plaintext request body. If the request is encrypted with vnd.ncryptf+<type>
95
     * It should return the decrypted plaintext.
96
     * 
97
     * If the request body is empty, an empty string `""` should be returned.
98
     * 
99
     * @param ServerRequestInterface $request
100
     * @return string
101
     */
102
    abstract protected function getRequestBody(ServerRequestInterface $request) : string;
103
}
104