From f2338e6bb20c59905baae150e8237c663e267a1d Mon Sep 17 00:00:00 2001 From: Sonia Zorba <sonia.zorba@inaf.it> Date: Mon, 27 Jan 2020 15:36:58 +0100 Subject: [PATCH] #2 Implemented basic token issuer page --- classes/IdTokenBuilder.php | 25 +++++++++++++++- config-example.json | 7 +++++ css/style.css | 4 +++ include/front-controller.php | 50 +++++++++++++++++++++++++++++++ js/index.js | 1 + views/account-management.php | 19 +++++++++--- views/token-issuer.php | 58 ++++++++++++++++++++++++++++++++++++ 7 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 views/token-issuer.php diff --git a/classes/IdTokenBuilder.php b/classes/IdTokenBuilder.php index 456a678..0f9ea17 100644 --- a/classes/IdTokenBuilder.php +++ b/classes/IdTokenBuilder.php @@ -22,7 +22,7 @@ class IdTokenBuilder { } private function createPayloadArray(AccessToken $accessToken, string $nonce = null) { - + $user = $this->locator->getUserDAO()->findUserById($accessToken->userId); $payloadArr = array( @@ -56,4 +56,27 @@ class IdTokenBuilder { return $payloadArr; } + /** + * @param int $lifespan in hours + * @param string $audit target service + */ + public function generateNewToken(int $lifespan, string $audit) { + $keyPair = $this->locator->getJWKSDAO()->getNewestKeyPair(); + + $user = $this->locator->getSession()->getUser(); + + $iat = time(); + $exp = $iat + $lifespan * 3600; + + $payload = array( + 'iss' => $this->locator->config->jwtIssuer, + 'sub' => strval($user->id), + 'iat' => $iat, + 'exp' => $exp, + 'aud' => $audit + ); + + return JWT::encode($payload, $keyPair->privateKey, $keyPair->alg, $keyPair->keyId); + } + } diff --git a/config-example.json b/config-example.json index db80960..7d8a686 100644 --- a/config-example.json +++ b/config-example.json @@ -47,5 +47,12 @@ "gms": { "id": "gms", "joinEndpoint": "http://localhost:8082/gms/ws/jwt/join" + }, + "tokenIssuer": { + "services": [{ + "id": "fileserver", + "label": "File Server" + }], + "lifespan": [1, 6, 12, 24] } } diff --git a/css/style.css b/css/style.css index 021218b..732e5dc 100644 --- a/css/style.css +++ b/css/style.css @@ -188,4 +188,8 @@ body { .service-logo { padding-right: 10px; max-height: 50px; +} + +#token-issuer-btn { + margin-top: 20px; } \ No newline at end of file diff --git a/include/front-controller.php b/include/front-controller.php index 88010c7..4df876e 100644 --- a/include/front-controller.php +++ b/include/front-controller.php @@ -349,4 +349,54 @@ Flight::route('GET /account', function () { } }); +Flight::route('GET /token-issuer', function () { + + session_start(); + + if (empty($_SESSION['csrf_token'])) { + $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); + } + $csrfToken = $_SESSION['csrf_token']; + + global $locator; + + $user = $locator->getSession()->getUser(); + $config = $locator->config->tokenIssuer; + + if ($user === null) { + Flight::redirect('/'); + } else { + $admin = $locator->getUserDAO()->isAdmin($user->id); + Flight::render('token-issuer.php', array('title' => 'RAP Token Issuer', + 'version' => $locator->getVersion(), 'session' => $locator->getSession(), + 'config' => $config, 'csrfToken' => $csrfToken, + 'contextRoot' => $locator->config->contextRoot)); + } +}); + +Flight::route('POST /token-issuer', function () { + + session_start(); + global $locator; + + if (empty($_POST['csrf_token']) || !(hash_equals($_SESSION['csrf_token'], $_POST['csrf_token']))) { + throw new \RAP\UnauthorizedException("Invalid CSRF token"); + } + if ($locator->getSession()->getUser() === null) { + throw new \RAP\UnauthorizedException("You must be registered to perform this action"); + } + + $postData = Flight::request()->data; + if (!isset($postData['lifespan']) || !isset($postData['audit'])) { + throw new \RAP\BadRequestException("Missing form parameter"); + } + + $tokenBuilder = $locator->getIdTokenBuilder(); + $token = $tokenBuilder->generateNewToken($postData['lifespan'], $postData['audit']); + + header('Content-Type: text/plain'); + header("Content-disposition: attachment; filename=\"token.txt\""); + echo $token; +}); + include 'admin.php'; diff --git a/js/index.js b/js/index.js index d6b1003..78e521a 100644 --- a/js/index.js +++ b/js/index.js @@ -28,6 +28,7 @@ function loadTooltips() { $('.primary-identity-icon').tooltip(); $('#join-btn').tooltip(); + $('#token-issuer-btn').tooltip(); } // When the document is loaded diff --git a/views/account-management.php b/views/account-management.php index 5cb798c..03e9e4c 100644 --- a/views/account-management.php +++ b/views/account-management.php @@ -17,10 +17,21 @@ include 'include/header.php'; </div> </div> </div> - <div class="col-sm-2 text-center"> - <a class="btn btn-success" id="join-btn" href="<?php echo $contextRoot; ?>?action=join" title="Perform an additional login to join your identities" data-toggle="tooltip" data-placement="bottom"> - Join with another identity - </a> + <div class="col-sm-2"> + <div class="row"> + <div class="col-sm-12"> + <a class="btn btn-success" id="join-btn" href="<?php echo $contextRoot; ?>?action=join" title="Perform an additional login to join your identities" data-toggle="tooltip" data-placement="bottom"> + Join with another identity + </a> + </div> + </div> + <div class="row"> + <div class="col-sm-12"> + <a class="btn btn-default" id="token-issuer-btn" href="<?php echo $contextRoot; ?>/token-issuer" title="Generate tokens for CLI" data-toggle="tooltip" data-placement="bottom"> + Token issuer + </a> + </div> + </div> </div> <div class="col-sm-5"> <a href="logout" class="btn btn-primary pull-right">Logout</a> diff --git a/views/token-issuer.php b/views/token-issuer.php new file mode 100644 index 0000000..12ce18a --- /dev/null +++ b/views/token-issuer.php @@ -0,0 +1,58 @@ +<?php +include 'include/header.php'; +?> + +<div class="row"> + <div class="col-sm-6 col-sm-offset-3"> + <p>This panel can be used to generate tokens to be used from command line interfaces and desktop applications.</p> + <br/> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">Token issuer</h3> + </div> + <div class="panel-body"> + <form class="form-horizontal" action="<?php echo $contextRoot . '/token-issuer'; ?>" method="post"> + <div class="form-group"> + <label for="service" class="col-sm-4 control-label">Service</label> + <div class="col-sm-8"> + <select class="form-control" id="service" name="audit"> + <?php + foreach ($config->services as $service) { + echo "<option value=\"$service->id\">$service->label</option>"; + } + ?> + </select> + </div> + </div> + <div class="form-group"> + <label for="lifespan" class="col-sm-4 control-label">Duration (hours)</label> + <div class="col-sm-8"> + <select class="form-control" id="lifespan" name="lifespan"> + <?php + foreach ($config->lifespans as $lifespan) { + echo "<option>$lifespan</option>"; + } + ?> + </select> + </div> + </div> + <div class="form-group"> + <div class="col-sm-8 col-sm-offset-4"> + <input type="submit" class="btn btn-primary" value="Download token" /> + </div> + </div> + <input type="hidden" value="<?php echo $csrfToken; ?>" name="csrf_token" /> + </form> + </div> + </div> + <br/> + <p class="text-center"> + <strong> + <a href="<?php echo $contextRoot . '/account'; ?>">Back to account manager</a> + </strong> + </p> + </div> +</div> + +<?php +include 'include/footer.php'; -- GitLab