Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like AuthnRequest 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
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 AuthnRequest, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
15 | class AuthnRequest extends Request |
||
16 | { |
||
17 | /** |
||
18 | * The options for what type of name identifier should be returned. |
||
19 | * |
||
20 | * @var array |
||
21 | */ |
||
22 | private $nameIdPolicy; |
||
23 | |||
24 | /** |
||
25 | * Whether the Identity Provider must authenticate the user again. |
||
26 | * |
||
27 | * @var bool |
||
28 | */ |
||
29 | private $forceAuthn; |
||
30 | |||
31 | |||
32 | /** |
||
33 | * Optional ProviderID attribute |
||
34 | * |
||
35 | * @var string |
||
36 | */ |
||
37 | private $ProviderName; |
||
38 | |||
39 | |||
40 | /** |
||
41 | * Set to true if this request is passive. |
||
42 | * |
||
43 | * @var bool. |
||
44 | */ |
||
45 | private $isPassive; |
||
46 | |||
47 | /** |
||
48 | * The list of providerIDs in this request's scoping element |
||
49 | * |
||
50 | * @var array |
||
51 | */ |
||
52 | private $IDPList = []; |
||
53 | |||
54 | /** |
||
55 | * The ProxyCount in this request's scoping element |
||
56 | * |
||
57 | * @var int |
||
58 | */ |
||
59 | private $ProxyCount = null; |
||
60 | |||
61 | /** |
||
62 | * The RequesterID list in this request's scoping element |
||
63 | * |
||
64 | * @var array |
||
65 | */ |
||
66 | |||
67 | private $RequesterID = []; |
||
68 | |||
69 | /** |
||
70 | * The URL of the asertion consumer service where the response should be delivered. |
||
71 | * |
||
72 | * @var string|null |
||
73 | */ |
||
74 | private $assertionConsumerServiceURL; |
||
75 | |||
76 | |||
77 | /** |
||
78 | * What binding should be used when sending the response. |
||
79 | * |
||
80 | * @var string|null |
||
81 | */ |
||
82 | private $protocolBinding; |
||
83 | |||
84 | |||
85 | /** |
||
86 | * The index of the AttributeConsumingService. |
||
87 | * |
||
88 | * @var int|null |
||
89 | */ |
||
90 | private $attributeConsumingServiceIndex; |
||
91 | |||
92 | /** |
||
93 | * The index of the AssertionConsumerService. |
||
94 | * |
||
95 | * @var int|null |
||
96 | */ |
||
97 | private $assertionConsumerServiceIndex; |
||
98 | |||
99 | |||
100 | /** |
||
101 | * What authentication context was requested. |
||
102 | * |
||
103 | * Array with the following elements. |
||
104 | * - AuthnContextClassRef (required) |
||
105 | * - Comparison (optinal) |
||
106 | * |
||
107 | * @var array |
||
108 | */ |
||
109 | private $requestedAuthnContext; |
||
110 | |||
111 | /** |
||
112 | * Audiences to send in the request. |
||
113 | * |
||
114 | * @var array |
||
115 | */ |
||
116 | private $audiences; |
||
117 | |||
118 | /** |
||
119 | * @var \SAML2\XML\saml\SubjectConfirmation[] |
||
120 | */ |
||
121 | private $subjectConfirmation = []; |
||
122 | |||
123 | /** |
||
124 | * @var string |
||
125 | */ |
||
126 | private $encryptedNameId; |
||
127 | |||
128 | /** |
||
129 | * @var \SAML2\XML\saml\NameID |
||
130 | */ |
||
131 | private $nameId; |
||
132 | |||
133 | /** |
||
134 | * Constructor for SAML 2 authentication request messages. |
||
135 | * |
||
136 | * @param \DOMElement|null $xml The input message. |
||
137 | * @throws \Exception |
||
138 | */ |
||
139 | public function __construct(\DOMElement $xml = null) |
||
180 | |||
181 | /** |
||
182 | * @param $xml |
||
183 | * |
||
184 | * @throws \Exception |
||
185 | */ |
||
186 | private function parseSubject(\DOMElement $xml) |
||
220 | |||
221 | /** |
||
222 | * @param \DOMElement $xml |
||
223 | * |
||
224 | * @throws \Exception |
||
225 | */ |
||
226 | protected function parseNameIdPolicy(\DOMElement $xml) |
||
244 | |||
245 | /** |
||
246 | * @param \DOMElement $xml |
||
247 | */ |
||
248 | protected function parseRequestedAuthnContext(\DOMElement $xml) |
||
273 | |||
274 | /** |
||
275 | * @param \DOMElement $xml |
||
276 | * |
||
277 | * @throws \Exception |
||
278 | */ |
||
279 | protected function parseScoping(\DOMElement $xml) |
||
305 | |||
306 | /** |
||
307 | * @param \DOMElement $xml |
||
308 | */ |
||
309 | protected function parseConditions(\DOMElement $xml) |
||
329 | |||
330 | /** |
||
331 | * Retrieve the NameIdPolicy. |
||
332 | * |
||
333 | * @see \SAML2\AuthnRequest::setNameIdPolicy() |
||
334 | * @return array The NameIdPolicy. |
||
335 | */ |
||
336 | public function getNameIdPolicy() |
||
340 | |||
341 | |||
342 | /** |
||
343 | * Set the NameIDPolicy. |
||
344 | * |
||
345 | * This function accepts an array with the following options: |
||
346 | * - 'Format' (string) |
||
347 | * - 'SPNameQualifier' (string) |
||
348 | * - 'AllowCreate' (bool) |
||
349 | * |
||
350 | * @param array $nameIdPolicy The NameIDPolicy. |
||
351 | */ |
||
352 | public function setNameIdPolicy(array $nameIdPolicy) |
||
366 | |||
367 | |||
368 | /** |
||
369 | * Retrieve the value of the ForceAuthn attribute. |
||
370 | * |
||
371 | * @return bool The ForceAuthn attribute. |
||
372 | */ |
||
373 | public function getForceAuthn() |
||
377 | |||
378 | |||
379 | /** |
||
380 | * Set the value of the ForceAuthn attribute. |
||
381 | * |
||
382 | * @param bool $forceAuthn The ForceAuthn attribute. |
||
383 | */ |
||
384 | public function setForceAuthn($forceAuthn) |
||
390 | |||
391 | |||
392 | /** |
||
393 | * Retrieve the value of the ProviderName attribute. |
||
394 | * |
||
395 | * @return string The ProviderName attribute. |
||
396 | */ |
||
397 | public function getProviderName() |
||
401 | |||
402 | |||
403 | /** |
||
404 | * Set the value of the ProviderName attribute. |
||
405 | * |
||
406 | * @param string $ProviderName The ProviderName attribute. |
||
407 | */ |
||
408 | public function setProviderName($ProviderName) |
||
414 | |||
415 | |||
416 | /** |
||
417 | * Retrieve the value of the IsPassive attribute. |
||
418 | * |
||
419 | * @return bool The IsPassive attribute. |
||
420 | */ |
||
421 | public function getIsPassive() |
||
425 | |||
426 | |||
427 | /** |
||
428 | * Set the value of the IsPassive attribute. |
||
429 | * |
||
430 | * @param bool $isPassive The IsPassive attribute. |
||
431 | */ |
||
432 | public function setIsPassive($isPassive) |
||
438 | |||
439 | /** |
||
440 | * Retrieve the audiences from the request. |
||
441 | * |
||
442 | * This may be null, in which case no audience is included. |
||
443 | * |
||
444 | * @return array|null The audiences. |
||
445 | */ |
||
446 | public function getAudiences() |
||
450 | |||
451 | /** |
||
452 | * Set the audiences to send in the request. |
||
453 | * |
||
454 | * This may be null, in which case no audience will be sent. |
||
455 | * |
||
456 | * @param array|null $audiences The audiences. |
||
457 | */ |
||
458 | public function setAudiences(array $audiences = null) |
||
462 | |||
463 | |||
464 | /** |
||
465 | * This function sets the scoping for the request. |
||
466 | * See Core 3.4.1.2 for the definition of scoping. |
||
467 | * Currently we support an IDPList of idpEntries. |
||
468 | * |
||
469 | * Each idpEntries consists of an array, containing |
||
470 | * keys (mapped to attributes) and corresponding values. |
||
471 | * Allowed attributes: Loc, Name, ProviderID. |
||
472 | * |
||
473 | * For backward compatibility, an idpEntries can also |
||
474 | * be a string instead of an array, where each string |
||
475 | * is mapped to the value of attribute ProviderID. |
||
476 | * |
||
477 | * @param array List of idpEntries to scope the request to. |
||
478 | */ |
||
479 | public function setIDPList(array $IDPList) |
||
483 | |||
484 | |||
485 | /** |
||
486 | * This function retrieves the list of providerIDs from this authentication request. |
||
487 | * Currently we only support a list of ipd ientity id's. |
||
488 | * @return array List of idp EntityIDs from the request |
||
489 | */ |
||
490 | public function getIDPList() |
||
494 | |||
495 | /** |
||
496 | * @param int $ProxyCount |
||
497 | */ |
||
498 | public function setProxyCount($ProxyCount) |
||
503 | |||
504 | /** |
||
505 | * @return int|null |
||
506 | */ |
||
507 | public function getProxyCount() |
||
511 | |||
512 | /** |
||
513 | * @param array $RequesterID |
||
514 | */ |
||
515 | public function setRequesterID(array $RequesterID) |
||
519 | |||
520 | /** |
||
521 | * @return array |
||
522 | */ |
||
523 | public function getRequesterID() |
||
527 | |||
528 | /** |
||
529 | * Retrieve the value of the AssertionConsumerServiceURL attribute. |
||
530 | * |
||
531 | * @return string|null The AssertionConsumerServiceURL attribute. |
||
532 | */ |
||
533 | public function getAssertionConsumerServiceURL() |
||
537 | |||
538 | /** |
||
539 | * Set the value of the AssertionConsumerServiceURL attribute. |
||
540 | * |
||
541 | * @param string|null $assertionConsumerServiceURL The AssertionConsumerServiceURL attribute. |
||
542 | */ |
||
543 | public function setAssertionConsumerServiceURL($assertionConsumerServiceURL) |
||
549 | |||
550 | /** |
||
551 | * Retrieve the value of the ProtocolBinding attribute. |
||
552 | * |
||
553 | * @return string|null The ProtocolBinding attribute. |
||
554 | */ |
||
555 | public function getProtocolBinding() |
||
559 | |||
560 | /** |
||
561 | * Set the value of the ProtocolBinding attribute. |
||
562 | * |
||
563 | * @param string $protocolBinding The ProtocolBinding attribute. |
||
564 | */ |
||
565 | public function setProtocolBinding($protocolBinding) |
||
571 | |||
572 | /** |
||
573 | * Retrieve the value of the AttributeConsumingServiceIndex attribute. |
||
574 | * |
||
575 | * @return int|null The AttributeConsumingServiceIndex attribute. |
||
576 | */ |
||
577 | public function getAttributeConsumingServiceIndex() |
||
581 | |||
582 | /** |
||
583 | * Set the value of the AttributeConsumingServiceIndex attribute. |
||
584 | * |
||
585 | * @param int|null $attributeConsumingServiceIndex The AttributeConsumingServiceIndex attribute. |
||
586 | */ |
||
587 | public function setAttributeConsumingServiceIndex($attributeConsumingServiceIndex) |
||
593 | |||
594 | /** |
||
595 | * Retrieve the value of the AssertionConsumerServiceIndex attribute. |
||
596 | * |
||
597 | * @return int|null The AssertionConsumerServiceIndex attribute. |
||
598 | */ |
||
599 | public function getAssertionConsumerServiceIndex() |
||
603 | |||
604 | /** |
||
605 | * Set the value of the AssertionConsumerServiceIndex attribute. |
||
606 | * |
||
607 | * @param int|null $assertionConsumerServiceIndex The AssertionConsumerServiceIndex attribute. |
||
608 | */ |
||
609 | public function setAssertionConsumerServiceIndex($assertionConsumerServiceIndex) |
||
615 | |||
616 | /** |
||
617 | * Retrieve the RequestedAuthnContext. |
||
618 | * |
||
619 | * @return array|null The RequestedAuthnContext. |
||
620 | */ |
||
621 | public function getRequestedAuthnContext() |
||
625 | |||
626 | /** |
||
627 | * Set the RequestedAuthnContext. |
||
628 | * |
||
629 | * @param array|null $requestedAuthnContext The RequestedAuthnContext. |
||
630 | */ |
||
631 | public function setRequestedAuthnContext($requestedAuthnContext) |
||
637 | |||
638 | /** |
||
639 | * Retrieve the NameId of the subject in the assertion. |
||
640 | * |
||
641 | * @return \SAML2\XML\saml\NameID|null The name identifier of the assertion. |
||
642 | * @throws \Exception |
||
643 | */ |
||
644 | public function getNameId() |
||
652 | |||
653 | /** |
||
654 | * Set the NameId of the subject in the assertion. |
||
655 | * |
||
656 | * @param \SAML2\XML\saml\NameID|null $nameId The name identifier of the assertion. |
||
657 | */ |
||
658 | View Code Duplication | public function setNameId($nameId) |
|
667 | |||
668 | /** |
||
669 | * Encrypt the NameID in the AuthnRequest. |
||
670 | * |
||
671 | * @param XMLSecurityKey $key The encryption key. |
||
672 | */ |
||
673 | View Code Duplication | public function encryptNameId(XMLSecurityKey $key) |
|
698 | |||
699 | /** |
||
700 | * Decrypt the NameId of the subject in the assertion. |
||
701 | * |
||
702 | * @param XMLSecurityKey $key The decryption key. |
||
703 | * @param array $blacklist Blacklisted decryption algorithms. |
||
704 | */ |
||
705 | View Code Duplication | public function decryptNameId(XMLSecurityKey $key, array $blacklist = []) |
|
718 | |||
719 | /** |
||
720 | * Retrieve the SubjectConfirmation elements we have in our Subject element. |
||
721 | * |
||
722 | * @return \SAML2\XML\saml\SubjectConfirmation[] |
||
723 | */ |
||
724 | public function getSubjectConfirmation() |
||
728 | |||
729 | /** |
||
730 | * Set the SubjectConfirmation elements that should be included in the assertion. |
||
731 | * |
||
732 | * @param array \SAML2\XML\saml\SubjectConfirmation[] |
||
733 | */ |
||
734 | public function setSubjectConfirmation(array $subjectConfirmation) |
||
738 | |||
739 | /** |
||
740 | * Convert this authentication request to an XML element. |
||
741 | * |
||
742 | * @return \DOMElement This authentication request. |
||
743 | */ |
||
744 | public function toUnsignedXML() |
||
839 | |||
840 | /** |
||
841 | * Add a Subject-node to the assertion. |
||
842 | * |
||
843 | * @param \DOMElement $root The assertion element we should add the subject to. |
||
844 | */ |
||
845 | View Code Duplication | private function addSubject(\DOMElement $root) |
|
867 | |||
868 | /** |
||
869 | * Add a Conditions-node to the request. |
||
870 | * |
||
871 | * @param \DOMElement $root The request element we should add the conditions to. |
||
872 | */ |
||
873 | private function addConditions(\DOMElement $root) |
||
887 | } |
||
888 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.