ConsentController::getconsent()   F
last analyzed

Complexity

Conditions 28
Paths 1334

Size

Total Lines 143
Code Lines 91

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 28
eloc 91
c 1
b 0
f 0
nc 1334
nop 1
dl 0
loc 143
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\Module\consent\Controller;
6
7
use Exception;
8
use SimpleSAML\Auth;
9
use SimpleSAML\Configuration;
10
use SimpleSAML\Error;
11
use SimpleSAML\HTTP\RunnableResponse;
12
use SimpleSAML\IdP;
13
use SimpleSAML\Logger;
14
use SimpleSAML\Module;
15
use SimpleSAML\Session;
16
use SimpleSAML\Stats;
17
use SimpleSAML\XHTML\Template;
18
use Symfony\Component\HttpFoundation\Request;
19
20
/**
21
 * Controller class for the consent module.
22
 *
23
 * This class serves the consent views available in the module.
24
 *
25
 * @package SimpleSAML\Module\consent
26
 */
27
class ConsentController
28
{
29
    /** @var \SimpleSAML\Configuration */
30
    protected $config;
31
32
    /** @var \SimpleSAML\Session */
33
    protected $session;
34
35
    /**
36
     * @var \SimpleSAML\Auth\State|string
37
     * @psalm-var \SimpleSAML\Auth\State|class-string
38
     */
39
    protected $authState = Auth\State::class;
40
41
    /**
42
     * @var \SimpleSAML\Logger|string
43
     * @psalm-var \SimpleSAML\Logger|class-string
44
     */
45
    protected $logger = Logger::class;
46
47
48
    /**
49
     * ConsentController constructor.
50
     *
51
     * @param \SimpleSAML\Configuration $config The configuration to use.
52
     * @param \SimpleSAML\Session $session The current user session.
53
     */
54
    public function __construct(Configuration $config, Session $session)
55
    {
56
        $this->config = $config;
57
        $this->session = $session;
58
    }
59
60
61
    /**
62
     * Inject the \SimpleSAML\Auth\State dependency.
63
     *
64
     * @param \SimpleSAML\Auth\State $authState
65
     */
66
    public function setAuthState(Auth\State $authState): void
67
    {
68
        $this->authState = $authState;
69
    }
70
71
72
    /**
73
     * Inject the \SimpleSAML\Logger dependency.
74
     *
75
     * @param \SimpleSAML\Logger $logger
76
     */
77
    public function setLogger(Logger $logger): void
78
    {
79
        $this->logger = $logger;
80
    }
81
82
83
    /**
84
     * Display consent form.
85
     *
86
     * @param \Symfony\Component\HttpFoundation\Request $request The current request.
87
     *
88
     * @return \SimpleSAML\XHTML\Template|\SimpleSAML\HTTP\RunnableResponse
89
     */
90
    public function getconsent(Request $request)
91
    {
92
        $this->logger::info('Consent - getconsent: Accessing consent interface');
93
94
        $stateId = $request->query->get('StateId');
95
        if ($stateId === null) {
96
            throw new Error\BadRequest('Missing required StateId query parameter.');
97
        }
98
99
        $state = $this->authState::loadState($stateId, 'consent:request');
100
101
        if (is_null($state)) {
102
            throw new Error\NoState();
103
        } elseif (array_key_exists('core:SP', $state)) {
104
            $spentityid = $state['core:SP'];
105
        } elseif (array_key_exists('saml:sp:State', $state)) {
106
            $spentityid = $state['saml:sp:State']['core:SP'];
107
        } else {
108
            $spentityid = 'UNKNOWN';
109
        }
110
111
        // The user has pressed the yes-button
112
        if ($request->query->get('yes') !== null) {
113
            if ($request->query->get('saveconsent') !== null) {
114
                $this->logger::stats('consentResponse remember');
115
            } else {
116
                $this->logger::stats('consentResponse rememberNot');
117
            }
118
119
            $statsInfo = [
120
                'remember' => $request->query->get('saveconsent'),
121
            ];
122
            if (isset($state['Destination']['entityid'])) {
123
                $statsInfo['spEntityID'] = $state['Destination']['entityid'];
124
            }
125
            Stats::log('consent:accept', $statsInfo);
126
127
            if (
128
                array_key_exists('consent:store', $state)
129
                && $request->query->get('saveconsent') === '1'
130
            ) {
131
                // Save consent
132
                $store = $state['consent:store'];
133
                $userId = $state['consent:store.userId'];
134
                $targetedId = $state['consent:store.destination'];
135
                $attributeSet = $state['consent:store.attributeSet'];
136
137
                $this->logger::debug(
138
                    'Consent - saveConsent() : [' . $userId . '|' . $targetedId . '|' . $attributeSet . ']',
139
                );
140
                try {
141
                    $store->saveConsent($userId, $targetedId, $attributeSet);
142
                } catch (Exception $e) {
143
                    $this->logger::error('Consent: Error writing to storage: ' . $e->getMessage());
144
                }
145
            }
146
147
            return new RunnableResponse([Auth\ProcessingChain::class, 'resumeProcessing'], [$state]);
148
        }
149
150
        // Prepare attributes for presentation
151
        $attributes = $state['Attributes'];
152
        $noconsentattributes = $state['consent:noconsentattributes'];
153
154
        // Remove attributes that do not require consent
155
        foreach ($attributes as $attrkey => $attrval) {
156
            if (in_array($attrkey, $noconsentattributes, true)) {
157
                unset($attributes[$attrkey]);
158
            }
159
        }
160
        $para = [
161
            'attributes' => &$attributes,
162
        ];
163
164
        // Reorder attributes according to attributepresentation hooks
165
        Module::callHooks('attributepresentation', $para);
166
167
        // Unset the values for attributes that need to be hidden
168
        if (array_key_exists('consent:hiddenAttributes', $state)) {
169
            foreach ($state['consent:hiddenAttributes'] as $hidden) {
170
                if (array_key_exists($hidden, $attributes)) {
171
                    $attributes[$hidden] = null;
172
                }
173
            }
174
        }
175
176
        // Make, populate and layout consent form
177
        $t = new Template($this->config, 'consent:consentform.twig');
178
        $l = $t->getLocalization();
179
        $l->addAttributeDomains();
180
        $t->data['attributes'] = $attributes;
181
        $t->data['checked'] = $state['consent:checked'];
182
        $t->data['stateId'] = $stateId;
183
        $t->data['source'] = $state['Source'];
184
        $t->data['destination'] = $state['Destination'];
185
186
        if (isset($state['Destination']['description'])) {
187
            $t->data['descr_purpose'] = $state['Destination']['description'];
188
        } elseif (isset($state['Destination']['UIInfo']['Description'])) {
189
            $t->data['descr_purpose'] = $state['Destination']['UIInfo']['Description'];
190
        }
191
192
        // Fetch privacy policy
193
        if (
194
            array_key_exists('UIInfo', $state['Destination']) &&
195
            array_key_exists('PrivacyStatementURL', $state['Destination']['UIInfo']) &&
196
            (!empty($state['Destination']['UIInfo']['PrivacyStatementURL']))
197
        ) {
198
            $privacypolicy = reset($state['Destination']['UIInfo']['PrivacyStatementURL']);
199
        } elseif (
200
            array_key_exists('UIInfo', $state['Source']) &&
201
            array_key_exists('PrivacyStatementURL', $state['Source']['UIInfo']) &&
202
            (!empty($state['Source']['UIInfo']['PrivacyStatementURL']))
203
        ) {
204
            $privacypolicy = reset($state['Source']['UIInfo']['PrivacyStatementURL']);
205
        } else {
206
            $privacypolicy = false;
207
        }
208
        if ($privacypolicy !== false) {
209
            $privacypolicy = str_replace(
210
                '%SPENTITYID%',
211
                urlencode($spentityid),
212
                $privacypolicy,
213
            );
214
        }
215
        $t->data['sppp'] = $privacypolicy;
216
217
        // Set focus element
218
        switch ($state['consent:focus']) {
219
            case 'yes':
220
                $t->data['autofocus'] = 'yesbutton';
221
                break;
222
            case 'no':
223
                $t->data['autofocus'] = 'nobutton';
224
                break;
225
            case null:
226
            default:
227
                break;
228
        }
229
230
        $t->data['usestorage'] = array_key_exists('consent:store', $state);
231
232
        return $t;
233
    }
234
235
236
    /**
237
     * @param \Symfony\Component\HttpFoundation\Request $request The current request.
238
     *
239
     * @return \SimpleSAML\XHTML\Template
240
     */
241
    public function noconsent(Request $request): Template
242
    {
243
        $stateId = $request->query->get('StateId');
244
        if ($stateId === null) {
245
            throw new Error\BadRequest('Missing required StateId query parameter.');
246
        }
247
248
        $state = $this->authState::loadState($stateId, 'consent:request');
249
        if (is_null($state)) {
250
            throw new Error\NoState();
251
        }
252
253
        $resumeFrom = Module::getModuleURL(
254
            'consent/getconsent',
255
            ['StateId' => $stateId],
256
        );
257
258
        $logoutLink = Module::getModuleURL(
259
            'consent/logout',
260
            ['StateId' => $stateId],
261
        );
262
263
        $aboutService = null;
264
        if (!isset($state['consent:showNoConsentAboutService']) || $state['consent:showNoConsentAboutService']) {
265
            if (isset($state['Destination']['UIInfo']['InformationURL'])) {
266
                $aboutService = reset($state['Destination']['UIInfo']['InformationURL']);
267
            }
268
        }
269
270
        $statsInfo = [];
271
        if (isset($state['Destination']['entityid'])) {
272
            $statsInfo['spEntityID'] = $state['Destination']['entityid'];
273
        }
274
        Stats::log('consent:reject', $statsInfo);
275
276
        $t = new Template($this->config, 'consent:noconsent.twig');
277
        $t->data['dstMetadata'] = $state['Destination'];
278
        $t->data['resumeFrom'] = $resumeFrom;
279
        $t->data['aboutService'] = $aboutService;
280
        $t->data['logoutLink'] = $logoutLink;
281
        return $t;
282
    }
283
284
285
    /**
286
     * @param \Symfony\Component\HttpFoundation\Request $request The current request.
287
     *
288
     * @return \SimpleSAML\HTTP\RunnableResponse
289
     */
290
    public function logout(Request $request): RunnableResponse
291
    {
292
        $stateId = $request->query->get('StateId', null);
293
        if ($stateId === null) {
294
            throw new Error\BadRequest('Missing required StateId query parameter.');
295
        }
296
297
        $state = $this->authState::loadState($stateId, 'consent:request');
298
        if (is_null($state)) {
299
            throw new Error\NoState();
300
        }
301
        $state['Responder'] = ['\SimpleSAML\Module\consent\Logout', 'postLogout'];
302
303
        $idp = IdP::getByState($state);
304
        return new RunnableResponse([$idp, 'handleLogoutRequest'], [&$state, $stateId]);
305
    }
306
307
308
    /**
309
     * @return \SimpleSAML\XHTML\Template
310
     */
311
    public function logoutcompleted(): Template
312
    {
313
        return new Template($this->config, 'consent:logout_completed.twig');
314
    }
315
}
316