diff --git a/classes/CallbackHandler.php b/classes/CallbackHandler.php new file mode 100644 index 0000000000000000000000000000000000000000..de88c9e88153c36c0a043f7fc93d6954a3387a8c --- /dev/null +++ b/classes/CallbackHandler.php @@ -0,0 +1,67 @@ +<?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; + +class CallbackHandler { + + /** + * returns null if the callback URL is not listed in configuration file. + */ + public static function getCallbackTitle($callbackURL) { + + if ($callbackURL === null) { + return "Account Management"; + } + + global $CALLBACKS; + + foreach ($CALLBACKS as $callback) { + if ($callback['url'] === $callbackURL) { + return $callback['title']; + } + } + + throw new \Exception("Unauthorized callback URL"); + } + + public static function manageLoginRedirect($user) { + + global $BASE_PATH, $session; + + if (isset($session->callback) && $session->callback !== null) { + // External login using token + $token = Util::createNewToken(); + DAO::get()->insertTokenData($token, $user->id); + header('Location: ' . $session->callback . '?token=' . $token); + } else { + // Login in session + $session->user = $user; + $session->save(); + // Return to index + header('Location: ' . $BASE_PATH); + } + } + +} diff --git a/classes/DAO.php b/classes/DAO.php index ccbabd8da1301d281064c2621212f34ff0d22d89..8a9d0789f7eb5fa76b2d669f0b6bcdb2ae96bfaf 100644 --- a/classes/DAO.php +++ b/classes/DAO.php @@ -28,11 +28,11 @@ abstract class DAO { public abstract function getDBHandler(); - public abstract function insertTokenData($token, $data); + public abstract function createLoginToken($token, $userId); - public abstract function findTokenData($token); + public abstract function findLoginToken($token); - public abstract function deleteToken($token); + public abstract function deleteLoginToken($token); /** * Return the new identity ID. @@ -45,7 +45,7 @@ abstract class DAO { public abstract function createUser(); public abstract function findUserById($userId); - + /** * Return a User object, null if nothing was found. * @param type $type Identity type (EDU_GAIN, X509, GOOGLE, ...) @@ -54,8 +54,12 @@ abstract class DAO { */ public abstract function findUserByIdentity($type, $identifier, $dbIdentifier); + public abstract function searchUser($searchText); + public abstract function addEmailToUser($email, $userId); + public abstract function createJoinRequest($token, $applicantUserId, $targetUserId); + public $config; public function __construct($config) { @@ -63,12 +67,13 @@ abstract class DAO { } public static function get() { - $config = parse_ini_file(ROOT . '/config.ini', true); - switch ($config['dbtype']) { + global $DATABASE; + + switch ($DATABASE['dbtype']) { case 'MySQL': - return new MySQLDAO($config); + return new MySQLDAO($DATABASE); default: - throw new \Exception($config['dbtype'] . ' not supported yet'); + throw new \Exception($DATABASE['dbtype'] . ' not supported yet'); } } diff --git a/classes/Identity.php b/classes/Identity.php index e792c17a3649ea5d46dc73ad0b8363e494f02e63..c611494dd7b1472c1bc755a70fe127c1adc159e2 100644 --- a/classes/Identity.php +++ b/classes/Identity.php @@ -43,7 +43,7 @@ class Identity { /** * One of the types specified above. Mandatory field. */ - private $type; + public $type; /** * Data related to specific account type (shibboleth persistent id, facebook id, etc, ...). Mandatory field. @@ -101,8 +101,4 @@ class Identity { $this->type = $userType; } - public function getType() { - return $this->type; - } - } diff --git a/classes/MySQLDAO.php b/classes/MySQLDAO.php index e484c927b3e5d72fb5abf7ac955907ba40a7eb9b..05ba51a75a2afb6d38ec3656612934d49c4bb650 100644 --- a/classes/MySQLDAO.php +++ b/classes/MySQLDAO.php @@ -33,16 +33,16 @@ class MySQLDAO extends DAO { return new PDO($connectionString, $this->config['username'], $this->config['password']); } - public function insertTokenData($token, $data) { + public function createLoginToken($token, $userId) { global $log; $dbh = $this->getDBHandler(); - $stmt = $dbh->prepare("INSERT INTO token (token, data) VALUES(:token, :data)"); + $stmt = $dbh->prepare("INSERT INTO login_token (token, data) VALUES(:token, :data)"); $params = array( ':token' => $token, - ':data' => $data + ':data' => $userId ); if ($stmt->execute($params)) { @@ -53,11 +53,11 @@ class MySQLDAO extends DAO { } } - public function findTokenData($token) { + public function findLoginToken($token) { $dbh = $this->getDBHandler(); - $stmt = $dbh->prepare("SELECT data FROM token WHERE token = :token AND CURRENT_TIMESTAMP < TIMESTAMPADD(MINUTE,1,creation_time)"); + $stmt = $dbh->prepare("SELECT data FROM login_token WHERE token = :token AND CURRENT_TIMESTAMP < TIMESTAMPADD(MINUTE,1,creation_time)"); $stmt->bindParam(':token', $token); $stmt->execute(); @@ -69,11 +69,11 @@ class MySQLDAO extends DAO { return null; } - public function deleteToken($token) { + public function deleteLoginToken($token) { $dbh = $this->getDBHandler(); - $stmt = $dbh->prepare("DELETE FROM token WHERE token = :token"); + $stmt = $dbh->prepare("DELETE FROM login_token WHERE token = :token"); $stmt->bindParam(':token', $token); $stmt->execute(); } @@ -86,7 +86,7 @@ class MySQLDAO extends DAO { . " VALUES(:user_id, :type, :email, :name, :surname, :institution, :username, :local_db_id, :typed_id, :eppn)"); $stmt->bindParam(':user_id', $userId); - $stmt->bindParam(':type', $identity->getType()); + $stmt->bindParam(':type', $identity->type); $stmt->bindParam(':email', $identity->email); $stmt->bindParam(':name', $identity->name); $stmt->bindParam(':surname', $identity->surname); @@ -111,6 +111,23 @@ class MySQLDAO extends DAO { return $dbh->lastInsertId(); } + private function getIdentityByRow($row) { + + $identity = new Identity($row['type']); + + $identity->id = $row['id']; + $identity->typedId = $row['typed_id']; + $identity->email = $row['email']; + $identity->localDBId = $row['local_db_id']; + $identity->name = $row['name']; + $identity->surname = $row['surname']; + $identity->institution = $row['institution']; + $identity->username = $row['username']; + $identity->eppn = $row['eppn']; + + return $identity; + } + public function findUserById($userId) { $dbh = $this->getDBHandler(); @@ -121,20 +138,16 @@ class MySQLDAO extends DAO { $stmt->bindParam(':user_id', $userId); $stmt->execute(); + $result = $stmt->fetchAll(); + if (count($result) === 0) { + return null; + } + $user = new User(); $user->id = $userId; - foreach ($stmt->fetchAll() as $row) { - $identity = new Identity($row['type']); - $identity->id = $row['id']; - $identity->typedId = $row['typed_id']; - $identity->email = $row['email']; - $identity->localDBId = $row['local_db_id']; - $identity->name = $row['name']; - $identity->surname = $row['surname']; - $identity->institution = $row['institution']; - $identity->username = $row['username']; - $identity->eppn = $row['eppn']; + foreach ($result as $row) { + $identity = $this->getIdentityByRow($row); $user->addIdentity($identity); } @@ -152,15 +165,25 @@ class MySQLDAO extends DAO { $dbh = $this->getDBHandler(); - $stmt = $dbh->prepare("SELECT user_id FROM identity WHERE type = :type AND typed_id = :typed_id AND local_db_id = :local_db_id"); + $query = "SELECT user_id FROM identity WHERE type = :type AND typed_id = :typed_id"; + if (isset($dbIdentifier) && $dbIdentifier !== null) { + $query .= " AND local_db_id = :local_db_id"; + } + + $stmt = $dbh->prepare($query); $stmt->bindParam(':type', $type); $stmt->bindParam(':typed_id', $identifier); - $stmt->bindParam(':local_db_id', $dbIdentifier); + if (isset($dbIdentifier) && $dbIdentifier !== null) { + $stmt->bindParam(':local_db_id', $dbIdentifier); + } $stmt->execute(); $result = $stmt->fetchAll(); + global $log; + $log->debug("count = " . count($result)); + if (count($result) === 0) { return null; } @@ -172,6 +195,55 @@ class MySQLDAO extends DAO { return $this->findUserById($userId); } + public function searchUser($searchText) { + + $dbh = $this->getDBHandler(); + + // TODO: Add additional email search... + + $query = "SELECT `user_id`, `id`, `type`, `typed_id`, `email`, `local_db_id`, `name`, `surname`, `institution`, `username`, `eppn`" + . " FROM identity WHERE `email` LIKE :email OR `name` LIKE :name OR `surname` LIKE :surname"; + + $stmt = $dbh->prepare($query); + + $searchParam = $searchText . '%'; + $stmt->bindParam(':email', $searchParam); + $stmt->bindParam(':name', $searchParam); + $stmt->bindParam(':surname', $searchParam); + + $stmt->execute(); + + $userMap = array(); + + //global $log; + //$log->debug('In searchUser'); + + foreach ($stmt->fetchAll() as $row) { + + //$log->debug($row['user_id']); + + $identity = $this->getIdentityByRow($row); + //$log->debug(json_encode($identity)); + + $userId = $row['user_id']; + if (array_key_exists($userId, $userMap)) { + $user = $userMap[$userId]; + } else { + $user = new User(); + $user->id = $userId; + $userMap[$userId] = $user; + } + + array_push($user->identities, $identity); + } + + $users = []; + foreach ($userMap as $userId => $user) { + array_push($users, $user); + } + return $users; + } + public function addEmailToUser($email, $userId) { $dbh = $this->getDBHandler(); @@ -183,4 +255,18 @@ class MySQLDAO extends DAO { $stmt->execute(); } + public function createJoinRequest($token, $applicantUserId, $targetUserId) { + + $dbh = $this->getDBHandler(); + + $stmt = $dbh->prepare("INSERT INTO `join_request`(`token`, `applicant_user_id`, `target_user_id`)" + . " VALUES(:token, :applicant_user_id, :target_user_id)"); + + $stmt->bindParam(':token', $token); + $stmt->bindParam(':applicant_user_id', $applicantUserId); + $stmt->bindParam(':target_user_id', $targetUserId); + + $stmt->execute(); + } + } diff --git a/classes/SessionData.php b/classes/SessionData.php index c6d807741a67a3433cfad618e6c567d136e87590..b2a885ea5f9529bf29c597bf4f7af44010c84dfc 100644 --- a/classes/SessionData.php +++ b/classes/SessionData.php @@ -26,8 +26,10 @@ namespace RAP; class SessionData { - public $callback; + private $callbackURL; + private $callbackTitle; public $user; + public $userSearchResults; public function save() { $_SESSION['SessionData'] = $this; @@ -41,4 +43,34 @@ class SessionData { } return $_SESSION['SessionData']; } + + public function setCallbackURL($callbackURL) { + $this->callbackURL = $callbackURL; + $this->callbackTitle = CallbackHandler::getCallbackTitle($callbackURL); + $this->save(); + } + + public function getCallbackURL() { + return $this->callbackURL; + } + + public function getCallbackTitle() { + return $this->callbackTitle; + } + + public function searchUser($searchText) { + $users = DAO::get()->searchUser($searchText); + + $this->userSearchResults = []; + foreach ($users as $user) { + // this search shouldn't contains the user itself + if ($user->id !== $this->user->id) { + $searchResult = UserSearchResult::buildFromUser($user); + array_push($this->userSearchResults, $searchResult); + } + } + + $this->save(); + } + } diff --git a/classes/TokenHandler.php b/classes/TokenHandler.php index c096a01710e9f52969e21bb8f25a311cd34804fc..4c7998ade71c855226a52c1a943644c5f50a347f 100644 --- a/classes/TokenHandler.php +++ b/classes/TokenHandler.php @@ -29,6 +29,7 @@ class TokenHandler { public static function createNewToken($data) { $token = bin2hex(openssl_random_pseudo_bytes(16)); // http://stackoverflow.com/a/18890309/771431 DAO::get()->insertTokenData($token, $data); + return $token; } public static function deleteToken($token) { diff --git a/classes/UserSearchResult.php b/classes/UserSearchResult.php new file mode 100644 index 0000000000000000000000000000000000000000..daada02ea3d19caadf4e04cd3b6c512c74454640 --- /dev/null +++ b/classes/UserSearchResult.php @@ -0,0 +1,78 @@ +<?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; + +class UserSearchResult { + + private $userId; + public $userDisplayText; + + public static function buildFromUser(User $user) { + $usr = new UserSearchResult(); + $usr->userId = $user->id; + + $nameAndSurname = null; + $email = null; + $identityTypes = []; + foreach ($user->identities as $identity) { + array_push($identityTypes, $identity->type); + 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 getUserId() { + return $this->userId; + } + +} diff --git a/classes/Util.php b/classes/Util.php new file mode 100644 index 0000000000000000000000000000000000000000..9a786b1a9f4aba5a7a057cc9250043daee978504 --- /dev/null +++ b/classes/Util.php @@ -0,0 +1,37 @@ +<?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 { + + public static function createNewToken() { + // Credits: http://stackoverflow.com/a/18890309/771431 + return bin2hex(openssl_random_pseudo_bytes(16)); + } + +} diff --git a/config.ini b/config.ini deleted file mode 100644 index 2065065c528b35849d8c65f91530a3e4de6b91f8..0000000000000000000000000000000000000000 --- a/config.ini +++ /dev/null @@ -1,8 +0,0 @@ - -;connection_string = mysql:host=localhost;dbname=rap" -dbtype = MySQL -hostname = localhost -port = 3306 -username = rap -password = ***REMOVED*** -dbname = rap diff --git a/config.php b/config.php index 732e9d8aa72c26518821172f5a4a035525ac10f7..53d270460b050d208cb0bd061f6c7305b8ef6826 100644 --- a/config.php +++ b/config.php @@ -31,20 +31,44 @@ $BASE_PATH = $PROTOCOL . $_SERVER['HTTP_HOST'] . $CONTEXT_ROOT; $LOG_PATH = ROOT . "/logs/rap-service.log"; $LOG_LEVEL = Monolog\Logger::DEBUG; -$PDO = array( - "connection_string" => "mysql:host=localhost;dbname=rap", - "user" => "rap", - "password" => "***REMOVED***" -); - -$Google = array( - 'id' => "***REMOVED***.apps.googleusercontent.com", - 'secret' => "***REMOVED***", - 'callback' => $BASE_PATH . "/oauth2/google_token.php"); +$CALLBACKS = [ + array( + 'url' => 'http://localhost:8087/grouper', + 'title' => 'Login to Grouper' + ) +]; -$Facebook = array( - 'id' => "***REMOVED***", - 'secret' => "***REMOVED***", - 'version' => "v2.2", - 'callback' => $BASE_PATH . "/oauth2/facebook_token.php"); +$DATABASE = array( + 'dbtype' => 'MySQL', + 'hostname' => 'localhost', + 'port' => 3306, + 'username' => 'rap', + 'password' => '***REMOVED***', + 'dbname' => 'rap' +); +$AUTHENTICATION_METHODS = array( + 'eduGAIN' => array(), + 'Google' => array( + 'id' => "***REMOVED***.apps.googleusercontent.com", + 'secret' => "***REMOVED***", + 'callback' => $BASE_PATH . "/oauth2/google_token.php"), + 'Facebook' => array( + 'id' => "***REMOVED***", + 'secret' => "***REMOVED***", + 'version' => "v2.2", + 'callback' => $BASE_PATH . "/oauth2/facebook_token.php"), + 'LinkedIn' => array(), + 'X.509' => array(), + 'Direct' => array( + array( + 'name' => 'IA2', + 'label' => '', + 'logo' => 'ia2-logo-60x60.png', + 'description' => 'Use the IA2 logo if you have an IA2 account (provided by IA2 or self-registered)', + 'type' => 'ldap', + 'ldap_user_scope' => 'ou=custom_users,dc=oats,dc=inaf,dc=it', + 'ldap_user_id_field' => 'uid' + ) + ) +); diff --git a/css/chosen.min.css b/css/chosen.min.css new file mode 100644 index 0000000000000000000000000000000000000000..a264b6d8797a223fa398fad195f07149c4d22088 --- /dev/null +++ b/css/chosen.min.css @@ -0,0 +1,3 @@ +/* Chosen v1.7.0 | (c) 2011-2017 by Harvest | MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md */ + +.chosen-container{position:relative;display:inline-block;vertical-align:middle;font-size:13px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.chosen-container *{box-sizing:border-box}.chosen-container .chosen-drop{position:absolute;top:100%;z-index:1010;width:100%;border:1px solid #aaa;border-top:0;background:#fff;box-shadow:0 4px 5px rgba(0,0,0,.15);clip:rect(0,0,0,0)}.chosen-container.chosen-with-drop .chosen-drop{clip:auto}.chosen-container a{cursor:pointer}.chosen-container .search-choice .group-name,.chosen-container .chosen-single .group-name{margin-right:4px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-weight:400;color:#999}.chosen-container .search-choice .group-name:after,.chosen-container .chosen-single .group-name:after{content:":";padding-left:2px;vertical-align:top}.chosen-container-single .chosen-single{position:relative;display:block;overflow:hidden;padding:0 0 0 8px;height:25px;border:1px solid #aaa;border-radius:5px;background-color:#fff;background:linear-gradient(#fff 20%,#f6f6f6 50%,#eee 52%,#f4f4f4 100%);background-clip:padding-box;box-shadow:0 0 3px #fff inset,0 1px 1px rgba(0,0,0,.1);color:#444;text-decoration:none;white-space:nowrap;line-height:24px}.chosen-container-single .chosen-default{color:#999}.chosen-container-single .chosen-single span{display:block;overflow:hidden;margin-right:26px;text-overflow:ellipsis;white-space:nowrap}.chosen-container-single .chosen-single-with-deselect span{margin-right:38px}.chosen-container-single .chosen-single abbr{position:absolute;top:6px;right:26px;display:block;width:12px;height:12px;background:url(chosen-sprite.png) -42px 1px no-repeat;font-size:1px}.chosen-container-single .chosen-single abbr:hover{background-position:-42px -10px}.chosen-container-single.chosen-disabled .chosen-single abbr:hover{background-position:-42px -10px}.chosen-container-single .chosen-single div{position:absolute;top:0;right:0;display:block;width:18px;height:100%}.chosen-container-single .chosen-single div b{display:block;width:100%;height:100%;background:url(chosen-sprite.png) no-repeat 0 2px}.chosen-container-single .chosen-search{position:relative;z-index:1010;margin:0;padding:3px 4px;white-space:nowrap}.chosen-container-single .chosen-search input[type=text]{margin:1px 0;padding:4px 20px 4px 5px;width:100%;height:auto;outline:0;border:1px solid #aaa;background:url(chosen-sprite.png) no-repeat 100% -20px;font-size:1em;font-family:sans-serif;line-height:normal;border-radius:0}.chosen-container-single .chosen-drop{margin-top:-1px;border-radius:0 0 4px 4px;background-clip:padding-box}.chosen-container-single.chosen-container-single-nosearch .chosen-search{position:absolute;clip:rect(0,0,0,0)}.chosen-container .chosen-results{color:#444;position:relative;overflow-x:hidden;overflow-y:auto;margin:0 4px 4px 0;padding:0 0 0 4px;max-height:240px;-webkit-overflow-scrolling:touch}.chosen-container .chosen-results li{display:none;margin:0;padding:5px 6px;list-style:none;line-height:15px;word-wrap:break-word;-webkit-touch-callout:none}.chosen-container .chosen-results li.active-result{display:list-item;cursor:pointer}.chosen-container .chosen-results li.disabled-result{display:list-item;color:#ccc;cursor:default}.chosen-container .chosen-results li.highlighted{background-color:#3875d7;background-image:linear-gradient(#3875d7 20%,#2a62bc 90%);color:#fff}.chosen-container .chosen-results li.no-results{color:#777;display:list-item;background:#f4f4f4}.chosen-container .chosen-results li.group-result{display:list-item;font-weight:700;cursor:default}.chosen-container .chosen-results li.group-option{padding-left:15px}.chosen-container .chosen-results li em{font-style:normal;text-decoration:underline}.chosen-container-multi .chosen-choices{position:relative;overflow:hidden;margin:0;padding:0 5px;width:100%;height:auto;border:1px solid #aaa;background-color:#fff;background-image:linear-gradient(#eee 1%,#fff 15%);cursor:text}.chosen-container-multi .chosen-choices li{float:left;list-style:none}.chosen-container-multi .chosen-choices li.search-field{margin:0;padding:0;white-space:nowrap}.chosen-container-multi .chosen-choices li.search-field input[type=text]{margin:1px 0;padding:0;height:25px;outline:0;border:0!important;background:transparent!important;box-shadow:none;color:#999;font-size:100%;font-family:sans-serif;line-height:normal;border-radius:0;width:25px}.chosen-container-multi .chosen-choices li.search-choice{position:relative;margin:3px 5px 3px 0;padding:3px 20px 3px 5px;border:1px solid #aaa;max-width:100%;border-radius:3px;background-color:#eee;background-image:linear-gradient(#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-size:100% 19px;background-repeat:repeat-x;background-clip:padding-box;box-shadow:0 0 2px #fff inset,0 1px 0 rgba(0,0,0,.05);color:#333;line-height:13px;cursor:default}.chosen-container-multi .chosen-choices li.search-choice span{word-wrap:break-word}.chosen-container-multi .chosen-choices li.search-choice .search-choice-close{position:absolute;top:4px;right:3px;display:block;width:12px;height:12px;background:url(chosen-sprite.png) -42px 1px no-repeat;font-size:1px}.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover{background-position:-42px -10px}.chosen-container-multi .chosen-choices li.search-choice-disabled{padding-right:5px;border:1px solid #ccc;background-color:#e4e4e4;background-image:linear-gradient(#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);color:#666}.chosen-container-multi .chosen-choices li.search-choice-focus{background:#d4d4d4}.chosen-container-multi .chosen-choices li.search-choice-focus .search-choice-close{background-position:-42px -10px}.chosen-container-multi .chosen-results{margin:0;padding:0}.chosen-container-multi .chosen-drop .result-selected{display:list-item;color:#ccc;cursor:default}.chosen-container-active .chosen-single{border:1px solid #5897fb;box-shadow:0 0 5px rgba(0,0,0,.3)}.chosen-container-active.chosen-with-drop .chosen-single{border:1px solid #aaa;border-bottom-right-radius:0;border-bottom-left-radius:0;background-image:linear-gradient(#eee 20%,#fff 80%);box-shadow:0 1px 0 #fff inset}.chosen-container-active.chosen-with-drop .chosen-single div{border-left:0;background:transparent}.chosen-container-active.chosen-with-drop .chosen-single div b{background-position:-18px 2px}.chosen-container-active .chosen-choices{border:1px solid #5897fb;box-shadow:0 0 5px rgba(0,0,0,.3)}.chosen-container-active .chosen-choices li.search-field input[type=text]{color:#222!important}.chosen-disabled{opacity:.5!important;cursor:default}.chosen-disabled .chosen-single{cursor:default}.chosen-disabled .chosen-choices .search-choice .search-choice-close{cursor:default}.chosen-rtl{text-align:right}.chosen-rtl .chosen-single{overflow:visible;padding:0 8px 0 0}.chosen-rtl .chosen-single span{margin-right:0;margin-left:26px;direction:rtl}.chosen-rtl .chosen-single-with-deselect span{margin-left:38px}.chosen-rtl .chosen-single div{right:auto;left:3px}.chosen-rtl .chosen-single abbr{right:auto;left:26px}.chosen-rtl .chosen-choices li{float:right}.chosen-rtl .chosen-choices li.search-field input[type=text]{direction:rtl}.chosen-rtl .chosen-choices li.search-choice{margin:3px 5px 3px 0;padding:3px 5px 3px 19px}.chosen-rtl .chosen-choices li.search-choice .search-choice-close{right:auto;left:4px}.chosen-rtl.chosen-container-single .chosen-results{margin:0 0 4px 4px;padding:0 4px 0 0}.chosen-rtl .chosen-results li.group-option{padding-right:15px;padding-left:0}.chosen-rtl.chosen-container-active.chosen-with-drop .chosen-single div{border-right:0}.chosen-rtl .chosen-search input[type=text]{padding:4px 5px 4px 20px;background:url(chosen-sprite.png) no-repeat -30px -20px;direction:rtl}.chosen-rtl.chosen-container-single .chosen-single div b{background-position:6px 2px}.chosen-rtl.chosen-container-single.chosen-with-drop .chosen-single div b{background-position:-12px 2px}@media only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min-resolution:144dpi),only screen and (min-resolution:1.5dppx){.chosen-rtl .chosen-search input[type=text],.chosen-container-single .chosen-single abbr,.chosen-container-single .chosen-single div b,.chosen-container-single .chosen-search input[type=text],.chosen-container-multi .chosen-choices .search-choice .search-choice-close,.chosen-container .chosen-results-scroll-down span,.chosen-container .chosen-results-scroll-up span{background-image:url(chosen-sprite@2x.png)!important;background-size:52px 37px!important;background-repeat:no-repeat!important}} \ No newline at end of file diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000000000000000000000000000000000000..f44bc67f44b4bf00b74b952b30650633980f908d --- /dev/null +++ b/css/style.css @@ -0,0 +1,123 @@ +body { + background-color: #eee; + padding-bottom: 150px; +} + +@keyframes pulse { + from { + transform: scale(1, 1); + } + + to { + transform: scale(1.07, 1.07); + } +} + +.home-box { + float: left; + width: 240px; + height: 165px; + padding: 2px; + margin: 10px; + border-radius: 15px; + border: 1px solid #ccc; + background-color: #fff; + padding: 4px 8px 8px 8px; + box-shadow: 0 1px 2px rgba(0,0,0,.1); +} + +.home-box .img-wrapper { + width: 100%; + height: 80px; + text-align: center; + display: table; +} + +.home-box .img-wrapper a { + display: table-cell; + vertical-align: middle; +} + +.home-box .img-wrapper a:hover { + animation-duration: 0.2s; + animation-fill-mode: both; + animation-name: pulse; + animation-timing-function: ease-in; +} + +#main-header { + background-image: url('../img/rap-background.jpg'); + background-position: center; + background-repeat: repeat-x; + height: 90px; + position: relative; + border-bottom: 1px #9c9c9c solid; + margin-bottom: 20px; + box-shadow: 0 1px 2px rgba(0,0,0,.1); + text-shadow: 0 2px 3px rgba(0,0,0,.6); +} + +.credits { + position: absolute; + top: 66px; + bottom: 0; + right: 11px; + left: 0; + text-align: right; + font-size: 12px; + color: #fff; +} + +.page-title-wrapper { + position: absolute; + top: 0; + bottom: 0; + right: 0; + left: 0; +} + +.page-title-wrapper h1 { + color: #fff; + font-weight: bold; + font-size: 42px; +} + +#main-footer-wrapper { + position: fixed; + bottom: 0; + right: 0; + left: 0; + background-color: #eee; +} + +#main-footer { + color: #666; + border-top: 1px #d4d4d4 solid; + background-color: #f8f8f8; + padding: 5px 0; +} + +#footer-credits { + font-size: 13px; + color: #666; + margin-bottom: 8px +} + +.callback-title { + margin-top: 0; + font-weight: bold; + color: #24388e; + text-shadow: 0 2px 3px rgba(0,0,0,.35); +} + +.panel { + box-shadow: 0 1px 2px rgba(0,0,0,.1); +} + +.panel-default { + border-color: #ccc +} + +.panel-default > .panel-heading { + background-image: linear-gradient(to bottom,#f5f5f5 0,#ccc 100%); +} diff --git a/img/ia2-logo-60x60.png b/img/ia2-logo-60x60.png new file mode 100644 index 0000000000000000000000000000000000000000..f93ef2495577ed01ad2a5ac25578607dd9891670 Binary files /dev/null and b/img/ia2-logo-60x60.png differ diff --git a/img/logo-ia2-small.png b/img/logo-ia2-small.png new file mode 100644 index 0000000000000000000000000000000000000000..cb913c9d1bfb1815de802febddfdec6dd2b56552 Binary files /dev/null and b/img/logo-ia2-small.png differ diff --git a/img/rap-background.jpg b/img/rap-background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..538bb0ba4d26db032bdf97fa41d9ea6c21c5cc81 Binary files /dev/null and b/img/rap-background.jpg differ diff --git a/include/footer.php b/include/footer.php index 9943ff0f851844f5daaccd7e1adca02a193936dc..0de7f71286b14074892fc0ca7fe0144ed099a376 100644 --- a/include/footer.php +++ b/include/footer.php @@ -1,3 +1,11 @@ </div> +<footer id="main-footer-wrapper" class="text-center"> + <p id="footer-credits">This software has been adapted by the IA2 team from the Remote Authentication Portal written by Franco Tinarelli at INAF-IRA.</p> + <div id="main-footer"> + Powered by + <img src="img/logo-ia2-small.png" alt="logo IA2" /> + <a href="http://www.ia2.inaf.it/" target="blank_">IA2</a> + </div> +</footer> </body> </html> diff --git a/include/front-controller.php b/include/front-controller.php new file mode 100644 index 0000000000000000000000000000000000000000..28c26903c7951c8e86a48fd96d0a407d14ed5f90 --- /dev/null +++ b/include/front-controller.php @@ -0,0 +1,39 @@ +<?php + +/** + * Front Controller using http://flightphp.com/ + * In all these calls user session must exist, so we have to start it at the + * beginning using the startSession() function. + */ +// + +function setCallback() { + global $session; + + $callback = Flight::request()->data['callback']; + $session->setCallbackURL(isset($callback) ? $callback : null); +} + +Flight::route('/', function() { + startSession(); + setCallback(); + global $session, $AUTHENTICATION_METHODS; + Flight::render('index.php', array('title' => 'RAP', + 'session' => $session, 'auth' => $AUTHENTICATION_METHODS)); +}); + +Flight::route('GET /logout', function() { + startSession(); + session_destroy(); + Flight::redirect('/'); +}); + +Flight::route('/google', function() { + startSession(); + Flight::redirect('/oauth2/google_token.php'); +}); + +Flight::route('/facebook', function() { + startSession(); + Flight::redirect('/oauth2/facebook_login.php'); +}); diff --git a/include/gui-backend.php b/include/gui-backend.php new file mode 100644 index 0000000000000000000000000000000000000000..6087bb3277fd8abaf3529aa0d07c55c3b658e518 --- /dev/null +++ b/include/gui-backend.php @@ -0,0 +1,47 @@ +<?php + +/** + * REST backend for JavaScript code. + */ +// + +function checkSession() { + + startSession(); + + global $session; + if ($session->user === null) { + http_response_code(401); + die("You must be registered to perform this action"); + } +} + +Flight::route('GET /user', function() { + + checkSession(); + global $session; + + $searchText = Flight::request()->query['search']; + $session->searchUser($searchText); + + $jsRes = []; + foreach ($session->userSearchResults as $searchResult) { + array_push($jsRes, $searchResult->userDisplayText); + } + + echo json_encode($jsRes); +}); + +Flight::route('POST /join', function() { + + checkSession(); + global $session; + + $selectedUserIndex = Flight::request()->data['selectedUserIndex']; + $targetUserId = $session->userSearchResults[$selectedUserIndex]->getUserId(); + + $token = RAP\Util::createNewToken(); + RAP\DAO::get()->createJoinRequest($token, $session->user->id, $targetUserId); + + echo ""; +}); diff --git a/include/header.php b/include/header.php index 92c810d6804db1bcd19937e8f5a83fd149166a48..29356dd43f6fc35a546977657bbd11615e9c09d9 100644 --- a/include/header.php +++ b/include/header.php @@ -7,6 +7,16 @@ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous" /> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> + <link rel="stylesheet" href="css/style.css" /> + <script src="js/script.js"></script> </head> <body> + <header id="main-header"> + <div class="credits"> + Image Credits & Copyright: Colombari/E.Recurt + </div> + <div class="page-title-wrapper"> + <h1 class="text-center">Remote Authentication Portal</h1> + </div> + </header> <div class="container"> diff --git a/include/init.php b/include/init.php index e6124cf334fb2bd854a60655bfc38b845626d3c6..cfb824c825299a2ea4d47908c6fb0517ffa4a0c7 100644 --- a/include/init.php +++ b/include/init.php @@ -40,5 +40,8 @@ include ROOT . '/config.php'; $log = new Monolog\Logger('mainLogger'); $log->pushHandler(new Monolog\Handler\StreamHandler($LOG_PATH, $LOG_LEVEL)); -session_start(); -$session = RAP\SessionData::get(); +function startSession() { + session_start(); + global $session; + $session = RAP\SessionData::get(); +} diff --git a/include/rest-web-service.php b/include/rest-web-service.php new file mode 100644 index 0000000000000000000000000000000000000000..e913e8a70c73feb2bfd76d9f780e3e7e4102439f --- /dev/null +++ b/include/rest-web-service.php @@ -0,0 +1,42 @@ +<?php + +/** + * REST Web Service using http://flightphp.com/ + */ +// +$WS_PREFIX = '/ws'; + +Flight::route('GET ' . $WS_PREFIX . '/user-info', function() { + + $token = Flight::request()->query['token']; + $userData = RAP\DAO::get()->findTokenData($token); + + if (is_null($userData)) { + http_response_code(404); + die("Token not found"); + } + + RAP\DAO::get()->deleteToken($token); + + header('Content-Type: text/plain'); + echo $userData; +}); + +Flight::route('GET ' . $WS_PREFIX . '/user/@userId', function($userId) { + + $user = RAP\DAO::get()->findUserById($userId); + if ($user !== null) { + header('Content-Type: application/json'); + echo json_encode($user); + } else { + http_response_code(404); + die("User not found"); + } +}); + +Flight::route('GET ' . $WS_PREFIX . '/user', function() { + + $searchText = Flight::request()->query['search']; + $users = RAP\DAO::get()->searchUser($searchText); + echo json_encode($users); +}); diff --git a/index.php b/index.php index 8241bc3ffe5b8cc06cb4b91d4b73845a5d01e16d..754f719c6ba324aeb4dd06185284f4094c3d769c 100644 --- a/index.php +++ b/index.php @@ -24,71 +24,9 @@ include './include/init.php'; -/** - * REST Web Service using http://flightphp.com/ - */ -Flight::route('/demo', function() { - $callback = (isset($_SERVER['HTTPS']) ? "https" : "http") . '://' . $_SERVER['HTTP_HOST'] . "/rap-service/user-info"; - Flight::render('demo.php', array('callback' => $callback)); -}); - -Flight::route('/', function() { - global $session; - Flight::render('index.php', array('title' => 'RAP', 'session' => $session)); -}); - -Flight::route('GET /logout', function() { - session_destroy(); - Flight::redirect('/'); -}); - -Flight::route('/google', function() { - global $session; - - $callback = Flight::request()->data['callback']; - $session->callback = isset($callback) ? $callback : null; - $session->save(); - - Flight::redirect('/oauth2/google_token.php'); -}); - -Flight::route('POST /facebook', function() { - $callback = Flight::request()->data['callback']; - if (!isset($callback)) { - throw new Exception("Callback URL not set!"); - } - session_start(); - $_SESSION['rap_callback'] = $callback; - Flight::redirect('/oauth2/facebook_login.php'); -}); - -Flight::route('GET /user-info', function() { - - $token = Flight::request()->query['token']; - $userData = RAP\DAO::getTokenData($token); - - if (is_null($userData)) { - http_response_code(404); - die("Token not found"); - } - - RAP\DAO::deleteToken($token); - - header('Content-Type: application/json'); - echo $userData; -}); - -Flight::route('GET /user/@userId', function($userId) { - - $user = RAP\DAO::get()->findUserById($userId); - if ($user !== null) { - global $log; - $log->debug(count($user->identities)); - echo json_encode($user); - } else { - http_response_code(404); - die("User not found"); - } -}); +include './include/front-controller.php'; +include './include/gui-backend.php'; +include './include/rest-web-service.php'; +// Starting Flight framework Flight::start(); diff --git a/js/script.js b/js/script.js new file mode 100644 index 0000000000000000000000000000000000000000..2ee30793e57f581b539ac38f219a31fc289db004 --- /dev/null +++ b/js/script.js @@ -0,0 +1,48 @@ +(function ($) { + + // function factory used to generate function to be executed at timeout (see below) + function searchUserFactory(searchText) { + return function () { + $.get('user?search=' + searchText, function (response) { + var users = JSON.parse(response); + + // Display the selector only if we have some results + $('#user-selector-group').toggleClass('hide', users.length === 0); + + // Fill the user selector + $userSelector = $('#user-selector-group select'); + $userSelector.empty(); + for (var i = 0; i < users.length; i++) { + $userSelector.append('<option value="' + i + '">' + users[i] + '</option>'); + } + }); + }; + } + + function sendJoinRequest() { + $userSelector = $('#user-selector-group select'); + var selectedUserIndex = $userSelector.val(); + if (selectedUserIndex !== null) { + $.post('join', {selectedUserIndex: selectedUserIndex}, function (response) { + console.log(response); + }); + } + } + + // When the document is loaded + $(document).ready(function () { + + // Add keyup event handler on user search input text + var timeoutId = 0; + $(document).on('keyup', '#user-search-text', function (event) { + clearTimeout(timeoutId); + var searchUser = searchUserFactory($(event.target).val()); + // wait 500 ms without typing before doing the AJAX call + timeoutId = setTimeout(searchUser, 500); + }); + + // Add click event handler to join request button + $(document).on('click', '#send-join-request-btn', sendJoinRequest); + }); + +})(jQuery); \ No newline at end of file diff --git a/oauth2/facebook_login.php b/oauth2/facebook_login.php index a970bb25a26a17d0321fa8f49b7faec3f7b8d9af..e89404eddf27bfb84feb2b8b447be209348b4060 100755 --- a/oauth2/facebook_login.php +++ b/oauth2/facebook_login.php @@ -23,6 +23,9 @@ */ include '../include/init.php'; +startSession(); + +$Facebook = $AUTHENTICATION_METHODS['Facebook']; $fb = new Facebook\Facebook([ 'app_id' => $Facebook['id'], @@ -35,6 +38,5 @@ $helper = $fb->getRedirectLoginHelper(); $permissions = ['email']; // Optional permissions $loginUrl = $helper->getLoginUrl($Facebook['callback'], $permissions); - header("Location: $loginUrl"); ?> diff --git a/oauth2/facebook_token.php b/oauth2/facebook_token.php index 8a41986b43e8711d397d573af5fd84048cd3bb41..7e05a14fc6a7f4c0c482f6d9e2b4220076683c24 100755 --- a/oauth2/facebook_token.php +++ b/oauth2/facebook_token.php @@ -23,13 +23,9 @@ */ include '../include/init.php'; +startSession(); -session_start(); -$callback = $_SESSION['rap_callback']; -if (!isset($callback)) { - http_response_code(422); - die("Callback URL not set!"); -} +$Facebook = $AUTHENTICATION_METHODS['Facebook']; $fb = new Facebook\Facebook([ 'app_id' => $Facebook['id'], @@ -78,20 +74,27 @@ try { exit; } -$user = $response->getGraphUser(); - $_SESSION['fb_access_token'] = (string) $accessToken; -// Creating user object -$userData = array( - "type" => "Facebook", - "name" => $user["first_name"], - "surname" => $user["last_name"], - "emailAddresses" => [$user["email"]], - "typed_id" => $user["id"] -); - -$token = RAP\DAO::insertLogin($userData); -header('Location: ' . $callback . '?token=' . $token); -die(); +$fbUser = $response->getGraphUser(); + +$typedId = $fbUser["id"]; + +$user = RAP\UserHandler::findUserByIdentity(RAP\Identity::FACEBOOK, $typedId, null); + +if ($user === null) { + $user = new RAP\User(); + + $identity = new RAP\Identity(RAP\Identity::FACEBOOK); + $identity->email = $fbUser["email"]; + $identity->name = $fbUser["first_name"]; + $identity->surname = $fbUser["last_name"]; + $identity->typedId = $typedId; + + $user->addIdentity($identity); + + RAP\UserHandler::saveUser($user); +} + +RAP\CallbackHandler::manageLoginRedirect($user); ?> diff --git a/oauth2/google_token.php b/oauth2/google_token.php index 553bbb03666660be22538b21baedd354312dce6c..990ee84b9e76584665fb101b5f9342033808c364 100644 --- a/oauth2/google_token.php +++ b/oauth2/google_token.php @@ -23,6 +23,9 @@ */ include '../include/init.php'; +startSession(); + +$Google = $AUTHENTICATION_METHODS['Google']; $client = new Google_Client(array( 'client_id' => $Google['id'], @@ -87,17 +90,7 @@ if ($client->getAccessToken()) { RAP\UserHandler::saveUser($user); } - if (isset($session->callback) && $session->callback !== null) { - // External login using token - $token = RAP\TokenHandler::createNewToken($user->id); - header('Location: ' . $session->callback . '?token=' . $token); - } else { - // Login in session - $session->user = $user; - $session->save(); - // Return to index - header('Location: ' . $BASE_PATH); - } + RAP\CallbackHandler::manageLoginRedirect($user); die(); } else { diff --git a/sql/setup-database.sql b/sql/setup-database.sql index 5ea15e11748c60a6028e6f7f272b2f1ae2a4a909..cff418a55e4cf7dcf68b8d0132b2c94331104b7c 100644 --- a/sql/setup-database.sql +++ b/sql/setup-database.sql @@ -27,7 +27,7 @@ CREATE TABLE `additional_email` ( FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE `token` ( +CREATE TABLE `login_token` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `token` varchar(255) NOT NULL, `data` text, @@ -35,9 +35,20 @@ CREATE TABLE `token` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE EVENT tokens_cleanup +CREATE TABLE `join_request` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `token` varchar(255) NOT NULL, + `applicant_user_id` bigint(20) NOT NULL, + `target_user_id` bigint(20) NOT NULL, + `creation_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + FOREIGN KEY (`applicant_user_id`) REFERENCES `user`(`id`), + FOREIGN KEY (`target_user_id`) REFERENCES `user`(`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE EVENT login_tokens_cleanup ON SCHEDULE EVERY 1 MINUTE - COMMENT 'Remove expired tokens' + COMMENT 'Remove expired login tokens' DO - DELETE FROM token WHERE CURRENT_TIMESTAMP > TIMESTAMPADD(MINUTE,1,creation_time); + DELETE FROM login_token WHERE CURRENT_TIMESTAMP > TIMESTAMPADD(MINUTE,1,creation_time); diff --git a/views/demo.php b/views/demo.php deleted file mode 100644 index 7048eb49e9dc966fef3a770ddf4ef0fefdb6c65a..0000000000000000000000000000000000000000 --- a/views/demo.php +++ /dev/null @@ -1,16 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>RAP Service</title> - </head> - <body> - <form method="POST" action="google"> - <input type="hidden" name="callback" value="<?php echo $callback; ?>" /> - <input type="submit" value="Google" /> - </form> - <form method="POST" action="facebook"> - <input type="hidden" name="callback" value="<?php echo $callback; ?>" /> - <input type="submit" value="Facebook" /> - </form> - </body> -</html> \ No newline at end of file diff --git a/views/index.php b/views/index.php index 52a446c8e5a0ad43994a137df6ba0ff5033440f7..5a27057e4d0140edb905b53fd92886f2dd0b1ff9 100644 --- a/views/index.php +++ b/views/index.php @@ -3,12 +3,155 @@ include 'include/header.php'; ?> <?php if ($session->user === null) { ?> - <a href="google"> - <img src="img/google-60.png" alt="Google Logo" /> - </a> + <div class="row"> + <div class="col-xs-12"> + <h1 class="text-center callback-title"><?php echo $session->getCallbackTitle(); ?></h1> + </div> + </div> + <div class="row"> + <div class="col-xs-12"> + <?php if (isset($auth['eduGAIN'])) { ?> + <div class="home-box"> + <div class="img-wrapper"> + <a href="edugain"> + <img src="img/eduGain-200.png" alt="eduGAIN Logo" /> + </a> + </div> + Use the eduGAIN Logo to Login or Register to the RAP facility if you belong to an eduGAIN IdP. + </div> + <?php } ?> + <?php if (isset($auth['Google']) || isset($auth['Facebook']) || isset($auth['LinkedIn'])) { ?> + <div class="home-box"> + <div class="img-wrapper"> + <?php if (isset($auth['Google'])) { ?> + <a href="google" class="animated pulse"> + <img src="img/google-60.png" alt="Google Logo" /> + </a> + <?php } ?> + <?php if (isset($auth['Facebook'])) { ?> + <a href="facebook"> + <img src="img/facebook-60.png" alt="Facebook Logo" /> + </a> + <?php } ?> + <?php if (isset($auth['LinkedIn'])) { ?> + <a href="linkedin"> + <img src="img/linkedin-60.png" alt="LinkedIn Logo" /> + </a> + <?php } ?> + </div> + Use these Logos to Login or Register to the RAP facility with your social identity + </div> + <?php } ?> + <?php if (isset($auth['X.509'])) { ?> + <div class="home-box"> + <div class="img-wrapper"> + <a href="x509"> + <img src="img/x509-200.png" alt="X.509 Logo" /> + </a> + </div> + Use the X.509 Logo to Login with your personal certificate (IGTF and TERENA-TACAR, are allowed). + </div> + <?php } ?> + <?php + if (isset($auth['Direct'])) { + foreach ($auth['Direct'] as $directAuth) { + ?> + <div class="home-box"> + <div class="img-wrapper"> + <a href="#"> + <img src="img/<?php echo $directAuth['logo']; ?>" alt="" /> + </a> + </div> + <?php echo $directAuth['description']; ?> + </div> + <?php + } + } + ?> + </div> + </div> <?php } else { ?> - <?php echo json_encode($session->user); ?> - <a href="logout">Logout</a> + <div class="row"> + <div class="col-sm-5 col-xs-12"> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">Your identities</h3> + </div> + <div class="panel-body"> + <?php foreach ($session->user->identities as $identity) { ?> + <dl class="dl-horizontal"> + <dt>Type</dt> + <dd><?php echo $identity->type; ?></dd> + <dt>E-mail</dt> + <dd><?php echo $identity->email; ?></dd> + <?php if ($identity->eppn !== null) { ?> + <dt>EduPersonPrincipalName</dt> + <dd><?php echo $identity->eppn; ?></dd> + <?php } ?> + <?php if ($identity->username !== null) { ?> + <dt>Username</dt> + <dd><?php echo $identity->username; ?></dd> + <?php } ?> + <?php if ($identity->name !== null) { ?> + <dt>Name</dt> + <dd><?php echo $identity->name; ?></dd> + <?php } ?> + <?php if ($identity->surname !== null) { ?> + <dt>Surname</dt> + <dd><?php echo $identity->surname; ?></dd> + <?php } ?> + <?php if ($identity->institution !== null) { ?> + <dt>Institution</dt> + <dd><?php echo $identity->institution; ?></dd> + <?php } ?> + </dl> + <?php } ?> + </div> + </div> + </div> + <div class="col-sm-2 text-center"> + <button class="btn btn-success" type="button" data-toggle="modal" data-target="#search-user-modal"> + Join with another identity + </button> + </div> + <div class="col-sm-5"> + <a href="logout" class="btn btn-primary pull-right">Logout</a> + </div> + </div> + + <div class="modal fade" id="search-user-modal" tabindex="-1" role="dialog" aria-labelledby="search-user-modal-title"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="search-user-modal-title">Search user</h4> + </div> + <div class="modal-body"> + <form class="form-horizontal"> + <div class="form-group"> + <label for="user-search-text" class="col-xs-3 control-label">Search text</label> + <div class="col-xs-9"> + <input type="text" class="form-control" id="user-search-text" placeholder="Name, surname or email..."> + </div> + </div> + <div class="form-group hide" id="user-selector-group"> + <label for="user-selector" class="col-xs-3 control-label">Select user</label> + <div class="col-xs-9"> + <select id="user-selector" class="form-control"> + + </select> + </div> + </div> + </form> + </div> + <div class="modal-footer"> + <button class="btn btn-primary" type="button" id="send-join-request-btn"> + Send join request + </button> + </div> + </div> + </div> + </div> <?php } ?> <?php