Skip to content

Commit

Permalink
Make the other Authentication controllers invokable
Browse files Browse the repository at this point in the history
  • Loading branch information
MKodde committed Sep 2, 2024
1 parent 5f669d5 commit 8022610
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 133 deletions.
134 changes: 1 addition & 133 deletions src/Controller/AuthenticationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
use Surfnet\Tiqr\Tiqr\TiqrUserRepositoryInterface;
use Surfnet\Tiqr\WithContextLogger;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
Expand All @@ -65,7 +64,7 @@ public function __construct(
* @throws Exception
*/
#[Route(path: '/authentication', name: 'app_identity_authentication', methods: ['GET', 'POST'])]
public function authentication(Request $request): Response
public function __invoke(Request $request): Response
{
$nameId = $this->authenticationService->getNameId();
$sari = $this->stateHandler->getRequestId();
Expand Down Expand Up @@ -151,105 +150,6 @@ public function authentication(Request $request): Response
]);
}

/**
* Generate a notification response for authentication.html.
*
* The javascript in the authentication page expects one of three statuses:
*
* - success: Notification send successfully
* - error: Notification was not send successfully
* - no-device: There was no device to send the notification
*
* @return JsonResponse
*/
private function generateNotificationResponse(string $status): JsonResponse
{
return new JsonResponse($status);
}

/**
*
* @throws InvalidArgumentException
*/
#[Route(path: '/authentication/qr', name: 'app_identity_authentication_qr', methods: ['GET'])]
public function authenticationQr(): Response
{
$nameId = $this->authenticationService->getNameId();
$sari = $this->stateHandler->getRequestId();
$logger = WithContextLogger::from($this->logger, ['nameId' => $nameId, 'sari' => $sari]);
$logger->info('Client request QR image');

// Do have a valid sample AuthnRequest?.
if (!$this->authenticationService->authenticationRequired()) {
$logger->error('There is no pending authentication request from SP');

return new Response('No authentication required', Response::HTTP_BAD_REQUEST);
}

$logger->info('Return QR image response');

return $this->tiqrService->createAuthenticationQRResponse();
}

/**
*
* @throws InvalidArgumentException
*/
#[Route(path: '/authentication/notification', name: 'app_identity_authentication_notification', methods: ['POST'])]
public function authenticationNotification(): Response
{
$nameId = $this->authenticationService->getNameId();
$sari = $this->stateHandler->getRequestId();
$logger = WithContextLogger::from($this->logger, ['nameId' => $nameId, 'sari' => $sari]);
$logger->info('Client requests sending push notification');

// Do have a valid sample AuthnRequest?.
if (!$this->authenticationService->authenticationRequired()) {
$logger->error('There is no pending authentication request from SP');

return new Response('No authentication required', Response::HTTP_BAD_REQUEST);
}

$logger->info('Sending push notification');

// Get user.
try {
$user = $this->userRepository->getUser($nameId);
} catch (UserNotExistsException $exception) {
$logger->error(sprintf(
'User with nameId "%s" not found, error "%s"',
$nameId,
$exception->getMessage()
));

return new Response(null, Response::HTTP_BAD_REQUEST);
}

// Send notification.
$notificationType = $user->getNotificationType();
$notificationAddress = $user->getNotificationAddress();

if ($notificationType && $notificationAddress) {
$this->logger->notice(sprintf(
'Sending push notification for user "%s" with type "%s" and (untranslated) address "%s"',
$nameId,
$notificationType,
$notificationAddress
));

$result = $this->sendNotification($notificationType, $notificationAddress);
if ($result) {
return $this->generateNotificationResponse('success');
}
return $this->generateNotificationResponse('error');
}

$this->logger->notice(sprintf('No notification address for user "%s", no notification was sent', $nameId));

return $this->generateNotificationResponse('no-device');
}


private function handleInvalidResponse(TiqrUserInterface $user, AuthenticationResponse $response, LoggerInterface $logger): Response
{
try {
Expand Down Expand Up @@ -285,36 +185,4 @@ private function showUserIsBlockedErrorPage(bool $isBlockedPermanently): Respons
]
);
}

/**
* @return bool True when the notification was successfully sent, false otherwise
*/
private function sendNotification(string $notificationType, string $notificationAddress): bool
{
try {
$this->tiqrService->sendNotification($notificationType, $notificationAddress);
} catch (Exception $e) {
$this->logger->warning(
sprintf(
'Failed to send push notification for type "%s" and address "%s"',
$notificationType,
$notificationAddress
),
[
'exception' => $e,
]
);
return false;
}

$this->logger->notice(
sprintf(
'Successfully sent push notification for type "%s" and address "%s"',
$notificationType,
$notificationAddress
)
);

return true;
}
}
155 changes: 155 additions & 0 deletions src/Controller/AuthenticationNotificationController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<?php

declare(strict_types = 1);

/**
* Copyright 2018 SURFnet B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Surfnet\Tiqr\Controller;

use Exception;
use InvalidArgumentException;
use Psr\Log\LoggerInterface;
use Surfnet\GsspBundle\Service\AuthenticationService;
use Surfnet\GsspBundle\Service\StateHandlerInterface;
use Surfnet\Tiqr\Tiqr\Exception\UserNotExistsException;
use Surfnet\Tiqr\Tiqr\TiqrServiceInterface;
use Surfnet\Tiqr\Tiqr\TiqrUserRepositoryInterface;
use Surfnet\Tiqr\WithContextLogger;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class AuthenticationNotificationController extends AbstractController
{
public function __construct(
private readonly AuthenticationService $authenticationService,
private readonly StateHandlerInterface $stateHandler,
private readonly TiqrServiceInterface $tiqrService,
private readonly TiqrUserRepositoryInterface $userRepository,
private readonly LoggerInterface $logger
) {
}

/**
* @throws InvalidArgumentException
*/
#[Route(path: '/authentication/notification', name: 'app_identity_authentication_notification', methods: ['POST'])]
public function __invoke(): Response
{
$nameId = $this->authenticationService->getNameId();
$sari = $this->stateHandler->getRequestId();
$logger = WithContextLogger::from($this->logger, ['nameId' => $nameId, 'sari' => $sari]);
$logger->info('Client requests sending push notification');

// Do have a valid sample AuthnRequest?.
if (!$this->authenticationService->authenticationRequired()) {
$logger->error('There is no pending authentication request from SP');

return new Response('No authentication required', Response::HTTP_BAD_REQUEST);
}

$logger->info('Sending push notification');

// Get user.
try {
$user = $this->userRepository->getUser($nameId);
} catch (UserNotExistsException $exception) {
$logger->error(sprintf(
'User with nameId "%s" not found, error "%s"',
$nameId,
$exception->getMessage()
));

return new Response(null, Response::HTTP_BAD_REQUEST);
}

// Send notification.
$notificationType = $user->getNotificationType();
$notificationAddress = $user->getNotificationAddress();

if ($notificationType && $notificationAddress) {
$this->logger->notice(sprintf(
'Sending push notification for user "%s" with type "%s" and (untranslated) address "%s"',
$nameId,
$notificationType,
$notificationAddress
));

$result = $this->sendNotification($notificationType, $notificationAddress);
if ($result) {
return $this->generateNotificationResponse('success');
}
return $this->generateNotificationResponse('error');
}

$this->logger->notice(sprintf('No notification address for user "%s", no notification was sent', $nameId));

return $this->generateNotificationResponse('no-device');
}

/**
* @return bool True when the notification was successfully sent, false otherwise
*/
private function sendNotification(string $notificationType, string $notificationAddress): bool
{
try {
$this->tiqrService->sendNotification($notificationType, $notificationAddress);
} catch (Exception $e) {
$this->logger->warning(
sprintf(
'Failed to send push notification for type "%s" and address "%s"',
$notificationType,
$notificationAddress
),
[
'exception' => $e,
]
);
return false;
}

$this->logger->notice(
sprintf(
'Successfully sent push notification for type "%s" and address "%s"',
$notificationType,
$notificationAddress
)
);

return true;
}

/**
* Generate a notification response for authentication.html.
*
* The javascript in the authentication page expects one of three statuses:
*
* - success: Notification send successfully
* - error: Notification was not send successfully
* - no-device: There was no device to send the notification
*
* @return JsonResponse
*/
private function generateNotificationResponse(string $status): JsonResponse
{
return new JsonResponse($status);
}
}
65 changes: 65 additions & 0 deletions src/Controller/AuthenticationQrController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types = 1);

/**
* Copyright 2018 SURFnet B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Surfnet\Tiqr\Controller;

use InvalidArgumentException;
use Psr\Log\LoggerInterface;
use Surfnet\GsspBundle\Service\AuthenticationService;
use Surfnet\GsspBundle\Service\StateHandlerInterface;
use Surfnet\Tiqr\Tiqr\TiqrServiceInterface;
use Surfnet\Tiqr\WithContextLogger;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class AuthenticationQrController
{
public function __construct(
private readonly AuthenticationService $authenticationService,
private readonly StateHandlerInterface $stateHandler,
private readonly TiqrServiceInterface $tiqrService,
private readonly LoggerInterface $logger
) {
}

/**
*
* @throws InvalidArgumentException
*/
#[Route(path: '/authentication/qr', name: 'app_identity_authentication_qr', methods: ['GET'])]
public function __invoke(): Response
{
$nameId = $this->authenticationService->getNameId();
$sari = $this->stateHandler->getRequestId();
$logger = WithContextLogger::from($this->logger, ['nameId' => $nameId, 'sari' => $sari]);
$logger->info('Client request QR image');

// Do have a valid sample AuthnRequest?.
if (!$this->authenticationService->authenticationRequired()) {
$logger->error('There is no pending authentication request from SP');

return new Response('No authentication required', Response::HTTP_BAD_REQUEST);
}

$logger->info('Return QR image response');

return $this->tiqrService->createAuthenticationQRResponse();
}
}

0 comments on commit 8022610

Please sign in to comment.