From c749a87e81c9f40db61731146b51c28fb632558b Mon Sep 17 00:00:00 2001 From: Sonia Zorba Date: Fri, 30 Jun 2017 12:13:25 +0200 Subject: [PATCH] Added LinkedIn, little fixes --- auth/oauth2/linkedin_login.php | 37 ++++++++++ auth/oauth2/linkedin_token.php | 124 +++++++++++++++++++++++++++++++++ classes/CallbackHandler.php | 14 ++-- classes/MailSender.php | 56 ++++++++++++++- classes/MySQLDAO.php | 4 ++ config.php | 9 ++- include/front-controller.php | 19 +++-- include/gui-backend.php | 4 +- include/init.php | 1 + include/rest-web-service.php | 38 +++++++++- include/user-data.php | 24 ++++--- js/index.js | 3 + views/confirm-join.php | 2 + 13 files changed, 308 insertions(+), 27 deletions(-) create mode 100644 auth/oauth2/linkedin_login.php create mode 100644 auth/oauth2/linkedin_token.php diff --git a/auth/oauth2/linkedin_login.php b/auth/oauth2/linkedin_login.php new file mode 100644 index 0000000..df940e8 --- /dev/null +++ b/auth/oauth2/linkedin_login.php @@ -0,0 +1,37 @@ + diff --git a/auth/oauth2/linkedin_token.php b/auth/oauth2/linkedin_token.php new file mode 100644 index 0000000..d4e88e4 --- /dev/null +++ b/auth/oauth2/linkedin_token.php @@ -0,0 +1,124 @@ + "authorization_code", + 'code' => $_REQUEST['code'], + 'redirect_uri' => $LinkedIn['callback'], + 'client_id' => $LinkedIn['id'], + 'client_secret' => $LinkedIn['secret']); + +//traverse array and prepare data for posting (key1=value1) +foreach ($post_data as $key => $value) { + $post_items[] = $key . '=' . $value; +} + +//create the final string to be posted +$post_string = implode('&', $post_items); + +//create cURL connection +$conn1 = curl_init('https://www.linkedin.com/oauth/v2/accessToken'); + +//set options +curl_setopt($conn1, CURLOPT_CONNECTTIMEOUT, 30); +curl_setopt($conn1, CURLOPT_RETURNTRANSFER, true); +curl_setopt($conn1, CURLOPT_SSL_VERIFYPEER, true); +curl_setopt($conn1, CURLOPT_FOLLOWLOCATION, 1); + +//set data to be posted +curl_setopt($conn1, CURLOPT_POSTFIELDS, $post_string); + +//perform our request +$result1 = curl_exec($conn1); + +if ($result1) { + $my_token = json_decode($result1, TRUE); + $access_token = $my_token['access_token']; + $expires_in = $my_token['expires_in']; + curl_close($conn1); +} else { + //show information regarding the error + $errorMessage = curl_errno($conn1) . "-"; + $errorMessage = $errorMessage . curl_error($conn1); + curl_close($conn1); + die($errorMessage); +} + +// Call to API +$conn2 = curl_init(); +curl_setopt($conn2, CURLOPT_URL, "https://api.linkedin.com/v1/people/~:(first-name,last-name,email-address,id)?format=json"); +curl_setopt($conn2, CURLOPT_HTTPHEADER, array( + 'Authorization: Bearer ' . $access_token +)); + +curl_setopt($conn2, CURLOPT_RETURNTRANSFER, true); +$result = curl_exec($conn2); + +if ($result) { + $data = json_decode($result, TRUE); + + curl_close($conn2); + + if (isset($data['errorCode'])) { + $errorMessage = $data['message']; + die($errorMessage); + } + + $typedId = $data['id']; + + $user = $userHandler->findUserByIdentity(RAP\Identity::LINKEDIN, $typedId); + + if ($user === null) { + $user = new RAP\User(); + + $identity = new RAP\Identity(RAP\Identity::LINKEDIN); + $identity->email = $data['emailAddress']; + $identity->name = $data['firstName']; + $identity->surname = $data['lastName']; + $identity->typedId = $typedId; + + $user->addIdentity($identity); + + $userHandler->saveUser($user); + } + + $callbackHandler->manageLoginRedirect($user, $session); +} else { + //show information regarding the error + $errorMessage = curl_errno($conn2) . "-"; + $errorMessage = $errorMessage . curl_error($conn2); + curl_close($conn2); + die($errorMessage); +} +?> diff --git a/classes/CallbackHandler.php b/classes/CallbackHandler.php index a569844..bd48a0d 100644 --- a/classes/CallbackHandler.php +++ b/classes/CallbackHandler.php @@ -39,7 +39,7 @@ class CallbackHandler { /** * returns null if the callback URL is not listed in configuration file. */ - public static function getCallbackTitle($callbackURL) { + public function getCallbackTitle($callbackURL) { if ($callbackURL === null) { return "Account Management"; @@ -58,16 +58,22 @@ class CallbackHandler { if ($session->getCallbackURL() !== null) { // External login using token - $token = Util::createNewToken(); - $this->dao->createLoginToken($token, $user->id); - header('Location: ' . $session->getCallbackURL() . '?token=' . $token); + header('Location: ' . $this->getLoginWithTokenURL($user->id, $session->getCallbackURL())); + die(); } else { // Login in session $session->user = $user; $session->save(); // Return to index header('Location: ' . $this->basePath); + die(); } } + public function getLoginWithTokenURL($userId, $callbackURL) { + $token = Util::createNewToken(); + $this->dao->createLoginToken($token, $userId); + return $callbackURL . '?token=' . $token; + } + } diff --git a/classes/MailSender.php b/classes/MailSender.php index cede88a..606743d 100644 --- a/classes/MailSender.php +++ b/classes/MailSender.php @@ -26,8 +26,60 @@ namespace RAP; class MailSender { - public static function sendJoinEmail(User $recipientUser, User $applicantUser) { - + private $serverName; + private $basePath; + + public function __construct($serverName, $basePath) { + $this->serverName = $serverName; + $this->basePath = $basePath; + } + + public function sendJoinEmail(User $recipientUser, User $applicantUser, $token) { + + $subject = "IA2 RAP: Join request"; + + $header = "From: noreply@" . $this->serverName . "\r\n"; + $header .= "Content-Type: text/html; charset=UTF-8"; + + $confirmJoinURL = $this->basePath . '/confirm-join?token=' . $token; + + $body = "Dear IA2 user,

"; + $body .= "the following user requested to join your accounts on the " + . "RAP facility:

"; + + foreach ($applicantUser->identities as $identity) { + + $body .= "Type: " . $identity->type . "
"; + + if ($identity->name !== null) { + $body .= "Name: " . $identity->name . "
"; + } + + if ($identity->surname !== null) { + $body .= "Surname: " . $identity->surname . "
"; + } + + $body .= "E-mail: " . $identity->email . "
"; + + if ($identity->eppn !== null) { + $body .= "Eppn: " . $identity->eppn . "
"; + } + + if ($identity->institution !== null) { + $body .= "Institution: " . $identity->institution . "
"; + } + + $body .= "
"; + } + + $body .= "
If you and this user are the same person click on the following link for joining your accounts:
"; + $body .= "$confirmJoinURL"; + $body .= "

Otherwise you can ignore this email

"; + + $body .= "*** This is an automatically generated email, please do not reply to this message ***
"; + $body .= "If you need information please contact IA2 Staff"; + + mail($recipientUser->getPrimaryEmail(), $subject, $body, $header); } } diff --git a/classes/MySQLDAO.php b/classes/MySQLDAO.php index 536882d..c5c5d9f 100644 --- a/classes/MySQLDAO.php +++ b/classes/MySQLDAO.php @@ -246,6 +246,10 @@ class MySQLDAO implements DAO { public function createJoinRequest($token, $applicantUserId, $targetUserId) { + if($applicantUserId === $targetUserId) { + throw new \Exception("Invalid target user id"); + } + $dbh = $this->getDBHandler(); $stmt = $dbh->prepare("INSERT INTO `join_request`(`token`, `applicant_user_id`, `target_user_id`)" diff --git a/config.php b/config.php index 840befa..e13a8c3 100644 --- a/config.php +++ b/config.php @@ -22,7 +22,7 @@ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -$CONTEXT_ROOT = "/rap-service"; +$CONTEXT_ROOT = "/rap-ia2"; $VERSION = "1.0.0"; $PROTOCOL = stripos($_SERVER['SERVER_PROTOCOL'], 'https') ? 'https://' : 'http://'; @@ -58,12 +58,15 @@ $AUTHENTICATION_METHODS = array( 'secret' => "***REMOVED***", 'version' => "v2.2", 'callback' => $BASE_PATH . "/auth/oauth2/facebook_token.php"), - 'LinkedIn' => array(), + 'LinkedIn' => array( + 'id' => '***REMOVED***', + 'secret' => '***REMOVED***', + 'callback' => $BASE_PATH . '/auth/oauth2/linkedin_token.php' + ), 'X.509' => array(), ); $GROUPER = array( - //'serviceBaseURL' => 'https://sso.ia2.inaf.it/grouper-ws/servicesRest', 'wsdlURL' => 'http://localhost:8087/grouper-ws/services/GrouperService_v2_3?wsdl', 'user' => 'GrouperSystem', 'password' => '***REMOVED***' diff --git a/include/front-controller.php b/include/front-controller.php index f1996e2..2c94ee4 100644 --- a/include/front-controller.php +++ b/include/front-controller.php @@ -12,14 +12,20 @@ function setCallback() { $callback = Flight::request()->data['callback']; $session->setCallbackURL($callbackHandler, isset($callback) ? $callback : null); + return $session->getCallbackURL(); } Flight::route('/', function() { startSession(); - setCallback(); - global $session, $AUTHENTICATION_METHODS; - Flight::render('index.php', array('title' => 'RAP', - 'session' => $session, 'auth' => $AUTHENTICATION_METHODS)); + $callback = setCallback(); + global $session, $callbackHandler, $AUTHENTICATION_METHODS; + if ($callback !== null && $session->user !== null) { + $redirectURL = $callbackHandler->getLoginWithTokenURL($session->user->id, $callback); + Flight::redirect($redirectURL); + } else { + Flight::render('index.php', array('title' => 'RAP', + 'session' => $session, 'auth' => $AUTHENTICATION_METHODS)); + } }); Flight::route('GET /logout', function() { @@ -38,6 +44,11 @@ Flight::route('/facebook', function() { Flight::redirect('/auth/oauth2/facebook_login.php'); }); +Flight::route('/linkedIn', function() { + startSession(); + Flight::redirect('/auth/oauth2/linkedin_login.php'); +}); + Flight::route('/eduGAIN', function() { startSession(); Flight::redirect('/auth/saml2/aai.php'); diff --git a/include/gui-backend.php b/include/gui-backend.php index 0d1b281..d29b905 100644 --- a/include/gui-backend.php +++ b/include/gui-backend.php @@ -35,7 +35,7 @@ Flight::route('GET /user', function() { Flight::route('POST /join', function() { checkSession(); - global $session, $dao; + global $session, $dao, $mailSender; $selectedUserIndex = Flight::request()->data['selectedUserIndex']; $selectedSearchResult = $session->userSearchResults[$selectedUserIndex]; @@ -43,7 +43,7 @@ Flight::route('POST /join', function() { $token = RAP\Util::createNewToken(); $dao->createJoinRequest($token, $session->user->id, $targetUserId); - RAP\MailSender::sendJoinEmail($selectedSearchResult->getUser(), $session->user); + $mailSender->sendJoinEmail($selectedSearchResult->getUser(), $session->user, $token); echo $selectedSearchResult->userDisplayText; }); diff --git a/include/init.php b/include/init.php index dccbb58..28f6587 100644 --- a/include/init.php +++ b/include/init.php @@ -55,6 +55,7 @@ switch ($DATABASE['dbtype']) { $callbackHandler = new RAP\CallbackHandler($dao, $BASE_PATH, $CALLBACKS); $userHandler = new RAP\UserHandler($dao, $GROUPER); +$mailSender = new RAP\MailSender($_SERVER['HTTP_HOST'], $BASE_PATH); function startSession() { session_start(); diff --git a/include/rest-web-service.php b/include/rest-web-service.php index 27aca4c..64d5880 100644 --- a/include/rest-web-service.php +++ b/include/rest-web-service.php @@ -41,11 +41,47 @@ Flight::route('GET ' . $WS_PREFIX . '/user/@userId', function($userId) { Flight::route('GET ' . $WS_PREFIX . '/user', function() { global $dao; - + $searchText = Flight::request()->query['search']; $users = $dao->searchUser($searchText); echo json_encode($users); }); +/** + * Create new user from identity data. Return the new user. + */ +Flight::route('POST ' . $WS_PREFIX . '/user', function() { + + global $userHandler; + + $postData = Flight::request()->data; + + $user = new RAP\User(); + + $identity = new RAP\Identity($postData['type']); + + $identity->email = $postData['email']; + $identity->typedId = $postData['typedId']; + if (isset($postData['name'])) { + $identity->name = $postData['name']; + } + if (isset($postData['surname'])) { + $identity->surname = $postData['surname']; + } + if (isset($postData['institution'])) { + $identity->institution = $postData['institution']; + } + if (isset($postData['eppn'])) { + $identity->eppn = $postData['eppn']; + } + + $user->addIdentity($identity); + + $userHandler->saveUser($user); + + echo json_encode($user); +}); + Flight::route('GET ' . $WS_PREFIX . '/test', function() { + }); diff --git a/include/user-data.php b/include/user-data.php index 9221903..ca50bf0 100644 --- a/include/user-data.php +++ b/include/user-data.php @@ -1,16 +1,18 @@ identities as $identity) { ?>
- primary) { ?> - - - - - - - - - + + primary) { ?> + + + + + + + + + + Type
@@ -18,7 +20,7 @@
E-mail
email; ?>
eppn !== null) { ?> -
EduPersonPrincipalName
+
EPPN
eppn; ?>
name !== null) { ?> diff --git a/js/index.js b/js/index.js index 7ca7057..a55d573 100644 --- a/js/index.js +++ b/js/index.js @@ -63,6 +63,9 @@ // Add click event handler to join request button $(document).on('click', '#send-join-request-btn', sendJoinRequest); + // Add event handler for closing the info alert message. + // This is used instead of data-dismiss="alert" in order to maintain + // the alert inside the DOM and be able to show it again if necessary. $(document).on('click', '#info-message-alert .close', function () { $('#info-message-alert').addClass('hide'); }); diff --git a/views/confirm-join.php b/views/confirm-join.php index aafd5fd..15372a6 100644 --- a/views/confirm-join.php +++ b/views/confirm-join.php @@ -12,6 +12,7 @@ include 'include/header.php';
@@ -25,6 +26,7 @@ include 'include/header.php';
-- GitLab