OpenConext /
Stepup-Gateway
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * Copyright 2020 SURFnet bv |
||
| 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\Controller; |
||
| 20 | |||
| 21 | use Exception; |
||
| 22 | use Psr\Log\LoggerInterface; |
||
| 23 | use RobRichards\XMLSecLibs\XMLSecurityKey; |
||
| 24 | use RuntimeException; |
||
| 25 | use SAML2\AuthnRequest; |
||
| 26 | use SAML2\Certificate\PrivateKeyLoader; |
||
| 27 | use SAML2\Configuration\PrivateKey; |
||
| 28 | use SAML2\Constants; |
||
| 29 | use SAML2\HTTPPost; |
||
| 30 | use SAML2\HTTPRedirect; |
||
| 31 | use SAML2\Response as SAMLResponse; |
||
| 32 | use SAML2\XML\saml\Issuer; |
||
| 33 | use SAML2\XML\saml\NameID; |
||
| 34 | use Surfnet\SamlBundle\Http\XMLResponse; |
||
| 35 | use Surfnet\StepupGateway\Behat\Repository\SamlEntityRepository; |
||
| 36 | use Surfnet\StepupGateway\Behat\ServiceProviderContext; |
||
| 37 | use Surfnet\StepupGateway\SecondFactorOnlyBundle\Adfs\ValueObject\Response as AdfsResponse; |
||
| 38 | use Symfony\Component\HttpFoundation\Request; |
||
| 39 | use Symfony\Component\HttpFoundation\Response; |
||
| 40 | use Twig\Environment; |
||
| 41 | |||
| 42 | class ServiceProviderController |
||
| 43 | { |
||
| 44 | private $twig; |
||
| 45 | |||
| 46 | private $logger; |
||
| 47 | |||
| 48 | public function __construct(Environment $twig, LoggerInterface $logger) |
||
| 49 | { |
||
| 50 | $this->logger = $logger; |
||
| 51 | $this->twig = $twig; |
||
| 52 | } |
||
| 53 | |||
| 54 | /** |
||
| 55 | * Simply dumps the SAMLResponse XML |
||
| 56 | */ |
||
| 57 | public function acsAction(Request $request) |
||
| 58 | { |
||
| 59 | $this->logger->notice('Getting ready to consume the assertion on the test SP'); |
||
| 60 | $isAdfs = false; |
||
| 61 | if ($request->request->has('_SAMLResponse')) { |
||
| 62 | $this->logger->notice('Handling a test ADFS assertion'); |
||
| 63 | // The ADFS saml response is hidden in the _SAMLResponse input, in order to get the |
||
| 64 | $request->request->set('SAMLResponse', $request->request->get('_SAMLResponse')); |
||
| 65 | $_POST['SAMLResponse'] = $request->request->get('_SAMLResponse'); |
||
| 66 | $isAdfs = true; |
||
| 67 | } |
||
| 68 | try { |
||
| 69 | $this->logger->notice('Process the assertion on the test SP (try POST binding)'); |
||
| 70 | $httpPostBinding = new HTTPPost(); |
||
| 71 | $message = $httpPostBinding->receive(); |
||
| 72 | } catch (Exception $e1) { |
||
| 73 | try { |
||
| 74 | $this->logger->alert('Processing failed on the test SP'); |
||
| 75 | $httpRedirectBinding = new HTTPRedirect(); |
||
| 76 | $message = $httpRedirectBinding->receive(); |
||
| 77 | } catch (Exception) { |
||
| 78 | throw new RuntimeException('Unable to retrieve SAML message?', 1, $e1); |
||
| 79 | } |
||
| 80 | } |
||
| 81 | |||
| 82 | if (!$message instanceof SAMLResponse) { |
||
| 83 | throw new RuntimeException(sprintf('Unrecognized message type received: "%s"', get_class($message))); |
||
| 84 | } |
||
| 85 | |||
| 86 | $xml = base64_decode($request->get('SAMLResponse')); |
||
| 87 | $this->logger->notice(sprintf('Received SAMLResponse with status "%s"', implode($message->getStatus()))); |
||
| 88 | $this->logger->notice('The XML received', ['response-xml' => $xml]); |
||
| 89 | |||
| 90 | if ($isAdfs) { |
||
| 91 | $html = $this->twig->render( |
||
| 92 | '@test_resources/adfs_acs.html.twig', |
||
| 93 | [ |
||
| 94 | 'samlResponse' => $xml, |
||
| 95 | 'context' => $request->request->get('Context'), |
||
| 96 | 'authMethod' => $request->request->get('AuthMethod'), |
||
| 97 | ] |
||
| 98 | ); |
||
| 99 | return new Response($html); |
||
| 100 | } |
||
| 101 | return new XMLResponse($xml); |
||
| 102 | } |
||
| 103 | |||
| 104 | /** |
||
| 105 | * Posts an authn request to the SA Gateway, adding two additional |
||
| 106 | * parameters to the POST in addition to those found on a regular |
||
| 107 | * authn request (AuthNRequest and RelayState) |
||
| 108 | */ |
||
| 109 | public function adfsSsoAction(Request $request) |
||
| 110 | { |
||
| 111 | $nameId = $request->get('nameId'); |
||
| 112 | $loa = $request->get('loa'); |
||
| 113 | $entityId = $request->get('entityId'); |
||
| 114 | |||
| 115 | $authnRequest = new AuthnRequest(); |
||
| 116 | // In order to later assert if the response succeeded or failed, set our own dummy ACS location |
||
| 117 | $authnRequest->setAssertionConsumerServiceURL(SamlEntityRepository::SP_ACS_LOCATION); |
||
| 118 | $issuerVo = new Issuer(); |
||
| 119 | $issuerVo->setValue($entityId); |
||
| 120 | $authnRequest->setIssuer($issuerVo); |
||
| 121 | $authnRequest->setDestination(ServiceProviderContext::SFO_ENDPOINT_URL); |
||
| 122 | $authnRequest->setProtocolBinding(Constants::BINDING_HTTP_REDIRECT); |
||
| 123 | |||
| 124 | $nameIdVo = new NameID(); |
||
| 125 | $nameIdVo->setValue($nameId); |
||
| 126 | $nameIdVo->setFormat(Constants::NAMEFORMAT_UNSPECIFIED); |
||
| 127 | |||
| 128 | $authnRequest->setNameId($nameIdVo); |
||
| 129 | |||
| 130 | $keyLoader = new PrivateKeyLoader(); |
||
| 131 | $privateKey = $keyLoader->loadPrivateKey(new PrivateKey('/config/ssp/sp.key', 'default')); |
||
| 132 | $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, ['type' => 'private']); |
||
| 133 | $key->loadKey($privateKey->getKeyAsString()); |
||
| 134 | |||
| 135 | $authnRequest->setSignatureKey($key); |
||
| 136 | $authnRequest->setRequestedAuthnContext( |
||
| 137 | ['AuthnContextClassRef' => [$loa]] |
||
| 138 | ); |
||
| 139 | |||
| 140 | $context = '<EncryptedData></EncryptedData>'; |
||
| 141 | $authMethod = 'ADFS.SCSA'; |
||
| 142 | $arXml = $authnRequest->toSignedXML(); |
||
| 143 | $arBase64Encoded = base64_encode($arXml->ownerDocument->saveXml($arXml)); |
||
|
0 ignored issues
–
show
|
|||
| 144 | $response = $this->twig->render( |
||
| 145 | '@test_resources/adfs_login.html.twig', |
||
| 146 | [ |
||
| 147 | 'ssoUrl' => $authnRequest->getDestination(), |
||
| 148 | 'authNRequest' => $arBase64Encoded, |
||
| 149 | 'adfs' => AdfsResponse::fromValues($authMethod, $context) |
||
| 150 | ] |
||
| 151 | ); |
||
| 152 | |||
| 153 | return new Response($response); |
||
| 154 | } |
||
| 155 | } |
||
| 156 |
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.