1 | <?php |
||||||
2 | |||||||
3 | /** |
||||||
4 | * Copyright 2020 SURFnet B.V. |
||||||
5 | * |
||||||
6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
7 | * you may not use this file except in compliance with the License. |
||||||
8 | * You may obtain a copy of the License at |
||||||
9 | * |
||||||
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
||||||
11 | * |
||||||
12 | * Unless required by applicable law or agreed to in writing, software |
||||||
13 | * distributed under the License is distributed on an "AS IS" BASIS, |
||||||
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
15 | * See the License for the specific language governing permissions and |
||||||
16 | * limitations under the License. |
||||||
17 | */ |
||||||
18 | |||||||
19 | namespace Surfnet\StepupGateway\Behat; |
||||||
20 | |||||||
21 | use Behat\Behat\Context\Context; |
||||||
22 | use Behat\Behat\Hook\Scope\BeforeScenarioScope; |
||||||
23 | use Behat\Mink\Driver\Selenium2Driver; |
||||||
0 ignored issues
–
show
|
|||||||
24 | use FriendsOfBehat\SymfonyExtension\Driver\SymfonyDriver; |
||||||
25 | use RobRichards\XMLSecLibs\XMLSecurityKey; |
||||||
26 | use RuntimeException; |
||||||
27 | use SAML2\AuthnRequest; |
||||||
28 | use SAML2\Certificate\Key; |
||||||
29 | use SAML2\Certificate\KeyLoader; |
||||||
30 | use SAML2\Certificate\PrivateKeyLoader; |
||||||
31 | use SAML2\Configuration\PrivateKey; |
||||||
32 | use SAML2\Constants; |
||||||
33 | use SAML2\DOMDocumentFactory; |
||||||
34 | use SAML2\XML\Chunk; |
||||||
35 | use SAML2\XML\saml\Issuer; |
||||||
36 | use SAML2\XML\saml\NameID; |
||||||
37 | use Surfnet\SamlBundle\Entity\IdentityProvider; |
||||||
38 | use Surfnet\SamlBundle\SAML2\AuthnRequest as Saml2AuthnRequest; |
||||||
39 | use Surfnet\StepupGateway\Behat\Repository\SamlEntityRepository; |
||||||
40 | use Surfnet\StepupGateway\Behat\Service\FixtureService; |
||||||
41 | use Symfony\Component\HttpFoundation\Request; |
||||||
42 | use Symfony\Component\HttpFoundation\RequestStack; |
||||||
43 | use Symfony\Component\HttpKernel\KernelInterface; |
||||||
44 | |||||||
45 | class ServiceProviderContext implements Context |
||||||
46 | { |
||||||
47 | const SSP_URL = 'https://ssp.dev.openconext.local/simplesaml/sp.php'; |
||||||
48 | const SSO_ENDPOINT_URL = 'https://gateway.dev.openconext.local/authentication/single-sign-on'; |
||||||
49 | const SFO_ENDPOINT_URL = 'https://gateway.dev.openconext.local/second-factor-only/single-sign-on'; |
||||||
50 | |||||||
51 | /** |
||||||
52 | * @var array |
||||||
53 | */ |
||||||
54 | private $currentSp; |
||||||
55 | |||||||
56 | /** |
||||||
57 | * @var array |
||||||
58 | */ |
||||||
59 | private $currentSfoSp; |
||||||
60 | |||||||
61 | /** |
||||||
62 | * @var array |
||||||
63 | */ |
||||||
64 | private $currentIdP; |
||||||
65 | |||||||
66 | /** |
||||||
67 | * @var FixtureService |
||||||
68 | */ |
||||||
69 | private $fixtureService; |
||||||
70 | |||||||
71 | /** |
||||||
72 | * @var KernelInterface |
||||||
73 | */ |
||||||
74 | private $kernel; |
||||||
75 | |||||||
76 | /** |
||||||
77 | * @var MinkContext |
||||||
78 | */ |
||||||
79 | private $minkContext; |
||||||
80 | |||||||
81 | public function __construct( |
||||||
82 | FixtureService $fixtureService, |
||||||
83 | KernelInterface $kernel |
||||||
84 | ) { |
||||||
85 | $this->fixtureService = $fixtureService; |
||||||
86 | $this->kernel = $kernel; |
||||||
87 | } |
||||||
88 | |||||||
89 | /** |
||||||
90 | * @BeforeScenario |
||||||
91 | */ |
||||||
92 | public function gatherContexts(BeforeScenarioScope $scope): void |
||||||
93 | { |
||||||
94 | $environment = $scope->getEnvironment(); |
||||||
95 | $this->minkContext = $environment->getContext(MinkContext::class); |
||||||
0 ignored issues
–
show
The method
getContext() does not exist on Behat\Testwork\Environment\Environment . It seems like you code against a sub-type of Behat\Testwork\Environment\Environment such as Behat\Behat\Context\Envi...lizedContextEnvironment or Behat\Behat\Context\Envi...lizedContextEnvironment or FriendsOfBehat\SymfonyEx...onyExtensionEnvironment .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
96 | } |
||||||
97 | |||||||
98 | /** |
||||||
99 | * @Given /^an SFO enabled SP with EntityID ([^\']*)$/ |
||||||
100 | */ |
||||||
101 | public function anSFOEnabledSPWithEntityID($entityId): void |
||||||
102 | { |
||||||
103 | $this->registerSp($entityId, true); |
||||||
104 | } |
||||||
105 | |||||||
106 | /** |
||||||
107 | * @Given /^an SP with EntityID ([^\']*)$/ |
||||||
108 | */ |
||||||
109 | public function anSPWithEntityID($entityId): void |
||||||
110 | { |
||||||
111 | $this->registerSp($entityId, false); |
||||||
112 | } |
||||||
113 | /** |
||||||
114 | * @Given /^an IdP with EntityID ([^\']*)$/ |
||||||
115 | */ |
||||||
116 | public function anIdPWithEntityID($entityId): void |
||||||
117 | { |
||||||
118 | $this->registerIdp($entityId, false); |
||||||
0 ignored issues
–
show
The call to
Surfnet\StepupGateway\Be...rContext::registerIdP() has too many arguments starting with false .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
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. Please note the @ignore annotation hint above. ![]() |
|||||||
119 | } |
||||||
120 | |||||||
121 | private function registerSp($entityId, $sfoEnabled): void |
||||||
122 | { |
||||||
123 | $publicKeyLoader = new KeyLoader(); |
||||||
124 | $publicKeyLoader->loadCertificateFile('/config/ssp/sp.crt'); |
||||||
125 | $keys = $publicKeyLoader->getKeys(); |
||||||
126 | /** @var Key $cert */ |
||||||
127 | $cert = $keys->first(); |
||||||
128 | |||||||
129 | $spEntity = $this->fixtureService->registerSP($entityId, $cert['X509Certificate'], $sfoEnabled); |
||||||
130 | |||||||
131 | $spEntity['configuration'] = json_decode($spEntity['configuration'], true); |
||||||
132 | if ($sfoEnabled) { |
||||||
133 | $this->currentSfoSp = $spEntity; |
||||||
134 | } else { |
||||||
135 | $this->currentSp = $spEntity; |
||||||
136 | } |
||||||
137 | } |
||||||
138 | |||||||
139 | private function registerIdP($entityId): void |
||||||
140 | { |
||||||
141 | $publicKeyLoader = new KeyLoader(); |
||||||
142 | $publicKeyLoader->loadCertificateFile('/config/ssp/idp.crt'); |
||||||
143 | $keys = $publicKeyLoader->getKeys(); |
||||||
144 | /** @var Key $cert */ |
||||||
145 | $cert = $keys->first(); |
||||||
146 | |||||||
147 | $idpEntity = $this->fixtureService->registerIdP($entityId, $cert['X509Certificate']); |
||||||
148 | |||||||
149 | $idpEntity['configuration'] = json_decode($idpEntity['configuration'], true); |
||||||
150 | $this->currentIdP = $idpEntity; |
||||||
151 | } |
||||||
152 | |||||||
153 | /** |
||||||
154 | * @When /^([^\']*) starts an SFO authentication$/ |
||||||
155 | */ |
||||||
156 | public function iStartAnSFOAuthentication($nameId): void |
||||||
157 | { |
||||||
158 | $this->iStartAnSFOAuthenticationWithLoa($nameId, "self-asserted"); |
||||||
159 | } |
||||||
160 | |||||||
161 | /** |
||||||
162 | * @When /^([^\']*) starts an SFO authentication with LoA ([^\']*)$/ |
||||||
163 | */ |
||||||
164 | public function iStartAnSFOAuthenticationWithLoa($nameId, string $loa, bool $forceAuthN = false, ?string $gsspFallbackSubject = null, ?string $gsspFallbackInstitution = null): void |
||||||
165 | { |
||||||
166 | $authnRequest = new AuthnRequest(); |
||||||
167 | // In order to later assert if the response succeeded or failed, set our own dummy ACS location |
||||||
168 | $authnRequest->setAssertionConsumerServiceURL(SamlEntityRepository::SP_ACS_LOCATION); |
||||||
169 | $issuerVo = new Issuer(); |
||||||
170 | $issuerVo->setValue($this->currentSfoSp['entityId']); |
||||||
171 | $authnRequest->setIssuer($issuerVo); |
||||||
172 | $authnRequest->setDestination(self::SFO_ENDPOINT_URL); |
||||||
173 | $authnRequest->setProtocolBinding(Constants::BINDING_HTTP_REDIRECT); |
||||||
174 | $authnRequest->setNameId($this->buildNameId($nameId)); |
||||||
175 | if ($forceAuthN) { |
||||||
176 | $authnRequest->setForceAuthn(true); |
||||||
177 | } |
||||||
178 | // Sign with random key, does not mather for now. |
||||||
179 | $authnRequest->setSignatureKey( |
||||||
180 | $this->loadPrivateKey(new PrivateKey('/config/ssp/sp.key', 'default')) |
||||||
181 | ); |
||||||
182 | switch ($loa) { |
||||||
183 | case "1": |
||||||
184 | case "1.5": |
||||||
185 | case "2": |
||||||
186 | case "3": |
||||||
187 | $authnRequest->setRequestedAuthnContext( |
||||||
188 | ['AuthnContextClassRef' => ['http://dev.openconext.local/assurance/sfo-level' . $loa]] |
||||||
189 | ); |
||||||
190 | break; |
||||||
191 | case "self-asserted": |
||||||
192 | $authnRequest->setRequestedAuthnContext( |
||||||
193 | ['AuthnContextClassRef' => ['http://dev.openconext.local/assurance/sfo-level1.5']] |
||||||
194 | ); |
||||||
195 | break; |
||||||
196 | default: |
||||||
197 | throw new RuntimeException(sprintf('The specified LoA-%s is not supported', $loa)); |
||||||
198 | } |
||||||
199 | |||||||
200 | if ($gsspFallbackSubject != null) { |
||||||
201 | $dom = DOMDocumentFactory::create(); |
||||||
202 | $ce = $dom->createElementNS('urn:mace:surf.nl:stepup:gssp-extensions', 'gssp:UserAttributes'); |
||||||
203 | $ce->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); |
||||||
204 | $ce->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xs', 'http://www.w3.org/2001/XMLSchema'); |
||||||
205 | |||||||
206 | foreach ([ |
||||||
207 | 'urn:mace:dir:attribute-def:mail' => $gsspFallbackSubject, |
||||||
208 | 'urn:mace:terena.org:attribute-def:schacHomeOrganization' => $gsspFallbackInstitution, |
||||||
209 | |||||||
210 | ] as $name => $value) { |
||||||
211 | $attrib = $ce->ownerDocument->createElementNS('urn:oasis:names:tc:SAML:2.0:assertion', 'saml:Attribute'); |
||||||
0 ignored issues
–
show
The method
createElementNS() does not exist on null .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||
212 | $attrib->setAttribute('NameFormat', 'urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified'); |
||||||
213 | $attrib->setAttribute('Name', $name); |
||||||
214 | $attribValue = $ce->ownerDocument->createElementNS('urn:oasis:names:tc:SAML:2.0:assertion', 'saml:AttributeValue', $value); |
||||||
215 | $attribValue->setAttribute('xsi:type', 'xs:string'); |
||||||
216 | $attrib->appendChild($attribValue); |
||||||
217 | |||||||
218 | $ce->appendChild($attrib); |
||||||
219 | } |
||||||
220 | |||||||
221 | $ext = $authnRequest->getExtensions(); |
||||||
222 | $ext['saml:Extensions'] = new Chunk($ce); |
||||||
223 | $authnRequest->setExtensions($ext); |
||||||
224 | } |
||||||
225 | $request = Saml2AuthnRequest::createNew($authnRequest); |
||||||
226 | $query = $request->buildRequestQuery(); |
||||||
227 | |||||||
228 | $this->getSession()->visit($request->getDestination().'?'.$query); |
||||||
229 | } |
||||||
230 | |||||||
231 | /** |
||||||
232 | * @When /^([^\']*) starts an SFO authentication requiring LoA ([^\']*)$/ |
||||||
233 | */ |
||||||
234 | public function iStartAnSFOAuthenticationWithLoaRequirement($nameId, $loa): void |
||||||
235 | { |
||||||
236 | $this->iStartAnSFOAuthenticationWithLoa($nameId, $loa); |
||||||
237 | } |
||||||
238 | /** |
||||||
239 | * @When /^([^\']*) starts a forced SFO authentication requiring LoA ([^\']*)$/ |
||||||
240 | */ |
||||||
241 | public function iStartAForcedSFOAuthenticationWithLoaRequirement($nameId, $loa): void |
||||||
242 | { |
||||||
243 | $this->iStartAnSFOAuthenticationWithLoa($nameId, $loa, true); |
||||||
244 | } |
||||||
245 | |||||||
246 | /** |
||||||
247 | * @When /^([^\']*) starts an SFO authentication with GSSP fallback requiring LoA ([^\']*) and Gssp extension subject ([^\']*) and institution ([^\']*)$/ |
||||||
248 | */ |
||||||
249 | public function iStartAForcedSFOAuthenticationWithLoaRequirementAndGsspExtension($nameId, $loa, $subject, $institution): void |
||||||
250 | { |
||||||
251 | $this->iStartAnSFOAuthenticationWithLoa($nameId, $loa, false, $subject, $institution); |
||||||
252 | } |
||||||
253 | |||||||
254 | /** |
||||||
255 | * @When /^([^\']*) starts an ADFS authentication requiring ([^\']*)$/ |
||||||
256 | */ |
||||||
257 | public function iStartAnADFSAuthenticationWithLoaRequirement($nameId, $loa): void |
||||||
258 | { |
||||||
259 | $requestParams = [ |
||||||
260 | 'loa' => $loa, |
||||||
261 | 'nameId' => $nameId, |
||||||
262 | 'entityId' => $this->currentSfoSp['entityId'] |
||||||
263 | ]; |
||||||
264 | $this->getSession()->visit(SamlEntityRepository::SP_ADFS_SSO_LOCATION . '?' . http_build_query($requestParams)); |
||||||
265 | $this->pressButtonWhenNoJavascriptSupport(); |
||||||
266 | } |
||||||
267 | |||||||
268 | /** |
||||||
269 | * @When /^([^\']*) starts an authentication at Default SP$/ |
||||||
270 | */ |
||||||
271 | public function iStartAnAuthenticationAtDefaultSP($nameId): void |
||||||
272 | { |
||||||
273 | $authnRequest = new AuthnRequest(); |
||||||
274 | // In order to later assert if the response succeeded or failed, set our own dummy ACS location |
||||||
275 | $authnRequest->setAssertionConsumerServiceURL(SamlEntityRepository::SP_ACS_LOCATION); |
||||||
276 | $issuerVo = new Issuer(); |
||||||
277 | $issuerVo->setValue('https://ssp.dev.openconext.local/module.php/saml/sp/metadata.php/default-sp'); |
||||||
278 | $authnRequest->setIssuer($issuerVo); |
||||||
279 | $authnRequest->setDestination(self::SSO_ENDPOINT_URL); |
||||||
280 | $authnRequest->setProtocolBinding(Constants::BINDING_HTTP_REDIRECT); |
||||||
281 | $authnRequest->setNameId($this->buildNameId($nameId)); |
||||||
282 | // Sign with random key, does not mather for now. |
||||||
283 | $authnRequest->setSignatureKey( |
||||||
284 | $this->loadPrivateKey(new PrivateKey('/config/ssp/sp.key', 'default')) |
||||||
285 | ); |
||||||
286 | $authnRequest->setRequestedAuthnContext( |
||||||
287 | ['AuthnContextClassRef' => ['http://dev.openconext.local/assurance/loa2']] |
||||||
288 | ); |
||||||
289 | $request = Saml2AuthnRequest::createNew($authnRequest); |
||||||
290 | $query = $request->buildRequestQuery(); |
||||||
291 | $this->getSession()->visit($authnRequest->getDestination().'?'.$query); |
||||||
292 | } |
||||||
293 | |||||||
294 | /** |
||||||
295 | * @When /^([^\']*) starts an authentication requiring LoA ([^\']*)$/ |
||||||
296 | */ |
||||||
297 | public function iStartAnSsoAuthenticationWithLoaRequirement($nameId, $loa): void |
||||||
298 | { |
||||||
299 | $authnRequest = new AuthnRequest(); |
||||||
300 | // In order to later assert if the response succeeded or failed, set our own dummy ACS location |
||||||
301 | $authnRequest->setAssertionConsumerServiceURL(SamlEntityRepository::SP_ACS_LOCATION); |
||||||
302 | $issuerVo = new Issuer(); |
||||||
303 | $issuerVo->setValue($this->currentSp['entityId']); |
||||||
304 | $authnRequest->setIssuer($issuerVo); |
||||||
305 | $authnRequest->setDestination(self::SSO_ENDPOINT_URL); |
||||||
306 | $authnRequest->setProtocolBinding(Constants::BINDING_HTTP_REDIRECT); |
||||||
307 | $authnRequest->setNameId($this->buildNameId($nameId)); |
||||||
308 | // Sign with random key, does not mather for now. |
||||||
309 | $authnRequest->setSignatureKey( |
||||||
310 | $this->loadPrivateKey(new PrivateKey('/config/ssp/sp.key', 'default')) |
||||||
311 | ); |
||||||
312 | |||||||
313 | switch ($loa) { |
||||||
314 | case "1": |
||||||
315 | case "1.5": |
||||||
316 | case "2": |
||||||
317 | case "3": |
||||||
318 | $authnRequest->setRequestedAuthnContext( |
||||||
319 | ['AuthnContextClassRef' => ['http://dev.openconext.local/assurance/loa' . $loa]] |
||||||
320 | ); |
||||||
321 | break; |
||||||
322 | case "self-asserted": |
||||||
323 | $authnRequest->setRequestedAuthnContext( |
||||||
324 | ['AuthnContextClassRef' => ['http://dev.openconext.local/assurance/loa1.5']] |
||||||
325 | ); |
||||||
326 | break; |
||||||
327 | default: |
||||||
328 | throw new RuntimeException(sprintf('The specified LoA-%s is not supported', $loa)); |
||||||
329 | } |
||||||
330 | |||||||
331 | $request = Saml2AuthnRequest::createNew($authnRequest); |
||||||
332 | $query = $request->buildRequestQuery(); |
||||||
333 | |||||||
334 | $this->getSession()->visit($request->getDestination().'?'.$query); |
||||||
335 | } |
||||||
336 | |||||||
337 | /** |
||||||
338 | * @When /^I authenticate at the IdP as ([^\']*)$/ |
||||||
339 | */ |
||||||
340 | public function iAuthenticateAtTheIdp($username): void |
||||||
341 | { |
||||||
342 | $this->minkContext->fillField('username', $username); |
||||||
343 | $this->minkContext->fillField('password', $username); |
||||||
344 | // Submit the form |
||||||
345 | $this->minkContext->pressButton('Login'); |
||||||
346 | |||||||
347 | if ($this->getSession()->getDriver() instanceof SymfonyDriver) { |
||||||
348 | // Submit the SAML Response from SimpleSamplPHP IdP |
||||||
349 | $this->minkContext->pressButton('Yes, continue'); |
||||||
350 | } |
||||||
351 | } |
||||||
352 | |||||||
353 | /** |
||||||
354 | * @When /^I authenticate at AzureMFA as "([^"]*)"$/ |
||||||
355 | */ |
||||||
356 | public function iAuthenticateAtAzureMfaAs($username): void |
||||||
357 | { |
||||||
358 | $this->minkContext->assertPageAddress('https://azuremfa.dev.openconext.local/mock/sso'); |
||||||
359 | $attributes = sprintf('[ |
||||||
360 | { |
||||||
361 | "name":"urn:mace:dir:attribute-def:mail", |
||||||
362 | "value": [ |
||||||
363 | "%s" |
||||||
364 | ] |
||||||
365 | }, |
||||||
366 | { |
||||||
367 | "name": "http://schemas.microsoft.com/claims/authnmethodsreferences", |
||||||
368 | "value": [ |
||||||
369 | "http://schemas.microsoft.com/claims/multipleauthn" |
||||||
370 | ] |
||||||
371 | } |
||||||
372 | ] |
||||||
373 | ', $username); |
||||||
374 | $this->minkContext->fillField('attributes', $attributes); |
||||||
375 | $this->minkContext->pressButton('success'); |
||||||
376 | |||||||
377 | $this->minkContext->assertPageAddress('https://azuremfa.dev.openconext.local/mock/sso'); |
||||||
378 | $this->minkContext->pressButton('Submit assertion'); |
||||||
379 | |||||||
380 | $this->minkContext->assertPageAddress('https://gateway.dev.openconext.local/test/authentication/consume-assertion'); |
||||||
381 | } |
||||||
382 | |||||||
383 | /** |
||||||
384 | * @When /^I cancel the authentication at AzureMFA$/ |
||||||
385 | */ |
||||||
386 | public function iCancelTheAuthenticationAtAzureMfa(): void |
||||||
387 | { |
||||||
388 | $this->minkContext->assertPageAddress('https://azuremfa.dev.openconext.local/mock/sso'); |
||||||
389 | $this->minkContext->pressButton('cancel'); |
||||||
390 | |||||||
391 | $this->minkContext->assertPageAddress('https://azuremfa.dev.openconext.local/mock/sso'); |
||||||
392 | $this->minkContext->pressButton('Submit assertion'); |
||||||
393 | |||||||
394 | $this->minkContext->assertPageAddress('https://gateway.dev.openconext.local/test/authentication/consume-assertion'); |
||||||
395 | } |
||||||
396 | |||||||
397 | private static function loadPrivateKey(PrivateKey $key) |
||||||
398 | { |
||||||
399 | $keyLoader = new PrivateKeyLoader(); |
||||||
400 | $privateKey = $keyLoader->loadPrivateKey($key); |
||||||
401 | |||||||
402 | $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, ['type' => 'private']); |
||||||
403 | $key->loadKey($privateKey->getKeyAsString()); |
||||||
404 | |||||||
405 | return $key; |
||||||
406 | } |
||||||
407 | |||||||
408 | /** |
||||||
409 | * @Given /^I log out at the IdP$/ |
||||||
410 | */ |
||||||
411 | public function iLogOutAtTheIdP(): void |
||||||
412 | { |
||||||
413 | $this->minkContext->visit(self::SSP_URL); |
||||||
414 | $this->minkContext->pressButton('Logout'); |
||||||
415 | } |
||||||
416 | |||||||
417 | private function getSession() |
||||||
418 | { |
||||||
419 | return $this->minkContext->getSession(); |
||||||
420 | } |
||||||
421 | |||||||
422 | private function buildNameId(string $nameId): NameID |
||||||
423 | { |
||||||
424 | $nameIdVo = new NameID(); |
||||||
425 | $nameIdVo->setValue($nameId); |
||||||
426 | $nameIdVo->setFormat(Constants::NAMEFORMAT_UNSPECIFIED); |
||||||
427 | return $nameIdVo; |
||||||
428 | } |
||||||
429 | |||||||
430 | private function pressButtonWhenNoJavascriptSupport() |
||||||
431 | { |
||||||
432 | if ($this->minkContext->getSession()->getDriver() instanceof SymfonyDriver) { |
||||||
433 | $this->minkContext->pressButton('Submit'); |
||||||
434 | } |
||||||
435 | } |
||||||
436 | } |
||||||
437 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths