SlackAuthenticator::start()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 2
1
<?php
2
3
/** @noinspection DuplicatedCode */
4
5
declare(strict_types=1);
6
7
/*
8
 * This file is part of the zibios/sharep.
9
 *
10
 * (c) Zbigniew Ślązak
11
 */
12
13
namespace App\Security\GuardAuthenticator;
14
15
use AdamPaterson\OAuth2\Client\Provider\SlackResourceOwner;
16
use App\Entity\Access\SlackIdentity;
17
use App\Entity\Access\User;
18
use App\Entity\Parking\Member;
19
use App\Enum\Functional\RoleEnum;
20
use Doctrine\ORM\EntityManagerInterface;
21
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
22
use KnpU\OAuth2ClientBundle\Client\Provider\SlackClient;
23
use KnpU\OAuth2ClientBundle\Security\Authenticator\SocialAuthenticator;
24
use League\OAuth2\Client\Token\AccessToken;
25
use Symfony\Component\HttpFoundation\JsonResponse;
26
use Symfony\Component\HttpFoundation\RedirectResponse;
27
use Symfony\Component\HttpFoundation\Request;
28
use Symfony\Component\HttpFoundation\Response;
29
use Symfony\Component\Routing\RouterInterface;
30
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
31
use Symfony\Component\Security\Core\Exception\AuthenticationException;
32
use Symfony\Component\Security\Core\User\UserProviderInterface;
33
34
class SlackAuthenticator extends SocialAuthenticator
35
{
36
    /** @var ClientRegistry */
37
    protected $clientRegistry;
38
    /** @var EntityManagerInterface */
39
    protected $entityManager;
40
    /** @var RouterInterface */
41
    protected $router;
42
43 21
    public function __construct(
44
        ClientRegistry $clientRegistry,
45
        EntityManagerInterface $entityManager,
46
        RouterInterface $router
47
    ) {
48 21
        $this->clientRegistry = $clientRegistry;
49 21
        $this->entityManager = $entityManager;
50 21
        $this->router = $router;
51 21
    }
52
53
    /**
54
     * @param Request                      $request       The request that resulted in an AuthenticationException
55
     * @param AuthenticationException|null $authException The exception that started the authentication process
56
     */
57
    public function start(
58
        Request $request,
59
        AuthenticationException $authException = null
60
    ): Response {
61
        return new Response('No authorized!', 403);
62
    }
63
64 21
    public function supports(Request $request): bool
65
    {
66 21
        return 'oauth2_slack_check' === $request->attributes->get('_route') && $request->isMethod('GET');
67
    }
68
69
    public function getCredentials(Request $request): AccessToken
70
    {
71
        return $this->fetchAccessToken($this->getSlackClient());
72
    }
73
74
    /**
75
     * @param AccessToken $credentials
76
     */
77
    public function getUser($credentials, UserProviderInterface $userProvider): ?User
78
    {
79
        /** @var SlackResourceOwner $slackUser */
80
        $slackUser = $this->getSlackClient()->fetchUserFromToken($credentials);
81
82
        /** @var User $user */
83
        $user = $this->entityManager
84
            ->getRepository(User::class)
85
            ->findOneBy(['email' => $slackUser->getEmail()]);
86
87
        if (!$user) {
88
            return null;
89
        }
90
91
        $slackIdentity = $user->getSlackIdentity();
92
        if (!$slackIdentity) {
93
            $slackIdentity = new SlackIdentity($user, (string) $slackUser->getId(), (string) $slackUser->getEmail());
94
        }
95
        $slackIdentity->setTeamId((string) $slackUser->toArray()['team_id']);
96
        $slackIdentity->setName((string) $slackUser->toArray()['name']);
97
        $slackIdentity->setIsDeleted((bool) $slackUser->toArray()['deleted']);
98
        $slackIdentity->setColor((string) $slackUser->toArray()['color']);
99
        $slackIdentity->setRealName((string) $slackUser->toArray()['real_name']);
100
        $slackIdentity->setTz((string) $slackUser->toArray()['tz']);
101
        $slackIdentity->setTzLabel((string) $slackUser->toArray()['tz_label']);
102
        $slackIdentity->setTzOffset((int) $slackUser->toArray()['tz_offset']);
103
        $slackIdentity->setIsAdmin((bool) $slackUser->toArray()['is_admin']);
104
        $slackIdentity->setIsBot((bool) $slackUser->toArray()['is_bot']);
105
        $slackIdentity->setUpdated((int) $slackUser->toArray()['updated']);
106
        $slackIdentity->setIsAppUser((bool) $slackUser->toArray()['is_app_user']);
107
108
        $member = $user->getMember();
109
        if (!$member) {
110
            $member = new Member($slackIdentity->getName(), RoleEnum::MEMBER(), $user);
111
        }
112
        $member->setName($slackIdentity->getName());
113
114
        $this->entityManager->persist($slackIdentity);
115
        $this->entityManager->persist($member);
116
        $this->entityManager->persist($user);
117
        $this->entityManager->flush();
118
119
        return $user;
120
    }
121
122
    public function onAuthenticationFailure(
123
        Request $request,
124
        AuthenticationException $exception
125
    ): JsonResponse {
126
        return new JsonResponse(
127
            [
128
                'message' => strtr(
129
                    $exception->getMessageKey(),
130
                    $exception->getMessageData()
131
                ),
132
            ],
133
            JsonResponse::HTTP_FORBIDDEN
134
        );
135
    }
136
137
    /**
138
     * @param string $providerKey The provider (i.e. firewall) key
139
     */
140
    public function onAuthenticationSuccess(
141
        Request $request,
142
        TokenInterface $token,
143
        $providerKey
144
    ): ?Response {
145
        return new RedirectResponse(
146
            $this->router->generate('site_page_contact'),
147
            Response::HTTP_TEMPORARY_REDIRECT
148
        );
149
    }
150
151
    private function getSlackClient(): SlackClient
152
    {
153
        $client = $this->clientRegistry->getClient('slack');
154
        \assert($client instanceof SlackClient);
155
156
        return $client;
157
    }
158
}
159