diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..a0fb898 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,10 @@ +Copyright (c) 2016, University of Freiburg, Chair of Algorithms and Data Structures. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/adm/style/auth_provider_cas.html b/adm/style/auth_provider_cas.html new file mode 100644 index 0000000..4bbe1e4 --- /dev/null +++ b/adm/style/auth_provider_cas.html @@ -0,0 +1,23 @@ +
diff --git a/auth/provider/cas.php b/auth/provider/cas.php new file mode 100644 index 0000000..b47e0e0 --- /dev/null +++ b/auth/provider/cas.php @@ -0,0 +1,308 @@ +db = $db; + $this->config = $config; + $this->passwords_manager = $passwords_manager; + $this->user = $user; + $this->is_setup = false; + $this->setupCas(); + } + + protected function setupCas() + { + if ($this->is_setup) + { + return true; + } + + global $request; + $request->enable_super_globals(); + if (strlen((string) $this->config['cas_server']) < 1) { + return false; + } + \phpCAS::client(CAS_VERSION_2_0, (string) $this->config['cas_server'], (int) $this->config['cas_port'], (string) $this->config['cas_uri']); + + if ($this->config['force_server_vars']) + { + $service = $this->config['server_protocol'].$this->config['server_name'].$this->config['script_path']; + \phpCAS::setFixedServiceURL($service); + } + + /*if ($this->config['cas_validate'] == 0) + \phpCAS::setNoCasServerValidation();*/ + \phpCAS::setNoCasServerValidation(); + + if (defined('IN_LOGIN') && request_var('mode', '') == 'login') + { + \phpCAS::forceAuthentication(); + } + $request->disable_super_globals(); + $this->is_setup = true; + return true; + } + + /** + * {@inheritdoc} + */ + public function init() + { + if (!@extension_loaded('curl')) + { + return $this->user->lang['CAS_NO_CURL_EXTENSION']; + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function login($username, $password) + { + global $request; + // do not allow empty password + if (!$password) + { + return array( + 'status' => LOGIN_ERROR_PASSWORD, + 'error_msg' => 'NO_PASSWORD_SUPPLIED', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + if (!$username) + { + return array( + 'status' => LOGIN_ERROR_USERNAME, + 'error_msg' => 'LOGIN_ERROR_USERNAME', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + if (!@extension_loaded('curl')) + { + return array( + 'status' => LOGIN_ERROR_EXTERNAL_AUTH, + 'error_msg' => 'CAS_NO_CURL_EXTENSION', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + $user_row = array('user_id' => ANONYMOUS); + $status = LOGIN_ERROR_USERNAME; + $error_msg = 'LOGIN_ERROR_USERNAME'; + if($this->setupCas()) + { + $request->enable_super_globals(); + if (!\phpCAS::isAuthenticated()) + { + $user->session_kill(); + $user->session_begin(); + } + \phpCAS::forceAuthentication(); + + if (\phpCAS::isAuthenticated()) { + $user_row = $this->get_user_row(\phpCAS::getUser(), $password); + if ($user_row['user_id'] != ANONYMOUS) { + $error_msg = false; + $status = LOGIN_SUCCESS; + } + } + $request->disable_super_globals(); + } + + return array('status' => $status, 'error_msg' => $error_msg, 'user_row' => $user_row); + } + + /** + * {@inheritdoc} + */ + public function autologin() + { + global $request; + $result = array(); + if($this->setupCas()) + { + $request->enable_super_globals(); + if (!defined('IN_LOGIN') && !\phpCAS::isAuthenticated()) + \phpCAS::checkAuthentication(); + if (\phpCAS::isAuthenticated()) + $result = $this->get_user_row(\phpCAS::getUser()); + $request->disable_super_globals(); + } + return $result; + } + + /** + * {@inheritdoc} + */ + public function logout($data, $new_session) + { + global $request; + if($this->setupCas()) + { + $request->enable_super_globals(); + \phpCAS::logout(); + $request->disable_super_globals(); + } + } + + /** + * {@inheritdoc} + */ + public function validate_session($user) + { + global $request; + $result = false; + if($this->setupCas()) + { + $request->enable_super_globals(); + if (!defined('IN_LOGIN') or request_var('mode', '') != 'login') + $result = \phpCAS::isAuthenticated(); + $request->disable_super_globals(); + } + return $result; + } + + /** + * {@inheritdoc} + */ + public function acp() + { + // These are fields required in the config table + return array( + 'cas_server', 'cas_port', 'cas_uri', 'cas_validate', 'cas_email_attribute', + ); + } + + /** + * {@inheritdoc} + */ + public function get_acp_template($new_config) + { + return array( + 'TEMPLATE_FILE' => '@daphnetf_casauth/auth_provider_cas.html', + 'TEMPLATE_VARS' => array( + 'AUTH_CAS_SERVER' => $new_config['cas_server'], + 'AUTH_CAS_PORT' => $new_config['cas_port'], + 'AUTH_CAS_URI' => $new_config['cas_uri'], + 'AUTH_CAS_VALIDATE' => $new_config['cas_validate'], + 'AUTH_CAS_EMAIL_ATTRIBUTE' => $new_config['cas_email_attribute'], + ), + ); + } + + protected function get_user_row($username, $password='') + { + global $db, $phpbb_root_path, $phpEx; + $username_clean = utf8_clean_string($username); + $user_row = array('user_id' => ANONYMOUS); + $sql ='SELECT * + FROM ' . USERS_TABLE . " + WHERE username_clean = '" . $db->sql_escape($username_clean) . "'"; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if ($row) + { + if ( !($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) ) + $user_row = $row; + } + else + { + // retrieve default group id + $sql = 'SELECT group_id + FROM ' . GROUPS_TABLE . " + WHERE group_name = '" . $db->sql_escape('REGISTERED') . "' + AND group_type = " . GROUP_SPECIAL; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if (!$row) + { + trigger_error('NO_GROUP'); + } + + // generate user account data + $user_row = array( + 'username' => $username, + 'username_clean' => $username_clean, + 'user_password' => $this->passwords_manager->hash($password), + 'user_email' => '', + 'group_id' => (int) $row['group_id'], + 'user_type' => USER_NORMAL, + 'user_ip' => $this->user->ip, + 'user_new' => ($this->config['new_member_post_limit']) ? 1 : 0, + ); + // we are going to use the user_add function so include functions_user.php if it wasn't defined yet + if (!function_exists('user_add')) + { + include($phpbb_root_path . 'includes/functions_user.' . $phpEx); + } + user_add($user_row); + // reload user data + $sql ='SELECT * + FROM ' . USERS_TABLE . " + WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; + $result = $db->sql_query($sql); + $user_row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + } + if ( isset($user_row['user_id']) && $user_row['user_id'] != ANONYMOUS ) { + $this->setupCas(); + $attributes = \phpCAS::getAttributes(); + $attributes[$this->config['cas_email_attribute']] = strtolower($attributes[$this->config['cas_email_attribute']]); + $update = ''; + // Update user email to match value provided by cas + if ( $user_row['user_email'] != $attributes[$this->config['cas_email_attribute']] ) { + $user_row['user_email'] = $attributes[$this->config['cas_email_attribute']]; + $user_row['user_email_hash'] = phpbb_email_hash($user_row['user_email']); + $update .= "user_email='".$user_row['user_email']."', "; + $update .= "user_email_hash='".$user_row['user_email_hash']."', "; + } + if ( strlen($password) ) { + $user_row['user_password'] = $this->passwords_manager->hash($password); + $update .= "user_password='".$user_row['user_password']."', "; + } + if ( strlen($update) ) { + $sql = 'UPDATE ' . USERS_TABLE . " + SET " . substr($update, 0, -2). " + WHERE user_id = " . $user_row['user_id']; + $result = $db->sql_query($sql); + } + } + return $user_row; + } +} \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..80b4c90 --- /dev/null +++ b/composer.json @@ -0,0 +1,32 @@ +{ + "name": "daphnetf/casauth", + "type": "phpbb-extension", + "description": "CAS Auth for phpBB 3.1 interfacing with phpCAS", + "homepage": "https://github.com/daphnetf/casauth", + "version": "0.9.9", + "time": "2016-05-20", + "license": "BSD-2-Clause", + "authors": [{ + "name": "Axel Lehmann", + "email": "lehmann.4178656ch@gmail.com", + "homepage": "", + "role": "Lead Developer" + }], + "support": { + "irc": "irc://irc.freenode.org/daphnetf" + }, + "require": { + "php": ">=5.5.9" + }, + "extra": { + "display-name": "CAS auth", + "soft-require": { + "phpbb/phpbb": ">=3.1.9,<3.2.*@dev" + }, + "version-check": { + "host": "daphnetf.github.io", + "directory": "/casauth", + "filename": "version.json" + } + } +} diff --git a/config/services.yml b/config/services.yml new file mode 100644 index 0000000..7be64e9 --- /dev/null +++ b/config/services.yml @@ -0,0 +1,17 @@ +services: + auth.provider.cas: + class: daphnetf\casauth\auth\provider\cas + arguments: + - @dbal.conn + - @config + - @passwords.manager + - @user + tags: + - { name: auth.provider } + daphnetf.casauth.listener: + class: daphnetf\casauth\event\main_listener + arguments: + - @template + - @user + tags: + - { name: event.listener } \ No newline at end of file diff --git a/event/main_listener.php b/event/main_listener.php new file mode 100644 index 0000000..3012779 --- /dev/null +++ b/event/main_listener.php @@ -0,0 +1,58 @@ +template = $template; + $this->user = $user; + } + + static public function getSubscribedEvents() + { + return array( + 'core.page_header' => 'insert_template_values', + 'core.user_setup' => 'load_language_on_setup', + ); + } + + public function insert_template_values($event) + { + $this->template->assign_var('U_USERNAME', $this->user->data["username"]); + } + + public function load_language_on_setup($event) + { + $lang_set_ext = $event['lang_set_ext']; + $lang_set_ext[] = array( + 'ext_name' => 'daphnetf/casauth', + 'lang_set' => 'cas_auth_acp', + ); + $event['lang_set_ext'] = $lang_set_ext; + } +} \ No newline at end of file diff --git a/ext.php b/ext.php new file mode 100644 index 0000000..035ae7a --- /dev/null +++ b/ext.php @@ -0,0 +1,16 @@ + 'Central Authentication Service', + 'CAS_EMAIL_ATTRIBUTE' => 'Email', + 'CAS_EMAIL_ATTRIBUTE_EXPLAIN' => 'Attribute name used for setting user email.', + 'CAS_NO_CURL_EXTENSION' => 'Curl not installed!', + 'CAS_PORT' => 'Port', + 'CAS_PORT_EXPLAIN' => 'Port on which the CAS server is listening to. Mostly 443.', + 'CAS_SERVER' => 'Server', + 'CAS_SERVER_EXPLAIN' => 'CAS server name, such as: cas.foo.biz', + 'CAS_URI' => 'URI', + 'CAS_URI_EXPLAIN' => 'Base URI of the cas server. Such as: /login, /cas...', + 'CAS_VALIDATE' => 'Validate', + 'CAS_VALIDATE_EXPLAIN' => 'Enable/Disable the validation of the CAS server SSL certificate', +)); diff --git a/vendor/place_phpCAS_here b/vendor/place_phpCAS_here new file mode 100644 index 0000000..e69de29