Completed
Push — master ( 4ad6bd...3873e4 )
by Ingo
11:53
created

ErrorControlChainMiddleware::safeReloadWithToken()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 2
nop 2
dl 0
loc 20
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Core\Startup;
4
5
use SilverStripe\Control\Director;
6
use SilverStripe\Control\HTTPRequest;
7
use SilverStripe\Control\HTTPResponse;
8
use SilverStripe\Control\HTTPResponse_Exception;
9
use SilverStripe\Core\Application;
10
use SilverStripe\Control\HTTPMiddleware;
11
use SilverStripe\Security\Permission;
12
use SilverStripe\Security\Security;
13
14
/**
15
 * Decorates application bootstrapping with errorcontrolchain
16
 */
17
class ErrorControlChainMiddleware implements HTTPMiddleware
18
{
19
    /**
20
     * @var Application
21
     */
22
    protected $application = null;
23
24
    /**
25
     * Build error control chain for an application
26
     *
27
     * @param Application $application
28
     */
29
    public function __construct(Application $application)
30
    {
31
        $this->application = $application;
32
    }
33
34
    public function process(HTTPRequest $request, callable $next)
35
    {
36
        $result = null;
37
38
        // Prepare tokens and execute chain
39
        $reloadToken = ParameterConfirmationToken::prepare_tokens(
40
            ['isTest', 'isDev', 'flush'],
41
            $request
42
        );
43
        $chain = new ErrorControlChain();
44
        $chain
45
            ->then(function () use ($request, $chain, $reloadToken, $next, &$result) {
46
                // If no redirection is necessary then we can disable error supression
47
                if (!$reloadToken) {
48
                    $chain->setSuppression(false);
49
                }
50
51
                try {
52
                    // Check if a token is requesting a redirect
53
                    if ($reloadToken) {
54
                        $result = $this->safeReloadWithToken($request, $reloadToken);
55
                    } else {
56
                        // If no reload necessary, process application
57
                        $result = call_user_func($next, $request);
58
                    }
59
                } catch (HTTPResponse_Exception $exception) {
60
                    $result = $exception->getResponse();
61
                }
62
            })
63
            // Finally if a token was requested but there was an error while figuring out if it's allowed, do it anyway
64
            ->thenIfErrored(function () use ($reloadToken, &$result) {
65
                if ($reloadToken) {
66
                    $result = $reloadToken->reloadWithToken();
67
                }
68
            })
69
            ->execute();
70
        return $result;
71
    }
72
73
    /**
74
     * Reload application with the given token, but only if either the user is authenticated,
75
     * or authentication is impossible.
76
     *
77
     * @param HTTPRequest $request
78
     * @param ParameterConfirmationToken $reloadToken
79
     * @return HTTPResponse
80
     */
81
    protected function safeReloadWithToken(HTTPRequest $request, $reloadToken)
82
    {
83
        // Safe reload requires manual boot
84
        $this->getApplication()->getKernel()->boot(false);
85
86
        // Ensure session is started
87
        $request->getSession()->init();
88
89
        // Next, check if we're in dev mode, or the database doesn't have any security data, or we are admin
90
        if (Director::isDev() || !Security::database_is_ready() || Permission::check('ADMIN')) {
91
            return $reloadToken->reloadWithToken();
92
        }
93
94
        // Fail and redirect the user to the login page
95
        $loginPage = Director::absoluteURL(Security::config()->get('login_url'));
96
        $loginPage .= "?BackURL=" . urlencode($request->getURL());
97
        $result = new HTTPResponse();
98
        $result->redirect($loginPage);
99
        return $result;
100
    }
101
102
    /**
103
     * @return Application
104
     */
105
    public function getApplication()
106
    {
107
        return $this->application;
108
    }
109
110
    /**
111
     * @param Application $application
112
     * @return $this
113
     */
114
    public function setApplication(Application $application)
115
    {
116
        $this->application = $application;
117
        return $this;
118
    }
119
}
120