Completed
Pull Request — master (#7028)
by Loz
12:53
created

CMSSecurity::getSessionMessage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Security;
4
5
use SilverStripe\Admin\AdminRootController;
6
use SilverStripe\Control\Controller;
7
use SilverStripe\Control\Director;
8
use SilverStripe\Admin\LeftAndMain;
9
use SilverStripe\Control\HTTPResponse;
10
use SilverStripe\Control\Session;
11
use SilverStripe\Core\Convert;
12
use SilverStripe\Core\Manifest\ModuleLoader;
13
use SilverStripe\ORM\FieldType\DBField;
14
use SilverStripe\ORM\FieldType\DBHTMLText;
15
use SilverStripe\View\Requirements;
16
use SilverStripe\View\SSViewer;
17
18
/**
19
 * Provides a security interface functionality within the cms
20
 */
21
class CMSSecurity extends Security
22
{
23
    private static $allowed_actions = array(
24
        'login',
25
        'LoginForm',
26
        'success'
27
    );
28
29
    /**
30
     * Enable in-cms reauthentication
31
     *
32
     * @var boolean
33
     * @config
34
     */
35
    private static $reauth_enabled = true;
36
37
    protected function init()
38
    {
39
        parent::init();
40
41
        // Assign default cms theme and replace user-specified themes
42
        SSViewer::set_themes(LeftAndMain::config()->uninherited('admin_themes'));
43
44
        // Core styles / vendor scripts
45
        $admin = ModuleLoader::getModule('silverstripe/admin');
46
        Requirements::javascript($admin->getResourcePath('client/dist/js/vendor.js'));
47
        Requirements::css($admin->getResourcePath('client/dist/styles/bundle.css'));
48
    }
49
50
    public function login($request = null, $service = Authenticator::CMS_LOGIN)
51
    {
52
        return parent::login($request, Authenticator::CMS_LOGIN);
53
    }
54
55
    public function Link($action = null)
56
    {
57
        /** @skipUpgrade */
58
        return Controller::join_links(Director::baseURL(), "CMSSecurity", $action);
59
    }
60
61
    protected function getAuthenticator($name = 'cms')
62
    {
63
        return parent::getAuthenticator($name);
64
    }
65
66
    public function getApplicableAuthenticators($service = Authenticator::CMS_LOGIN)
67
    {
68
        return parent::getApplicableAuthenticators($service);
69
    }
70
71
    /**
72
     * Get known logged out member
73
     *
74
     * @return Member
75
     */
76
    public function getTargetMember()
77
    {
78
        $tempid = $this->getRequest()->requestVar('tempid');
79
        if ($tempid) {
80
            return Member::member_from_tempid($tempid);
81
        }
82
83
        return null;
84
    }
85
86
    public function getResponseController($title)
87
    {
88
        // Use $this to prevent use of Page to render underlying templates
89
        return $this;
90
    }
91
92
    protected function getSessionMessage(&$messageType = null)
93
    {
94
        $message =  parent::getSessionMessage($messageType);
95
        if ($message) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $message of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
96
            return $message;
97
        }
98
99
        // Format
100
        return _t(
101
            __CLASS__.'.LOGIN_MESSAGE',
102
            '<p>Your session has timed out due to inactivity</p>'
103
        );
104
    }
105
106
    /**
107
     * Check if there is a logged in member
108
     *
109
     * @return bool
110
     */
111
    public function getIsloggedIn()
112
    {
113
        return !!Security::getCurrentUser();
114
    }
115
116
    /**
117
     * Redirects the user to the external login page
118
     *
119
     * @return HTTPResponse
120
     */
121
    protected function redirectToExternalLogin()
122
    {
123
        $loginURL = Security::create()->Link('login');
124
        $loginURLATT = Convert::raw2att($loginURL);
125
        $loginURLJS = Convert::raw2js($loginURL);
126
        $message = _t(
127
            __CLASS__.'.INVALIDUSER',
128
            '<p>Invalid user. <a target="_top" href="{link}">Please re-authenticate here</a> to continue.</p>',
129
            'Message displayed to user if their session cannot be restored',
130
            array('link' => $loginURLATT)
131
        );
132
        $response = $this->getResponse();
133
        $response->setStatusCode(200);
134
        $response->setBody(<<<PHP
135
<!DOCTYPE html>
136
<html><body>
137
$message
138
<script type="application/javascript">
139
setTimeout(function(){top.location.href = "$loginURLJS";}, 0);
140
</script>
141
</body></html>
142
PHP
143
        );
144
        $this->setResponse($response);
145
146
        return $response;
147
    }
148
149
    protected function preLogin()
150
    {
151
        // If no member has been previously logged in for this session, force a redirect to the main login page
152
        if (!$this->getTargetMember()) {
153
            return $this->redirectToExternalLogin();
154
        }
155
156
        return parent::preLogin();
157
    }
158
159
    /**
160
     * Determine if CMSSecurity is enabled
161
     *
162
     * @return bool
163
     */
164
    public function enabled()
165
    {
166
        // Disable shortcut
167
        if (!static::config()->get('reauth_enabled')) {
168
            return false;
169
        }
170
171
        return count($this->getApplicableAuthenticators(Authenticator::CMS_LOGIN)) > 0;
172
    }
173
174
    /**
175
     * Given a successful login, tell the parent frame to close the dialog
176
     *
177
     * @return HTTPResponse|DBField
178
     */
179
    public function success()
180
    {
181
        // Ensure member is properly logged in
182
        if (!Security::getCurrentUser() || !class_exists(AdminRootController::class)) {
183
            return $this->redirectToExternalLogin();
184
        }
185
186
        // Get redirect url
187
        $controller = $this->getResponseController(_t(__CLASS__.'.SUCCESS', 'Success'));
188
        $backURLs = array(
189
            $this->getRequest()->requestVar('BackURL'),
190
            Session::get('BackURL'),
191
            Director::absoluteURL(AdminRootController::config()->get('url_base'), true),
192
        );
193
        $backURL = null;
194
        foreach ($backURLs as $backURL) {
195
            if ($backURL && Director::is_site_url($backURL)) {
196
                break;
197
            }
198
        }
199
200
        // Show login
201
        $controller = $controller->customise(array(
202
            'Content' => DBField::create_field(DBHTMLText::class, _t(
203
                __CLASS__.'.SUCCESSCONTENT',
204
                '<p>Login success. If you are not automatically redirected '.
205
                '<a target="_top" href="{link}">click here</a></p>',
206
                'Login message displayed in the cms popup once a user has re-authenticated themselves',
207
                array('link' => Convert::raw2att($backURL))
208
            ))
209
        ));
210
211
        return $controller->renderWith($this->getTemplatesFor('success'));
212
    }
213
}
214