Passed
Push — master ( 66a546...4ec22f )
by Gabor
03:10
created

AclMiddleware::setIdentityForTemplate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 11
nc 2
nop 2
1
<?php
2
/**
3
 * WebHemi.
4
 *
5
 * PHP version 7.1
6
 *
7
 * @copyright 2012 - 2017 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link      http://www.gixx-web.com
11
 */
12
declare(strict_types = 1);
13
14
namespace WebHemi\Middleware\Security;
15
16
use Exception;
17
use WebHemi\Adapter\Acl\AclAdapterInterface;
18
use WebHemi\Adapter\Auth\AuthAdapterInterface;
19
use WebHemi\Adapter\Http\ResponseInterface;
20
use WebHemi\Adapter\Http\ServerRequestInterface;
21
use WebHemi\Application\EnvironmentManager;
22
use WebHemi\Data\Entity\AccessManagement\ResourceEntity;
23
use WebHemi\Data\Entity\ApplicationEntity;
24
use WebHemi\Data\Entity\User\UserEntity;
25
use WebHemi\Data\Entity\User\UserMetaEntity;
26
use WebHemi\Data\Storage\AccessManagement\ResourceStorage;
27
use WebHemi\Data\Storage\ApplicationStorage;
28
use WebHemi\Data\Storage\User\UserMetaStorage;
29
use WebHemi\Middleware\Action;
30
use WebHemi\Middleware\MiddlewareInterface;
31
32
/**
33
 * Class AclMiddleware.
34
 */
35
class AclMiddleware implements MiddlewareInterface
36
{
37
    /** @var AuthAdapterInterface */
38
    private $authAdapter;
39
    /** @var AclAdapterInterface */
40
    private $aclAdapter;
41
    /** @var EnvironmentManager */
42
    private $environmentManager;
43
    /** @var ApplicationStorage */
44
    private $applicationStorage;
45
    /** @var ResourceStorage */
46
    private $resourceStorage;
47
    /** @var UserMetaStorage */
48
    private $userMetaStorage;
49
    /** @var array */
50
    private $middlewareWhiteList = [
51
        Action\Auth\LoginAction::class,
52
        Action\Auth\LogoutAction::class,
53
    ];
54
55
    /**
56
     * AclMiddleware constructor.
57
     *
58
     * @param AuthAdapterInterface     $authAdapter
59
     * @param AclAdapterInterface      $aclAdapter
60
     * @param EnvironmentManager       $environmentManager
61
     * @param ApplicationStorage       $applicationStorage
62
     * @param ResourceStorage          $resourceStorage
63
     * @param UserMetaStorage          $userMetaStorage
64
     */
65
    public function __construct(
66
        AuthAdapterInterface $authAdapter,
67
        AclAdapterInterface $aclAdapter,
68
        EnvironmentManager $environmentManager,
69
        ApplicationStorage $applicationStorage,
70
        ResourceStorage $resourceStorage,
71
        UserMetaStorage $userMetaStorage
72
    ) {
73
        $this->authAdapter = $authAdapter;
74
        $this->aclAdapter = $aclAdapter;
75
        $this->environmentManager = $environmentManager;
76
        $this->applicationStorage = $applicationStorage;
77
        $this->resourceStorage = $resourceStorage;
78
        $this->userMetaStorage = $userMetaStorage;
79
    }
80
81
    /**
82
     * A middleware is a callable. It can do whatever is appropriate with the Request and Response objects.
83
     * The only hard requirement is that a middleware MUST return an instance of \Psr\Http\Message\ResponseInterface.
84
     * Each middleware SHOULD invoke the next middleware and pass it Request and Response objects as arguments.
85
     *
86
     * @param ServerRequestInterface $request
87
     * @param ResponseInterface      $response
88
     * @throws Exception
89
     * @return void
90
     */
91
    public function __invoke(ServerRequestInterface&$request, ResponseInterface&$response) : void
92
    {
93
        $actionMiddleware = $request->getAttribute(ServerRequestInterface::REQUEST_ATTR_RESOLVED_ACTION_CLASS);
94
        $identity = false;
95
96
        if (in_array($actionMiddleware, $this->middlewareWhiteList)) {
97
            return;
98
        }
99
100
        if ($this->authAdapter->hasIdentity()) {
101
            $identity = $this->authAdapter->getIdentity();
102
        }
103
104
        if ($identity instanceof UserEntity) {
105
            $selectedApplication = $this->environmentManager->getSelectedApplication();
106
            /** @var ApplicationEntity $applicationEntity */
107
            $applicationEntity = $this->applicationStorage->getApplicationByName($selectedApplication);
108
            /** @var ResourceEntity $resourceEntity */
109
            $resourceEntity = $this->resourceStorage->getResourceByName($actionMiddleware);
110
111
            // Check the user against the application and resource
112
            $hasAccess = $this->aclAdapter->isAllowed($identity, $resourceEntity, $applicationEntity);
113
114
            $request = $this->setIdentityForTemplate($request, $identity);
115
116
            if (!$hasAccess) {
117
                throw new Exception('Forbidden', 403);
118
            }
119
        } else {
120
            $appUri = rtrim($this->environmentManager->getSelectedApplicationUri(), '/');
121
            $response = $response->withStatus(ResponseInterface::STATUS_REDIRECT, 'Found')
122
                ->withHeader('Location', $appUri.'/auth/login');
123
        }
124
    }
125
126
    /**
127
     * Set identified user data for the templates
128
     *
129
     * @param ServerRequestInterface $request
130
     * @param UserEntity             $identity
131
     * @return ServerRequestInterface
132
     */
133
    private function setIdentityForTemplate(
134
        ServerRequestInterface $request,
135
        UserEntity $identity
136
    ) : ServerRequestInterface {
137
        // Set authenticated user for the templates
138
        $templateData = $request->getAttribute(ServerRequestInterface::REQUEST_ATTR_DISPATCH_DATA, []);
139
        $templateData['authenticated_user'] = $identity;
140
        $templateData['authenticated_user_meta'] = [];
141
        $userMeta = $this->userMetaStorage->getUserMetaForUserId($identity->getUserId());
142
        /** @var UserMetaEntity $metaEntity */
143
        foreach ($userMeta as $metaEntity) {
144
            $templateData['authenticated_user_meta'][$metaEntity->getMetaKey()] = $metaEntity->getMetaData();
145
        }
146
147
        return $request->withAttribute(ServerRequestInterface::REQUEST_ATTR_DISPATCH_DATA, $templateData);
148
    }
149
}
150