%PDF- %PDF-
| Direktori : /backups/router/usr/local/opnsense/mvc/app/library/OPNsense/Auth/ |
| Current File : //backups/router/usr/local/opnsense/mvc/app/library/OPNsense/Auth/AuthenticationFactory.php |
<?php
/*
* Copyright (C) 2015-2019 Deciso B.V.
* 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 ``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
* AUTHOR 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.
*/
namespace OPNsense\Auth;
use OPNsense\Core\Config;
/**
* Class AuthenticationFactory
* @package OPNsense\Auth
*/
class AuthenticationFactory
{
/**
* @var IAuthConnector|null last used authentication method in authenticate()
*/
var $lastUsedAuth = null;
/**
* list installed auth connectors
* @return array
*/
private function listConnectors()
{
$connectors = array();
foreach (glob(__DIR__ . "/*.php") as $filename) {
$pathParts = explode('/', $filename);
$vendor = $pathParts[count($pathParts) - 3];
$module = $pathParts[count($pathParts) - 2];
$classname = explode('.php', $pathParts[count($pathParts) - 1])[0];
$reflClass = new \ReflectionClass("{$vendor}\\{$module}\\{$classname}");
if ($reflClass->implementsInterface('OPNsense\\Auth\\IAuthConnector')) {
if ($reflClass->hasMethod('getType')) {
$connectorType = $reflClass->getMethod('getType')->invoke(null);
$connector = array();
$connector['class'] = "{$vendor}\\{$module}\\{$classname}";
$connector['classHandle'] = $reflClass;
$connector['type'] = $connectorType;
$connectors[$connectorType] = $connector;
}
}
}
return $connectors;
}
/**
* request list of configured servers, the factory needs to be aware of its options and settings to
* be able to instantiate useful connectors.
* @return array list of configured servers
*/
public function listServers()
{
$servers = array();
$servers['Local Database'] = array("name" => "Local Database", "type" => "local");
$configObj = Config::getInstance()->object();
foreach ($configObj->system->children() as $key => $value) {
if ($key == 'authserver' && !empty($value->type) && !empty($value->name)) {
$authServerSettings = array();
foreach ($value as $itemKey => $itemValue) {
$authServerSettings[$itemKey] = (string)$itemValue;
}
$servers[$authServerSettings['name']] = $authServerSettings;
}
}
return $servers;
}
/**
* get new authenticator
* @param string $authserver authentication server name
* @return IAuthConnector|null
*/
public function get($authserver)
{
$servers = $this->listServers();
$servers['Local API'] = array("name" => "Local API Database", "type" => "api");
// create a new auth connector
if (isset($servers[$authserver]['type'])) {
$connectors = $this->listConnectors();
if (!empty($connectors[$servers[$authserver]['type']])) {
$authObject = $connectors[$servers[$authserver]['type']]['classHandle']->newInstance();
}
if (isset($authObject)) {
$props = $servers[$authserver];
$authObject->setProperties($props);
return $authObject;
}
}
return null;
}
/**
* get Service object
* @param $service_name string service name to use, defined in Services directory
* @return IService|null service object or null if not found
*/
public function getService($service_name)
{
$aliases = array();
// cleanse service name
$srv_name = strtolower(str_replace(array('-', '_'), '', $service_name));
foreach (glob(__DIR__ . "/Services/*.php") as $filename) {
$srv_found = basename($filename, '.php');
$reflClass = new \ReflectionClass("OPNsense\\Auth\\Services\\{$srv_found}");
if ($reflClass->implementsInterface('OPNsense\\Auth\\IService')) {
// stash aliases
foreach ($reflClass->getMethod('aliases')->invoke(null) as $alias) {
$aliases[$alias] = $reflClass;
}
if (strtolower($srv_found) == $srv_name) {
return $reflClass->newInstance();
}
}
}
// class not found, test if one of the classes found aliases our requested service
foreach ($aliases as $alias => $reflClass) {
if (strtolower($alias) == $srv_name) {
return $reflClass->newInstance();
}
}
return null;
}
/**
* Authenticate user for requested service
* @param $service_name string service name to use, defined in Services directory
* @param $username string username
* @param $password string password
* @return boolean
*/
public function authenticate($service_name, $username, $password)
{
openlog("audit", LOG_ODELAY, LOG_AUTH);
$service = $this->getService($service_name);
if ($service !== null) {
$service->setUserName($username);
foreach ($service->supportedAuthenticators() as $authname) {
$authenticator = $this->get($authname);
if ($authenticator !== null) {
$this->lastUsedAuth = $authenticator;
if ($authenticator->authenticate($service->getUserName(), $password)) {
if ($service->checkConstraints()) {
syslog(LOG_NOTICE, sprintf(
"user %s authenticated successfully for %s [using %s + %s]",
$username,
$service_name,
get_class($service),
get_class($authenticator)
));
return true;
} else {
// since checkConstraints() is defined on the service, who doesn't know about the
// authentication method. We can safely assume we cannot authenticate.
syslog(LOG_WARNING, sprintf(
"user %s could not authenticate for %s, failed constraints on %s authenticated via %s",
$username,
$service_name,
get_class($service),
get_class($authenticator)
));
return false;
}
} else {
syslog(LOG_DEBUG, sprintf(
"user %s failed authentication for %s on %s via %s",
$username,
$service_name,
get_class($service),
get_class($authenticator)
));
}
}
}
}
syslog(LOG_WARNING, sprintf(
"user %s could not authenticate for %s. [using %s + %s]",
$username,
$service_name,
!empty($service) ? get_class($service) : '-',
!empty($authenticator) ? get_class($authenticator) : '-'
));
return false;
}
/**
* list configuration options for pluggable auth modules
* @return array
*/
public function listConfigOptions()
{
$result = array();
foreach ($this->listConnectors() as $connector) {
if ($connector['classHandle']->hasMethod('getDescription')) {
$obj = $connector['classHandle']->newInstance();
$authItem = $connector;
$authItem['description'] = $obj->getDescription();
if ($connector['classHandle']->hasMethod('getConfigurationOptions')) {
$authItem['additionalFields'] = $obj->getConfigurationOptions();
} else {
$authItem['additionalFields'] = array();
}
$result[$obj->getType()] = $authItem;
}
}
return $result;
}
/**
* return authenticator properties from last authentication
* @return array mixed named list of authentication properties
*/
public function getLastAuthProperties()
{
if ($this->lastUsedAuth != null) {
return $this->lastUsedAuth->getLastAuthProperties();
} else {
return [];
}
}
}