Total Complexity | 45 |
Total Lines | 385 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like Consent often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Consent, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
20 | class Consent extends \SimpleSAML\Auth\ProcessingFilter |
||
21 | { |
||
22 | /** |
||
23 | * Button to receive focus |
||
24 | * |
||
25 | * @var string|null |
||
26 | */ |
||
27 | private $focus = null; |
||
28 | |||
29 | /** |
||
30 | * Include attribute values |
||
31 | * |
||
32 | * @var bool |
||
33 | */ |
||
34 | private $includeValues = false; |
||
35 | |||
36 | /** |
||
37 | * Check remember consent |
||
38 | * |
||
39 | * @var bool |
||
40 | */ |
||
41 | private $checked = false; |
||
42 | |||
43 | /** |
||
44 | * Consent backend storage configuration |
||
45 | * |
||
46 | * @var \SimpleSAML\Module\consent\Store|null |
||
47 | */ |
||
48 | private $store = null; |
||
49 | |||
50 | /** |
||
51 | * Attributes where the value should be hidden |
||
52 | * |
||
53 | * @var array |
||
54 | */ |
||
55 | private $hiddenAttributes = []; |
||
56 | |||
57 | /** |
||
58 | * Attributes which should not require consent |
||
59 | * |
||
60 | * @var array |
||
61 | */ |
||
62 | private $noconsentattributes = []; |
||
63 | |||
64 | /** |
||
65 | * Whether we should show the "about service"-link on the no consent page. |
||
66 | * |
||
67 | * @var bool |
||
68 | */ |
||
69 | private $showNoConsentAboutService = true; |
||
70 | |||
71 | |||
72 | /** |
||
73 | * Initialize consent filter. |
||
74 | * |
||
75 | * Validates and parses the configuration. |
||
76 | * |
||
77 | * @param array $config Configuration information. |
||
78 | * @param mixed $reserved For future use. |
||
79 | * |
||
80 | * @throws \SimpleSAML\Error\Exception if the configuration is not valid. |
||
81 | */ |
||
82 | public function __construct(array $config, array $reserved) |
||
83 | { |
||
84 | parent::__construct($config, $reserved); |
||
85 | |||
86 | if (array_key_exists('includeValues', $config)) { |
||
87 | if (!is_bool($config['includeValues'])) { |
||
88 | throw new \SimpleSAML\Error\Exception( |
||
89 | 'Consent: includeValues must be boolean. ' . |
||
90 | var_export($config['includeValues'], true) . ' given.' |
||
91 | ); |
||
92 | } |
||
93 | $this->includeValues = $config['includeValues']; |
||
94 | } |
||
95 | |||
96 | if (array_key_exists('checked', $config)) { |
||
97 | if (!is_bool($config['checked'])) { |
||
98 | throw new \SimpleSAML\Error\Exception( |
||
99 | 'Consent: checked must be boolean. ' . |
||
100 | var_export($config['checked'], true) . ' given.' |
||
101 | ); |
||
102 | } |
||
103 | $this->checked = $config['checked']; |
||
104 | } |
||
105 | |||
106 | if (array_key_exists('focus', $config)) { |
||
107 | if (!in_array($config['focus'], ['yes', 'no'], true)) { |
||
108 | throw new \SimpleSAML\Error\Exception( |
||
109 | 'Consent: focus must be a string with values `yes` or `no`. ' . |
||
110 | var_export($config['focus'], true) . ' given.' |
||
111 | ); |
||
112 | } |
||
113 | $this->focus = $config['focus']; |
||
114 | } |
||
115 | |||
116 | if (array_key_exists('hiddenAttributes', $config)) { |
||
117 | if (!is_array($config['hiddenAttributes'])) { |
||
118 | throw new \SimpleSAML\Error\Exception( |
||
119 | 'Consent: hiddenAttributes must be an array. ' . |
||
120 | var_export($config['hiddenAttributes'], true) . ' given.' |
||
121 | ); |
||
122 | } |
||
123 | $this->hiddenAttributes = $config['hiddenAttributes']; |
||
124 | } |
||
125 | |||
126 | if (array_key_exists('attributes.exclude', $config)) { |
||
127 | if (!is_array($config['attributes.exclude'])) { |
||
128 | throw new \SimpleSAML\Error\Exception( |
||
129 | 'Consent: attributes.exclude must be an array. ' . |
||
130 | var_export($config['attributes.exclude'], true) . ' given.' |
||
131 | ); |
||
132 | } |
||
133 | $this->noconsentattributes = $config['attributes.exclude']; |
||
134 | } elseif (array_key_exists('noconsentattributes', $config)) { |
||
135 | Logger::warning("The 'noconsentattributes' option has been deprecated in favour of 'attributes.exclude'."); |
||
136 | if (!is_array($config['noconsentattributes'])) { |
||
137 | throw new \SimpleSAML\Error\Exception( |
||
138 | 'Consent: noconsentattributes must be an array. ' . |
||
139 | var_export($config['noconsentattributes'], true) . ' given.' |
||
140 | ); |
||
141 | } |
||
142 | $this->noconsentattributes = $config['noconsentattributes']; |
||
143 | } |
||
144 | |||
145 | if (array_key_exists('store', $config)) { |
||
146 | try { |
||
147 | $this->store = \SimpleSAML\Module\consent\Store::parseStoreConfig($config['store']); |
||
148 | } catch (\Exception $e) { |
||
149 | Logger::error( |
||
150 | 'Consent: Could not create consent storage: ' . |
||
151 | $e->getMessage() |
||
152 | ); |
||
153 | } |
||
154 | } |
||
155 | |||
156 | if (array_key_exists('showNoConsentAboutService', $config)) { |
||
157 | if (!is_bool($config['showNoConsentAboutService'])) { |
||
158 | throw new \SimpleSAML\Error\Exception('Consent: showNoConsentAboutService must be a boolean.'); |
||
159 | } |
||
160 | $this->showNoConsentAboutService = $config['showNoConsentAboutService']; |
||
161 | } |
||
162 | } |
||
163 | |||
164 | |||
165 | /** |
||
166 | * Helper function to check whether consent is disabled. |
||
167 | * |
||
168 | * @param mixed $option The consent.disable option. Either an array of array, an array or a boolean. |
||
169 | * @param string $entityId The entityID of the SP/IdP. |
||
170 | * |
||
171 | * @return boolean True if disabled, false if not. |
||
172 | */ |
||
173 | private static function checkDisable($option, string $entityId): bool |
||
174 | { |
||
175 | if (is_array($option)) { |
||
176 | // Check if consent.disable array has one element that is an array |
||
177 | if (count($option) === count($option, COUNT_RECURSIVE)) { |
||
178 | // Array is not multidimensional. Simple in_array search suffices |
||
179 | return in_array($entityId, $option, true); |
||
180 | } |
||
181 | |||
182 | // Array contains at least one element that is an array, verify both possibilities |
||
183 | if (in_array($entityId, $option, true)) { |
||
184 | return true; |
||
185 | } |
||
186 | |||
187 | // Search in multidimensional arrays |
||
188 | foreach ($option as $optionToTest) { |
||
189 | if (!is_array($optionToTest)) { |
||
190 | continue; // bad option |
||
191 | } |
||
192 | |||
193 | if (!array_key_exists('type', $optionToTest)) { |
||
194 | continue; // option has no type |
||
195 | } |
||
196 | |||
197 | // Option has a type - switch processing depending on type value : |
||
198 | if ($optionToTest['type'] === 'regex') { |
||
199 | // regex-based consent disabling |
||
200 | |||
201 | if (!array_key_exists('pattern', $optionToTest)) { |
||
202 | continue; // no pattern defined |
||
203 | } |
||
204 | |||
205 | if (preg_match($optionToTest['pattern'], $entityId) === 1) { |
||
206 | return true; |
||
207 | } |
||
208 | } else { |
||
209 | // option type is not supported |
||
210 | continue; |
||
211 | } |
||
212 | } // end foreach |
||
213 | |||
214 | // Base case : no match |
||
215 | return false; |
||
216 | } else { |
||
217 | return (bool) $option; |
||
218 | } |
||
219 | } |
||
220 | |||
221 | |||
222 | /** |
||
223 | * Process a authentication response |
||
224 | * |
||
225 | * This function saves the state, and redirects the user to the page where the user can authorize the release of |
||
226 | * the attributes. If storage is used and the consent has already been given the user is passed on. |
||
227 | * |
||
228 | * @param array &$state The state of the response. |
||
229 | * |
||
230 | * @return void |
||
231 | * |
||
232 | * @throws \SimpleSAML\Error\NoPassive if the request was passive and consent is needed. |
||
233 | */ |
||
234 | public function process(array &$state): void |
||
348 | } |
||
349 | |||
350 | |||
351 | /** |
||
352 | * Generate a unique identifier of the user. |
||
353 | * |
||
354 | * @param string $userid The user id. |
||
355 | * @param string $source The source id. |
||
356 | * |
||
357 | * @return string SHA1 of the user id, source id and salt. |
||
358 | */ |
||
359 | public static function getHashedUserID(string $userid, string $source): string |
||
362 | } |
||
363 | |||
364 | |||
365 | /** |
||
366 | * Generate a unique targeted identifier. |
||
367 | * |
||
368 | * @param string $userid The user id. |
||
369 | * @param string $source The source id. |
||
370 | * @param string $destination The destination id. |
||
371 | * |
||
372 | * @return string SHA1 of the user id, source id, destination id and salt. |
||
373 | */ |
||
374 | public static function getTargetedID(string $userid, string $source, string $destination): string |
||
377 | } |
||
378 | |||
379 | |||
380 | /** |
||
381 | * Generate unique identifier for attributes. |
||
382 | * |
||
383 | * Create a hash value for the attributes that changes when attributes are added or removed. If the attribute |
||
384 | * values are included in the hash, the hash will change if the values change. |
||
385 | * |
||
386 | * @param array $attributes The attributes. |
||
387 | * @param bool $includeValues Whether or not to include the attribute value in the generation of the hash. |
||
388 | * |
||
389 | * @return string SHA1 of the user id, source id, destination id and salt. |
||
390 | */ |
||
391 | public static function getAttributeHash(array $attributes, bool $includeValues = false): string |
||
405 | } |
||
406 | } |
||
407 |