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 |
||
34 | class GatewayController extends Controller |
||
35 | { |
||
36 | const RESPONSE_CONTEXT_SERVICE_ID = 'gateway.proxy.response_context'; |
||
37 | |||
38 | public function ssoAction(Request $httpRequest) |
||
39 | { |
||
40 | /** @var \Psr\Log\LoggerInterface $logger */ |
||
41 | $logger = $this->get('logger'); |
||
42 | $logger->notice('Received AuthnRequest, started processing'); |
||
43 | |||
44 | /** @var \Surfnet\SamlBundle\Http\RedirectBinding $redirectBinding */ |
||
45 | $redirectBinding = $this->get('surfnet_saml.http.redirect_binding'); |
||
46 | |||
47 | $originalRequest = $redirectBinding->receiveSignedAuthnRequestFrom($httpRequest); |
||
48 | |||
49 | $originalRequestId = $originalRequest->getRequestId(); |
||
50 | $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId); |
||
51 | $logger->notice(sprintf( |
||
52 | 'AuthnRequest processing complete, received AuthnRequest from "%s", request ID: "%s"', |
||
53 | $originalRequest->getServiceProvider(), |
||
54 | $originalRequest->getRequestId() |
||
55 | )); |
||
56 | |||
57 | /** @var \Surfnet\StepupGateway\GatewayBundle\Saml\Proxy\ProxyStateHandler $stateHandler */ |
||
58 | $stateHandler = $this->get('gateway.proxy.state_handler'); |
||
59 | |||
60 | // Clear the state of the previous SSO action. Request data of previous |
||
61 | // SSO actions should not have any effect in subsequent SSO actions. |
||
62 | $stateHandler->clear(); |
||
63 | |||
64 | $stateHandler |
||
65 | ->setRequestId($originalRequestId) |
||
66 | ->setRequestServiceProvider($originalRequest->getServiceProvider()) |
||
|
|||
67 | ->setRelayState($httpRequest->get(AuthnRequest::PARAMETER_RELAY_STATE, '')) |
||
68 | ->setResponseAction('SurfnetStepupGatewayGatewayBundle:Gateway:respond') |
||
69 | ->setResponseContextServiceId(static::RESPONSE_CONTEXT_SERVICE_ID); |
||
70 | |||
71 | // check if the requested Loa is supported |
||
72 | $requiredLoa = $originalRequest->getAuthenticationContextClassRef(); |
||
73 | if ($requiredLoa && !$this->get('surfnet_stepup.service.loa_resolution')->hasLoa($requiredLoa)) { |
||
74 | $logger->info(sprintf( |
||
75 | 'Requested required Loa "%s" does not exist, sending response with status Requester Error', |
||
76 | $requiredLoa |
||
77 | )); |
||
78 | |||
79 | $response = $this->createRequesterFailureResponse(); |
||
80 | |||
81 | return $this->renderSamlResponse('consumeAssertion', $response); |
||
82 | } |
||
83 | |||
84 | $stateHandler->setRequiredLoaIdentifier($requiredLoa); |
||
85 | |||
86 | $proxyRequest = AuthnRequestFactory::createNewRequest( |
||
87 | $this->get('surfnet_saml.hosted.service_provider'), |
||
88 | $this->get('surfnet_saml.remote.idp') |
||
89 | ); |
||
90 | |||
91 | $proxyRequest->setScoping([$originalRequest->getServiceProvider()]); |
||
92 | $stateHandler->setGatewayRequestId($proxyRequest->getRequestId()); |
||
93 | |||
94 | $logger->notice(sprintf( |
||
95 | 'Sending Proxy AuthnRequest with request ID: "%s" for original AuthnRequest "%s"', |
||
96 | $proxyRequest->getRequestId(), |
||
97 | $originalRequest->getRequestId() |
||
98 | )); |
||
99 | |||
100 | return $redirectBinding->createResponseFor($proxyRequest); |
||
101 | } |
||
102 | |||
103 | public function proxySsoAction() |
||
104 | { |
||
105 | throw new HttpException(418, 'Not Yet Implemented'); |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * @param Request $request |
||
110 | * @return \Symfony\Component\HttpFoundation\Response |
||
111 | */ |
||
112 | public function consumeAssertionAction(Request $request) |
||
113 | { |
||
114 | $responseContext = $this->getResponseContext(); |
||
115 | $originalRequestId = $responseContext->getInResponseTo(); |
||
116 | |||
117 | /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */ |
||
118 | $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId); |
||
119 | $logger->notice('Received SAMLResponse, attempting to process for Proxy Response'); |
||
120 | |||
121 | try { |
||
122 | /** @var \SAML2\Assertion $assertion */ |
||
123 | $assertion = $this->get('surfnet_saml.http.post_binding')->processResponse( |
||
124 | $request, |
||
125 | $this->get('surfnet_saml.remote.idp'), |
||
126 | $this->get('surfnet_saml.hosted.service_provider') |
||
127 | ); |
||
128 | } catch (Exception $exception) { |
||
129 | $logger->error(sprintf('Could not process received Response, error: "%s"', $exception->getMessage())); |
||
130 | |||
131 | $response = $this->createResponseFailureResponse($responseContext); |
||
132 | |||
133 | return $this->renderSamlResponse('unprocessableResponse', $response); |
||
134 | } |
||
135 | |||
136 | $adaptedAssertion = new AssertionAdapter($assertion); |
||
137 | $expectedInResponseTo = $responseContext->getExpectedInResponseTo(); |
||
138 | if (!$adaptedAssertion->inResponseToMatches($expectedInResponseTo)) { |
||
139 | throw new UnknownInResponseToException( |
||
140 | $adaptedAssertion->getInResponseTo(), |
||
141 | $expectedInResponseTo |
||
142 | ); |
||
143 | } |
||
144 | |||
145 | $logger->notice('Successfully processed SAMLResponse'); |
||
146 | |||
147 | $responseContext->saveAssertion($assertion); |
||
148 | |||
149 | $logger->notice(sprintf('Forwarding to second factor controller for loa determination and handling')); |
||
150 | |||
151 | return $this->forward('SurfnetStepupGatewayGatewayBundle:SecondFactor:selectSecondFactorForVerification'); |
||
152 | } |
||
153 | |||
154 | public function respondAction() |
||
155 | { |
||
156 | $responseContext = $this->getResponseContext(); |
||
157 | $originalRequestId = $responseContext->getInResponseTo(); |
||
158 | |||
159 | /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */ |
||
160 | $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId); |
||
161 | $logger->notice('Creating Response'); |
||
162 | |||
163 | $grantedLoa = null; |
||
164 | if ($responseContext->isSecondFactorVerified()) { |
||
165 | $secondFactor = $this->get('gateway.service.second_factor_service')->findByUuid( |
||
166 | $responseContext->getSelectedSecondFactor() |
||
167 | ); |
||
168 | |||
169 | $secondFactorTypeService = $this->get('surfnet_stepup.service.second_factor_type'); |
||
170 | $grantedLoa = $this->get('surfnet_stepup.service.loa_resolution')->getLoaByLevel( |
||
171 | $secondFactor->getLoaLevel($secondFactorTypeService) |
||
172 | ); |
||
173 | } |
||
174 | |||
175 | /** @var \Surfnet\StepupGateway\GatewayBundle\Service\ProxyResponseService $proxyResponseService */ |
||
176 | $proxyResponseService = $this->get('gateway.service.response_proxy'); |
||
177 | |||
178 | $response = $proxyResponseService->createProxyResponse( |
||
179 | $responseContext->reconstituteAssertion(), |
||
180 | $responseContext->getServiceProvider(), |
||
181 | (string)$grantedLoa |
||
182 | ); |
||
183 | |||
184 | $responseContext->responseSent(); |
||
185 | |||
186 | $logger->notice(sprintf( |
||
187 | 'Responding to request "%s" with response based on response from the remote IdP with response "%s"', |
||
188 | $responseContext->getInResponseTo(), |
||
189 | $response->getId() |
||
190 | )); |
||
191 | |||
192 | return $this->renderSamlResponse('consumeAssertion', $response); |
||
193 | } |
||
194 | |||
195 | View Code Duplication | public function sendLoaCannotBeGivenAction() |
|
220 | |||
221 | View Code Duplication | public function sendAuthenticationCancelledByUserAction() |
|
222 | { |
||
223 | $responseContext = $this->getResponseContext(); |
||
224 | $originalRequestId = $responseContext->getInResponseTo(); |
||
225 | |||
226 | /** @var \Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger $logger */ |
||
227 | $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId); |
||
228 | $logger->notice('Authentication was cancelled by the user, creating Response with AuthnFailed status'); |
||
229 | |||
230 | /** @var \Surfnet\StepupGateway\GatewayBundle\Saml\ResponseBuilder $responseBuilder */ |
||
231 | $responseBuilder = $this->get('gateway.proxy.response_builder'); |
||
232 | |||
233 | $response = $responseBuilder |
||
234 | ->createNewResponse($responseContext) |
||
235 | ->setResponseStatus( |
||
236 | Constants::STATUS_RESPONDER, |
||
237 | Constants::STATUS_AUTHN_FAILED, |
||
238 | 'Authentication cancelled by user' |
||
239 | ) |
||
240 | ->get(); |
||
241 | |||
242 | $logger->notice(sprintf( |
||
243 | 'Responding to request "%s" with response based on response from the remote IdP with response "%s"', |
||
244 | $responseContext->getInResponseTo(), |
||
245 | $response->getId() |
||
246 | )); |
||
247 | |||
248 | return $this->renderSamlResponse('consumeAssertion', $response); |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * @param string $view |
||
253 | * @param SAMLResponse $response |
||
254 | * @return Response |
||
255 | */ |
||
256 | View Code Duplication | public function renderSamlResponse($view, SAMLResponse $response) |
|
266 | |||
267 | /** |
||
268 | * @param string $view |
||
269 | * @param array $parameters |
||
270 | * @param Response $response |
||
271 | * @return Response |
||
272 | */ |
||
273 | public function render($view, array $parameters = array(), Response $response = null) |
||
281 | |||
282 | /** |
||
283 | * @return \Surfnet\StepupGateway\GatewayBundle\Saml\ResponseContext |
||
284 | */ |
||
285 | public function getResponseContext() |
||
286 | { |
||
287 | $stateHandler = $this->get('gateway.proxy.state_handler'); |
||
288 | $responseContextServiceId = $stateHandler->getResponseContextServiceId(); |
||
289 | |||
290 | if (!$responseContextServiceId) { |
||
291 | return $this->get(static::RESPONSE_CONTEXT_SERVICE_ID); |
||
292 | } |
||
293 | |||
294 | return $this->get($responseContextServiceId); |
||
295 | } |
||
296 | |||
297 | /** |
||
298 | * @param SAMLResponse $response |
||
299 | * @return string |
||
300 | */ |
||
301 | private function getResponseAsXML(SAMLResponse $response) |
||
305 | |||
306 | /** |
||
307 | * @return SAMLResponse |
||
308 | */ |
||
309 | private function createRequesterFailureResponse() |
||
323 | |||
324 | /** |
||
325 | * @param $context |
||
326 | * @return SAMLResponse |
||
327 | */ |
||
328 | private function createResponseFailureResponse($context) |
||
340 | } |
||
341 |
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.