aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/auth_plugins/StudipAuthAbstract.class.php
diff options
context:
space:
mode:
authorPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
committerPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
commit4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch)
tree5c07151ae61276d334e88f6309c30d439a85c12e /lib/classes/auth_plugins/StudipAuthAbstract.class.php
parentda0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff)
parent97a188592c679890a25c37ab78463add76a52ff7 (diff)
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'lib/classes/auth_plugins/StudipAuthAbstract.class.php')
-rw-r--r--lib/classes/auth_plugins/StudipAuthAbstract.class.php578
1 files changed, 0 insertions, 578 deletions
diff --git a/lib/classes/auth_plugins/StudipAuthAbstract.class.php b/lib/classes/auth_plugins/StudipAuthAbstract.class.php
deleted file mode 100644
index 36c75df..0000000
--- a/lib/classes/auth_plugins/StudipAuthAbstract.class.php
+++ /dev/null
@@ -1,578 +0,0 @@
-<?php
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// StudipAuthAbstract.class.php
-// Abstract class, used as a template for authentication plugins
-//
-// Copyright (c) 2003 André Noack <noack@data-quest.de>
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// 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.
-// +---------------------------------------------------------------------------+
-
-/**
- * abstract base class for authentication plugins
- *
- * abstract base class for authentication plugins
- * to write your own authentication plugin, derive it from this class and
- * implement the following abstract methods: isUsedUsername($username) and
- * isAuthenticated($username, $password, $jscript)
- * don't forget to call the parents constructor if you implement your own, php
- * won't do that for you !
- *
- * @abstract
- * @author André Noack <noack@data-quest.de>
- * @package
- */
-class StudipAuthAbstract
-{
-
- /**
- * contains error message, if authentication fails
- *
- *
- * @var string $error_msg
- */
- public $error_msg;
-
- /**
- * indicates whether the authenticated user logs in for the first time
- *
- *
- * @var bool $is_new_user
- */
- public $is_new_user = false;
-
- /**
- * array of user domains to assign to each user, can be set in local.inc
- *
- * @access public
- * @var array $user_domains
- */
- public $user_domains;
-
- /**
- * associative array with mapping for database fields
- *
- * associative array with mapping for database fields,
- * should be set in local.inc
- * structure :
- * array('<table name>.<field name>' => array( 'callback' => '<name of callback method used for data retrieval>',
- * 'map_args' => '<arguments passed to callback method>'))
- * @var array $user_data_mapping
- */
- public $user_data_mapping = null;
-
- /**
- * name of the plugin
- *
- * name of the plugin (last part of class name) is set in the constructor
- * @var string $plugin_name
- */
- public $plugin_name;
-
- /**
- * text, which precedes error message for the plugin
- *
- *
- * @var string $error_head
- */
- public $error_head;
-
- /**
- * toggles display of standard login
- *
- *
- * @var bool $show_login
- */
- public $show_login;
-
- /**
- * @var $plugin_instances
- */
- private static $plugin_instances;
-
- private $config_data = [];
-
- /**
- * static method to instantiate and retrieve a reference to an object (singleton)
- *
- * always use this method to instantiate a plugin object, it will ensure that only one object of each
- * plugin will exist
- * @param string $plugin_name name of plugin, if omitted an array with all plugin objects will be returned
- * @return mixed either a reference to the plugin with the passed name, or an array with references to all plugins
- */
- public static function getInstance($plugin_name = false)
- {
- if (!is_array(self::$plugin_instances)) {
- foreach ($GLOBALS['STUDIP_AUTH_PLUGIN'] as $plugin) {
- $config = $GLOBALS['STUDIP_AUTH_CONFIG_' . strtoupper($plugin)];
- $plugin_class = $config['plugin_class'] ?? 'StudipAuth' . $plugin;
- if (empty($config['plugin_name'])) {
- $config['plugin_name'] = strtolower($plugin);
- }
- self::$plugin_instances[strtoupper($plugin)] = new $plugin_class($config);
- }
- }
- return ($plugin_name) ? self::$plugin_instances[strtoupper($plugin_name)]??null : self::$plugin_instances;
- }
-
- /**
- * static method to check if SSO login is enabled
- *
- * @return bool
- */
- public static function isSSOEnabled(): bool
- {
- self::getInstance();
- foreach (self::$plugin_instances as $auth_plugin) {
- if ($auth_plugin instanceof StudipAuthSSO) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * static method to check if standard login is enabled
- *
- * @return bool
- */
- public static function isLoginEnabled(): bool
- {
- self::getInstance();
- foreach (self::$plugin_instances as $auth_plugin) {
- if ($auth_plugin->show_login === true) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * static method to check authentication in all plugins
- *
- * if authentication fails in one plugin, the error message is stored and the next plugin is used
- * if authentication succeeds, the uid element in the returned array will contain the Stud.IP user id
- *
- * @param string $username the username to check
- * @param string $password the password to check
- * @return array structure: array('uid'=>'string <Stud.IP user id>','error'=>'string <error message>','is_new_user'=>'bool')
- */
- public static function CheckAuthentication($username, $password)
- {
-
- $plugins = StudipAuthAbstract::GetInstance();
- $error = false;
- $uid = false;
- foreach ($plugins as $object) {
- // SSO plugins can't be used
- if ($object instanceof StudipAuthSSO) {
- continue;
- }
- if ($user = $object->authenticateUser($username, $password)) {
- if ($user) {
- $uid = $user->id;
- $locked = $user['locked'];
- $key = $user['validation_key'];
- $checkIPRange = ($GLOBALS['ENABLE_ADMIN_IP_CHECK'] && $user['perms'] === 'admin')
- || ($GLOBALS['ENABLE_ROOT_IP_CHECK'] && $user['perms'] === 'root');
-
- if ($user->isExpired()) {
- $error .= _('Dieses Benutzerkonto ist abgelaufen.<br> Wenden Sie sich bitte an die Administration.') . '<BR>';
- return ['uid' => false, 'error' => $error];
- } else if ($locked) {
- $error .= _('Dieser Benutzer ist gesperrt! Wenden Sie sich bitte an die Administration.') . '<BR>';
- return ['uid' => false, 'error' => $error];
- } else if ($key != '') {
- return ['uid' => $uid, 'user' => $user, 'error' => $error, 'need_email_activation' => $uid];
- } else if ($checkIPRange && !self::CheckIPRange()) {
- $error .= _('Der Login in Ihren Account ist aus diesem Netzwerk nicht erlaubt.') . '<BR>';
- return ['uid' => false, 'error' => $error];
- }
- }
- return ['uid' => $uid, 'user' => $user, 'error' => $error, 'is_new_user' => $object->is_new_user];
- } else {
- $error .= (($object->error_head) ? ('<b>' . $object->error_head . ':</b> ') : '') . $object->error_msg . '<br>';
- }
- }
- return ['uid' => $uid, 'error' => $error];
- }
-
- /**
- * static method to check if passed username is used in external data sources
- *
- * all plugins are checked, the error messages are stored and returned
- *
- * @param string $username the username
- * @return array
- */
- public static function CheckUsername($username)
- {
- $plugins = StudipAuthAbstract::GetInstance();
- $error = false;
- $found = false;
- foreach ($plugins as $object) {
- if ($found = $object->isUsedUsername($username)) {
- return ['found' => $found, 'error' => $error];
- } else {
- $error .= (($object->error_head) ? ('<b>' . $object->error_head . ':</b> ') : '') . $object->error_msg . '<br>';
- }
- }
- return ['found' => $found, 'error' => $error];
- }
-
- /**
- * static method to check for a mapped field
- *
- * this method checks in the plugin with the passed name, if the passed
- * Stud.IP DB field is mapped to an external data source
- *
- * @param string the name of the db field must be in form '<table name>.<field name>'
- * @param string the name of the plugin to check
- * @return bool true if the field is mapped, else false
- */
- public static function CheckField($field_name, $plugin_name)
- {
- if (!$plugin_name) {
- return false;
- }
- $plugin = StudipAuthAbstract::GetInstance($plugin_name);
- return (is_object($plugin) ? $plugin->isMappedField($field_name) : false);
- }
-
- /**
- * static method to check if ip address belongs to allowed range
- *
- * @return bool true if the client ip address is within the valid range
- */
- public static function CheckIPRange()
- {
- $ip = $_SERVER['REMOTE_ADDR'];
- $version = substr_count($ip, ':') > 1 ? 'V6' : 'V4'; // valid ip v6 addresses have atleast two colons
- $method = 'CheckIPRange' . $version;
- if (is_array($GLOBALS['LOGIN_IP_RANGES'][$version])) {
- foreach ($GLOBALS['LOGIN_IP_RANGES'][$version] as $range) {
- if (self::$method($ip, $range)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * @param $ip string IPv4 adress
- * @param $range array assoc array with [start] & [end]
- * @return bool
- */
- public static function CheckIPRangeV4($ip, $range)
- {
- $ipv4 = ip2long($ip);
- if ($ipv4 === false) {
- return false; // invalid ip address
- }
-
- $start = ip2long($range['start']);
- $end = ip2long($range['end']);
-
- return $ipv4 >= $start && $ipv4 <= $end;
- }
-
- /**
- * @param $ip string IPv6 address
- * @param $range array assoc array with [start] & [end]
- * @return bool
- */
- public static function CheckIPRangeV6($ip, $range)
- {
- $ipv6 = inet_pton($ip);
- if ($ipv6 === false) {
- return false; // invalid ip address
- }
-
- $start = inet_pton($range['start']);
- $end = inet_pton($range['end']);
-
- return strlen($ipv6) === strlen($start)
- && $ipv6 >= $start && $ipv6 <= $end;
- }
-
- /**
- * Constructor
- *
- * you should use StudipAuthAbstract::GetInstance($plugin_name)
- * to get a reference to a plugin object. Make sure the constructor in the base class is called
- * when deriving your own plugin class, it assigns the settings from local.inc as members of the plugin
- * each key of the $STUDIP_AUTH_CONFIG_<plugin name> array will become a member of the object
- *
- * @param array $config
- */
- public function __construct($config = [])
- {
- //get configuration array set in local inc
- if (empty($config)) {
- $this->plugin_name = strtolower(substr(get_class($this), 10));
- $config = $GLOBALS['STUDIP_AUTH_CONFIG_' . strtoupper($this->plugin_name)];
- }
- //assign each key in the config array as a member of the plugin object
- foreach ($config as $key => $value) {
- $this->$key = $value;
- }
- }
-
- /**
- * authentication method
- *
- * this method authenticates the passed username, it is used by StudipAuthAbstract::CheckAuthentication()
- * if authentication succeeds it calls StudipAuthAbstract::doDataMapping() to map data fields
- * if the authenticated user logs in for the first time it calls StudipAuthAbstract::doNewUserInit() to
- * initialize the new user
- * @param string $username the username to check
- * @param string $password the password to check
- * @return string if authentication succeeds the Stud.IP user , else false
- */
- public function authenticateUser($username, $password)
- {
- $username = $this->verifyUsername($username);
- if ($this->isAuthenticated($username, $password)) {
- if ($user = $this->getStudipUser($username)) {
- $this->doDataMapping($user);
- if ($this->is_new_user) {
- $this->doNewUserInit($user);
- }
- $this->setUserDomains($user);
- }
- return $user;
- } else {
- return false;
- }
- }
-
- /**
- * method to retrieve the Stud.IP user id to a given username
- *
- *
- * @access private
- * @param string the username
- * @return User the Stud.IP or false if an error occurs
- */
- function getStudipUser($username)
- {
- $user = User::findByUsername($username);
- if ($user) {
- $auth_plugin = $user->auth_plugin;
- if ($auth_plugin === null) {
- $this->error_msg = _('Dies ist ein vorläufiger Benutzer.') . '<br>';
- return false;
- }
- if ($auth_plugin != $this->plugin_name) {
- $this->error_msg = sprintf(_('Dieser Benutzername wird bereits über %s authentifiziert!'), $auth_plugin) . '<br>';
- return false;
- }
- return $user;
- }
- $new_user = new User();
- $new_user->username = $username;
- $new_user->perms = 'autor';
- $new_user->auth_plugin = $this->plugin_name;
- $new_user->preferred_language = $_SESSION['_language'];
- if ($new_user->store()) {
- $this->is_new_user = true;
- return $new_user;
- }
- }
-
- /**
- * initialize a new user
- *
- * this method is invoked for one time, if a new user logs in ($this->is_new_user is true)
- * place special treatment of new users here
- *
- * @access private
- * @param User $user the user object
- */
- function doNewUserInit($user)
- {
- // auto insertion of new users, according to $AUTO_INSERT_SEM[] (defined in local.inc)
- AutoInsert::instance()->saveUser($user->id, $user->perms);
- }
-
- /**
- * This method sets the user domains for the current user.
- *
- * @access private
- * @param User the user object
- */
- function setUserDomains($user)
- {
- $user_domains = $this->getUserDomains();
- $uid = $user->id;
- if (isset($user_domains)) {
- $old_domains = UserDomain::getUserDomainsForUser($uid);
-
- foreach ($old_domains as $domain) {
- if (!in_array($domain->id, $user_domains)) {
- $domain->removeUser($uid);
- }
- }
-
- foreach ($user_domains as $user_domain) {
- $domain = new UserDomain($user_domain);
-
- if ($domain->isNew()) {
- $domain->name = $user_domain;
- $domain->store();
- }
-
- if (!in_array($domain, $old_domains)) {
- $domain->addUser($uid);
- }
- }
- }
- }
-
- /**
- * Get the user domains to assign to the current user.
- */
- function getUserDomains()
- {
- return $this->user_domains;
- }
-
- /**
- * this method handles the data mapping
- *
- * for each entry in $this->user_data_mapping the according callback will be invoked
- * the return value of the callback method is then written to the db field, which is specified
- * in the key of the array
- *
- * @access private
- * @param User the user object
- * @return bool
- */
- function doDataMapping($user)
- {
- if ($user && is_array($this->user_data_mapping)) {
- foreach ($this->user_data_mapping as $key => $value) {
- $callback = null;
- if (method_exists($this, $value['callback'])) {
- $callback = [$this, $value['callback']];
- } else if (is_callable($value['callback'])) {
- $callback = $value['callback'];
- }
- if ($callback) {
- $split = explode('.', $key);
- $table = $split[0];
- $field = $split[1];
- if ($table === 'auth_user_md5' || $table === 'user_info') {
- $mapped_value = call_user_func($callback, $value['map_args']);
- if (isset($mapped_value)) {
- $user->setValue($field, $mapped_value);
- }
- } else {
- call_user_func($callback, [$table, $field, $user, $value['map_args']]);
- }
- }
- }
- return $user->store();
- }
- return false;
- }
-
- /**
- * method to check, if a given db field is mapped by the plugin
- *
- *
- * @access private
- * @param string the name of the db field (<table_name>.<field_name>)
- * @return bool true if the field is mapped
- */
- function isMappedField($name)
- {
- return isset($this->user_data_mapping[$name]);
- }
-
- /**
- * method to eliminate bad characters in the given username
- *
- *
- * @access private
- * @param string the username
- * @return string the username
- */
- function verifyUsername($username)
- {
- if ($this->username_case_insensitiv) {
- $username = mb_strtolower($username);
- }
- if ($this->bad_char_regex) {
- return preg_replace($this->bad_char_regex, '', $username);
- } else {
- return trim($username);
- }
- }
-
- /**
- * method to check, if username is used
- *
- * abstract MUST be realized
- *
- * @access private
- * @param string the username
- * @return bool true if the username exists
- */
- function isUsedUsername($username)
- {
- $this->error_msg = sprintf(_('Methode %s nicht implementiert!'), get_class($this) . '::isUsedUsername()');
- return false;
- }
-
- /**
- * method to check the authentication of a given username and a given password
- *
- * abstract, MUST be realized
- *
- * @access private
- * @param string the username
- * @param string the password
- * @return bool true if authentication succeeds
- */
- function isAuthenticated($username, $password)
- {
- $this->error = sprintf(_('Methode %s nicht implementiert!'), get_class($this) . '::isAuthenticated()');
- return false;
- }
-
- // Store dynamically set dynamically created properties in $config_data
- public function __isset($offset)
- {
- return isset($this->config_data[$offset]);
- }
-
- public function __set($offset, $value)
- {
- $this->config_data[$offset] = $value;
- }
-
- public function __get($offset)
- {
- return $this->config_data[$offset] ?? null;
- }
-
- public function __unset($offset)
- {
- unset($this->config_data[$offset]);
- }
-}