Test Failed
Push — master ( 42e257...dadfc2 )
by Charles
02:28
created

AbstractAuthentication::getRequestBody()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
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 Middlewares\Utils\HttpErrorException;
12
13
use Psr\Http\Message\ResponseInterface;
14
use Psr\Http\Message\ServerRequestInterface;
15
use Psr\Http\Server\MiddlewareInterface;
16
use Psr\Http\Server\RequestHandlerInterface;
17
18
/**
19
 * PSR-15 Authentication middleware for handling ncryptf Authorization requests
20
 * Abstract class should be extended and implement `getTokenFromAccessToken` and `getRequestBody`
21
 */
22
abstract class AbstractAuthentication implements MiddlewareInterface
23
{
24
    use \Middlewares\Utils\Traits\HasResponseFactory;
25
26
    // The date header
27
    const DATE_HEADER = 'X-DATE';
28
29
    // The authorization header
30
    const AUTHORIZATION_HEADER = 'Authorization';
31
32
    // The amount of the seconds the request is permitted to differ from the server time
33
    const DRIFT_TIME_ALLOWANCE = 90;
34
35
    /**
36
     * Process a request
37
     * @param ServerRequestInterface $request
38
     * @param RequestHandlerInterface $handler
39
     * @return ResponseInterface
40
     */
41
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
42
    {
43
        $params = Authorization::extractParamsFromHeaderString(
44
            $request->getHeaderLine(self::AUTHORIZATION_HEADER)
45
        );
46
47
        if ($params) {
48
            if ($token = $this->getTokenFromAccessToken($params['access_token'])) {
49
                try {
50
                    $date = new DateTime($params['date'] ?? $request->getHeaderLine(self::DATE_HEADER));
51
52
                    $auth = new Authorization(
53
                        $request->getMethod(),
54
                        $this->getRequestUri($request),
55
                        $token,
56
                        $date,
57
                        $this->getRequestBody($request),
58
                        $params['v'],
59
                        \base64_decode($params['salt'])
60
                    );
61
62
                    if ($auth->verify(\base64_decode($params['hmac']), $auth, static::DRIFT_TIME_ALLOWANCE)) {
63
                        return $handler->handle(
64
                            $request->withAttribute('ncryptf-token', $token)
65
                                ->withAttribute('ncryptf-user', $this->getUserFromToken($token))
66
                        );
67
                    }
68
                } catch (Exception $e) {
69
                    throw HttpErrorException::create(401, [], $e);
70
                }
71
            }
72
        }
73
74
        throw HttpErrorException::create(401);
75
    }
76
77
    /**
78
     * Returns the full URI
79
     * @param ServerRequestInterface $request
80
     * @return string
81
     */
82
    private function getRequestUri(ServerRequestInterface $request) : string
83
    {
84
        $uri = $request->getUri()->getPath();
85
        $query = $request->getUri()->getQuery();
86
87
        if (!empty($query)) {
88
            return $uri . '?' . \urldecode($query);
89
        }
90
91
        return $uri;
92
    }
93
94
    /**
95
     * Returns the plaintext request body.
96
     *
97
     * @param ServerRequestInterface $request
98
     * @return string
99
     */
100
    protected function getRequestBody(ServerRequestInterface $request) : string
101
    {
102
        if ($decryptedBody = $request->getAttribute('ncryptf-decrypted-body', false)) {
103
            return $decryptedBody;
104
        }
105
106
        return $request->getBody()->getContents();
107
    }
108
109
    /**
110
     * Returns the \ncryptf\Token associated to the given access token.
111
     * If the access token is not found, `NULL` should be returned
112
     *
113
     * @param string $accessToken
114
     * @return \ncryptf\Token
115
     */
116
    abstract protected function getTokenFromAccessToken(string $accessToken) :? Token;
117
118
    /**
119
     * Given a particular token, returns an object, array, or integer representing the user
120
     *
121
     * @param \ncryptf\Token $token
122
     * @return integer|array|object
123
     */
124
    abstract protected function getUserFromToken(Token $token);
125
}
126