Passed
Push — master ( de89ff...d6415e )
by Tim
08:02 queued 02:23
created

driveProcessingChain()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 62
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 4
eloc 23
c 4
b 0
f 0
nc 6
nop 8
dl 0
loc 62
rs 9.552

How to fix   Long Method    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/*
4
 * consentAdmin - Consent administration module
5
 *
6
 * This module enables the user to add and remove consents given for a given
7
 * Service Provider.
8
 *
9
 * The module relies on methods and functions from the Consent module and can
10
 * not be user without it.
11
 *
12
 * Author: Mads Freek <[email protected]>, Jacob Christiansen <[email protected]>
13
 */
14
15
/**
16
 * Runs the processing chain and ignores all filter which have user
17
 * interaction.
18
 *
19
 * @param array $idp_metadata
20
 * @param string $source
21
 * @param array $sp_metadata
22
 * @param string $sp_entityid
23
 * @param array $attributes
24
 * @param string $userid
25
 * @param bool $hashAttributes
26
 * @param array $excludeAttributes
27
 * @return array
28
 */
29
function driveProcessingChain(
30
    array $idp_metadata,
31
    string $source,
32
    array $sp_metadata,
33
    string $sp_entityid,
34
    array $attributes,
35
    string $userid,
36
    bool $hashAttributes = false,
37
    array $excludeAttributes = []
38
): array {
39
    /*
40
     * Create a new processing chain
41
     */
42
    $pc = new \SimpleSAML\Auth\ProcessingChain($idp_metadata, $sp_metadata, 'idp');
43
44
    /*
45
     * Construct the state.
46
     * REMEMBER: Do not set Return URL if you are calling processStatePassive
47
     */
48
    $authProcState = [
49
        'Attributes'  => $attributes,
50
        'Destination' => $sp_metadata,
51
        'SPMetadata'  => $sp_metadata,
52
        'Source'      => $idp_metadata,
53
        'IdPMetadata' => $idp_metadata,
54
        'isPassive'   => true,
55
    ];
56
    /* we're being bridged, so add that info to the state */
57
    if (strpos($source, '-idp-remote|') !== false) {
58
        /** @var int $i */
59
        $i = strpos($source, '|');
60
        $authProcState['saml:sp:IdP'] = substr($source, $i + 1);
61
    }
62
63
    /*
64
     * Call processStatePAssive.
65
     * We are not interested in any user interaction, only modifications to the attributes
66
     */
67
    $pc->processStatePassive($authProcState);
68
69
    $attributes = $authProcState['Attributes'];
70
    // Remove attributes that do not require consent/should be excluded
71
    foreach ($attributes as $attrkey => $attrval) {
72
        if (in_array($attrkey, $excludeAttributes)) {
73
            unset($attributes[$attrkey]);
74
        }
75
    }
76
77
    /*
78
     * Generate identifiers and hashes
79
     */
80
    $destination = $sp_metadata['metadata-set'] . '|' . $sp_entityid;
81
82
    $targeted_id = \SimpleSAML\Module\consent\Auth\Process\Consent::getTargetedID($userid, $source, $destination);
83
    $attribute_hash = \SimpleSAML\Module\consent\Auth\Process\Consent::getAttributeHash($attributes, $hashAttributes);
84
85
    \SimpleSAML\Logger::info('consentAdmin: user: ' . $userid);
86
    \SimpleSAML\Logger::info('consentAdmin: target: ' . $targeted_id);
87
    \SimpleSAML\Logger::info('consentAdmin: attribute: ' . $attribute_hash);
88
89
    // Return values
90
    return [$targeted_id, $attribute_hash, $attributes];
91
}
92
93
// Get config object
94
$config = \SimpleSAML\Configuration::getInstance();
95
$cA_config = \SimpleSAML\Configuration::getConfig('module_consentAdmin.php');
96
$authority = $cA_config->getValue('authority');
97
98
$as = new \SimpleSAML\Auth\Simple($authority);
0 ignored issues
show
Bug introduced by
It seems like $authority can also be of type null; however, parameter $authSource of SimpleSAML\Auth\Simple::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

98
$as = new \SimpleSAML\Auth\Simple(/** @scrutinizer ignore-type */ $authority);
Loading history...
99
100
// If request is a logout request
101
if (array_key_exists('logout', $_REQUEST)) {
102
    $returnURL = $cA_config->getValue('returnURL');
103
    $as->logout($returnURL);
104
}
105
106
$hashAttributes = $cA_config->getValue('attributes.hash');
107
108
$excludeAttributes = $cA_config->getValue('attributes.exclude', []);
109
110
// Check if valid local session exists
111
$as->requireAuth();
112
113
// Get released attributes
114
$attributes = $as->getAttributes();
115
116
// Get metadata storage handler
117
$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
118
119
/*
120
 * Get IdP id and metadata
121
 */
122
123
$idp_entityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
124
$idp_metadata = $metadata->getMetaData($idp_entityid, 'saml20-idp-hosted');
125
126
// Calc correct source
127
if ($as->getAuthData('saml:sp:IdP') !== null) {
128
    // from a remote idp (as bridge)
129
    $source = 'saml20-idp-remote|' . $as->getAuthData('saml:sp:IdP');
130
} else {
131
    // from the local idp
132
    $source = $idp_metadata['metadata-set'] . '|' . $idp_entityid;
133
}
134
135
// Get user ID
136
if (isset($idp_metadata['userid.attribute']) && is_string($idp_metadata['userid.attribute'])) {
137
    $userid_attributename = $idp_metadata['userid.attribute'];
138
} else {
139
    $userid_attributename = 'eduPersonPrincipalName';
140
}
141
142
$userids = $attributes[$userid_attributename];
143
144
if (empty($userids)) {
145
    throw new \Exception('Could not generate useridentifier for storing consent. Attribute [' .
146
        $userid_attributename . '] was not available.');
147
}
148
149
$userid = $userids[0];
150
151
// Get all SP metadata
152
$all_sp_metadata = $metadata->getList('saml20-sp-remote');
153
154
// Parse action, if any
155
$action = null;
156
$sp_entityid = null;
157
if (!empty($_GET['cv'])) {
158
    $sp_entityid = $_GET['cv'];
159
}
160
if (!empty($_GET['action'])) {
161
    $action = $_GET["action"];
162
}
163
164
\SimpleSAML\Logger::critical('consentAdmin: sp: ' . $sp_entityid . ' action: ' . $action);
165
166
// Remove services, whitch have consent disabled
167
if (isset($idp_metadata['consent.disable'])) {
168
    foreach ($idp_metadata['consent.disable'] as $disable) {
169
        if (array_key_exists($disable, $all_sp_metadata)) {
170
            unset($all_sp_metadata[$disable]);
171
        }
172
    }
173
}
174
175
\SimpleSAML\Logger::info('consentAdmin: ' . $idp_entityid);
176
177
// Parse consent config
178
$consent_storage = \SimpleSAML\Module\consent\Store::parseStoreConfig($cA_config->getValue('consentadmin'));
179
180
// Calc correct user ID hash
181
$hashed_user_id = \SimpleSAML\Module\consent\Auth\Process\Consent::getHashedUserID($userid, $source);
182
183
// If a checkbox have been clicked
184
if ($action !== null && $sp_entityid !== null) {
185
    // init template to enable translation of status messages
186
    $template = new \SimpleSAML\XHTML\Template(
187
        $config,
188
        'consentAdmin:consentadminajax.twig',
189
        'consentAdmin:consentadmin'
190
    );
191
    $translator = $template->getTranslator();
192
193
    // Get SP metadata
194
    $sp_metadata = $metadata->getMetaData($sp_entityid, 'saml20-sp-remote');
195
196
    // Run AuthProc filters
197
    list($targeted_id, $attribute_hash, $attributes_new) = driveProcessingChain(
198
        $idp_metadata,
199
        $source,
200
        $sp_metadata,
201
        $sp_entityid,
202
        $attributes,
203
        $userid,
204
        $hashAttributes,
0 ignored issues
show
Bug introduced by
It seems like $hashAttributes can also be of type null; however, parameter $hashAttributes of driveProcessingChain() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

204
        /** @scrutinizer ignore-type */ $hashAttributes,
Loading history...
205
        $excludeAttributes
206
    );
207
208
    // Add a consent (or update if attributes have changed and old consent for SP and IdP exists)
209
    if ($action == 'true') {
210
        $isStored = $consent_storage->saveConsent($hashed_user_id, $targeted_id, $attribute_hash);
211
    } else {
212
        if ($action == 'false') {
213
            // Got consent, so this is a request to remove it
214
            $rowcount = $consent_storage->deleteConsent($hashed_user_id, $targeted_id);
215
            if ($rowcount > 0) {
216
                $isStored = false;
217
            } else {
218
                throw new \Exception("Unknown action (should not happen)");
219
            }
220
        } else {
221
            \SimpleSAML\Logger::info('consentAdmin: unknown action');
222
            $isStored = null;
223
        }
224
    }
225
    $template->data['isStored'] = $isStored;
226
    $template->send();
227
    exit;
228
}
229
230
// Get all consents for user
231
$user_consent_list = $consent_storage->getConsents($hashed_user_id);
232
233
// Parse list of consents
234
$user_consent = [];
235
foreach ($user_consent_list as $c) {
236
    $user_consent[$c[0]] = $c[1];
237
}
238
239
$template_sp_content = [];
240
241
// Init template
242
$template = new \SimpleSAML\XHTML\Template($config, 'consentAdmin:consentadmin.twig', 'consentAdmin:consentadmin');
243
$translator = $template->getTranslator();
244
$translator->includeLanguageFile('attributes'); // attribute listings translated by this dictionary
245
246
$sp_empty_description = $translator->getTag('sp_empty_description');
247
$sp_list = [];
248
249
// Process consents for all SP
250
foreach ($all_sp_metadata as $sp_entityid => $sp_values) {
251
    // Get metadata for SP
252
    $sp_metadata = $metadata->getMetaData($sp_entityid, 'saml20-sp-remote');
253
254
    // Run attribute filters
255
    list($targeted_id, $attribute_hash, $attributes_new) = driveProcessingChain(
256
        $idp_metadata,
257
        $source,
258
        $sp_metadata,
259
        $sp_entityid,
260
        $attributes,
261
        $userid,
262
        $hashAttributes,
263
        $excludeAttributes
264
    );
265
266
    // Translate attribute-names
267
    foreach ($attributes_new as $orig_name => $value) {
268
        if (isset($template->data['attribute_' . htmlspecialchars(strtolower($orig_name))])) {
269
            $old_name = $template->data['attribute_' . htmlspecialchars(strtolower($orig_name))];
270
        }
271
        $name = $translator->getAttributeTranslation(strtolower($orig_name)); // translate
272
273
        $attributes_new[$name] = $value;
274
        unset($attributes_new[$orig_name]);
275
    }
276
277
    // Check if consent exists
278
    if (array_key_exists($targeted_id, $user_consent)) {
279
        $sp_status = "changed";
280
        \SimpleSAML\Logger::info('consentAdmin: changed');
281
        // Check if consent is valid. (Possible that attributes has changed)
282
        if ($user_consent[$targeted_id] == $attribute_hash) {
283
            \SimpleSAML\Logger::info('consentAdmin: ok');
284
            $sp_status = "ok";
285
        }
286
        // Consent does not exist
287
    } else {
288
        SimpleSAML\Logger::info('consentAdmin: none');
289
        $sp_status = "none";
290
    }
291
292
    // Set name of SP
293
    if (isset($sp_values['name']) && is_array($sp_values['name'])) {
294
        $sp_name = $sp_metadata['name'];
295
    } else {
296
        if (isset($sp_values['name']) && is_string($sp_values['name'])) {
297
            $sp_name = $sp_metadata['name'];
298
        } elseif (isset($sp_values['OrganizationDisplayName']) && is_array($sp_values['OrganizationDisplayName'])) {
299
            $sp_name = $sp_metadata['OrganizationDisplayName'];
300
        } else {
301
            $sp_name = $sp_entityid;
302
        }
303
    }
304
305
    // Set description of SP
306
    if (empty($sp_metadata['description']) || !is_array($sp_metadata['description'])) {
307
        $sp_description = $sp_empty_description;
308
    } else {
309
        $sp_description = $sp_metadata['description'];
310
    }
311
312
    // Add a URL to the service if present in metadata
313
    $sp_service_url = isset($sp_metadata['ServiceURL']) ? $sp_metadata['ServiceURL'] : null;
314
315
    // Translate SP name and description
316
    $translator->includeInlineTranslation('spname', $sp_name);
317
    $translator->includeInlineTranslation('spdescription', $sp_description);
318
319
    $sp_name = $translator->getPreferredTranslation($translator->getTag('spname') ?? []);
320
    $sp_description = $translator->getPreferredTranslation($translator->getTag('spdescription') ?? []);
321
322
    // Fill out array for the template
323
    $sp_list[$sp_entityid] = [
324
        'spentityid'       => $sp_entityid,
325
        'name'             => $sp_name,
326
        'description'      => $sp_description,
327
        'consentStatus'    => $sp_status,
328
        'consentValue'     => $sp_entityid,
329
        'attributes_by_sp' => $attributes_new,
330
        'serviceurl'       => $sp_service_url,
331
    ];
332
}
333
334
$template->data['header'] = 'Consent Administration';
335
$template->data['spList'] = $sp_list;
336
$template->data['showDescription'] = $cA_config->getValue('showDescription');
337
$template->send();
338