From a643943d4c7e75b4889713a605f7861c5f056519 Mon Sep 17 00:00:00 2001 From: Demian Katz <demian.katz@villanova.edu> Date: Wed, 7 Jan 2015 13:18:37 -0500 Subject: [PATCH] Added Facebook authentication support. --- config/vufind/config.ini | 12 +- module/VuFind/config/module.config.php | 3 +- module/VuFind/src/VuFind/Auth/Facebook.php | 203 +++++++++++++++++++++ 3 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 module/VuFind/src/VuFind/Auth/Facebook.php diff --git a/config/vufind/config.ini b/config/vufind/config.ini index c98e827d7f5..84079bfc43b 100644 --- a/config/vufind/config.ini +++ b/config/vufind/config.ini @@ -202,7 +202,8 @@ title_level_holds_mode = "disabled" ; This section allows you to determine how the users will authenticate. ; You can use an LDAP directory, the local ILS (or multiple ILSes through ; the MultiILS option), the VuFind database (Database), Shibboleth, SIP2, -; CAS or some combination of these (via the MultiAuth or ChoiceAuth options). +; CAS, Facebook or some combination of these (via the MultiAuth or ChoiceAuth +; options). [Authentication] ;method = LDAP ;method = ILS @@ -213,6 +214,7 @@ method = Database ;method = MultiAuth ;method = ChoiceAuth ;method = MultiILS +;method = Facebook ; This setting only applies when method is set to ILS. It determines which ; field of the ILS driver's patronLogin() return array is used as the username @@ -489,6 +491,14 @@ database = mysql://root@localhost/vufind ;major = major1 ;home_library = library +; Facebook may be used for authentication; fill in this section in addition to +; turning it on in [Authentication] above to use it. You must register your +; VuFind instance as an application at http://developers.facebook.com to obtain +; credentials. +;[Facebook] +;appId = "your app ID" +;secret = "your app secret" + ; External Content is Optional. ; To use multiple, separate with a comma. Priority will be given by the order listed ; Account id is separated with a colon, if no id is used then no colon is necessary diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php index 6862ddff496..d71720ff9ae 100644 --- a/module/VuFind/config/module.config.php +++ b/module/VuFind/config/module.config.php @@ -234,12 +234,13 @@ $config = array( 'multiils' => 'VuFind\Auth\Factory::getMultiILS', ), 'invokables' => array( + 'cas' => 'VuFind\Auth\CAS', 'choiceauth' => 'VuFind\Auth\ChoiceAuth', 'database' => 'VuFind\Auth\Database', + 'facebook' => 'VuFind\Auth\Facebook', 'ldap' => 'VuFind\Auth\LDAP', 'multiauth' => 'VuFind\Auth\MultiAuth', 'shibboleth' => 'VuFind\Auth\Shibboleth', - 'cas' => 'VuFind\Auth\CAS', 'sip2' => 'VuFind\Auth\SIP2', ), 'aliases' => array( diff --git a/module/VuFind/src/VuFind/Auth/Facebook.php b/module/VuFind/src/VuFind/Auth/Facebook.php new file mode 100644 index 00000000000..e0d913f952d --- /dev/null +++ b/module/VuFind/src/VuFind/Auth/Facebook.php @@ -0,0 +1,203 @@ +<?php +/** + * Facebook authentication module. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind2 + * @package Authentication + * @author Franck Borel <franck.borel@gbv.de> + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://www.vufind.org Main Page + */ +namespace VuFind\Auth; +use VuFind\Exception\Auth as AuthException; + +/** + * Facebook authentication module. + * + * @category VuFind2 + * @package Authentication + * @author Franck Borel <franck.borel@gbv.de> + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://www.vufind.org Main Page + */ +class Facebook extends AbstractBase implements + \VuFindHttp\HttpServiceAwareInterface +{ + /** + * HTTP service + * + * @var \VuFindHttp\HttpServiceInterface + */ + protected $httpService = null; + + /** + * Session container + * + * @var \Zend\Session\Container + */ + protected $session; + + /** + * Constructor + */ + public function __construct() + { + $this->session = new \Zend\Session\Container('Facebook'); + } + + /** + * Set the HTTP service to be used for HTTP requests. + * + * @param HttpServiceInterface $service HTTP service + * + * @return void + */ + public function setHttpService(\VuFindHttp\HttpServiceInterface $service) + { + $this->httpService = $service; + } + + /** + * Validate configuration parameters. This is a support method for getConfig(), + * so the configuration MUST be accessed using $this->config; do not call + * $this->getConfig() from within this method! + * + * @throws AuthException + * @return void + */ + protected function validateConfig() + { + // Throw an exception if the required username setting is missing. + $fb = $this->config->Facebook; + if (!isset($fb->appId) || empty($fb->appId)) { + throw new AuthException( + 'Facebook app ID is missing in your configuration file.' + ); + } + + if (!isset($fb->secret) || empty($fb->secret)) { + throw new AuthException( + 'Facebook app secret is missing in your configuration file.' + ); + } + } + + /** + * Attempt to authenticate the current user. Throws exception if login fails. + * + * @param \Zend\Http\PhpEnvironment\Request $request Request object containing + * account credentials. + * + * @throws AuthException + * @return \VuFind\Db\Row\User Object representing logged-in user. + */ + public function authenticate($request) + { + $code = $request->getQuery()->get('code'); + if (empty($code)) { + throw new AuthException('authentication_error_admin'); + } + $accessToken = $this->getAccessTokenFromCode($code); + if (empty($accessToken)) { + throw new AuthException('authentication_error_admin'); + } + $details = $this->getDetailsFromAccessToken($accessToken); + if (empty($details->id)) { + throw new AuthException('authentication_error_admin'); + } + + // If we made it this far, we should log in the user! + $user = $this->getUserTable()->getByUsername($details->id); + if (isset($details->first_name)) { + $user->firstname = $details->first_name; + } + if (isset($details->last_name)) { + $user->lastname = $details->last_name; + } + if (isset($details->email)) { + $user->email = $details->email; + } + + // Save and return the user object: + $user->save(); + return $user; + } + + /** + * Get the URL to establish a session (needed when the internal VuFind login + * form is inadequate). Returns false when no session initiator is needed. + * + * @param string $target Full URL where external authentication method should + * send user after login (some drivers may override this). + * + * @return bool|string + */ + public function getSessionInitiator($target) + { + $base = 'https://www.facebook.com/dialog/oauth'; + // Adding the auth_method setting makes it possible to handle logins when + // using an auth method that proxies others (e.g. ChoiceAuth) + $target .= ((strpos($target, '?') !== false) ? '&' : '?') + . 'auth_method=Facebook'; + $this->session->lastUri = $target; + return $base . '?client_id=' + . urlencode($this->config->Facebook->appId) + . '&redirect_uri=' . urlencode($target) + . '&scope=public_profile,email'; + } + + /** + * Obtain an access token from a code. + * + * @param string $code Code to look up. + * + * @return string + */ + protected function getAccessTokenFromCode($code) + { + $requestUrl = 'https://graph.facebook.com/oauth/access_token?' + . 'client_id=' . urlencode($this->config->Facebook->appId) + . '&redirect_uri=' . urlencode($this->session->lastUri) + . '&client_secret=' . urlencode($this->config->Facebook->secret) + . '&code=' . urlencode($code); + $response = $this->httpService->get($requestUrl); + $parts = explode('&', $response->getBody(), 2); + $parts = explode('=', $parts[0], 2); + return isset($parts[1]) ? $parts[1] : null; + } + + /** + * Given an access token, look up user details. + * + * @param string $accessToken Access token + * + * @return array + */ + protected function getDetailsFromAccessToken($accessToken) + { + $request = 'https://graph.facebook.com/v2.2/me?' + . '&access_token=' . urlencode($accessToken); + $response = $this->httpService->get($request); + $json = json_decode($response->getBody()); + return $json; + } +} -- GitLab