Compare commits

...

23 Commits

Author SHA1 Message Date
Eric Espie
68fa3d0236 N°7080 - EVENT_DB_LINKS_CHANGED not fired when deleting a user 2024-01-05 10:36:37 +01:00
Pierre Goiffon
abb3ea3272 N°7080 - EVENT_DB_LINKS_CHANGED not fired when deleting a user
Fix regressions caused by deletion plan reorder
2024-01-04 18:07:16 +01:00
Eric Espie
1de390a24d N°7080 - EVENT_DB_LINKS_CHANGED not fired when deleting a user 2024-01-04 15:56:48 +01:00
jf-cbd
34499a719f Update test - broken with N°7079 fix 2024-01-04 10:59:51 +01:00
jf-cbd
8092f566a5 N°7079 - EVENT_DB_LINKS_CHANGED not fired when creating/updating a user with profiles 2024-01-04 10:29:25 +01:00
denis.flaven@combodo.com
a1e2b648f4 N°7001 - Being admin to generate oAuth token is too restrictive 2024-01-02 11:38:43 +01:00
Pierre Goiffon
797aae58e3 Merge remote-tracking branch 'origin/support/3.0' into support/3.1 2023-12-08 17:21:01 +01:00
Pierre Goiffon
f63f3bb547 Merge remote-tracking branch 'origin/support/2.7' into support/3.0 2023-12-08 17:20:48 +01:00
Pierre Goiffon
d5449cca42 💡 iTopMutex: add link to mysql doc 2023-12-08 17:20:37 +01:00
Pierre Goiffon
3f8017f43d N°7046 Fix authent-cas: "CAS_ServiceBaseUrl_Static" not found
Regression in 3.1.0 brought by N°5270 (02afa2f1)
2023-12-08 10:41:04 +01:00
Molkobain
4846532368 N°7047 - Fix regression from 7b59df21, portal themes others than "bootstrap" and "portal" not loaded due to change in expected path (now relative) 2023-12-08 08:28:43 +01:00
Molkobain
90d28c1f90 N°7039 - Fix incorrect retrieval of SecurityHelper due to previous merge 2023-12-07 12:38:16 +01:00
Molkobain
8cc1970931 💚 Fix unit test not working on server with self-signed certificate 2023-12-07 11:18:51 +01:00
Molkobain
75732faf1d N°7039 - Fix warnings in the CI due to unnecessary use statement 2023-12-07 11:18:02 +01:00
Molkobain
c13d0a60e8 N°7039 - Fix placeholder :current_contact->id not working in OQL in iTop 3.1 2023-12-07 10:04:53 +01:00
Molkobain
66d1ffa00f Merge remote-tracking branch 'origin/support/3.0' into support/3.1 2023-12-06 16:31:03 +01:00
Molkobain
181c180824 Merge remote-tracking branch 'origin/support/2.7' into support/3.0 2023-12-06 16:28:27 +01:00
Molkobain
5d38d22c50 N°7023 - Fix regression from the initial fix that throw exceptions even for ext. keys set programatically (eg. ComputeValues), which we still want to allow 2023-12-06 16:27:37 +01:00
Molkobain
c8d2cff0ff Merge remote-tracking branch 'origin/support/3.0' into support/3.1 2023-12-04 23:19:22 +01:00
Molkobain
974c155855 Merge remote-tracking branch 'origin/support/2.7' into support/3.0 2023-12-04 23:16:35 +01:00
Pierre Goiffon
99d69493d1 N°7023 - Update tests so that we are now checking negative ext. keys 2023-12-04 22:36:26 +01:00
Molkobain
c9bb628c30 N°7023 - Improve debug message on portal \DBObject::CheckChangedExtKeysValues() call 2023-12-04 22:36:09 +01:00
Molkobain
08e8d15d78 N°7023 - Fix check to write error when adding a contact on a new user request on the end-users portal 2023-12-04 22:35:07 +01:00
20 changed files with 558 additions and 31 deletions

View File

@@ -4591,6 +4591,7 @@ HTML;
public function DBUpdate()
{
$this->LogCRUDEnter(__METHOD__);
$res = 0;
try {
if (count($this->ListChanges()) === 0) {
@@ -4651,6 +4652,7 @@ HTML;
if (static::IsCrudStackEmpty()) {
// Avoid signaling the current object that links were modified
static::RemoveObjectAwaitingEventDbLinksChanged(get_class($this), $this->GetKey());
$this->LogCRUDDebug(__METHOD__, var_export(self::$aObjectsAwaitingEventDbLinksChanged, true));
static::FireEventDbLinksChangedForAllObjects();
}
}
@@ -4659,6 +4661,11 @@ HTML;
return $oDeletionPlan;
}
protected function PostDeleteActions(): void
{
parent::PostDeleteActions();
}
/**
* @deprecated 3.1.1 3.2.0 N°6967 We will have only one DBDelete method in the future
*/
@@ -5953,7 +5960,6 @@ JS
final protected function FireEventAfterDelete(): void
{
$this->NotifyAttachedObjectsOnLinkClassModification();
$this->FireEventDbLinksChangedForCurrentObject();
$this->FireEvent(EVENT_DB_AFTER_DELETE);
}
@@ -5986,13 +5992,16 @@ JS
}
$sTargetObjectId = $this->Get($sExternalKeyAttCode);
$sTargetClass = $oAttDef->GetTargetClass();
if ($sTargetObjectId > 0) {
self::RegisterObjectAwaitingEventDbLinksChanged($oAttDef->GetTargetClass(), $sTargetObjectId);
$this->LogCRUDDebug(__METHOD__, "Add $sTargetClass:$sTargetObjectId for DBLINKS_CHANGED");
self::RegisterObjectAwaitingEventDbLinksChanged($sTargetClass, $sTargetObjectId);
}
$sPreviousTargetObjectId = $aPreviousValues[$sExternalKeyAttCode] ?? 0;
if ($sPreviousTargetObjectId > 0) {
self::RegisterObjectAwaitingEventDbLinksChanged($oAttDef->GetTargetClass(), $sPreviousTargetObjectId);
$this->LogCRUDDebug(__METHOD__, "Add $sTargetClass:$sPreviousTargetObjectId for DBLINKS_CHANGED");
self::RegisterObjectAwaitingEventDbLinksChanged($sTargetClass, $sPreviousTargetObjectId);
}
}
}
@@ -6042,7 +6051,12 @@ JS
$sClass = get_class($this);
$sId = $this->GetKey();
self::FireEventDbLinksChangedForClassId($sClass, $sId);
$bIsObjectAwaitingEventDbLinksChanged = self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
if (false === $bIsObjectAwaitingEventDbLinksChanged) {
return;
}
self::FireEventDbLinksChangedForObject($this);
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
}
/**
@@ -6074,9 +6088,15 @@ JS
// We want to avoid launching the listener twice, first here, and secondly after saving the Ticket in the listener
// By disabling the event to be fired, we can remove the current object from the attribute !
$oObject = MetaModel::GetObject($sClass, $sId, false);
self::FireEventDbLinksChangedForObject($oObject);
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
}
private static function FireEventDbLinksChangedForObject(DBObject $oObject)
{
self::SetEventDBLinksChangedBlocked(true);
// N°6408 The object can have been deleted
if (!is_null($oObject)) {
self::SetEventDBLinksChangedBlocked(true);
MetaModel::StartReentranceProtection($oObject);
$oObject->FireEvent(EVENT_DB_LINKS_CHANGED);
MetaModel::StopReentranceProtection($oObject);
@@ -6084,7 +6104,6 @@ JS
$oObject->DBUpdate();
}
}
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
cmdbAbstractObject::SetEventDBLinksChangedBlocked(false);
}

View File

@@ -763,6 +763,18 @@ abstract class DBObject implements iDisplay
$this->Set($sAttCode, $sValue);
}
/**
* @return void
* @throws \ReflectionException
*/
protected function PostDeleteActions(): void
{
$this->FireEventAfterDelete();
$oKPI = new ExecutionKPI();
$this->AfterDelete();
$oKPI->ComputeStatsForExtension($this, 'AfterDelete');
}
/**
* Compute (and optionally start) the StopWatches deadlines
*
@@ -2704,15 +2716,19 @@ abstract class DBObject implements iDisplay
continue;
}
/** @noinspection NotOptimalIfConditionsInspection */
/** @noinspection TypeUnsafeComparisonInspection */
if (utils::IsNullOrEmptyString($sRemoteObjectClass)
|| utils::IsNullOrEmptyString($sRemoteObjectKey)
|| ($sRemoteObjectKey == 0) // non-strict comparison as we might have bad surprises
) {
continue;
}
// 0 : Undefined ext. key (EG. non-mandatory and no value provided)
// < 0 : Non yet persisted object
/** @noinspection TypeUnsafeComparisonInspection Non-strict comparison as object ID can be string */
if ($sRemoteObjectKey <= 0) {
continue;
}
if (false === $oIsObjectLoadableCallback($sRemoteObjectClass, $sRemoteObjectKey)) {
throw new InvalidExternalKeyValueException($this, $sAttDefCode);
}
@@ -4199,15 +4215,13 @@ abstract class DBObject implements iDisplay
}
}
$this->FireEventAfterDelete();
$oKPI = new ExecutionKPI();
$this->AfterDelete();
$oKPI->ComputeStatsForExtension($this, 'AfterDelete');
$this->m_bIsInDB = false;
$this->PostDeleteActions();
// - Trigger for object pointing to the current object
$this->ActivateOnObjectUpdateTriggersForTargetObjects();
$this->m_bIsInDB = false;
$this->LogCRUDExit(__METHOD__);
// Fix for N°926: do NOT reset m_iKey as it can be used to have it for reporting purposes (see the REST service to delete
// objects, reported as bug N°926)
@@ -4263,6 +4277,7 @@ abstract class DBObject implements iDisplay
foreach ($aToDelete as $iId => $aData) {
/** @var \DBObject $oToDelete */
$oToDelete = $aData['to_delete'];
// The deletion based on a deletion plan should not be done for each object if the deletion plan is common (Trac #457)
// because for each object we would try to update all the preceding ones... that are already deleted
// A better approach would be to change the API to apply the DBDelete on the deletion plan itself... just once

View File

@@ -4267,16 +4267,17 @@ abstract class MetaModel
];
IssueLog::Warning("Unresolved placeholders due to null object in current context", null,
$aContext);
$aPlaceholders[$sPlaceHolderKey] = \Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
foreach ($aCurrentUser as $sField) {
$sPlaceHolderKey = $sPlaceHolderPrefix . "->$sField";
$aPlaceholders[$sPlaceHolderKey] = \Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
}
} else {
$aPlaceholders[$sPlaceHolderKey] = $oObject;
foreach ($aCurrentUser as $sField) {
$sPlaceHolderKey = $sPlaceHolderPrefix . "->$sField";
if (false === MetaModel::IsValidAttCode(get_class($oObject), $sField)){
// Mind that the "id" is not viewed as a valid att. code by \MetaModel::IsValidAttCode() so we have to test it manually
if ($sField !== "id" && false === MetaModel::IsValidAttCode(get_class($oObject), $sField)){
$aContext = [
"current_user_id" => UserRights::GetUserId(),
"obj_class" => get_class($oObject),
@@ -4285,7 +4286,7 @@ abstract class MetaModel
];
IssueLog::Warning("Unresolved placeholder due to invalid attribute", null,
$aContext);
$aPlaceholders[$sPlaceHolderKey] = \Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
continue;
}

View File

@@ -22,7 +22,9 @@
* A class to serialize the execution of some code sections
* Emulates the API of PECL Mutex class
* Relies on MySQL locks because the API sem_get is not always present in the
* installed PHP.
* installed PHP.
*
* @link https://dev.mysql.com/doc/refman/5.7/en/locking-functions.html MySQL locking functions documentation
*
* @copyright Copyright (C) 2013-2023 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -248,7 +248,7 @@ abstract class User extends cmdbAbstractObject
"depends_on" => array(),
)));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("profile_list",array("linked_class" => "URP_UserProfile", "ext_key_to_me" => "userid", "ext_key_to_remote" => "profileid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), "display_style" => 'property', "with_php_constraint" => true)));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("profile_list",array("linked_class" => "URP_UserProfile", "ext_key_to_me" => "userid", "ext_key_to_remote" => "profileid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), "display_style" => 'property', "with_php_constraint" => true, "with_php_computation" => true)));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("allowed_org_list", array("linked_class" => "URP_UserOrg", "ext_key_to_me" => "userid", "ext_key_to_remote" => "allowed_org_id", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), 'with_php_constraint' => true)));
MetaModel::Init_AddAttribute(new AttributeCaseLog("log", array("sql" => 'log', "is_null_allowed" => true, "default_value" => '', "allowed_values" => null, "depends_on" => array(), "always_load_in_tables" => false)));

View File

@@ -1146,13 +1146,13 @@ class ObjectFormManager extends FormManager
// Writing object to DB
try
{
$this->oObject->CheckChangedExtKeysValues(function ($sClass, $sId) use ($oSecurityHelper): bool {
return $oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $sClass, $sId);
});
$this->oObject->DBWrite();
} catch (CoreCannotSaveObjectException $e) {
throw new Exception($e->getHtmlMessage());
} catch (InvalidExternalKeyValueException $e) {
ExceptionLog::LogException($e, $e->getContextData());
$bExceptionLogged = true;
throw new Exception($e->getIssue());
} catch (Exception $e) {
$aContext = [
@@ -1403,6 +1403,12 @@ class ObjectFormManager extends FormManager
}
}
}
/** @var SecurityHelper $oSecurityHelper */
$oSecurityHelper = $this->oFormHandlerHelper->GetSecurityHelper();
// N°7023 - Note that we check for ext. key now as we want the check to be done on user inputs and NOT on ext. keys set programatically, so it must be done before the DoComputeValues
$this->oObject->CheckChangedExtKeysValues(function ($sClass, $sId) use ($oSecurityHelper): bool {
return $oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $sClass, $sId);
});
$this->oObject->DoComputeValues();
}

View File

@@ -64,12 +64,12 @@
{% endif %}
{# Custom CSS that is supposed to do adjustments to the portal #}
{% if app['combodo.portal.instance.conf'].properties.themes.custom is defined %}
<link href="{{ app['combodo.portal.instance.conf'].properties.themes.custom|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] ~ app['combodo.portal.instance.conf'].properties.themes.custom|add_itop_version }}" rel="stylesheet">
{% endif %}
{# Others CSS that will come after the theme/portal/custom, in an undefined order #}
{% if app['combodo.portal.instance.conf'].properties.themes.others is defined %}
{% for theme in app['combodo.portal.instance.conf'].properties.themes.others %}
<link href="{{ theme|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] ~ theme|add_itop_version }}" rel="stylesheet">
{% endfor %}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,152 @@
<?php
/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP Version 7
*
* @file CAS/ServiceBaseUrl/AllowedListDiscovery.php
* @category Authentication
* @package PhpCAS
* @author Henry Pan <git@phy25.com>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://wiki.jasig.org/display/CASC/phpCAS
*/
/**
* Class that gets the service base URL of the PHP server by HTTP header
* discovery and allowlist check. This is used to generate service URL
* and PGT callback URL.
*
* @class CAS_ServiceBaseUrl_AllowedListDiscovery
* @category Authentication
* @package PhpCAS
* @author Henry Pan <git@phy25.com>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://wiki.jasig.org/display/CASC/phpCAS
*/
class CAS_ServiceBaseUrl_AllowedListDiscovery
extends CAS_ServiceBaseUrl_Base
{
private $_list = array();
public function __construct($list) {
if (is_array($list)) {
if (count($list) === 0) {
throw new CAS_InvalidArgumentException('$list should not be empty');
}
foreach ($list as $value) {
$this->allow($value);
}
} else {
throw new CAS_TypeMismatchException($list, '$list', 'array');
}
}
/**
* Add a base URL to the allowed list.
*
* @param $url protocol, host name and port to add to the allowed list
*
* @return void
*/
public function allow($url)
{
$this->_list[] = $this->removeStandardPort($url);
}
/**
* Check if the server name is allowed by configuration.
*
* @param $name server name to check
*
* @return bool whether the allowed list contains the server name
*/
protected function isAllowed($name)
{
return in_array($name, $this->_list);
}
/**
* Discover the server name through HTTP headers.
*
* We read:
* - HTTP header X-Forwarded-Host
* - HTTP header X-Forwarded-Server and X-Forwarded-Port
* - HTTP header Host and SERVER_PORT
* - PHP SERVER_NAME (which can change based on the HTTP server used)
*
* The standard port will be omitted (80 for HTTP, 443 for HTTPS).
*
* @return string the discovered, unsanitized server protocol, hostname and port
*/
protected function discover()
{
$isHttps = $this->isHttps();
$protocol = $isHttps ? 'https' : 'http';
$protocol .= '://';
if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
// explode the host list separated by comma and use the first host
$hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
// see rfc7239#5.3 and rfc7230#2.7.1: port is in HTTP_X_FORWARDED_HOST if non default
return $protocol . $hosts[0];
} else if (!empty($_SERVER['HTTP_X_FORWARDED_SERVER'])) {
$server_url = $_SERVER['HTTP_X_FORWARDED_SERVER'];
} else {
if (empty($_SERVER['SERVER_NAME'])) {
$server_url = $_SERVER['HTTP_HOST'];
} else {
$server_url = $_SERVER['SERVER_NAME'];
}
}
if (!strpos($server_url, ':')) {
if (empty($_SERVER['HTTP_X_FORWARDED_PORT'])) {
$server_port = $_SERVER['SERVER_PORT'];
} else {
$ports = explode(',', $_SERVER['HTTP_X_FORWARDED_PORT']);
$server_port = $ports[0];
}
$server_url .= ':';
$server_url .= $server_port;
}
return $protocol . $server_url;
}
/**
* Get PHP server base URL.
*
* @return string the server protocol, hostname and port
*/
public function get()
{
phpCAS::traceBegin();
$result = $this->removeStandardPort($this->discover());
phpCAS::trace("Discovered server base URL: " . $result);
if ($this->isAllowed($result)) {
phpCAS::trace("Server base URL is allowed");
phpCAS::traceEnd(true);
} else {
$result = $this->_list[0];
phpCAS::trace("Server base URL is not allowed, using default: " . $result);
phpCAS::traceEnd(false);
}
return $result;
}
}

View File

@@ -0,0 +1,98 @@
<?php
/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP Version 7
*
* @file CAS/ServiceBaseUrl/Base.php
* @category Authentication
* @package PhpCAS
* @author Henry Pan <git@phy25.com>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://wiki.jasig.org/display/CASC/phpCAS
*/
/**
* Base class of CAS/ServiceBaseUrl that implements isHTTPS method.
*
* @class CAS_ServiceBaseUrl_Base
* @category Authentication
* @package PhpCAS
* @author Henry Pan <git@phy25.com>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://wiki.jasig.org/display/CASC/phpCAS
*/
abstract class CAS_ServiceBaseUrl_Base
implements CAS_ServiceBaseUrl_Interface
{
/**
* Get PHP server name.
*
* @return string the server hostname and port of the server
*/
abstract public function get();
/**
* Check whether HTTPS is used.
*
* This is used to construct the protocol in the URL.
*
* @return bool true if HTTPS is used
*/
public function isHttps() {
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
return ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) {
return ($_SERVER['HTTP_X_FORWARDED_PROTOCOL'] === 'https');
} elseif ( isset($_SERVER['HTTPS'])
&& !empty($_SERVER['HTTPS'])
&& strcasecmp($_SERVER['HTTPS'], 'off') !== 0
) {
return true;
}
return false;
}
/**
* Remove standard HTTP and HTTPS port for discovery and allowlist input.
*
* @param $url URL as https://domain:port without trailing slash
* @return standardized URL, or the original URL
* @throws CAS_InvalidArgumentException if the URL does not include the protocol
*/
protected function removeStandardPort($url) {
if (strpos($url, "://") === false) {
throw new CAS_InvalidArgumentException(
"Configured base URL should include the protocol string: " . $url);
}
$url = rtrim($url, '/');
if (strpos($url, "https://") === 0 && substr_compare($url, ':443', -4) === 0) {
return substr($url, 0, -4);
}
if (strpos($url, "http://") === 0 && substr_compare($url, ':80', -3) === 0) {
return substr($url, 0, -3);
}
return $url;
}
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP Version 7
*
* @file CAS/ServerHostname/Interface.php
* @category Authentication
* @package PhpCAS
* @author Henry Pan <git@phy25.com>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://wiki.jasig.org/display/CASC/phpCAS
*/
/**
* An interface for classes that gets the server name of the PHP server.
* This is used to generate service URL and PGT callback URL.
*
* @class CAS_ServiceBaseUrl_Interface
* @category Authentication
* @package PhpCAS
* @author Henry Pan <git@phy25.com>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://wiki.jasig.org/display/CASC/phpCAS
*/
interface CAS_ServiceBaseUrl_Interface
{
/**
* Get PHP HTTP protocol and server name.
*
* @return string protocol, server hostname, and optionally port,
* without trailing slash (https://localhost:8443)
*/
public function get();
/**
* Check whether HTTPS is used.
*
* This is used to construct the protocol in the URL.
*
* @return bool true if HTTPS is used
*/
public function isHttps();
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP Version 7
*
* @file CAS/ServiceBaseUrl/Static.php
* @category Authentication
* @package PhpCAS
* @author Henry Pan <git@phy25.com>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://wiki.jasig.org/display/CASC/phpCAS
*/
/**
* Class that gets the server name of the PHP server by statically set
* hostname and port. This is used to generate service URL and PGT
* callback URL.
*
* @class CAS_ServiceBaseUrl_Static
* @category Authentication
* @package PhpCAS
* @author Henry Pan <git@phy25.com>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://wiki.jasig.org/display/CASC/phpCAS
*/
class CAS_ServiceBaseUrl_Static
extends CAS_ServiceBaseUrl_Base
{
private $_name = null;
public function __construct($name) {
if (is_string($name)) {
$this->_name = $this->removeStandardPort($name);
} else {
throw new CAS_TypeMismatchException($name, '$name', 'string');
}
}
/**
* Get the server name through static config.
*
* @return string the server hostname and port of the server configured
*/
public function get()
{
phpCAS::traceBegin();
phpCAS::trace("Returning static server name: " . $this->_name);
phpCAS::traceEnd(true);
return $this->_name;
}
}

View File

@@ -145,6 +145,10 @@ return array(
'CAS_Request_Exception' => $vendorDir . '/apereo/phpcas/source/CAS/Request/Exception.php',
'CAS_Request_MultiRequestInterface' => $vendorDir . '/apereo/phpcas/source/CAS/Request/MultiRequestInterface.php',
'CAS_Request_RequestInterface' => $vendorDir . '/apereo/phpcas/source/CAS/Request/RequestInterface.php',
'CAS_ServiceBaseUrl_AllowedListDiscovery' => $vendorDir . '/apereo/phpcas/source/CAS/ServiceBaseUrl/AllowedListDiscovery.php',
'CAS_ServiceBaseUrl_Base' => $vendorDir . '/apereo/phpcas/source/CAS/ServiceBaseUrl/Base.php',
'CAS_ServiceBaseUrl_Interface' => $vendorDir . '/apereo/phpcas/source/CAS/ServiceBaseUrl/Interface.php',
'CAS_ServiceBaseUrl_Static' => $vendorDir . '/apereo/phpcas/source/CAS/ServiceBaseUrl/Static.php',
'CAS_Session_PhpSession' => $vendorDir . '/apereo/phpcas/source/CAS/Session/PhpSession.php',
'CAS_TypeMismatchException' => $vendorDir . '/apereo/phpcas/source/CAS/TypeMismatchException.php',
'CLILikeWebPage' => $baseDir . '/sources/Application/WebPage/CLILikeWebPage.php',

View File

@@ -509,6 +509,10 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'CAS_Request_Exception' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Request/Exception.php',
'CAS_Request_MultiRequestInterface' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Request/MultiRequestInterface.php',
'CAS_Request_RequestInterface' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Request/RequestInterface.php',
'CAS_ServiceBaseUrl_AllowedListDiscovery' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ServiceBaseUrl/AllowedListDiscovery.php',
'CAS_ServiceBaseUrl_Base' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ServiceBaseUrl/Base.php',
'CAS_ServiceBaseUrl_Interface' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ServiceBaseUrl/Interface.php',
'CAS_ServiceBaseUrl_Static' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/ServiceBaseUrl/Static.php',
'CAS_Session_PhpSession' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/Session/PhpSession.php',
'CAS_TypeMismatchException' => __DIR__ . '/..' . '/apereo/phpcas/source/CAS/TypeMismatchException.php',
'CLILikeWebPage' => __DIR__ . '/../..' . '/sources/Application/WebPage/CLILikeWebPage.php',

View File

@@ -3,7 +3,7 @@
'name' => 'combodo/itop',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '5465287089bacacae3304af6688ce5991893835a',
'reference' => '90d28c1f90fedc1a3fccf37d3c2c6798d6503be3',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -22,7 +22,7 @@
'combodo/itop' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '5465287089bacacae3304af6688ce5991893835a',
'reference' => '90d28c1f90fedc1a3fccf37d3c2c6798d6503be3',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),

View File

@@ -10,6 +10,5 @@ IssueLog::Trace('----- Request: '.utils::GetRequestUri(), LogChannels::WEB_REQUE
$sTemplates = APPROOT.'templates/pages/backoffice/oauth';
$oUpdateController = new OAuthLandingController($sTemplates, 'core');
$oUpdateController->AllowOnlyAdmin();
$oUpdateController->SetDefaultOperation('Landing');
$oUpdateController->HandleOperation();

View File

@@ -178,6 +178,9 @@ class QueryTest extends ItopDataTestCase
curl_setopt($curl, CURLOPT_USERPWD, self::USER . ':' . self::PASSWORD);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
// Force disable of certificate check as most of dev / test env have a self-signed certificate
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
// execute curl
$result = curl_exec($curl);

View File

@@ -232,7 +232,7 @@ PHP
public function WithConstraintParameterProvider()
{
return [
['User', 'profile_list', true, false],
['User', 'profile_list', true, true],
['User', 'allowed_org_list', true, false],
['Person', 'team_list', false, false],
['Ticket', 'functionalcis_list', false, true],

View File

@@ -14,12 +14,22 @@ use DBObject;
use DBObject\MockDBObjectWithCRUDEventListener;
use DBObjectSet;
use DBSearch;
use IssueLog;
use lnkFunctionalCIToTicket;
use lnkPersonToTeam;
use MetaModel;
use ormLinkSet;
use Person;
use Server;
use Team;
use UserRequest;
use utils;
use const EVENT_DB_AFTER_DELETE;
use const EVENT_DB_AFTER_WRITE;
use const EVENT_DB_BEFORE_WRITE;
use const EVENT_DB_CHECK_TO_DELETE;
use const EVENT_DB_CHECK_TO_WRITE;
use const EVENT_DB_COMPUTE_VALUES;
use const EVENT_DB_LINKS_CHANGED;
class CRUDEventTest extends ItopDataTestCase
@@ -30,12 +40,32 @@ class CRUDEventTest extends ItopDataTestCase
// Count the events by name
private static array $aEventCalls = [];
private static int $iEventCalls = 0;
private static string $sLogFile = 'log/test_error_CRUDEventTest.log';
protected function setUp(): void
{
static::$aEventCalls = [];
static::$iEventCalls = 0;
static::CleanCallCount();
parent::setUp();
static::$DEBUG_UNIT_TEST = false;
if (static::$DEBUG_UNIT_TEST) {
echo "--- logging in ".APPROOT.static::$sLogFile."\n\n";
@unlink(APPROOT.static::$sLogFile);
IssueLog::Enable(APPROOT.static::$sLogFile);
$oConfig = utils::GetConfig();
$oConfig->Set('log_level_min', ['DMCRUD' => 'Trace']);
}
}
protected function tearDown(): void
{
if (is_file(APPROOT.static::$sLogFile)) {
$sLog = file_get_contents(APPROOT.static::$sLogFile);
echo "--- error.log\n$sLog\n\n";
@unlink(APPROOT.static::$sLogFile);
}
parent::tearDown();
}
public static function IncrementCallCount(string $sEvent)
@@ -44,6 +74,13 @@ class CRUDEventTest extends ItopDataTestCase
self::$iEventCalls++;
}
public static function CleanCallCount()
{
self::$aEventCalls = [];
self::$iEventCalls = 0;
}
/**
* Check that the 3 events EVENT_DB_COMPUTE_VALUES, EVENT_DB_CHECK_TO_WRITE and EVENT_DB_AFTER_WRITE are called on insert
*
@@ -343,6 +380,54 @@ class CRUDEventTest extends ItopDataTestCase
$this->assertEquals(16, self::$iEventCalls);
}
public function testDBDeleteUR()
{
// Prepare the link set
$sLinkedClass = lnkFunctionalCIToTicket::class;
$aLinkedObjectsArray = [];
$oSet = DBObjectSet::FromArray($sLinkedClass, $aLinkedObjectsArray);
$oLinkSet = new ormLinkSet(UserRequest::class, 'functionalcis_list', $oSet);
// Create the 3 servers
for ($i = 0; $i < 3; $i++) {
$oServer = $this->CreateServer($i);
$this->assertIsObject($oServer);
// Add the person to the link
$oLink = MetaModel::NewObject(lnkFunctionalCIToTicket::class, ['functionalci_id' => $oServer->GetKey()]);
$oLinkSet->AddItem($oLink);
}
$this->debug("\n-------------> Insert Starts HERE\n");
$oEventReceiver = new CRUDEventReceiver($this);
$oEventReceiver->RegisterCRUDListeners();
$oUserRequest = MetaModel::NewObject(UserRequest::class, array_merge($this->GetUserRequestParams(0), ['functionalcis_list' => $oLinkSet]));
$oUserRequest->DBInsert();
$this->assertIsObject($oUserRequest);
// 1 insert for UserRequest, 3 insert for lnkFunctionalCIToTicket
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_COMPUTE_VALUES]);
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_CHECK_TO_WRITE]);
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_BEFORE_WRITE]);
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_AFTER_WRITE]);
$this->assertEquals(1, self::$aEventCalls[EVENT_DB_LINKS_CHANGED]);
$this->assertEquals(17, self::$iEventCalls);
$this->debug("\n-------------> Delete Starts HERE\n");
$oEventReceiver->CleanCallbacks();
self::CleanCallCount();
$oUserRequest->DBDelete();
// 1 delete for UserRequest, 3 delete for lnkFunctionalCIToTicket
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_CHECK_TO_DELETE]);
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_AFTER_DELETE]);
$this->assertArrayNotHasKey(EVENT_DB_LINKS_CHANGED, self::$aEventCalls, 'no relation with the with_php_compute attribute !');
$this->assertEquals(8, self::$iEventCalls);
}
/**
* The test creates a team containing one Person.
* During the insert of the lnkPersonToTeam a modification is done on the link,

View File

@@ -558,6 +558,7 @@ class DBObjectTest extends ItopDataTestCase
$oPersonLinks = \DBObjectSet::FromScratch(lnkPersonToTeam::class);
$oPersonLinks->AddObject(MetaModel::NewObject(lnkPersonToTeam::class, [
'person_id' => self::INVALID_OBJECT_KEY,
'team_id' => $oTeam->GetKey(),
]));
$oTeam->Set('persons_list', $oPersonLinks);
@@ -582,6 +583,7 @@ class DBObjectTest extends ItopDataTestCase
$oPersonLinks = \DBObjectSet::FromScratch(lnkPersonToTeam::class);
$oPersonLinks->AddObject(MetaModel::NewObject(lnkPersonToTeam::class, [
'person_id' => $oPersonOnDemoOrg->GetKey(),
'team_id' => $oTeam->GetKey(),
]));
$oTeam->Set('persons_list', $oPersonLinks);
@@ -603,6 +605,7 @@ class DBObjectTest extends ItopDataTestCase
$oPersonLinks = \DBObjectSet::FromScratch(lnkPersonToTeam::class);
$oPersonLinks->AddObject(MetaModel::NewObject(lnkPersonToTeam::class, [
'person_id' => $oPersonOnItDepartmentOrg->GetKey(),
'team_id' => $oTeam->GetKey(),
]));
$oTeam->Set('persons_list', $oPersonLinks);

View File

@@ -79,7 +79,10 @@ class MetaModelMagicPlaceholderTest extends ItopDataTestCase
new VariableExpression('current_user->login'),
new VariableExpression('current_user->not_existing_attribute'),
new VariableExpression('current_contact_id'),
new VariableExpression('current_contact->id'),
new VariableExpression('current_contact->friendlyname'),
new VariableExpression('current_contact->org_id'),
new VariableExpression('current_contact->org_id_friendlyname'),
new VariableExpression('current_contact->not_existing_attribute'),
];
$aPlaceholders = MetaModel::AddMagicPlaceholders(['gabu' => "zomeu"], $aExpectedArgs);
@@ -91,7 +94,10 @@ class MetaModelMagicPlaceholderTest extends ItopDataTestCase
'current_user->not_existing_attribute' => '(current_user->not_existing_attribute : cannot be resolved)',
'current_user->login' => $sLogin,
'current_contact->object()' => $oPerson,
'current_contact->id' => $oPerson->GetKey(),
'current_contact->friendlyname' => $oPerson->GetName(),
'current_contact->org_id' => $oPerson->Get('org_id'),
'current_contact->org_id_friendlyname' => $oPerson->Get('org_id_friendlyname'),
'current_contact->not_existing_attribute' => '(current_contact->not_existing_attribute : cannot be resolved)',
],
$aPlaceholders,