Skip to content
Snippets Groups Projects
Commit ec3ca777 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Improved admin panel and services list

parent 1f04c39b
No related branches found
No related tags found
No related merge requests found
Showing with 105 additions and 161 deletions
...@@ -5,7 +5,7 @@ namespace RAP; ...@@ -5,7 +5,7 @@ namespace RAP;
use phpseclib\Crypt\RSA; use phpseclib\Crypt\RSA;
/** /**
* Manages the JWT Key Sets (currently only RSA . * Manages the JWT Key Sets (currently only RSA).
*/ */
class JWKSHandler { class JWKSHandler {
......
<?php
/* ----------------------------------------------------------------------------
* INAF - National Institute for Astrophysics
* IRA - Radioastronomical Institute - Bologna
* OATS - Astronomical Observatory - Trieste
* ----------------------------------------------------------------------------
*
* Copyright (C) 2016 Istituto Nazionale di Astrofisica
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License Version 3 as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
namespace RAP;
/**
* Data model representing an item of the result of an user search. This is used
* in order to display the dropdown menu for user selection in the join modal
* dialog avoiding exposing the user identifiers in the AJAX calls.
* This data is stored into a list inside the SessionData object. The user will
* select one of the item by index and not by the user ID.
*/
class UserSearchResult {
// The user object is wrapped by this class and hidden to AJAX.
private $user;
// Only this text is returned to the AJAX call.
// See gui-backend.php (/user?search endpoint)
public $userDisplayText;
public static function buildFromUser(User $user) {
$usr = new UserSearchResult();
$usr->user = $user;
$nameAndSurname = null;
$email = null;
$identityTypes = [];
foreach ($user->identities as $identity) {
array_push($identityTypes, $identity->getUIType());
if ($nameAndSurname === null && $identity->name !== null && $identity->surname !== null) {
$nameAndSurname = $identity->name . ' ' . $identity->surname;
}
if ($email === null) {
$email = $identity->email;
}
}
// Building display text string
$displayText = "";
if ($nameAndSurname !== null) {
$displayText .= $nameAndSurname;
} else {
$displayText .= $email;
}
$displayText .= ' (';
$firstIdentity = true;
foreach ($identityTypes as $type) {
if (!$firstIdentity) {
$displayText .= '+';
}
$displayText .= $type;
$firstIdentity = false;
}
$displayText .= ')';
$usr->userDisplayText = $displayText;
return $usr;
}
public function getUser() {
return $this->user;
}
}
<?php
/* ----------------------------------------------------------------------------
* INAF - National Institute for Astrophysics
* IRA - Radioastronomical Institute - Bologna
* OATS - Astronomical Observatory - Trieste
* ----------------------------------------------------------------------------
*
* Copyright (C) 2016 Istituto Nazionale di Astrofisica
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License Version 3 as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
namespace RAP;
/**
* Utility class
*/
class Util {
/**
* @return string random string
*/
public static function createNewToken() {
// Credits: http://stackoverflow.com/a/18890309/771431
return bin2hex(openssl_random_pseudo_bytes(16));
}
}
...@@ -9,9 +9,9 @@ interface OAuth2ClientDAO { ...@@ -9,9 +9,9 @@ interface OAuth2ClientDAO {
function getOAuth2Clients(): array; function getOAuth2Clients(): array;
function createOAuth2Client($client): OAuth2Client; function createOAuth2Client(OAuth2Client $client): OAuth2Client;
function updateOAuth2Client($client): OAuth2Client; function updateOAuth2Client(OAuth2Client $client): OAuth2Client;
function deleteOAuth2Client($clientId); function deleteOAuth2Client($clientId);
......
...@@ -75,4 +75,6 @@ interface UserDAO { ...@@ -75,4 +75,6 @@ interface UserDAO {
* deleted from the database * deleted from the database
*/ */
function joinUsers($userId1, $userId2); function joinUsers($userId1, $userId2);
function isAdmin($userId): bool;
} }
...@@ -12,7 +12,7 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO { ...@@ -12,7 +12,7 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO {
$dbh = $this->getDBHandler(); $dbh = $this->getDBHandler();
// Load clients info // Load clients info
$queryClient = "SELECT id, title, icon, client, secret, redirect_url, scope FROM oauth2_client"; $queryClient = "SELECT id, title, icon, client, secret, redirect_url, scope, home_page, show_in_home FROM oauth2_client";
$stmtClients = $dbh->prepare($queryClient); $stmtClients = $dbh->prepare($queryClient);
$stmtClients->execute(); $stmtClients->execute();
...@@ -27,6 +27,8 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO { ...@@ -27,6 +27,8 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO {
$client->secret = $row['secret']; $client->secret = $row['secret'];
$client->redirectUrl = $row['redirect_url']; $client->redirectUrl = $row['redirect_url'];
$client->scope = $row['scope']; $client->scope = $row['scope'];
$client->homePage = $row['home_page'];
$client->showInHome = boolval($row['show_in_home']);
$clientsMap[$client->id] = $client; $clientsMap[$client->id] = $client;
} }
...@@ -49,14 +51,14 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO { ...@@ -49,14 +51,14 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO {
return $clients; return $clients;
} }
function createOAuth2Client($client): OAuth2Client { function createOAuth2Client(OAuth2Client $client): OAuth2Client {
$dbh = $this->getDBHandler(); $dbh = $this->getDBHandler();
try { try {
$dbh->beginTransaction(); $dbh->beginTransaction();
$stmt = $dbh->prepare("INSERT INTO `oauth2_client`(`title`, `icon`, `client`, `secret`, `redirect_url`, `scope`)" $stmt = $dbh->prepare("INSERT INTO `oauth2_client`(`title`, `icon`, `client`, `secret`, `redirect_url`, `scope`, home_page, show_in_home)"
. " VALUES(:title, :icon, :client, :secret, :redirect_url, :scope)"); . " VALUES(:title, :icon, :client, :secret, :redirect_url, :scope, :home_page, :show_in_home)");
$stmt->bindParam(':title', $client->title); $stmt->bindParam(':title', $client->title);
$stmt->bindParam(':icon', $client->icon); $stmt->bindParam(':icon', $client->icon);
...@@ -64,6 +66,8 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO { ...@@ -64,6 +66,8 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO {
$stmt->bindParam(':secret', $client->secret); $stmt->bindParam(':secret', $client->secret);
$stmt->bindParam(':redirect_url', $client->redirectUrl); $stmt->bindParam(':redirect_url', $client->redirectUrl);
$stmt->bindParam(':scope', $client->scope); $stmt->bindParam(':scope', $client->scope);
$stmt->bindParam(':home_page', $client->homePage);
$stmt->bindParam(':show_in_home', $client->showInHome, \PDO::PARAM_INT);
$stmt->execute(); $stmt->execute();
...@@ -88,14 +92,15 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO { ...@@ -88,14 +92,15 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO {
return $client; return $client;
} }
function updateOAuth2Client($client): OAuth2Client { function updateOAuth2Client(OAuth2Client $client): OAuth2Client {
$dbh = $this->getDBHandler(); $dbh = $this->getDBHandler();
try { try {
$dbh->beginTransaction(); $dbh->beginTransaction();
$stmt = $dbh->prepare("UPDATE `oauth2_client` SET `title` = :title, `icon` = :icon, " $stmt = $dbh->prepare("UPDATE `oauth2_client` SET `title` = :title, `icon` = :icon, "
. " `client` = :client, `secret` = :secret, `redirect_url` = :redirect_url, `scope` = :scope " . " `client` = :client, `secret` = :secret, `redirect_url` = :redirect_url, `scope` = :scope, "
. " `home_page` = :home_page, `show_in_home` = :show_in_home"
. " WHERE id = :id"); . " WHERE id = :id");
$stmt->bindParam(':title', $client->title); $stmt->bindParam(':title', $client->title);
...@@ -104,6 +109,8 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO { ...@@ -104,6 +109,8 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO {
$stmt->bindParam(':secret', $client->secret); $stmt->bindParam(':secret', $client->secret);
$stmt->bindParam(':redirect_url', $client->redirectUrl); $stmt->bindParam(':redirect_url', $client->redirectUrl);
$stmt->bindParam(':scope', $client->scope); $stmt->bindParam(':scope', $client->scope);
$stmt->bindParam(':home_page', $client->homePage);
$stmt->bindParam(':show_in_home', $client->showInHome, \PDO::PARAM_INT);
$stmt->bindParam(':id', $client->id); $stmt->bindParam(':id', $client->id);
$stmt->execute(); $stmt->execute();
...@@ -158,7 +165,7 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO { ...@@ -158,7 +165,7 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO {
$dbh = $this->getDBHandler(); $dbh = $this->getDBHandler();
// Load clients info // Load clients info
$queryClient = "SELECT id, title, icon, client, secret, redirect_url, scope FROM oauth2_client WHERE client = :client"; $queryClient = "SELECT id, title, icon, client, secret, redirect_url, scope, home_page, show_in_home FROM oauth2_client WHERE client = :client";
$stmtClient = $dbh->prepare($queryClient); $stmtClient = $dbh->prepare($queryClient);
$stmtClient->bindParam(':client', $clientId); $stmtClient->bindParam(':client', $clientId);
$stmtClient->execute(); $stmtClient->execute();
...@@ -182,6 +189,8 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO { ...@@ -182,6 +189,8 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO {
$client->secret = $row['secret']; $client->secret = $row['secret'];
$client->redirectUrl = $row['redirect_url']; $client->redirectUrl = $row['redirect_url'];
$client->scope = $row['scope']; $client->scope = $row['scope'];
$client->homePage = $row['home_page'];
$client->showInHome = $row['show_in_home'];
// Load authentication methods info // Load authentication methods info
$queryAuthNMethods = "SELECT auth_method FROM oauth2_client_auth_methods WHERE client_id = :id"; $queryAuthNMethods = "SELECT auth_method FROM oauth2_client_auth_methods WHERE client_id = :id";
......
...@@ -266,4 +266,19 @@ class MySQLUserDAO extends BaseMySQLDAO implements UserDAO { ...@@ -266,4 +266,19 @@ class MySQLUserDAO extends BaseMySQLDAO implements UserDAO {
} }
} }
function isAdmin($userId): bool {
$dbh = $this->getDBHandler();
$query = "SELECT user_id FROM rap_permissions WHERE permission = 'ADMIN' AND user_id = :userId";
$stmt = $dbh->prepare($query);
$stmt->bindParam(':userId', $userId);
$stmt->execute();
$result = $stmt->fetchAll();
return count($result) === 1;
}
} }
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
namespace RAP; namespace RAP;
/**
* Represents a client that connects to parts of RAP itself (e.g. Account Manager).
* It doesn't use OAuth2, instead stores data directly into the PHP session.
*/
class InternalClient extends RAPClient { class InternalClient extends RAPClient {
public $action; public $action;
......
...@@ -34,6 +34,8 @@ class OAuth2Client extends RAPClient { ...@@ -34,6 +34,8 @@ class OAuth2Client extends RAPClient {
public $secret; public $secret;
public $redirectUrl; public $redirectUrl;
public $scope; public $scope;
public $homePage;
public $showInHome;
public function getIconBasePath() { public function getIconBasePath() {
return 'client-icons/'; return 'client-icons/';
......
...@@ -16,7 +16,10 @@ function checkUser() { ...@@ -16,7 +16,10 @@ function checkUser() {
die("You must be registered to perform this action"); die("You must be registered to perform this action");
} }
// TODO: check is admin $dao = $locator->getUserDAO();
if (!$dao->isAdmin($session->getUser()->id)) {
die("You must be an admin to perform this action");
}
} }
Flight::route('GET /admin', function() { Flight::route('GET /admin', function() {
...@@ -94,6 +97,8 @@ function buildOAuth2ClientFromData() { ...@@ -94,6 +97,8 @@ function buildOAuth2ClientFromData() {
$client->secret = $data['secret']; $client->secret = $data['secret'];
$client->redirectUrl = $data['redirectUrl']; $client->redirectUrl = $data['redirectUrl'];
$client->scope = $data['scope']; $client->scope = $data['scope'];
$client->homePage = $data['homePage'];
$client->showInHome = $data['showInHome'];
} }
if (isset($data['authMethods'])) { if (isset($data['authMethods'])) {
foreach ($data['authMethods'] as $method) { foreach ($data['authMethods'] as $method) {
......
...@@ -56,8 +56,10 @@ Flight::route('/', function() { ...@@ -56,8 +56,10 @@ Flight::route('/', function() {
break; break;
default: default:
session_destroy(); session_destroy();
$clients = $locator->getOAuth2ClientDAO()->getOAuth2Clients();
Flight::render('services-list.php', array('title' => 'RAP', Flight::render('services-list.php', array('title' => 'RAP',
'version' => $locator->getVersion(), 'version' => $locator->getVersion(),
'clients' => $clients,
'action' => $locator->getBasePath() . '/')); 'action' => $locator->getBasePath() . '/'));
break; break;
} }
...@@ -308,11 +310,14 @@ Flight::route('GET /account', function () { ...@@ -308,11 +310,14 @@ Flight::route('GET /account', function () {
session_start(); session_start();
global $locator; global $locator;
if ($locator->getSession()->getUser() === null) { $user = $locator->getSession()->getUser();
if ($user === null) {
Flight::redirect('/'); Flight::redirect('/');
} else { } else {
$admin = $locator->getUserDAO()->isAdmin($user->id);
Flight::render('account-management.php', array('title' => 'RAP Account Management', Flight::render('account-management.php', array('title' => 'RAP Account Management',
'version' => $locator->getVersion(), 'session' => $locator->getSession(), 'version' => $locator->getVersion(), 'session' => $locator->getSession(),
'admin' => $admin,
'contextRoot' => $locator->config->contextRoot)); 'contextRoot' => $locator->config->contextRoot));
} }
}); });
......
...@@ -54,6 +54,8 @@ ...@@ -54,6 +54,8 @@
secret: null, secret: null,
redirectUrl: null, redirectUrl: null,
scope: null, scope: null,
homePage: null,
showInHome: false,
authMethods: {}, authMethods: {},
edit: true edit: true
}; };
......
...@@ -6,6 +6,8 @@ CREATE TABLE `oauth2_client` ( ...@@ -6,6 +6,8 @@ CREATE TABLE `oauth2_client` (
`secret` varchar(255) NOT NULL, `secret` varchar(255) NOT NULL,
`redirect_url` text NOT NULL, `redirect_url` text NOT NULL,
`scope` varchar(255) NOT NULL, `scope` varchar(255) NOT NULL,
`home_page` varchar(255),
`show_in_home` boolean DEFAULT FALSE,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE(client) UNIQUE(client)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
...@@ -64,6 +66,12 @@ CREATE TABLE `rsa_keypairs` ( ...@@ -64,6 +66,12 @@ CREATE TABLE `rsa_keypairs` (
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
); );
CREATE TABLE `rap_permissions` (
`user_id` bigint NOT NULL,
`permission` varchar(255) NOT NULL,
PRIMARY KEY (`user_id`, `permission`)
);
CREATE EVENT login_tokens_cleanup CREATE EVENT login_tokens_cleanup
ON SCHEDULE ON SCHEDULE
EVERY 1 MINUTE EVERY 1 MINUTE
......
...@@ -25,6 +25,15 @@ include 'include/header.php'; ...@@ -25,6 +25,15 @@ include 'include/header.php';
<div class="col-sm-5"> <div class="col-sm-5">
<a href="logout" class="btn btn-primary pull-right">Logout</a> <a href="logout" class="btn btn-primary pull-right">Logout</a>
</div> </div>
<?php if ($admin) { ?>
<div class="col-sm-2">
<br/><br/>
<a class="btn btn-default" href="<?php echo $contextRoot; ?>/admin" title="Admin panel" data-toggle="tooltip" data-placement="bottom">
<span class="glyphicon glyphicon-wrench"></span>
Admin
</a>
</div>
<?php } ?>
</div> </div>
<?php <?php
......
...@@ -11,7 +11,7 @@ include 'include/header.php'; ...@@ -11,7 +11,7 @@ include 'include/header.php';
<button class="btn btn-success pull-right" v-on:click="addNewOAuth2Client"> <button class="btn btn-success pull-right" v-on:click="addNewOAuth2Client">
<span class="glyphicon glyphicon-plus-sign"></span> Add client <span class="glyphicon glyphicon-plus-sign"></span> Add client
</button> </button>
<h2>OAuth2 clients</h2> <h2>OAuth2/OIDC clients</h2>
<br/> <br/>
<div class="panel panel-default" v-for="(client, index) in oauth2Clients"> <div class="panel panel-default" v-for="(client, index) in oauth2Clients">
<div class="panel-heading"> <div class="panel-heading">
...@@ -39,6 +39,7 @@ include 'include/header.php'; ...@@ -39,6 +39,7 @@ include 'include/header.php';
<label class="col-sm-3 control-label">Icon</label> <label class="col-sm-3 control-label">Icon</label>
<div class="col-sm-9"> <div class="col-sm-9">
<p class="form-control-static" v-if="!client.edit">{{client.icon}}</p> <p class="form-control-static" v-if="!client.edit">{{client.icon}}</p>
<input type="text" class="form-control" id="client_icon" v-model="client.icon" v-if="client.edit" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
...@@ -69,6 +70,26 @@ include 'include/header.php'; ...@@ -69,6 +70,26 @@ include 'include/header.php';
<input type="text" class="form-control" id="scope" v-model="client.scope" v-if="client.edit" /> <input type="text" class="form-control" id="scope" v-model="client.scope" v-if="client.edit" />
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-sm-3 control-label" for="homePage">Home Page</label>
<div class="col-sm-9">
<p class="form-control-static" v-if="!client.edit">{{client.homePage}}</p>
<input type="text" class="form-control" id="homePage" v-model="client.homePage" v-if="client.edit" />
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="showInHome">Show in home</label>
<div class="col-sm-9">
<p class="form-control-static" v-if="!client.edit">
<span class="glyphicon glyphicon-ok" v-if="client.showInHome"></span>
</p>
<div class="checkbox" v-if="client.edit">
<label>
<input type="checkbox" v-model="client.showInHome" />
</label>
</div>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label" for="authenticationMethods">Authentication methods</label> <label class="col-sm-3 control-label" for="authenticationMethods">Authentication methods</label>
<div class="col-sm-9"> <div class="col-sm-9">
......
<?php <?php
/** /**
* This page is specific for IA2. * Shows the list of available services.
*/ */
include 'include/header.php'; include 'include/header.php';
?> ?>
<div class="col-sm-offset-2 col-sm-10 services-list-wrapper"> <div class="col-sm-offset-2 col-sm-10 services-list-wrapper">
<p>Please choose the service where you want to login:</p> <p>Please choose the service where you want to login:</p>
<ul> <ul>
<li> <?php
<form action="<?php echo $action; ?>" method="POST"> foreach ($clients as $client) {
<input name="callback" type="hidden" value="http://archives.ia2.inaf.it/tng/rest/login/rapinput" /> if ($client->showInHome) {
<input type="submit" class="btn btn-link" value="Telescopio Nazionale Galileo (TNG) portal" /> echo '<li>';
</form> echo '<a href="' . $client->homePage . '">' . $client->title . '</a>';
</li> echo '</li>';
<li> }
<form action="<?php echo $action; ?>" method="POST"> }
<input name="callback" type="hidden" value="http://archives.ia2.inaf.it/aao/rest/login/rapinput" /> ?>
<input type="submit" class="btn btn-link" value="Asiago Astrophysical Observatory portal" />
</form>
</li>
<li> <li>
<a href="?action=account">RAP Account Management</a> <a href="?action=account">RAP Account Management</a>
</li> </li>
<li>
<form action="<?php echo $action; ?>" method="POST">
<input name="callback" type="hidden" value="https://sso.ia2.inaf.it/grouper" />
<input type="submit" class="btn btn-link" value="Grouper (groups management)" />
</form>
</li>
</ul> </ul>
<br/> <br/>
</div> </div>
<?php <?php
include 'include/footer.php'; include 'include/footer.php';
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment