Olivier Massot 2 місяців тому
батько
коміт
b0655edc5f

+ 1 - 15
src/ApiResources/HelloAsso/AuthUrl.php

@@ -35,11 +35,6 @@ class AuthUrl
      */
     private string $authUrl;
 
-    /**
-     * Vérificateur de défi PKCE pour sécuriser l'échange OAuth2.
-     */
-    private string $challengeVerifier;
-
     public function getId(): int
     {
         return $this->id;
@@ -48,6 +43,7 @@ class AuthUrl
     public function setId(int $id): self
     {
         $this->id = $id;
+
         return $this;
     }
 
@@ -59,17 +55,7 @@ class AuthUrl
     public function setAuthUrl(string $authUrl): self
     {
         $this->authUrl = $authUrl;
-        return $this;
-    }
 
-    public function getChallengeVerifier(): string
-    {
-        return $this->challengeVerifier;
-    }
-
-    public function setChallengeVerifier(string $challengeVerifier): self
-    {
-        $this->challengeVerifier = $challengeVerifier;
         return $this;
     }
 }

+ 19 - 3
src/ApiResources/HelloAsso/ConnectionRequest.php

@@ -1,4 +1,5 @@
 <?php
+
 declare(strict_types=1);
 
 namespace App\ApiResources\HelloAsso;
@@ -6,10 +7,11 @@ namespace App\ApiResources\HelloAsso;
 use ApiPlatform\Metadata\ApiProperty;
 use ApiPlatform\Metadata\ApiResource;
 use ApiPlatform\Metadata\Post;
+use App\ApiResources\ApiResourcesInterface;
 use App\State\Processor\HelloAsso\ConnectionRequestProcessor;
 
 /**
- * Demande de connexion d'une organisation à HelloAsso
+ * Demande de connexion d'une organisation à HelloAsso.
  */
 #[ApiResource(
     operations: [
@@ -18,9 +20,8 @@ use App\State\Processor\HelloAsso\ConnectionRequestProcessor;
         ),
     ],
     processor: ConnectionRequestProcessor::class,
-    security: '(is_granted("ROLE_ORGANIZATION") and object.getOrganizationId() == user.getOrganization().getId() )'
 )]
-class ConnectionRequest
+class ConnectionRequest implements ApiResourcesInterface
 {
     /**
      * Id 'bidon' ajouté par défaut pour permettre la construction
@@ -33,6 +34,8 @@ class ConnectionRequest
 
     private string $authorizationCode;
 
+    private string $challengeVerifier;
+
     public function getId(): int
     {
         return $this->id;
@@ -46,6 +49,7 @@ class ConnectionRequest
     public function setOrganizationId(int $organizationId): self
     {
         $this->organizationId = $organizationId;
+
         return $this;
     }
 
@@ -57,6 +61,18 @@ class ConnectionRequest
     public function setAuthorizationCode(string $authorizationCode): self
     {
         $this->authorizationCode = $authorizationCode;
+
+        return $this;
+    }
+
+    public function getChallengeVerifier(): string
+    {
+        return $this->challengeVerifier;
+    }
+
+    public function setChallengeVerifier(string $challengeVerifier): self
+    {
+        $this->challengeVerifier = $challengeVerifier;
         return $this;
     }
 }

+ 25 - 7
src/Entity/Organization/HelloAsso.php

@@ -4,10 +4,9 @@ namespace App\Entity\Organization;
 
 use App\Entity\Traits\CreatedOnAndByTrait;
 use Doctrine\ORM\Mapping as ORM;
-use Symfony\Component\Serializer\Annotation\Groups;
 
 /**
- * HelloAsso entity for storing HelloAsso connection information
+ * HelloAsso entity for storing HelloAsso connection information.
  *
  * @see https://dev.helloasso.com/docs/mire-authorisation
  */
@@ -22,17 +21,20 @@ class HelloAsso
     #[ORM\GeneratedValue]
     private ?int $id = null;
 
-    #[ORM\OneToOne(targetEntity: Organization::class, inversedBy: "helloAsso")]
-    #[ORM\JoinColumn(name: "organization_id", referencedColumnName: "id", nullable: false)]
+    #[ORM\OneToOne(targetEntity: Organization::class, inversedBy: 'helloAsso')]
+    #[ORM\JoinColumn(name: 'organization_id', referencedColumnName: 'id', nullable: false)]
     private Organization $organization;
 
-    #[ORM\Column(type: "text", nullable: true)]
+    #[ORM\Column(type: 'text', nullable: true)]
+    private ?string $challengeVerifier = null;
+
+    #[ORM\Column(type: 'text', nullable: true)]
     private ?string $token = null;
 
-    #[ORM\Column(type: "text", nullable: true)]
+    #[ORM\Column(type: 'text', nullable: true)]
     private ?string $refreshToken = null;
 
-    #[ORM\Column(type: "string", length: 255, nullable: true)]
+    #[ORM\Column(type: 'string', length: 255, nullable: true)]
     private ?string $organizationSlug = null;
 
     public function getId(): ?int
@@ -43,6 +45,7 @@ class HelloAsso
     public function setId(?int $id): self
     {
         $this->id = $id;
+
         return $this;
     }
 
@@ -54,6 +57,18 @@ class HelloAsso
     public function setOrganization(Organization $organization): self
     {
         $this->organization = $organization;
+
+        return $this;
+    }
+
+    public function getChallengeVerifier(): ?string
+    {
+        return $this->challengeVerifier;
+    }
+
+    public function setChallengeVerifier(?string $challengeVerifier): self
+    {
+        $this->challengeVerifier = $challengeVerifier;
         return $this;
     }
 
@@ -65,6 +80,7 @@ class HelloAsso
     public function setToken(?string $token): self
     {
         $this->token = $token;
+
         return $this;
     }
 
@@ -76,6 +92,7 @@ class HelloAsso
     public function setRefreshToken(?string $refreshToken): self
     {
         $this->refreshToken = $refreshToken;
+
         return $this;
     }
 
@@ -87,6 +104,7 @@ class HelloAsso
     public function setOrganizationSlug(?string $organizationSlug): self
     {
         $this->organizationSlug = $organizationSlug;
+
         return $this;
     }
 }

+ 0 - 1
src/Entity/Organization/Organization.php

@@ -38,7 +38,6 @@ use App\Entity\Message\Mail;
 use App\Entity\Message\Sms;
 use App\Entity\Network\NetworkOrganization;
 use App\Entity\Organization\Traits\OrganizationComputedTraits;
-use App\Entity\Organization\HelloAsso;
 use App\Entity\Person\Commission;
 use App\Entity\Place\Place;
 use App\Entity\Product\Equipment;

+ 2 - 2
src/Service/Security/OAuthPkceGenerator.php

@@ -1,4 +1,5 @@
 <?php
+
 declare(strict_types=1);
 
 namespace App\Service\Security;
@@ -20,8 +21,7 @@ class OAuthPkceGenerator
         return [
             'verifier' => $codeVerifier,
             'challenge' => $codeChallenge,
-            'method' => 'S256'
+            'method' => 'S256',
         ];
     }
-
 }

+ 13 - 4
src/State/Processor/HelloAsso/ConnectionRequestProcessor.php

@@ -8,22 +8,24 @@ use ApiPlatform\Metadata\Operation;
 use ApiPlatform\Metadata\Post;
 use ApiPlatform\State\ProcessorInterface;
 use App\ApiResources\HelloAsso\ConnectionRequest;
+use App\Entity\Access\Access;
 use App\Service\HelloAsso\ConnectionService;
 use http\Client\Response;
+use Symfony\Bundle\SecurityBundle\Security;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
-
 class ConnectionRequestProcessor implements ProcessorInterface
 {
     public function __construct(
-        private readonly ConnectionService $connectionService
+        private readonly ConnectionService $connectionService,
+        private Security $security,
     ) {
     }
 
     /**
      * @param ConnectionRequest $data
-     * @param mixed[]                     $uriVariables
-     * @param mixed[]                     $context
+     * @param mixed[]           $uriVariables
+     * @param mixed[]           $context
      *
      * @throws \Exception
      */
@@ -38,6 +40,13 @@ class ConnectionRequestProcessor implements ProcessorInterface
             throw new \RuntimeException('not supported', Response::HTTP_METHOD_NOT_ALLOWED);
         }
 
+        /** @var Access $access */
+        $access = $this->security->getUser();
+
+        if ($connectionRequest->getOrganizationId() !== $access->getOrganization()->getId()) {
+            throw new \RuntimeException('Forbidden');
+        }
+
         $helloAssoEntity = $this->connectionService->connect(
             $connectionRequest->getOrganizationId(),
             $connectionRequest->getAuthorizationCode()

+ 9 - 1
src/State/Provider/HelloAsso/AuthUrlProvider.php

@@ -8,7 +8,9 @@ use ApiPlatform\Metadata\GetCollection;
 use ApiPlatform\Metadata\Operation;
 use ApiPlatform\State\ProviderInterface;
 use App\ApiResources\HelloAsso\AuthUrl;
+use App\Entity\Access\Access;
 use App\Service\HelloAsso\ConnectionService;
+use Symfony\Bundle\SecurityBundle\Security;
 use Symfony\Component\HttpFoundation\Response;
 
 /**
@@ -18,6 +20,7 @@ final class AuthUrlProvider implements ProviderInterface
 {
     public function __construct(
         private ConnectionService $connectionService,
+        private Security $security,
     ) {
     }
 
@@ -33,6 +36,11 @@ final class AuthUrlProvider implements ProviderInterface
             throw new \RuntimeException('not supported', Response::HTTP_METHOD_NOT_ALLOWED);
         }
 
-        return $this->connectionService->getAuthUrl();
+        /** @var Access $access */
+        $access = $this->security->getUser();
+
+        $organizationId = $access->getOrganization()->getId();
+
+        return $this->connectionService->getAuthUrl($organizationId);
     }
 }