envole/docker/volume/nextcloud/envole/app/user_cas/lib/Service/AppService.php

1027 lines
35 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* ownCloud - user_cas
*
* @author Felix Rupp <kontakt@felixrupp.com>
* @copyright Felix Rupp <kontakt@felixrupp.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\UserCAS\Service;
use OC\Authentication\Token\IToken;
use OCA\UserCAS\Exception\PhpCas\PhpUserCasLibraryNotFoundException;
use OCP\App\IAppManager;
use \OCP\IConfig;
use \OCP\IUserSession;
use \OCP\IUserManager;
use \OCP\IURLGenerator;
/**
* Class UserService
*
* @package OCA\UserCAS\Service
*
* @author Felix Rupp <kontakt@felixrupp.com>
* @copyright Felix Rupp <kontakt@felixrupp.com>
*
* @since 1.4.0
*/
class AppService
{
/**
* @var string $appName
*/
private $appName;
/**
* @var \OCP\IConfig $appConfig
*/
private $config;
/**
* @var \OCA\UserCAS\Service\LoggingService
*/
private $loggingService;
/**
* @var \OCP\IUserManager $userManager
*/
private $userManager;
/**
* @var \OCP\IUserSession $userSession
*/
private $userSession;
/**
* @var \OCP\IURLGenerator $urlGenerator
*/
private $urlGenerator;
/**
* @var IAppManager $appManager
*/
private $appManager;
/**
* @var string
*/
private $casVersion;
/**
* @var string
*/
private $casHostname;
/**
* @var int
*/
private $casPort;
/**
* @var string
*/
private $casPath;
/**
* @var string
*/
private $casDebugFile;
/**
* @var string
*/
private $casCertPath;
/**
* @var string
*/
private $casPhpFile;
/**
* @var string
*/
private $casServiceUrl;
/**
* @var boolean
*/
private $casDisableLogout;
/**
* @var boolean
*/
private $casDisableSinglesignout;
/**
* @var array
*/
private $casHandleLogoutServers;
/**
* @var boolean
*/
private $casKeepTicketIds;
/**
* @var string
*/
private $cas_ecas_accepted_strengths;
/**
* @var string
*/
private $cas_ecas_retrieve_groups;
/**
* @var string
*/
private $cas_ecas_assurance_level;
/**
* @var boolean
*/
private $cas_ecas_request_full_userdetails;
/**
* @var string
*/
private $cas_ecas_internal_ip_range;
/**
* @var boolean
*/
private $casInitialized;
/**
* @var boolean
*/
private $ecasAttributeParserEnabled;
/**
* @var boolean
*/
private $casUseProxy;
/**
* UserService constructor.
* @param $appName
* @param \OCP\IConfig $config
* @param \OCA\UserCAS\Service\LoggingService $loggingService
* @param \OCP\IUserManager $userManager
* @param \OCP\IUserSession $userSession
* @param \OCP\IURLGenerator $urlGenerator
* @param IAppManager $appManager
*/
public function __construct($appName, IConfig $config, LoggingService $loggingService, IUserManager $userManager, IUserSession $userSession, IURLGenerator $urlGenerator, IAppManager $appManager)
{
$this->appName = $appName;
$this->config = $config;
$this->loggingService = $loggingService;
$this->userManager = $userManager;
$this->userSession = $userSession;
$this->urlGenerator = $urlGenerator;
$this->appManager = $appManager;
$this->casInitialized = FALSE;
}
/**
* init method.
* @throws PhpUserCasLibraryNotFoundException
*/
public function init()
{
$serverHostName = (isset($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : '';
// Gather all app config values
$this->casVersion = $this->config->getAppValue($this->appName, 'cas_server_version', '3.0');
$this->casHostname = $this->config->getAppValue($this->appName, 'cas_server_hostname', $serverHostName);
$this->casPort = intval($this->config->getAppValue($this->appName, 'cas_server_port', 443));
$this->casPath = $this->config->getAppValue($this->appName, 'cas_server_path', '/cas');
$this->casServiceUrl = $this->config->getAppValue($this->appName, 'cas_service_url', '');
$this->casCertPath = $this->config->getAppValue($this->appName, 'cas_cert_path', '');
// Correctly handle cas server path for document root
if ($this->casPath === '/') {
$this->casPath = '';
}
$this->casUseProxy = boolval($this->config->getAppValue($this->appName, 'cas_use_proxy', false));
$this->casDisableLogout = boolval($this->config->getAppValue($this->appName, 'cas_disable_logout', false));
$this->casDisableSinglesignout = boolval($this->config->getAppValue($this->appName, 'cas_disable_singlesignout', false));
$logoutServersArray = explode(",", $this->config->getAppValue($this->appName, 'cas_handlelogout_servers', ''));
$this->casHandleLogoutServers = array();
$this->casKeepTicketIds = boolval($this->config->getAppValue($this->appName, 'cas_keep_ticket_ids', false));
# ECAS
$this->ecasAttributeParserEnabled = boolval($this->config->getAppValue($this->appName, 'cas_ecas_attributeparserenabled', false));
$this->cas_ecas_request_full_userdetails = boolval($this->config->getAppValue($this->appName, 'cas_ecas_request_full_userdetails', false));
$this->cas_ecas_accepted_strengths = $this->config->getAppValue($this->appName, 'cas_ecas_accepted_strengths');
$this->cas_ecas_retrieve_groups = $this->config->getAppValue($this->appName, 'cas_ecas_retrieve_groups');
$this->cas_ecas_assurance_level = $this->config->getAppValue($this->appName, 'cas_ecas_assurance_level');
$this->cas_ecas_internal_ip_range = $this->config->getAppValue($this->appName, 'cas_ecas_internal_ip_range');
foreach ($logoutServersArray as $casHandleLogoutServer) {
$casHandleLogoutServer = ltrim(trim($casHandleLogoutServer));
if (strlen($casHandleLogoutServer) > 4) {
$this->casHandleLogoutServers[] = $casHandleLogoutServer;
}
}
$this->casDebugFile = $this->config->getAppValue($this->appName, 'cas_debug_file', '');
$this->casPhpFile = $this->config->getAppValue($this->appName, 'cas_php_cas_path', '');
if (is_string($this->casPhpFile) && strlen($this->casPhpFile) > 0) {
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, 'Use custom phpCAS file:: ' . $this->casPhpFile);
#\OCP\Util::writeLog('cas', 'Use custom phpCAS file:: ' . $this->casPhpFile, \OCA\UserCas\Service\LoggingService::DEBUG);
if (is_file($this->casPhpFile)) {
require_once("$this->casPhpFile");
} else {
throw new PhpUserCasLibraryNotFoundException('Your custom phpCAS library could not be loaded. The class was not found. Please disable the app with ./occ command or in Database and adjust the path to your library (or remove it to use the shipped library).', 500);
}
} else {
if (is_file(__DIR__ . '/../../vendor/jasig/phpcas/CAS.php')) {
require_once(__DIR__ . '/../../vendor/jasig/phpcas/CAS.php');
} else {
throw new PhpUserCasLibraryNotFoundException('phpCAS library could not be loaded. The class was not found.', 500);
}
}
if (!class_exists('\\phpCAS')) {
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::ERROR, 'phpCAS library could not be loaded. The class was not found.');
throw new PhpUserCasLibraryNotFoundException('phpCAS library could not be loaded. The class was not found.', 500);
}
if (!\phpCAS::isInitialized()) {
try {
\phpCAS::setVerbose(FALSE);
if (!empty($this->casDebugFile)) {
\phpCAS::setDebug($this->casDebugFile);
\phpCAS::setVerbose(TRUE);
}
$serviceBasedUrl = $this->getServiceBasedUrl();
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::ERROR, 'MON SERVICE BASE = '.$serviceBasedUrl);
# Initialize client
if ($this->casUseProxy) {
\phpCAS::proxy($this->casVersion, $this->casHostname, (int)($this->casPort), $this->casPath, $serviceBasedUrl);
} else {
\phpCAS::client($this->casVersion, $this->casHostname, (int)($this->casPort), $this->casPath, $serviceBasedUrl);
}
# Handle SingleSignout requests
if (!$this->casDisableSinglesignout) {
\phpCAS::setSingleSignoutCallback([$this, 'casSingleSignOut']);
\phpCAS::handleLogoutRequests(true, $this->casHandleLogoutServers);
}
# Handle fixed service URL
if (!empty($this->casServiceUrl)) {
\phpCAS::setFixedServiceURL($this->casServiceUrl);
}
# Handle certificate
if (!empty($this->casCertPath)) {
\phpCAS::setCasServerCACert($this->casCertPath);
} else {
\phpCAS::setNoCasServerValidation();
}
# Handle keeping of cas-ticket-ids
if ($this->casKeepTicketIds) {
\phpCAS::setNoClearTicketsFromUrl();
}
# Handle ECAS Attributes if enabled
if ($this->ecasAttributeParserEnabled) {
if (is_file(__DIR__ . '/../../vendor/ec-europa/ecas-phpcas-parser/src/EcasPhpCASParser.php')) {
require_once(__DIR__ . '/../../vendor/ec-europa/ecas-phpcas-parser/src/EcasPhpCASParser.php');
} else {
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::ERROR, 'phpCAS EcasPhpCASParser library could not be loaded. The class was not found.');
throw new PhpUserCasLibraryNotFoundException('phpCAS EcasPhpCASParser could not be loaded. The class was not found.', 500);
}
# Register the parser
\phpCAS::setCasAttributeParserCallback(array(new \EcasPhpCASParser\EcasPhpCASParser(), 'parse'));
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS EcasPhpCASParser has been successfully set.");
}
#### Register the new ticket validation url
if ((is_string($this->cas_ecas_retrieve_groups) && strlen($this->cas_ecas_retrieve_groups) > 0)
|| ($this->cas_ecas_request_full_userdetails)
|| (is_string($this->cas_ecas_assurance_level) && strlen($this->cas_ecas_assurance_level) > 0)
|| (is_string($this->cas_ecas_accepted_strengths) && strlen($this->cas_ecas_accepted_strengths) > 0)) {
## Check for external IP Ranges to en-/disable the Two-Factor-Authentication (AcceptedStrength at least MEDIUM)
if ($this->isIpInLocalRange($this->cas_ecas_internal_ip_range) && $this->cas_ecas_accepted_strengths !== '') {
$this->cas_ecas_accepted_strengths = 'BASIC';
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS ECAS AcceptedStrength Level is forced to BASIC, because the user is in the internal network. Test Address: " . $endIp . " | Users Remote Address: " . $remoteAddress);
}
# Add acceptedStrength Querystring Parameters
if (is_string($this->cas_ecas_accepted_strengths) && strlen($this->cas_ecas_accepted_strengths) > 0) {
# Register the new login url
$serverLoginUrl = \phpCAS::getServerLoginURL();
$serverLoginUrl = $this->buildQueryUrl($serverLoginUrl, 'acceptStrengths=' . urlencode($this->cas_ecas_accepted_strengths));
\phpCAS::setServerLoginURL($serverLoginUrl);
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS ECAS strength attribute has been successfully set. New service login URL: " . $serverLoginUrl);
}
## Change validation URL based on ECAS assuranceLevel
$newProtocol = 'http://';
$newUrl = '';
$newSamlUrl = '';
if ($this->getCasPort() === 443) {
$newProtocol = 'https://';
}
if ($this->getCasVersion() === "1.0") {
$newUrl = $newProtocol . $this->getCasHostname() . $this->getCasPath() . '/validate';
} else if ($this->getCasVersion() === "2.0") {
$newUrl = $newProtocol . $this->getCasHostname() . $this->getCasPath() . '/serviceValidate';
} else if ($this->getCasVersion() === "3.0") {
$newUrl = $newProtocol . $this->getCasHostname() . $this->getCasPath() . '/p3/serviceValidate';
} else if ($this->getCasVersion() === "S1") {
$newSamlUrl = $newProtocol . $this->getCasHostname() . $this->getCasPath() . '/samlValidate';
}
if (is_string($this->cas_ecas_assurance_level) && $this->cas_ecas_assurance_level === 'LOW') {
$newUrl = $newProtocol . $this->getCasHostname() . $this->getCasPath() . '/laxValidate';
} else if (is_string($this->cas_ecas_assurance_level) && $this->cas_ecas_assurance_level === 'MEDIUM') {
$newUrl = $newProtocol . $this->getCasHostname() . $this->getCasPath() . '/sponsorValidate';
} else if (is_string($this->cas_ecas_assurance_level) && $this->cas_ecas_assurance_level === 'HIGH') {
$newUrl = $newProtocol . $this->getCasHostname() . $this->getCasPath() . '/interinstitutionalValidate';
} else if (is_string($this->cas_ecas_assurance_level) && $this->cas_ecas_assurance_level === 'TOP') {
$newUrl = $newProtocol . $this->getCasHostname() . $this->getCasPath() . '/strictValidate';
}
if (!empty($this->casServiceUrl)) {
$newUrl = $this->buildQueryUrl($newUrl, 'service=' . urlencode($this->casServiceUrl));
$newSamlUrl = $this->buildQueryUrl($newSamlUrl, 'TARGET=' . urlencode($this->casServiceUrl));
} else {
$newUrl = $this->buildQueryUrl($newUrl, 'service=' . urlencode(\phpCAS::getServiceURL()));
$newSamlUrl = $this->buildQueryUrl($newSamlUrl, 'TARGET=' . urlencode(\phpCAS::getServiceURL()));
}
# Add the groups to retrieve
if (is_string($this->cas_ecas_retrieve_groups) && strlen($this->cas_ecas_retrieve_groups) > 0) {
$newUrl = $this->buildQueryUrl($newUrl, 'groups=' . urlencode($this->cas_ecas_retrieve_groups));
$newSamlUrl = $this->buildQueryUrl($newSamlUrl, 'groups=' . urlencode($this->cas_ecas_retrieve_groups));
}
# Add the requestFullUserDetails flag
if ($this->cas_ecas_request_full_userdetails) {
$newUrl = $this->buildQueryUrl($newUrl, 'userDetails=' . urlencode('true'));
$newSamlUrl = $this->buildQueryUrl($newSamlUrl, 'userDetails=' . urlencode('true'));
}
# Set the user agent to mimic an ecas client
$userAgent = sprintf("ECAS PHP Client (%s, %s)",
'2.1.3',
$_SERVER['SERVER_SOFTWARE']);
\phpCAS::setExtraCurlOption(CURLOPT_USERAGENT, $userAgent);
# Set the new URLs
if ($this->getCasVersion() !== "S1" && !empty($newUrl)) {
\phpCAS::setServerServiceValidateURL($newUrl);
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS ECAS additional attributes have been successfully set. New CAS " . $this->getCasVersion() . " service validate URL: " . $newUrl);
} elseif ($this->getCasVersion() === "S1" && !empty($newSamlUrl)) {
\phpCAS::setServerSamlValidateURL($newSamlUrl);
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS ECAS additional attributes have been successfully set. New SAML 1.0 service validate URL: " . $newSamlUrl);
}
}
$this->casInitialized = TRUE;
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS has been successfully initialized.");
} catch (\CAS_Exception $e) {
\phpCAS::setVerbose(TRUE);
$this->casInitialized = FALSE;
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::ERROR, "phpCAS has thrown an exception with code: " . $e->getCode() . " and message: " . $e->getMessage() . ".");
}
} else {
$this->casInitialized = TRUE;
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS has already been initialized.");
}
}
/**
* Test if the instance is not a Nextcloud instance
*
* @return bool
*/
public function isNotNextcloud()
{
require __DIR__ . '/../../../../version.php';
/**
* @var string $vendor The vendor of this instance
*/
#$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS vendor: ".$vendor);
if (strpos(strtolower($vendor), 'next') === FALSE) {
return TRUE;
}
return FALSE;
}
/**
* Check if login should be enforced using user_cas.
*
* @param $remoteAddress
* @param string $requestUri
* @return bool TRUE|FALSE
*/
public function isEnforceAuthentication($remoteAddress, $requestUri)
{
$isEnforced = TRUE;
$forceLoginExceptions = $this->config->getAppValue($this->appName, 'cas_force_login_exceptions', '');
$forceLoginExceptionsArray = explode(',', $forceLoginExceptions);
# Enforce off
if ($this->config->getAppValue($this->appName, 'cas_force_login') !== '1') {
$isEnforced = FALSE;
} else {
# Check enforce IP ranges
foreach ($forceLoginExceptionsArray as $forceLoginException) {
$forceLoginExceptionRanges = explode('-', $forceLoginException);
if (isset($forceLoginExceptionRanges[0])) {
if (isset($forceLoginExceptionRanges[1])) {
$baseIpComponents = explode('.', $forceLoginExceptionRanges[0]);
$baseIp = $baseIpComponents[0] . '.' . $baseIpComponents[1] . '.';
$additionalIpComponents = explode('.', $forceLoginExceptionRanges[1]);
if (isset($additionalIpComponents[1]) && $additionalIpComponents[0]) {
# We have a two part range here (eg. 127.0.0.1-1.19) which means, we have to cover 127.0.0.1-127.0.0.254 and 127.0.1.1-127.0.1.19
for ($ipThirdPart = intval($baseIpComponents[2]); $ipThirdPart <= intval($additionalIpComponents[0]); $ipThirdPart++) {
if ($ipThirdPart !== intval($additionalIpComponents[0])) {
$ipFourthPartMax = 254;
} else {
$ipFourthPartMax = intval($additionalIpComponents[1]);
}
for ($ipFourthPart = intval($baseIpComponents[3]); $ipFourthPart <= $ipFourthPartMax; $ipFourthPart++) {
$endIp = $baseIp . $ipThirdPart . '.' . $ipFourthPart;
#$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS Enforce Login IP checked: " . $endIp);
if ($remoteAddress === $endIp) {
$isEnforced = FALSE;
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS Enforce Login NOT triggered. Test Address: " . $endIp . " | Users Remote Address: " . $remoteAddress);
}
}
}
} elseif ($additionalIpComponents[0]) {
# We have a one part range here (eg. 127.0.0.1-19)
$newIp = $baseIp . $baseIpComponents[2] . '.';
for ($ipFourthPart = intval($baseIpComponents[3]); $ipFourthPart <= intval($additionalIpComponents[0]); $ipFourthPart++) {
$endIp = $newIp . $ipFourthPart;
if ($remoteAddress === $endIp) {
$isEnforced = FALSE;
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS Enforce Login NOT triggered. Test Address: " . $endIp . " | Users Remote Address: " . $remoteAddress);
}
}
}
} else {
# Single IP-Adress given
if ($remoteAddress === $forceLoginExceptionRanges[0]) {
$isEnforced = FALSE;
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS Enforce Login NOT triggered. Test Address: " . $forceLoginExceptionRanges[0] . " | Users Remote Address: " . $remoteAddress);
}
}
}
}
}
# User already logged in
if ($this->userSession->isLoggedIn()) {
$isEnforced = FALSE;
}
# Disable on Nextcloud login-flow use
if (!$this->isNotNextcloud() && strpos($requestUri, "/login/flow") !== FALSE) {
$isEnforced = FALSE;
}
return $isEnforced;
}
/**
* Check if public shares should be protected
*
* @return bool TRUE|FALSE
*/
public function arePublicSharesProtected()
{
$protected = (bool)$this->config->getAppValue($this->appName, 'cas_shares_protected', FALSE);
$loggedIn = $this->userSession->isLoggedIn();
if($loggedIn && $protected) {
$protected = FALSE;
}
return $protected;
}
/**
* Register Login
*
*/
public function registerLogIn()
{
$loginButtonLabel = $this->config->getAppValue($this->appName, 'cas_login_button_label', 'CAS Login');
// Login Button handling
if (strlen($loginButtonLabel) <= 0) {
$loginButtonLabel = 'CAS Login';
}
$this->unregisterLogin();
if ($this->isNotNextcloud()) {
/** @var array $loginAlternatives */
/*$loginAlternatives = $this->config->getSystemValue('login.alternatives', []);
$loginAlreadyRegistered = FALSE;
foreach ($loginAlternatives as $key => $loginAlternative) {
if (isset($loginAlternative['name']) && $loginAlternative['name'] === $loginButtonLabel) {
$loginAlternatives[$key]['href'] = $this->linkToRoute($this->appName . '.authentication.casLogin');
$this->config->setSystemValue('login.alternatives', $loginAlternatives);
$loginAlreadyRegistered = TRUE;
}
}
if (!$loginAlreadyRegistered) {*/
$loginAlternatives[] = ['href' => $this->linkToRoute($this->appName . '.authentication.casLogin'), 'name' => $loginButtonLabel, 'img' => $this->appManager->getAppWebPath($this->appName).'/img/cas-logo.png'];
$this->config->setSystemValue('login.alternatives', $loginAlternatives);
#}
} else {
#$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS Nextcloud " . $version[0] . "." . $version[1] . "." . $version[2] . "." . " detected.");
\OC_App::registerLogIn(array('href' => $this->linkToRoute($this->appName . '.authentication.casLogin'), 'name' => $loginButtonLabel));
}
}
/**
* UnregisterLogin
*/
public function unregisterLogin()
{
$loginButtonLabel = $this->config->getAppValue($this->appName, 'cas_login_button_label', 'CAS Login');
// Login Button handling
if (strlen($loginButtonLabel) <= 0) {
$loginButtonLabel = 'CAS Login';
}
if ($this->isNotNextcloud()) {
$loginAlternatives = $this->config->getSystemValue('login.alternatives', []);
foreach ($loginAlternatives as $key => $loginAlternative) {
if (isset($loginAlternative['name']) && ($loginAlternative['name'] === $loginButtonLabel || $loginAlternative['name'] === 'CAS Login')) {
unset($loginAlternatives[$key]);
}
}
$this->config->setSystemValue('login.alternatives', $loginAlternatives);
}
}
/**
* @return bool
*/
public function isSetupValid()
{
$casHostname = $this->config->getAppValue($this->appName, 'cas_server_hostname');
$casPort = intval($this->config->getAppValue($this->appName, 'cas_server_port'));
$casPath = $this->config->getAppValue($this->appName, 'cas_server_path');
if (is_string($casHostname) && strlen($casHostname) > 1 && is_int($casPort) && $casPort > 1 && is_string($casPath) && strpos($casPath, "/") === 0) {
return TRUE;
}
return FALSE;
}
/**
* Create a link to $route with URLGenerator.
*
* @param string $route
* @param array $arguments
* @return string
*/
public function linkToRoute($route, $arguments = array())
{
return $this->urlGenerator->linkToRoute($route, $arguments);
}
/**
* Create an absolute link to $route with URLGenerator.
*
* @param string $route
* @param array $arguments
* @return string
*/
public function linkToRouteAbsolute($route, $arguments = array())
{
return $this->urlGenerator->linkToRouteAbsolute($route, $arguments);
}
/**
* Create an url relative to owncloud host
*
* @param string $url
* @return mixed
*/
public function getAbsoluteURL($url)
{
return $this->urlGenerator->getAbsoluteURL($url);
}
/**
* @return boolean
*/
public function isCasInitialized()
{
return $this->casInitialized;
}
/**
* This method is used to append query parameters to an url. Since the url
* might already contain parameter it has to be detected and to build a proper
* URL
*
* @param string $url base url to add the query params to
* @param string $query params in query form with & separated
*
* @return string url with query params
*/
private function buildQueryUrl($url, $query)
{
$url .= (strstr($url, '?') === false) ? '?' : '&';
$url .= $query;
return $url;
}
/**
* Test if the clients IP adress is in our local range
*
* @param string|array $internalIps
* @return bool TRUE|FALSE
*/
private function isIpInLocalRange($internalIps)
{
if (is_string($internalIps)) {
$internalIps = explode(',', $internalIps);
}
$remoteAddress = $_SERVER['REMOTE_ADDR'];
$proxyHeader = "HTTP_X_FORWARDED_FOR";
# Header can contain multiple IP-s of proxies that are passed through.
# Only the IP added by the last proxy (last IP in the list) can be trusted.
if (array_key_exists($proxyHeader, $_SERVER)) {
$explodedProxyHeader = explode(",", $_SERVER[$proxyHeader]);
$proxyIp = trim(end($explodedProxyHeader));
if (filter_var($proxyIp, FILTER_VALIDATE_IP)) {
$remoteAddress = $proxyIp;
}
}
# Check enforce IP ranges for acceptedStrength attribute
foreach ($internalIps as $internalIp) {
$internalIpRanges = explode('-', $internalIp);
if (isset($internalIpRanges[0])) {
if (isset($internalIpRanges[1])) {
$baseIpComponents = explode('.', $internalIpRanges[0]);
$baseIp = $baseIpComponents[0] . '.' . $baseIpComponents[1] . '.';
$additionalIpComponents = explode('.', $internalIpRanges[1]);
if (isset($additionalIpComponents[1]) && $additionalIpComponents[0]) {
# We have a two part range here (eg. 127.0.0.1-1.19) which means, we have to cover 127.0.0.1-127.0.0.254 and 127.0.1.1-127.0.1.19
for ($ipThirdPart = intval($baseIpComponents[2]); $ipThirdPart <= intval($additionalIpComponents[0]); $ipThirdPart++) {
if ($ipThirdPart !== intval($additionalIpComponents[0])) {
$ipFourthPartMax = 254;
} else {
$ipFourthPartMax = intval($additionalIpComponents[1]);
}
for ($ipFourthPart = intval($baseIpComponents[3]); $ipFourthPart <= $ipFourthPartMax; $ipFourthPart++) {
$endIp = $baseIp . $ipThirdPart . '.' . $ipFourthPart;
#$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS Enforce Login IP checked: " . $endIp);
if ($remoteAddress === $endIp) {
return TRUE;
/*if ($this->cas_ecas_accepted_strengths !== '') {
$this->cas_ecas_accepted_strengths = 'BASIC';
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS ECAS AcceptedStrength Level is forced to BASIC, because the user is in the internal network. Test Address: " . $endIp . " | Users Remote Address: " . $remoteAddress);
}*/
}
}
}
} elseif ($additionalIpComponents[0]) {
# We have a one part range here (eg. 127.0.0.1-19)
$newIp = $baseIp . $baseIpComponents[2] . '.';
for ($ipFourthPart = intval($baseIpComponents[3]); $ipFourthPart <= intval($additionalIpComponents[0]); $ipFourthPart++) {
$endIp = $newIp . $ipFourthPart;
if ($remoteAddress === $endIp) {
return TRUE;
/*if ($this->cas_ecas_accepted_strengths !== '') {
$this->cas_ecas_accepted_strengths = 'BASIC';
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS ECAS AcceptedStrength is forced to BASIC, because the user is in the internal network. Test Address: " . $endIp . " | Users Remote Address: " . $remoteAddress);
}*/
}
}
}
} else {
# Single IP-Adress given
if ($remoteAddress === $internalIpRanges[0]) {
return TRUE;
/*if ($this->cas_ecas_accepted_strengths !== '') {
$this->cas_ecas_accepted_strengths = 'BASIC';
$this->loggingService->write(\OCA\UserCas\Service\LoggingService::DEBUG, "phpCAS ECAS AcceptedStrength is forced to BASIC, because the user is in the internal network. Test Address: " . $internalIpRanges[0] . " | Users Remote Address: " . $remoteAddress);
}*/
}
}
}
}
return FALSE;
}
/**
* Callback function for CAS singleSignOut call
*
* @author Vincent <https://github.com/pingou2712>
*
* @param string $ticket Ticket Object
*/
public function casSingleSignOut($ticket)
{
// Extract the userID from the SAML Request
$decodedLogoutRequest = urldecode($_POST['logoutRequest']);
preg_match(
"|<saml:NameID[^>]*>(.*)</saml:NameID>|",
$decodedLogoutRequest, $tick, PREG_OFFSET_CAPTURE, 3
);
$wrappedSamlNameId = preg_replace(
'|<saml:NameID[^>]*>|', '', $tick[0][0]
);
$nameId = preg_replace(
'|</saml:NameID>|', '', $wrappedSamlNameId
);
//Kill Session Of UserID:
$this->killSessionUserName($nameId);
}
/**
* Kill the username's session.
*
* @author Vincent <https://github.com/pingou2712>
* @author Felix Rupp <kontakt@felixrupp.com>
*
* @param string $username The username of the user.
* @return NULL
*/
private function killSessionUserName($username)
{
if ($this->userManager->userExists($username)) {
$tokenType = IToken::TEMPORARY_TOKEN;
$sql = "DELETE FROM oc_authtoken WHERE uid = ? AND type = ? AND password IS NULL;";
$stmt = \OC::$server->getDatabaseConnection()->prepare($sql);
$stmt->bindParam(1, $username, \PDO::PARAM_STR);
$stmt->bindParam(2, $tokenType, \PDO::PARAM_INT);
$stmt->execute();
}
return NULL;
}
## Setters/Getters
/**
* @return string
*/
public function getAppName()
{
return $this->appName;
}
/**
* @return string
*/
public function getCasVersion()
{
return $this->casVersion;
}
/**
* @return string
*/
public function getCasHostname()
{
return $this->casHostname;
}
/**
* @return int
*/
public function getCasPort()
{
return $this->casPort;
}
/**
* @return string
*/
public function getCasPath()
{
return $this->casPath;
}
private function getServiceBasedUrl(): string {
$overwrite = \OC::$server->getConfig()->getSystemValue('overwrite.cli.url');
if($overwrite) return $overwrite;
$httpProtocol = \OC::$server->getConfig()->getSystemValue('protocol');
$currentUrl = $_SERVER['SERVER_NAME'];
return $httpProtocol . $currentUrl;
}
}