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:
1 | <?php |
||
40 | class ServiceProviderContext implements Context, KernelAwareContext |
||
41 | { |
||
42 | const SFO_ENDPOINT_URL = 'https://gateway.stepup.example.com/second-factor-only/single-sign-on'; |
||
43 | const SSO_ENDPOINT_URL = 'https://gateway.stepup.example.com/authentication/single-sign-on'; |
||
44 | |||
45 | /** |
||
46 | * @var array |
||
47 | */ |
||
48 | private $currentSp; |
||
49 | |||
50 | /** |
||
51 | * @var array |
||
52 | */ |
||
53 | private $currentSfoSp; |
||
54 | |||
55 | /** |
||
56 | * @var array |
||
57 | */ |
||
58 | private $currentIdP; |
||
59 | |||
60 | /** |
||
61 | * @var FixtureService |
||
62 | */ |
||
63 | private $fixtureService; |
||
64 | |||
65 | /** |
||
66 | * @var KernelInterface |
||
67 | */ |
||
68 | private $kernel; |
||
69 | |||
70 | /** |
||
71 | * @var MinkContext |
||
72 | */ |
||
73 | private $minkContext; |
||
74 | |||
75 | public function __construct(FixtureService $fixtureService) |
||
79 | |||
80 | public function setKernel(KernelInterface $kernel) |
||
84 | |||
85 | /** |
||
86 | * @BeforeScenario |
||
87 | */ |
||
88 | public function gatherContexts(BeforeScenarioScope $scope) |
||
93 | |||
94 | /** |
||
95 | * @Given /^an SFO enabled SP with EntityID ([^\']*)$/ |
||
96 | */ |
||
97 | public function anSFOEnabledSPWithEntityID($entityId) |
||
101 | |||
102 | /** |
||
103 | * @Given /^an SP with EntityID ([^\']*)$/ |
||
104 | */ |
||
105 | public function anSPWithEntityID($entityId) |
||
109 | /** |
||
110 | * @Given /^an IdP with EntityID ([^\']*)$/ |
||
111 | */ |
||
112 | public function anIdPWithEntityID($entityId) |
||
116 | |||
117 | private function registerSp($entityId, $sfoEnabled) |
||
135 | |||
136 | private function registerIdP($entityId) |
||
150 | |||
151 | /** |
||
152 | * @When /^([^\']*) starts an SFO authentication$/ |
||
153 | */ |
||
154 | View Code Duplication | public function iStartAnSFOAuthentication($nameId) |
|
176 | |||
177 | /** |
||
178 | * @When /^([^\']*) starts an SFO authentication requiring ([^\']*)$/ |
||
179 | */ |
||
180 | View Code Duplication | public function iStartAnSFOAuthenticationWithLoaRequirement($nameId, $loa) |
|
202 | |||
203 | /** |
||
204 | * @When /^([^\']*) starts an authentication$/ |
||
205 | */ |
||
206 | View Code Duplication | public function iStartAnAuthentication($nameId) |
|
207 | { |
||
208 | $authnRequest = new AuthnRequest(); |
||
209 | // In order to later assert if the response succeeded or failed, set our own dummy ACS location |
||
210 | $authnRequest->setAssertionConsumerServiceURL(SamlEntityRepository::SP_ACS_LOCATION); |
||
211 | $authnRequest->setIssuer($this->currentSp['entityId']); |
||
212 | $authnRequest->setDestination(self::SSO_ENDPOINT_URL); |
||
213 | $authnRequest->setProtocolBinding(Constants::BINDING_HTTP_REDIRECT); |
||
214 | $authnRequest->setNameId($this->buildNameId($nameId)); |
||
215 | // Sign with random key, does not mather for now. |
||
216 | // todo: use from services_test.yml |
||
217 | $authnRequest->setSignatureKey( |
||
218 | $this->loadPrivateKey(new PrivateKey('/var/www/ci/certificates/sp.pem', 'default')) |
||
219 | ); |
||
220 | $authnRequest->setRequestedAuthnContext( |
||
221 | ['AuthnContextClassRef' => ['http://stepup.example.com/assurance/level2']] |
||
222 | ); |
||
223 | $request = Saml2AuthnRequest::createNew($authnRequest); |
||
224 | $query = $request->buildRequestQuery(); |
||
225 | $this->getSession()->visit($request->getDestination().'?'.$query); |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * @When /^([^\']*) starts an authentication requiring ([^\']*)$/ |
||
230 | */ |
||
231 | View Code Duplication | public function iStartAnSsoAuthenticationWithLoaRequirement($nameId, $loa) |
|
232 | { |
||
233 | $authnRequest = new AuthnRequest(); |
||
234 | // In order to later assert if the response succeeded or failed, set our own dummy ACS location |
||
235 | $authnRequest->setAssertionConsumerServiceURL(SamlEntityRepository::SP_ACS_LOCATION); |
||
236 | $authnRequest->setIssuer($this->currentSp['entityId']); |
||
237 | $authnRequest->setDestination(self::SSO_ENDPOINT_URL); |
||
238 | $authnRequest->setProtocolBinding(Constants::BINDING_HTTP_REDIRECT); |
||
239 | $authnRequest->setNameId($this->buildNameId($nameId)); |
||
240 | // Sign with random key, does not mather for now. |
||
241 | // todo: use from services_test.yml |
||
242 | $authnRequest->setSignatureKey( |
||
243 | $this->loadPrivateKey(new PrivateKey('/var/www/ci/certificates/sp.pem', 'default')) |
||
244 | ); |
||
245 | $authnRequest->setRequestedAuthnContext( |
||
246 | ['AuthnContextClassRef' => [$loa]] |
||
247 | ); |
||
248 | $request = Saml2AuthnRequest::createNew($authnRequest); |
||
249 | $query = $request->buildRequestQuery(); |
||
250 | $this->getSession()->visit($request->getDestination().'?'.$query); |
||
251 | } |
||
252 | |||
253 | /** |
||
254 | * @When /^I authenticate at the IdP as ([^\']*)$/ |
||
255 | */ |
||
256 | public function iAuthenticateAtTheIdp($username) |
||
264 | |||
265 | /** |
||
266 | * @return IdentityProvider |
||
267 | */ |
||
268 | public function getIdentityProvider() |
||
279 | |||
280 | private static function loadPrivateKey(PrivateKey $key) |
||
290 | |||
291 | private function getSession() |
||
295 | |||
296 | /** |
||
297 | * @param string $nameId |
||
298 | * @return NameID |
||
299 | */ |
||
300 | private function buildNameId($nameId) |
||
305 | } |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.