Refactor for monolog in security controller
This commit is contained in:
parent
5f4336d824
commit
3f9d388f7f
|
|
@ -5,6 +5,7 @@ namespace App\Controller;
|
|||
use App\Repository\UserRepository;
|
||||
use App\Repository\UsersOrganizationsRepository;
|
||||
use App\Service\AccessTokenService;
|
||||
use App\Service\LoggerService;
|
||||
use App\Service\OrganizationsService;
|
||||
use App\Service\UserService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
|
@ -30,7 +31,7 @@ class SecurityController extends AbstractController
|
|||
private readonly UsersOrganizationsRepository $uoRepository,
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly OrganizationsService $organizationsService)
|
||||
private readonly OrganizationsService $organizationsService, private readonly LoggerService $loggerService, private readonly Security $security)
|
||||
{
|
||||
$this->cguUserService = $cguUserService;
|
||||
}
|
||||
|
|
@ -50,14 +51,16 @@ class SecurityController extends AbstractController
|
|||
#[Route(path: '/sso_logout', name: 'sso_logout')]
|
||||
public function ssoLogout(RequestStack $stack, LoggerInterface $logger, AccessTokenService $accessTokenService, Security $security): Response
|
||||
{
|
||||
try{
|
||||
if( $stack->getSession()->invalidate()){
|
||||
$accessTokenService->revokeTokens($security->getUser()->getUserIdentifier());
|
||||
try {
|
||||
$user = $this->userService->getUserByIdentifier($this->security->getUser()->getUserIdentifier());
|
||||
$id = $user->getId();
|
||||
if ($stack->getSession()->invalidate()) {
|
||||
$accessTokenService->revokeUserTokens($security->getUser()->getUserIdentifier());
|
||||
$security->logout(false);
|
||||
$logger->info("Logout successfully");
|
||||
return $this->redirect('/');
|
||||
$this->loggerService->logUserConnection('User logged out', ['user_id' => $id]);
|
||||
return $this->redirect('/');
|
||||
}
|
||||
}catch (\Exception $e){
|
||||
} catch (\Exception $e) {
|
||||
$logger->log(LogLevel::ERROR, 'Error invalidating session: ' . $e->getMessage());
|
||||
}
|
||||
return $this->redirectToRoute('app_index');
|
||||
|
|
@ -69,6 +72,7 @@ class SecurityController extends AbstractController
|
|||
if ($request->isMethod('POST')) {
|
||||
if (!$request->request->has('decline')) {
|
||||
$this->cguUserService->acceptLatestCgu($this->getUser());
|
||||
$this->loggerService->logCGUAcceptance($this->getUser()->getId());
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('oauth2_authorize', $request->query->all());
|
||||
|
|
@ -83,12 +87,24 @@ class SecurityController extends AbstractController
|
|||
$error = $request->get('error');
|
||||
$user = $this->userRepository->find($id);
|
||||
if (!$user) {
|
||||
$this->loggerService->logEntityNotFound('User', ['user_id' => $id,
|
||||
'error' => $error ?? null,
|
||||
'message' => 'user not found for password setup'], $id);
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
$token = $request->get('token');
|
||||
if (empty($token) || !$this->userService->isPasswordTokenValid($user, $token)) {
|
||||
if (empty($token)) {
|
||||
$error = 'Le lien de définition du mot de passe est invalide ou a expiré. Veuillez en demander un nouveau.';
|
||||
$this->logger->warning($user->getUserIdentifier(). " tried to use an invalid or expired password setup token.");
|
||||
$this->loggerService->logTokenError('Token empty while trying to setup password', ['token' => $token,
|
||||
'token_empty' => true,
|
||||
'user_id' => $id,
|
||||
'message' => 'empty token provided for password setup']);
|
||||
}
|
||||
|
||||
if (!$this->userService->isPasswordTokenValid($user, $token)) {
|
||||
$error = 'Le lien de définition du mot de passe est invalide ou a expiré. Veuillez en demander un nouveau.';
|
||||
$this->loggerService->logTokenError('invalid or expired token for password setup', ['user_id' => $id,
|
||||
'token' => $token,]);
|
||||
}
|
||||
return $this->render('security/password_setup.html.twig', [
|
||||
'id' => $id,
|
||||
|
|
@ -102,34 +118,38 @@ class SecurityController extends AbstractController
|
|||
{
|
||||
$user = $this->userRepository->find($id);
|
||||
if (!$user) {
|
||||
$this->loggerService->logEntityNotFound('User', ['user_id' => $id,
|
||||
'message' => 'user not found for password reset'], $id);
|
||||
throw $this->createNotFoundException(self::NOT_FOUND);
|
||||
}
|
||||
$newPassword = $_POST['_password'] ?? null;
|
||||
$confirmPassword = $_POST['_passwordConfirm'] ?? null;
|
||||
if ($newPassword !== $confirmPassword) {
|
||||
$error = 'Les mots de passe ne correspondent pas. Veuillez réessayer.';
|
||||
$this->logger->warning($user->getUserIdentifier(). " provided non-matching passwords during password reset.");
|
||||
$this->loggerService->logUserAction($id, $id, 'Password confirmation does not match during password reset.');
|
||||
return $this->redirectToRoute('password_setup', [
|
||||
'id' => $id,
|
||||
'token' => $_POST['token'] ?? '',
|
||||
'error'=> $error]);
|
||||
'error' => $error]);
|
||||
}
|
||||
if (!$this->userService->isPasswordStrong($newPassword)) {
|
||||
$error = 'Le mot de passe ne respecte pas les critères de sécurité. Veuillez en choisir un autre.';
|
||||
$this->logger->warning($user->getUserIdentifier(). " provided a weak password during password reset.");
|
||||
return $this->redirectToRoute('password_setup', ['id' => $id, 'token' => $_POST['token'] ?? '', 'error'=> $error]);
|
||||
$this->loggerService->logUserAction($id, $id, ' provided a weak password during password reset.');
|
||||
return $this->redirectToRoute('password_setup', ['id' => $id, 'token' => $_POST['token'] ?? '', 'error' => $error]);
|
||||
}
|
||||
$this->userService->updateUserPassword($user, $newPassword);
|
||||
$orgId = $this->userService->getOrgFromToken( $_POST['token']);
|
||||
$this->loggerService->logUserAction($id, $id, 'Password reset user successfully.');
|
||||
$orgId = $this->userService->getOrgFromToken($_POST['token']);
|
||||
$uo = $this->uoRepository->findOneBy(['users' => $user, 'organization' => $orgId]);
|
||||
if($uo){
|
||||
if ($uo) {
|
||||
$uo->setStatut("ACCEPTED");
|
||||
$uo->setIsActive(true);
|
||||
$this->entityManager->persist($uo);
|
||||
$this->entityManager->flush();
|
||||
$this->loggerService->logOrganizationInformation($orgId, $user->getId(), 'User accepted organization invitation during password reset.');
|
||||
$this->loggerService->logUserAction($id, $id, "User accepted organization invitation successfully with uo link id : {$uo->getId()}");
|
||||
$data = ['user' => $user,
|
||||
'organization' => $uo->getOrganization(),
|
||||
'ip' => $request->getClientIp(),
|
||||
];
|
||||
|
||||
$this->organizationsService->notifyOrganizationAdmins($data, "USER_ACCEPTED");
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use App\Repository\OrganizationsRepository;
|
|||
use App\Repository\RolesRepository;
|
||||
use App\Repository\UserRepository;
|
||||
use App\Repository\UsersOrganizationsRepository;
|
||||
use App\Service\AccessTokenService;
|
||||
use App\Service\ActionService;
|
||||
use App\Service\AwsService;
|
||||
use App\Service\EmailService;
|
||||
|
|
@ -45,17 +46,17 @@ class UserController extends AbstractController
|
|||
private readonly UserOrganizationService $userOrganizationService,
|
||||
private readonly UserRepository $userRepository,
|
||||
private readonly UsersOrganizationsRepository $uoRepository,
|
||||
private readonly OrganizationsRepository $organizationRepository,
|
||||
private readonly LoggerInterface $userManagementLogger,
|
||||
private readonly LoggerInterface $organizationManagementLogger,
|
||||
private readonly LoggerInterface $errorLogger,
|
||||
private readonly LoggerInterface $securityLogger,
|
||||
private readonly LoggerService $loggerService,
|
||||
private readonly EmailService $emailService,
|
||||
private readonly AwsService $awsService,
|
||||
private readonly OrganizationsService $organizationsService,
|
||||
private readonly AppsRepository $appsRepository,
|
||||
private readonly RolesRepository $rolesRepository,
|
||||
private readonly OrganizationsRepository $organizationRepository,
|
||||
private readonly LoggerInterface $userManagementLogger,
|
||||
private readonly LoggerInterface $organizationManagementLogger,
|
||||
private readonly LoggerInterface $errorLogger,
|
||||
private readonly LoggerInterface $securityLogger,
|
||||
private readonly LoggerService $loggerService,
|
||||
private readonly EmailService $emailService,
|
||||
private readonly AwsService $awsService,
|
||||
private readonly OrganizationsService $organizationsService,
|
||||
private readonly AppsRepository $appsRepository,
|
||||
private readonly RolesRepository $rolesRepository, private readonly AccessTokenService $accessTokenService,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
|
@ -405,7 +406,7 @@ class UserController extends AbstractController
|
|||
$this->userOrganizationService->deactivateAllUserOrganizationLinks($actingUser, $user);
|
||||
|
||||
if ($this->userService->isUserConnected($user->getUserIdentifier())) {
|
||||
$this->userService->revokeUserTokens($user->getUserIdentifier());
|
||||
$this->accessTokenService->revokeUserTokens($user->getUserIdentifier());
|
||||
}
|
||||
|
||||
$user->setModifiedAt(new \DateTimeImmutable('now'));
|
||||
|
|
@ -563,7 +564,7 @@ class UserController extends AbstractController
|
|||
|
||||
// Revoke tokens if connected
|
||||
if ($this->userService->isUserConnected($user->getUserIdentifier())) {
|
||||
$this->userService->revokeUserTokens($user->getUserIdentifier());
|
||||
$this->accessTokenService->revokeUserTokens($user->getUserIdentifier());
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
|
|
|||
|
|
@ -11,17 +11,38 @@ class AccessTokenService
|
|||
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
public function __construct(EntityManagerInterface $entityManager,
|
||||
private readonly LoggerService $loggerService)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function revokeTokens(String $userIdentifier): void {
|
||||
$accessTokens = $this->entityManager->getRepository(AccessToken::class)->findBy(['userIdentifier' => $userIdentifier, 'revoked' => false]);
|
||||
foreach($accessTokens as $accessToken) {
|
||||
$accessToken->revoke();
|
||||
$this->entityManager->persist($accessToken);
|
||||
$this->entityManager->flush();
|
||||
public function revokeUserTokens(string $userIdentifier): void
|
||||
{
|
||||
$tokens = $this->entityManager->getRepository(AccessToken::class)->findBy([
|
||||
'userIdentifier' => $userIdentifier,
|
||||
'revoked' => false
|
||||
]);
|
||||
foreach ($tokens as $token) {
|
||||
try{
|
||||
$token->revoke();
|
||||
$this->loggerService->logTokenRevocation(
|
||||
'Access token revoked for user',
|
||||
[
|
||||
'user_identifier' => $userIdentifier,
|
||||
'token_id' => $token->getIdentifier(),
|
||||
]
|
||||
);
|
||||
}catch (\Exception $e){
|
||||
$this->loggerService->logError(
|
||||
'Error revoking access token: ' . $e->getMessage(),
|
||||
[
|
||||
'user_identifier' => $userIdentifier,
|
||||
'token_id' => $token->getIdentifier(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,16 +78,12 @@ readonly class LoggerService
|
|||
]);
|
||||
}
|
||||
|
||||
public function logAdminNotified(int $adminUserId, int $targetUserId, int $orgId, int $actingUserId): void
|
||||
public function logAdminNotified(array $array): void
|
||||
{
|
||||
$this->emailNotificationLogger->notice('Organization admin notified', [
|
||||
'admin_user_id' => $adminUserId,
|
||||
'target_user_id' => $targetUserId,
|
||||
'organization_id' => $orgId,
|
||||
'acting_user_id' => $actingUserId,
|
||||
$this->emailNotificationLogger->notice('Organization admin notified', array_merge($array, [
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
]));
|
||||
}
|
||||
|
||||
public function logSuperAdmin(int $userId, ?int $orgId = null, int $actingUserId, string $message): void
|
||||
|
|
@ -224,4 +220,34 @@ readonly class LoggerService
|
|||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logUserConnection(string $message, array $array)
|
||||
{
|
||||
$this->securityLogger->info($message, array_merge($array, [
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]));
|
||||
}
|
||||
|
||||
public function logCGUAcceptance(int $it)
|
||||
{
|
||||
$this->userManagementLogger->info("User accepted CGU", [
|
||||
'user_id' => $it,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
$this->securityLogger->info("User accepted CGU", [
|
||||
'user_id' => $it,
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
'timestamp' => $this->now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function logTokenError(string $message, array $context = []): void
|
||||
{
|
||||
$this->securityLogger->error($message, array_merge($context, [
|
||||
'timestamp' => $this->now(),
|
||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,14 +99,11 @@ class OrganizationsService
|
|||
$newUser,
|
||||
$data['organization']
|
||||
);
|
||||
$this->loggerService->logAdminNotified([
|
||||
'admin_user_id' =>$adminUO->getUsers()->getId(),
|
||||
'target_user_id' => $newUser->getId(),
|
||||
'organization_id' => $data['organization']->getId(),'case' =>$type]);
|
||||
}
|
||||
$this->emailNotificationLogger->info('Organization admins notified of new user accept', [
|
||||
'admin_user_id' => $adminUO->getUsers()->getId(),
|
||||
'organization_id' => $data['organization']->getId(),
|
||||
'ip' => $data['ip'] ?? null,
|
||||
'user_accepted' => $newUser->getId(),
|
||||
'timestamp' => (new \DateTimeImmutable('now'))->format(DATE_ATOM),
|
||||
]);
|
||||
break;
|
||||
case 'USER_INVITED':
|
||||
if ($uoa) {
|
||||
|
|
@ -116,14 +113,12 @@ class OrganizationsService
|
|||
$invitedUser,
|
||||
$data['organization']
|
||||
);
|
||||
$this->loggerService->logAdminNotified([
|
||||
'admin_user_id' =>$adminUO->getUsers()->getId(),
|
||||
'target_user_id' => $newUser->getId(),
|
||||
'organization_id' => $data['organization']->getId(),'case' =>$type]);
|
||||
}
|
||||
$this->emailNotificationLogger->info('Organization admins notified of new user invited', [
|
||||
'admin_user_id' => $adminUO->getUsers()->getId(),
|
||||
'organization_id' => $data['organization']->getId(),
|
||||
'ip' => $data['ip'] ?? null,
|
||||
'user_accepted' => $invitedUser->getId(),
|
||||
'timestamp' => (new \DateTimeImmutable('now'))->format(DATE_ATOM),
|
||||
]);
|
||||
|
||||
break;
|
||||
case 'USER_DEACTIVATED':
|
||||
if ($uoa && $adminUO->getUsers()->getId() !== $data['user']->getId() ) {
|
||||
|
|
@ -133,14 +128,12 @@ class OrganizationsService
|
|||
$removedUser,
|
||||
$data['organization']
|
||||
);
|
||||
$this->loggerService->logAdminNotified([
|
||||
'admin_user_id' =>$adminUO->getUsers()->getId(),
|
||||
'target_user_id' => $newUser->getId(),
|
||||
'organization_id' => $data['organization']->getId(),'case' =>$type]);
|
||||
}
|
||||
$this->emailNotificationLogger->info('Organization admins notified of user deactivated', [
|
||||
'admin_user_id' => $adminUO->getUsers()->getId(),
|
||||
'organization_id' => $data['organization']->getId(),
|
||||
'ip' => $data['ip'] ?? null,
|
||||
'user_accepted' => $removedUser->getId(),
|
||||
'timestamp' => (new \DateTimeImmutable('now'))->format(DATE_ATOM),
|
||||
]);
|
||||
|
||||
break;
|
||||
case 'USER_DELETED':
|
||||
if ($uoa && $adminUO->getUsers()->getId() !== $data['user']->getId() ) {
|
||||
|
|
@ -150,14 +143,11 @@ class OrganizationsService
|
|||
$removedUser,
|
||||
$data['organization']
|
||||
);
|
||||
$this->loggerService->logAdminNotified([
|
||||
'admin_user_id' =>$adminUO->getUsers()->getId(),
|
||||
'target_user_id' => $newUser->getId(),
|
||||
'organization_id' => $data['organization']->getId(),'case' =>$type]);
|
||||
}
|
||||
$this->emailNotificationLogger->info('Organization admins notified of user deleted', [
|
||||
'admin_user_id' => $adminUO->getUsers()->getId(),
|
||||
'organization_id' => $data['organization']->getId(),
|
||||
'ip' => $data['ip'] ?? null,
|
||||
'user_accepted' => $removedUser->getId(),
|
||||
'timestamp' => (new \DateTimeImmutable('now'))->format(DATE_ATOM),
|
||||
]);
|
||||
break;
|
||||
case 'USER_ACTIVATED':
|
||||
if ($uoa && $adminUO->getUsers()->getId() !== $data['user']->getId() ) {
|
||||
|
|
@ -167,14 +157,11 @@ class OrganizationsService
|
|||
$activatedUser,
|
||||
$data['organization']
|
||||
);
|
||||
$this->loggerService->logAdminNotified([
|
||||
'admin_user_id' =>$adminUO->getUsers()->getId(),
|
||||
'target_user_id' => $newUser->getId(),
|
||||
'organization_id' => $data['organization']->getId(),'case' =>$type]);
|
||||
}
|
||||
$this->emailNotificationLogger->info('Organization admins notified of user activated', [
|
||||
'admin_user_id' => $adminUO->getUsers()->getId(),
|
||||
'organization_id' => $data['organization']->getId(),
|
||||
'ip' => $data['ip'] ?? null,
|
||||
'user_accepted' => $activatedUser->getId(),
|
||||
'timestamp' => (new \DateTimeImmutable('now'))->format(DATE_ATOM),
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -302,34 +302,6 @@ class UserService
|
|||
return 'ROLE_' . $role;
|
||||
}
|
||||
|
||||
public function revokeUserTokens(string $userIdentifier)
|
||||
{
|
||||
$tokens = $this->entityManager->getRepository(AccessToken::class)->findBy([
|
||||
'userIdentifier' => $userIdentifier,
|
||||
'revoked' => false
|
||||
]);
|
||||
foreach ($tokens as $token) {
|
||||
try{
|
||||
$token->revoke();
|
||||
$this->loggerService->logTokenRevocation(
|
||||
'Access token revoked for user',
|
||||
[
|
||||
'user_identifier' => $userIdentifier,
|
||||
'token_id' => $token->getIdentifier(),
|
||||
]
|
||||
);
|
||||
}catch (\Exception $e){
|
||||
$this->loggerService->logError(
|
||||
'Error revoking access token: ' . $e->getMessage(),
|
||||
[
|
||||
'user_identifier' => $userIdentifier,
|
||||
'token_id' => $token->getIdentifier(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function formatStatutForOrganizations(array $rows): array
|
||||
{
|
||||
|
|
@ -626,13 +598,14 @@ class UserService
|
|||
$token = $this->generatePasswordToken($user, $org->getId());
|
||||
$this->emailService->sendExistingUserNotificationEmail($user, $org, $token);
|
||||
$this->loggerService->logExistingUserNotificationSent($user->getId(), $org->getId());
|
||||
$this->organizationsService->notifyOrganizationAdmins(['user'=> $user, 'acting_user_id'=>$actingUser->getId(),
|
||||
'organization'=> $org], 'USER_INVITED');
|
||||
} catch (\Exception $e) {
|
||||
$this->loggerService->logError("Error sending existing user notification: " . $e->getMessage(), [
|
||||
'target_user_id' => $user->getId(),
|
||||
'organization_id' => $org->getId(),
|
||||
]);
|
||||
}
|
||||
$this->notifyOrgAdmins($user, $org, $actingUser,);
|
||||
}
|
||||
|
||||
private function sendNewUserNotifications(User $user, Organizations $org, User $actingUser): void
|
||||
|
|
@ -640,37 +613,14 @@ class UserService
|
|||
try {
|
||||
$token = $this->generatePasswordToken($user, $org->getId());
|
||||
$this->emailService->sendPasswordSetupEmail($user, $token);
|
||||
$this->organizationsService->notifyOrganizationAdmins(['user'=> $user, 'acting_user_id'=>$actingUser->getId(),
|
||||
'organization'=> $org], 'USER_INVITED');
|
||||
} catch (\Exception $e) {
|
||||
$this->loggerService->logError("Error sending password setup email: " . $e->getMessage(), [
|
||||
'target_user_id' => $user->getId(),
|
||||
'organization_id' => $org->getId(),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->notifyOrgAdmins($user, $org, $actingUser);
|
||||
}
|
||||
|
||||
private function notifyOrgAdmins(User $user, Organizations $org, User $actingUser): void
|
||||
{
|
||||
try {
|
||||
$data = ['user' => $user,
|
||||
'organization' => $org];
|
||||
$adminsUos = $this->organizationsService->notifyOrganizationAdmins($data, 'USER_INVITED');
|
||||
|
||||
foreach ($adminsUos as $adminUo) {
|
||||
$this->loggerService->logAdminNotified(
|
||||
$adminUo->getUsers()->getId(),
|
||||
$user->getId(),
|
||||
$org->getId(),
|
||||
$actingUser->getId(),
|
||||
);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->loggerService->logError("Error notifying organization admins: " . $e->getMessage(), [
|
||||
'target_user_id' => $user->getId(),
|
||||
'organization_id' => $org->getId(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue