From 401641eabc66ef978b50681aa5a8ee0cc68c5ca6 Mon Sep 17 00:00:00 2001
From: Sonia Zorba <sonia.zorba@inaf.it>
Date: Tue, 6 Oct 2020 14:32:49 +0200
Subject: [PATCH] Refactoring and unit tests

---
 classes/ClientAuthChecker.php      |  13 ++-
 classes/ClientsLocator.php         |   2 +-
 classes/JWKSHandler.php            |   6 +-
 classes/Locator.php                |   8 --
 classes/OAuth2RequestHandler.php   |  37 ++++++--
 classes/TokenBuilder.php           |  14 +--
 config-example.yaml                |   6 +-
 include/front-controller.php       |  19 +---
 tests/ClientAuthCheckerTest.php    |  33 +++++++
 tests/LocatorTest.php              |  36 +++++++
 tests/OAuth2RequestHandlerTest.php | 147 +++++++++++++++++++++++++++++
 tests/TokenBuilderTest.php         |  68 +++++++++++--
 12 files changed, 329 insertions(+), 60 deletions(-)
 create mode 100644 tests/ClientAuthCheckerTest.php
 create mode 100644 tests/LocatorTest.php

diff --git a/classes/ClientAuthChecker.php b/classes/ClientAuthChecker.php
index 497f9bb..89598f8 100644
--- a/classes/ClientAuthChecker.php
+++ b/classes/ClientAuthChecker.php
@@ -15,19 +15,19 @@ class ClientAuthChecker {
         $this->locator = $locator;
     }
 
-    public function validateClientAuth(): void {
+    public function validateClientAuth(array $headers): BrowserBasedOAuth2Client {
 
-        $basic = $this->getBasicAuthArray();
+        $basic = $this->getBasicAuthArray($headers);
 
         $clientId = $basic[0];
         $clientSecret = $basic[1];
 
-        $this->locator->getBrowserBasedOAuth2ClientByIdAndSecret($clientId, $clientSecret);
+        return $this->locator->getBrowserBasedOAuth2ClientByIdAndSecret($clientId, $clientSecret);
     }
 
-    public function validateCliClientAuth(): CliOAuth2Client {
+    public function validateCliClientAuth(array $headers): CliOAuth2Client {
 
-        $basic = $this->getBasicAuthArray();
+        $basic = $this->getBasicAuthArray($headers);
 
         $clientId = $basic[0];
         $clientSecret = $basic[1];
@@ -35,8 +35,7 @@ class ClientAuthChecker {
         return $this->locator->getCliClientByIdAndSecret($clientId, $clientSecret);
     }
 
-    private function getBasicAuthArray(): array {
-        $headers = apache_request_headers();
+    private function getBasicAuthArray($headers): array {
 
         if (!isset($headers['Authorization'])) {
             throw new UnauthorizedException("Missing Authorization header");
diff --git a/classes/ClientsLocator.php b/classes/ClientsLocator.php
index 5ebe623..184f39c 100644
--- a/classes/ClientsLocator.php
+++ b/classes/ClientsLocator.php
@@ -31,7 +31,7 @@ trait ClientsLocator {
     private function getClientConfigFromListByIdAndSecret(array $clients, string $clientId, string $secret): object {
         $client = $this->getClientConfigFromListById($clients, $clientId);
         $secretHash = hash('sha256', $secret);
-        if ($client->secretHash !== $secretHash) {
+        if ($client->secret !== $secretHash) {
             throw new UnauthorizedException("Wrong secret provided for client '$clientId'");
         }
         return $client;
diff --git a/classes/JWKSHandler.php b/classes/JWKSHandler.php
index d759816..2f2d5bc 100644
--- a/classes/JWKSHandler.php
+++ b/classes/JWKSHandler.php
@@ -79,8 +79,10 @@ class JWKSHandler {
 
     public function loadAllJWKS(): array {
 
-        foreach ($this->locator->config->jwksUrls as $url) {
-            $this->loadJWKS($url);
+        foreach ($this->locator->getBrowserBasedOAuth2Clients() as $client) {
+            if ($client->jwks !== null) {
+                $this->loadJWKS($client->jwks);
+            }
         }
 
         $dao = $this->locator->getJWKSDAO();
diff --git a/classes/Locator.php b/classes/Locator.php
index 956b273..4b34c0c 100644
--- a/classes/Locator.php
+++ b/classes/Locator.php
@@ -74,18 +74,10 @@ class Locator {
         }
     }
 
-    public function getCallbackHandler(): CallbackHandler {
-        return new CallbackHandler($this);
-    }
-
     public function getUserHandler(): UserHandler {
         return new UserHandler($this);
     }
 
-    public function getMailSender(): MailSender {
-        return new MailSender($_SERVER['HTTP_HOST'], $this->getBasePath());
-    }
-
     public function getOAuth2RequestHandler(): OAuth2RequestHandler {
         return new OAuth2RequestHandler($this);
     }
diff --git a/classes/OAuth2RequestHandler.php b/classes/OAuth2RequestHandler.php
index 084d43c..2b45d36 100644
--- a/classes/OAuth2RequestHandler.php
+++ b/classes/OAuth2RequestHandler.php
@@ -76,7 +76,12 @@ class OAuth2RequestHandler {
         if ($state !== null) {
             // Authorization code grant flow
             $redirectUrl = $session->getOAuth2RequestData()->redirectUrl
-                    . '?code=' . $code . '&scope=profile&state=' . $state;
+                    . '?code=' . $code;
+            $scope = $tokenData->scope;
+            if ($scope !== null && count($scope) > 0) {
+                $redirectUrl .= '&scope=' . implode("%20", $scope);
+            }
+            $redirectUrl .= '&state=' . $state;
         } else {
             // Implicit grant flow
             $idToken = $this->locator->getTokenBuilder()->getIdToken($tokenData, function(& $jwt) use($nonce) {
@@ -88,9 +93,27 @@ class OAuth2RequestHandler {
         return $redirectUrl;
     }
 
-    public function handleGetTokenFromCodeRequest($params): array {
+    public function handleAccessTokenRequest(array $params, array $headers): array {
+
+        if ($params['grant_type'] === null) {
+            throw new \RAP\BadRequestException("grant_type is required");
+        }
+
+        switch ($params['grant_type']) {
+            case "authorization_code":
+                return $this->handleGetTokenFromCodeRequest($params, $headers);
+            case "client_credentials":
+                return $this->handleClientCredentialsRequest($headers);
+            case "refresh_token":
+                return $this->handleRefreshTokenRequest($params, $headers);
+            default:
+                throw new \RAP\BadRequestException("Unsupported grant type " . $params['grant_type']);
+        }
+    }
+
+    private function handleGetTokenFromCodeRequest(array $params, array $headers): array {
 
-        $this->locator->getClientAuthChecker()->validateClientAuth();
+        $this->locator->getClientAuthChecker()->validateClientAuth($headers);
 
         if ($params['code'] === null) {
             throw new BadRequestException("code id is required");
@@ -120,9 +143,9 @@ class OAuth2RequestHandler {
         return $response;
     }
 
-    public function handleClientCredentialsRequest($params): array {
+    private function handleClientCredentialsRequest(array $headers): array {
 
-        $client = $this->locator->getClientAuthChecker()->validateCliClientAuth();
+        $client = $this->locator->getClientAuthChecker()->validateCliClientAuth($headers);
 
         $accessTokenData = new AccessTokenData();
         $accessTokenData->clientId = $client->id;
@@ -133,9 +156,9 @@ class OAuth2RequestHandler {
         return $this->getAccessTokenResponse($accessTokenData, false);
     }
 
-    public function handleRefreshTokenRequest($params): array {
+    private function handleRefreshTokenRequest(array $params, array $headers): array {
 
-        $this->locator->getClientAuthChecker()->validateClientAuth();
+        $this->locator->getClientAuthChecker()->validateClientAuth($headers);
 
         if ($params['refresh_token'] === null) {
             throw new BadRequestException("refresh_token is required");
diff --git a/classes/TokenBuilder.php b/classes/TokenBuilder.php
index e64162d..912c13d 100644
--- a/classes/TokenBuilder.php
+++ b/classes/TokenBuilder.php
@@ -53,7 +53,7 @@ class TokenBuilder {
         return $payloadArr;
     }
 
-    public function getAccessToken(AccessTokenData $tokenData, \Closure $jwtCustomizer = null) {
+    public function getAccessToken(AccessTokenData $tokenData, \Closure $jwtCustomizer = null): string {
 
         $keyPair = $this->locator->getJWKSDAO()->getNewestKeyPair();
 
@@ -95,11 +95,13 @@ class TokenBuilder {
 
         $audiences = [$tokenData->clientId];
 
-        foreach ($tokenData->scope as $scope) {
-            if (array_key_exists($scope, $client->scopeAudienceMap)) {
-                $audience = $client->scopeAudienceMap[$scope];
-                if (!in_array($audience, $audiences)) {
-                    array_push($audiences, $audience);
+        if ($client->scopeAudienceMap !== null) {
+            foreach ($tokenData->scope as $scope) {
+                if (array_key_exists($scope, $client->scopeAudienceMap)) {
+                    $audience = $client->scopeAudienceMap[$scope];
+                    if (!in_array($audience, $audiences)) {
+                        array_push($audiences, $audience);
+                    }
                 }
             }
         }
diff --git a/config-example.yaml b/config-example.yaml
index fcd8cdb..a850423 100644
--- a/config-example.yaml
+++ b/config-example.yaml
@@ -52,7 +52,7 @@ tokenIssuer:
 clients:
   - label: "GMS Test (localhost)"
     id: gms
-    secret: "XXXXXX"
+    secret: 2a97516c354b68848cdbd8f54a226a0a55b21ed138e207ad6c5cbb9c00aa5aea
     redirect: http://localhost:8082/gms/login
     scope: "openid email"
     home: http://localhost:8082/gms
@@ -62,7 +62,7 @@ clients:
     jwks:
   - label: "Asiago Astrophysical Observatory (localhost)"
     id: aao-dev
-    secret: "XXXXXX"
+    secret: 2a97516c354b68848cdbd8f54a226a0a55b21ed138e207ad6c5cbb9c00aa5aea
     redirect: http://localhost:8081/aao/login
     scope: "openid read:userspace write:userspace read:fileserver write:fileserver read:gms"
     home: http://localhost:8081/aao
@@ -72,6 +72,6 @@ clients:
     jwks: http://localhost:8081/aao/jwks
 cliClients:
   - id: gms_cli
-    secret: "XXXXXX"
+    secret: 2a97516c354b68848cdbd8f54a226a0a55b21ed138e207ad6c5cbb9c00aa5aea
     scope: "read:gms write:gms read:rap"
     audience: gms
\ No newline at end of file
diff --git a/include/front-controller.php b/include/front-controller.php
index b7f9b2c..56b2021 100644
--- a/include/front-controller.php
+++ b/include/front-controller.php
@@ -102,25 +102,10 @@ Flight::route('POST /auth/oauth2/token', function() {
         "scope" => filter_input(INPUT_POST, "scope", FILTER_SANITIZE_STRING)
     ];
 
-    if ($params['grant_type'] === null) {
-        throw new \RAP\BadRequestException("grant_type is required");
-    }
+    $headers = apache_request_headers();
 
     $requestHandler = new \RAP\OAuth2RequestHandler($locator);
-
-    switch ($params['grant_type']) {
-        case "authorization_code":
-            $token = $requestHandler->handleGetTokenFromCodeRequest($params);
-            break;
-        case "client_credentials":
-            $token = $requestHandler->handleClientCredentialsRequest($params);
-            break;
-        case "refresh_token":
-            $token = $requestHandler->handleRefreshTokenRequest($params);
-            break;
-        default:
-            throw new \RAP\BadRequestException("Unsupported grant type " . $params['grant_type']);
-    }
+    $token = $requestHandler->handleAccessTokenRequest($params, $headers);
 
     Flight::json($token);
 });
diff --git a/tests/ClientAuthCheckerTest.php b/tests/ClientAuthCheckerTest.php
new file mode 100644
index 0000000..f98919a
--- /dev/null
+++ b/tests/ClientAuthCheckerTest.php
@@ -0,0 +1,33 @@
+<?php
+
+use PHPUnit\Framework\TestCase;
+
+class ClientAuthCheckerTest extends TestCase {
+
+    public function testValidateClientAuth() {
+
+        $locatorStub = $this->createMock(\RAP\Locator::class);
+
+        $locatorStub->expects($this->once())
+                ->method('getBrowserBasedOAuth2ClientByIdAndSecret')->with('client', 'secret');
+
+        $authChecker = new \RAP\ClientAuthChecker($locatorStub);
+        $authChecker->validateClientAuth([
+            "Authorization" => "Basic " . base64_encode("client:secret")
+        ]);
+    }
+
+    public function testValidateCliClientAuth() {
+
+        $locatorStub = $this->createMock(\RAP\Locator::class);
+
+        $locatorStub->expects($this->once())
+                ->method('getCliClientByIdAndSecret')->with('client', 'secret');
+
+        $authChecker = new \RAP\ClientAuthChecker($locatorStub);
+        $authChecker->validateCliClientAuth([
+            "Authorization" => "Basic " . base64_encode("client:secret")
+        ]);
+    }
+
+}
diff --git a/tests/LocatorTest.php b/tests/LocatorTest.php
new file mode 100644
index 0000000..d33b8c7
--- /dev/null
+++ b/tests/LocatorTest.php
@@ -0,0 +1,36 @@
+<?php
+
+use PHPUnit\Framework\TestCase;
+
+class LocatorTest extends TestCase {
+
+    public function testLocator() {
+
+        define('ROOT', dirname(dirname(__FILE__)));
+
+        $config = yaml_parse_file(ROOT . '/config-example.yaml');
+        $config = json_decode(json_encode($config), FALSE);
+
+        $locator = new \RAP\Locator($config);
+
+        $this->assertNotNull($locator->getUserDAO());
+        $this->assertNotNull($locator->getJWKSDAO());
+        $this->assertNotNull($locator->getAccessTokenDAO());
+        $this->assertNotNull($locator->getRefreshTokenDAO());
+        $this->assertNotNull($locator->getUserHandler());
+        $this->assertNotNull($locator->getOAuth2RequestHandler());
+        $this->assertNotNull($locator->getTokenBuilder());
+        $this->assertNotNull($locator->getTokenChecker());
+        $this->assertNotNull($locator->getClientAuthChecker());
+        $this->assertNotNull($locator->getSession());
+        $this->assertNotNull($locator->getServiceLogger());
+        $this->assertNotNull($locator->getAuditLogger());
+        $this->assertNotNull($locator->getJWKSHandler());
+
+        $this->assertNotNull($locator->getBrowserBasedOAuth2Clients());
+        $this->assertNotNull($locator->getBrowserBasedOAuth2ClientById("gms", false));
+        $this->assertNotNull($locator->getBrowserBasedOAuth2ClientByIdAndSecret("gms", "demo"));
+        $this->assertNotNull($locator->getCliClientByIdAndSecret("gms_cli", "demo"));
+    }
+
+}
diff --git a/tests/OAuth2RequestHandlerTest.php b/tests/OAuth2RequestHandlerTest.php
index f970eed..16cd723 100644
--- a/tests/OAuth2RequestHandlerTest.php
+++ b/tests/OAuth2RequestHandlerTest.php
@@ -105,4 +105,151 @@ final class OAuth2RequestHandlerTest extends TestCase {
         $this->assertEquals('id-token', $result['id_token']);
     }
 
+    public function testHandleGetTokenFromCodeRequest(): void {
+
+        $authCheckerStub = $this->createMock(\RAP\ClientAuthChecker::class);
+
+        $tokenData = new \RAP\AccessTokenData();
+        $tokenData->redirectUri = "redirect";
+        $tokenData->scope = ['openid'];
+
+        $tokenDaoStub = $this->createMock(\RAP\AccessTokenDAO::class);
+        $tokenDaoStub->method('retrieveTokenDataFromCode')->willReturn($tokenData);
+
+        $tokenBuilderStub = $this->createMock(\RAP\TokenBuilder::class);
+        $tokenBuilderStub->method('getAccessToken')->willReturn('<access_token>');
+
+        $refreshTokenDaoStub = $this->createMock(\RAP\RefreshTokenDAO::class);
+
+        $locatorStub = $this->createMock(\RAP\Locator::class);
+        $locatorStub->method('getClientAuthChecker')->willReturn($authCheckerStub);
+        $locatorStub->method('getAccessTokenDAO')->willReturn($tokenDaoStub);
+        $locatorStub->method('getTokenBuilder')->willReturn($tokenBuilderStub);
+        $locatorStub->method('getRefreshTokenDAO')->willReturn($refreshTokenDaoStub);
+
+        $authCheckerStub->expects($this->once())
+                ->method('validateClientAuth')->with($this->anything());
+
+        $tokenDaoStub->expects($this->once())
+                ->method('retrieveTokenDataFromCode')->with($this->anything());
+
+        $tokenDaoStub->expects($this->once())
+                ->method('deleteTokenData')->with($this->anything());
+
+        $requestHandler = new \RAP\OAuth2RequestHandler($locatorStub);
+
+        $params = [
+            "grant_type" => "authorization_code",
+            "redirect_uri" => "redirect",
+            "code" => "123"
+        ];
+        $result = $requestHandler->handleAccessTokenRequest($params, []);
+
+        $this->assertEquals(3600, $result['expires_in']);
+        $this->assertEquals("Bearer", $result['token_type']);
+        $this->assertEquals("<access_token>", $result['access_token']);
+        $this->assertNotNull($result['refresh_token']);
+    }
+
+    public function testHandleClientCredentialsRequest(): void {
+
+        $authCheckerStub = $this->createMock(\RAP\ClientAuthChecker::class);
+
+        $tokenBuilderStub = $this->createMock(\RAP\TokenBuilder::class);
+        $tokenBuilderStub->method('getAccessToken')->willReturn('<access_token>');
+
+        $locatorStub = $this->createMock(\RAP\Locator::class);
+        $locatorStub->method('getClientAuthChecker')->willReturn($authCheckerStub);
+        $locatorStub->method('getTokenBuilder')->willReturn($tokenBuilderStub);
+
+        $authCheckerStub->expects($this->once())
+                ->method('validateCliClientAuth')->with($this->anything());
+
+        $requestHandler = new \RAP\OAuth2RequestHandler($locatorStub);
+
+        $params = [
+            "grant_type" => "client_credentials"
+        ];
+        $result = $requestHandler->handleAccessTokenRequest($params, []);
+
+        $this->assertEquals(3600, $result['expires_in']);
+        $this->assertEquals("Bearer", $result['token_type']);
+        $this->assertEquals("<access_token>", $result['access_token']);
+        $this->assertFalse(isset($result['refresh_token']));
+    }
+
+    public function testHandleRefreshTokenRequest(): void {
+
+        $refreshTokenData = new \RAP\RefreshTokenData();
+        $refreshTokenData->scope = ['openid', 'email'];
+
+        $authCheckerStub = $this->createMock(\RAP\ClientAuthChecker::class);
+
+        $tokenBuilderStub = $this->createMock(\RAP\TokenBuilder::class);
+        $tokenBuilderStub->method('getAccessToken')->willReturn('<access_token>');
+
+        $refreshTokenDaoStub = $this->createMock(\RAP\RefreshTokenDAO::class);
+        $refreshTokenDaoStub->method('getRefreshTokenData')->willReturn($refreshTokenData);
+
+        $tokenDaoStub = $this->createMock(\RAP\AccessTokenDAO::class);
+        $tokenDaoStub->method('createTokenData')->will($this->returnArgument(0));
+
+        $locatorStub = $this->createMock(\RAP\Locator::class);
+        $locatorStub->method('getClientAuthChecker')->willReturn($authCheckerStub);
+        $locatorStub->method('getTokenBuilder')->willReturn($tokenBuilderStub);
+        $locatorStub->method('getRefreshTokenDAO')->willReturn($refreshTokenDaoStub);
+        $locatorStub->method('getAccessTokenDAO')->willReturn($tokenDaoStub);
+
+        $authCheckerStub->expects($this->once())
+                ->method('validateClientAuth')->with($this->anything());
+
+        $requestHandler = new \RAP\OAuth2RequestHandler($locatorStub);
+
+        $params = [
+            "grant_type" => "refresh_token",
+            "refresh_token" => "<refresh_token>",
+            "scope" => "openid email"
+        ];
+        $result = $requestHandler->handleAccessTokenRequest($params, []);
+
+        $this->assertEquals(3600, $result['expires_in']);
+        $this->assertEquals("Bearer", $result['token_type']);
+        $this->assertEquals("<access_token>", $result['access_token']);
+        $this->assertNotNull($result['refresh_token']);
+    }
+
+    public function testGetRedirectResponseUrlForAuthorizationCodeFlow(): void {
+
+        $user = new \RAP\User();
+        $user->id = "123";
+
+        $requestData = new \RAP\OAuth2RequestData();
+        $requestData->clientId = "<client-id>";
+        $requestData->redirectUrl = "<base-path>";
+        $requestData->scope = ["openid", "profile"];
+        $requestData->state = "<state>";
+
+        $sessionStub = $this->createMock(\RAP\SessionData::class);
+        $sessionStub->method('getUser')->willReturn($user);
+        $sessionStub->method('getOAuth2RequestData')->willReturn($requestData);
+
+        $locatorStub = $this->createMock(\RAP\Locator::class);
+        $locatorStub->method('getSession')->willReturn($sessionStub);
+
+        $requestHandler = new \RAP\OAuth2RequestHandler($locatorStub);
+
+        $result = $requestHandler->getRedirectResponseUrl();
+
+        $url_components = parse_url($result);
+        $this->assertEquals('<base-path>', $url_components['path']);
+
+        $params = [];
+        parse_str($url_components['query'], $params);
+
+        $this->assertEquals("<state>", $params['state']);
+        $this->assertEquals("openid profile", $params['scope']);
+
+        $this->assertNotNull($params['code']);
+    }
+
 }
diff --git a/tests/TokenBuilderTest.php b/tests/TokenBuilderTest.php
index 6161887..8e1636d 100644
--- a/tests/TokenBuilderTest.php
+++ b/tests/TokenBuilderTest.php
@@ -17,15 +17,7 @@ final class TokenBuilderTest extends TestCase {
 
         $jwksDAOStub->method('getNewestKeyPair')->willReturn($keyPair);
 
-        $user = new \RAP\User();
-        $user->id = "user_id";
-        $identity = new \RAP\Identity(\RAP\Identity::EDU_GAIN);
-        $identity->email = "name@inaf.it";
-        $identity->name = "Name";
-        $identity->surname = "Surname";
-        $identity->primary = true;
-        $identity->institution = "INAF";
-        $user->addIdentity($identity);
+        $user = $this->getUser();
 
         $daoStub = $this->createMock(\RAP\UserDAO::class);
         $locatorStub->method('getUserDAO')->willReturn($daoStub);
@@ -48,9 +40,67 @@ final class TokenBuilderTest extends TestCase {
         $this->assertEquals("issuer", $payload->iss);
         $this->assertEquals($user->id, $payload->sub);
         $this->assertEquals($user->getCompleteName(), $payload->name);
+        $identity = $user->identities[0];
         $this->assertEquals($identity->name, $payload->given_name);
         $this->assertEquals($identity->surname, $payload->family_name);
         $this->assertEquals($identity->institution, $payload->org);
     }
 
+    public function testGetAccessToken(): void {
+
+        $jwksDAOStub = $this->createMock(\RAP\JWKSDAO::class);
+
+        $locatorStub = $this->createMock(\RAP\Locator::class);
+        $locatorStub->method('getJWKSDAO')->willReturn($jwksDAOStub);
+
+        $jwksHandler = new \RAP\JWKSHandler($locatorStub);
+        $keyPair = $jwksHandler->generateKeyPair();
+
+        $jwksDAOStub->method('getNewestKeyPair')->willReturn($keyPair);
+
+        $userDaoStub = $this->createMock(\RAP\UserDAO::class);
+        $locatorStub->method('getUserDAO')->willReturn($userDaoStub);
+
+        $user = $this->getUser();
+        $userDaoStub->method('findUserById')->willReturn($user);
+
+        $client = new \RAP\BrowserBasedOAuth2Client((object) [
+                    "id" => "aao",
+                    "secret" => "2a97516c354b68848cdbd8f54a226a0a55b21ed138e207ad6c5cbb9c00aa5aea",
+                    "redirect" => "redirect",
+                    "scope" => "openid email",
+                    "methods" => [],
+                    "scopeAudienceMap" => ["read:gms" => "gms"]
+        ]);
+
+        $locatorStub->method('getBrowserBasedOAuth2ClientById')->willReturn($client);
+
+        $locatorStub->config = json_decode('{"jwtIssuer": "issuer"}');
+
+        $tokenBuilder = new \RAP\TokenBuilder($locatorStub);
+
+        $tokenData = new \RAP\AccessTokenData();
+        $tokenData->token = "ttt";
+        $tokenData->scope = ["openid", "read:gms"];
+        $tokenData->userId = "user_id";
+        $tokenData->clientId = "aao";
+
+        $jwt = $tokenBuilder->getAccessToken($tokenData);
+
+        $this->assertNotNull($jwt);
+    }
+
+    private function getUser(): \RAP\User {
+        $user = new \RAP\User();
+        $user->id = "user_id";
+        $identity = new \RAP\Identity(\RAP\Identity::EDU_GAIN);
+        $identity->email = "name@inaf.it";
+        $identity->name = "Name";
+        $identity->surname = "Surname";
+        $identity->primary = true;
+        $identity->institution = "INAF";
+        $user->addIdentity($identity);
+        return $user;
+    }
+
 }
-- 
GitLab