Skip to content

Commit 8a1a9d3

Browse files
committed
Make service function less complex
The test where failing as the complexity of the function became to big. Therefore, some logic had to be moved to a private function.
1 parent c5a3049 commit 8a1a9d3

File tree

1 file changed

+48
-34
lines changed

1 file changed

+48
-34
lines changed

src/Surfnet/AzureMfa/Application/Service/AzureMfaService.php

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
use Surfnet\AzureMfa\Application\Exception\InvalidMfaAuthenticationContextException;
2525
use Surfnet\AzureMfa\Application\Institution\Service\EmailDomainMatchingService;
2626
use Surfnet\AzureMfa\Domain\EmailAddress;
27+
use Surfnet\AzureMfa\Domain\Institution\ValueObject\IdentityProviderInterface;
28+
use Surfnet\AzureMfa\Domain\Institution\ValueObject\Institution;
2729
use Surfnet\AzureMfa\Domain\Exception\AzureADException;
2830
use Surfnet\AzureMfa\Domain\Exception\InstitutionNotFoundException;
2931
use Surfnet\AzureMfa\Domain\Exception\MailAttributeMismatchException;
@@ -33,6 +35,7 @@
3335
use Surfnet\AzureMfa\Domain\UserStatus;
3436
use Surfnet\AzureMfa\Infrastructure\Cache\IdentityProviderFactoryCache;
3537
use Surfnet\SamlBundle\Entity\ServiceProvider;
38+
use SAML2\Assertion;
3639
use Surfnet\SamlBundle\Http\PostBinding;
3740
use Surfnet\SamlBundle\SAML2\AuthnRequestFactory;
3841
use Symfony\Component\HttpFoundation\Request;
@@ -146,7 +149,7 @@ public function createAuthnRequest(User $user, bool $forceAuthn = false): string
146149

147150
// Use email address as subject if not sending to an AzureAD IdP
148151
if (!$azureMfaIdentityProvider->isAzureAD()) {
149-
$this->logger->info('Setting the users email address '.$user->getEmailAddress().' as the Subject for the request to '.$azureMfaIdentityProvider->getEntityId());
152+
$this->logger->info('Setting the users email address '.$user->getEmailAddress()->getEmailAddress().' as the Subject for the request to '.$azureMfaIdentityProvider->getEntityId());
150153
$authnRequest->setSubject($user->getEmailAddress()->getEmailAddress());
151154
}
152155

@@ -183,50 +186,68 @@ public function handleResponse(Request $request): User
183186
assert($user instanceof User);
184187

185188
// Retrieve its institution and identity provider
186-
$this->logger->info('Match the user email address '.$user->getEmailAddress().'to one of the registered institutions');
189+
$this->logger->info('Match the user email address '.$user->getEmailAddress()->getEmailAddress().' to one of the registered institutions');
187190
$institution = $this->matchingService->findInstitutionByEmail($user->getEmailAddress());
188191
if (is_null($institution)) {
189192
throw new AzureADException('The Institution could not be found using the users mail address');
190193
}
191194
$azureMfaIdentityProvider = $this->identityProviderCache->build($institution->getName());
192195

196+
$assertion = $this->processSamlResponse($request, $institution, $azureMfaIdentityProvider);
197+
$attributes = $assertion->getAttributes();
198+
199+
$this->validateResponseAttributes($attributes, $institution, $azureMfaIdentityProvider, $user);
200+
201+
$this->logger->info(sprintf(
202+
'The mail attribute in the response %s matched the email address of the registering/authenticating user: %s',
203+
$attributes[self::SAML_EMAIL_ATTRIBUTE],
204+
$user->getEmailAddress()->getEmailAddress()
205+
));
206+
207+
return $user;
208+
}
209+
210+
private function processSamlResponse(
211+
Request $request,
212+
Institution $institution,
213+
IdentityProviderInterface $azureMfaIdentityProvider,
214+
): Assertion {
193215
try {
194216
$this->logger->info('Process the SAML Response');
195-
$assertion = $this->postBinding->processResponse(
196-
$request,
197-
$azureMfaIdentityProvider,
198-
$this->serviceProvider
199-
);
217+
return $this->postBinding->processResponse($request, $azureMfaIdentityProvider, $this->serviceProvider);
200218
} catch (Exception $e) {
201219
// If the signature validation fails, we try to rebuild the identity provider
202220
// This will effectively refresh the metadata for the institution
203221
// Todo: refactor this to be more robust, e.g. by checking the exception type
204222
if (!$institution->supportsMetadataUpdate() || $e->getMessage() !== 'Unable to validate Signature') {
205223
throw $e;
206224
}
225+
}
207226

208-
$this->logger->info(sprintf('Unable to validate signature refreshing metadata for %s', $institution->getName()->getInstitutionName()));
209-
210-
$azureMfaIdentityProvider = $this->identityProviderCache->rebuild($institution->getName());
227+
$this->logger->info(sprintf('Unable to validate signature refreshing metadata for %s', $institution->getName()->getInstitutionName()));
228+
$azureMfaIdentityProvider = $this->identityProviderCache->rebuild($institution->getName());
211229

212-
$this->logger->info('Reprocess the SAML Response from '.$institution->getName()->getInstitutionName().' after updating the metadata');
213-
try {
214-
$assertion = $this->postBinding->processResponse(
215-
$request,
216-
$azureMfaIdentityProvider,
217-
$this->serviceProvider
218-
);
219-
} catch (Exception $retryException) {
220-
$this->logger->error(sprintf(
221-
'Unable to validate signature after refreshing metadata for %s',
222-
$institution->getName()->getInstitutionName()
223-
));
224-
throw $retryException;
225-
}
230+
$this->logger->info('Reprocess the SAML Response from '.$institution->getName()->getInstitutionName().' after updating the metadata');
231+
try {
232+
return $this->postBinding->processResponse($request, $azureMfaIdentityProvider, $this->serviceProvider);
233+
} catch (Exception $retryException) {
234+
$this->logger->error(sprintf(
235+
'Unable to validate signature after refreshing metadata for %s',
236+
$institution->getName()->getInstitutionName()
237+
));
238+
throw $retryException;
226239
}
240+
}
227241

228-
$attributes = $assertion->getAttributes();
229-
242+
/**
243+
* @param array<string, mixed> $attributes
244+
*/
245+
private function validateResponseAttributes(
246+
array $attributes,
247+
Institution $institution,
248+
IdentityProviderInterface $azureMfaIdentityProvider,
249+
User $user,
250+
): void {
230251
// If the IDP was an AzureAD endpoint (the entityID or Issuer starts with https://login.microsoftonline.com/, or preferably an config parameter in institutions.yaml)
231252
// the SAML response attribute 'http://schemas.microsoft.com/claims/authnmethodsreferences'
232253
// should contain 'http://schemas.microsoft.com/claims/multipleauthn'
@@ -241,7 +262,7 @@ public function handleResponse(Request $request): User
241262

242263
if (!isset($attributes[self::SAML_EMAIL_ATTRIBUTE])) {
243264
throw new MissingMailAttributeException(
244-
'The mail attribute in the Azure MFA assertion from '.$institution->getName()->getInstitutionName(). 'was missing'
265+
'The mail attribute in the Azure MFA assertion from '.$institution->getName()->getInstitutionName().' was missing'
245266
);
246267
}
247268

@@ -253,12 +274,5 @@ public function handleResponse(Request $request): User
253274
strtolower($user->getEmailAddress()->getEmailAddress())
254275
));
255276
}
256-
257-
$this->logger->info(sprintf(
258-
'The mail attribute in the response %s matched the email address of the registering/authenticating user: %s',
259-
$attributes[self::SAML_EMAIL_ATTRIBUTE],
260-
$user->getEmailAddress()->getEmailAddress()
261-
));
262-
return $user;
263277
}
264278
}

0 commit comments

Comments
 (0)