@@ -584,24 +584,22 @@ private function manageFieldValues()
584584
585585
586586 /**
587- * Get the ID associated with a value from the CSV file
588- *
589- * @param PluginDatainjectionInjectionInterface|null $injectionClass
590- * @param string $itemtype itemtype of the values to inject
591- * @param array $searchOption option associated with the field to check
592- * @param string $field the field to check
593- * @param string $value the value coming from the CSV file
594- * @param boolean $add is insertion (true) or update (false) (true by default)
595- *
596- * @return void nothing
597- **/
587+ * Get the ID associated with a value from the CSV file
588+ *
589+ * @param PluginDatainjectionInjectionInterface|null $injectionClass
590+ * @param string $itemtype itemtype of the values to inject
591+ * @param array $searchOption option associated with the field to check
592+ * @param string $field the field to check
593+ * @param string $value the value coming from the CSV file
594+ *
595+ * @return void nothing
596+ **/
598597 private function getFieldValue (
599598 $ injectionClass ,
600599 $ itemtype ,
601600 $ searchOption ,
602601 $ field ,
603- $ value ,
604- $ add = true
602+ $ value
605603 ) {
606604 $ linkfield = $ searchOption ['storevaluein ' ] ?? $ searchOption ['linkfield ' ];
607605
@@ -614,13 +612,12 @@ private function getFieldValue(
614612 break ;
615613
616614 case 'password ' :
617- //To add a user password, it's mandatory is give a password and it's confirmation
618- //Here we cannot detect if it's an add or update. We'll handle updates later in the process
619- if ($ add && $ itemtype == 'User ' ) {
615+ //Core needs both the password and its confirmation to validate and hash it, on add as well as on update
616+ if ($ itemtype == 'User ' ) {
620617 $ this ->setValueForItemtype ($ itemtype , $ linkfield , $ value );
621- //Add field password2 is not already present
618+ //Add field password2 if not already present
622619 //(can be present if password was an addtional information)
623- if (!isset ($ this ->values [$ itemtype ][$ field ])) {
620+ if (!isset ($ this ->values [$ itemtype ][$ linkfield . " 2 " ])) {
624621 $ this ->setValueForItemtype ($ itemtype , $ linkfield . "2 " , $ value );
625622 }
626623 }
@@ -976,7 +973,8 @@ private function unsetValue($itemtype, $field)
976973 **/
977974 private function setValueForItemtype ($ itemtype , $ field , $ value , $ fromdb = false )
978975 {
979- if ($ itemtype === User::class && $ field === "pdffont " && $ fromdb ) {
976+ //The stored password is a hash: taking it back from the DB would overwrite the imported one
977+ if ($ itemtype === User::class && in_array ($ field , ['pdffont ' , 'password ' ], true ) && $ fromdb ) {
980978 return ;
981979 }
982980
@@ -1708,13 +1706,16 @@ public function processAddOrUpdate()
17081706 $ newID = $ this ->effectiveAddOrUpdate ($ this ->injectionClass , $ item , $ values , $ add );
17091707
17101708 if (!$ newID ) {
1711- $ this ->results [ ' status ' ] = self ::WARNING ;
1709+ $ this ->addCheckWarning ( self ::WARNING , $ item ::class) ;
17121710 } else {
17131711 //Store id of the injected item
17141712 $ this ->setValueForItemtype ($ this ->primary_type , 'id ' , $ newID );
17151713
17161714 //If type needs it : process more data after type import
1717- $ this ->processAfterInsertOrUpdate ($ this ->injectionClass , $ add );
1715+ if ($ this ->processAfterInsertOrUpdate ($ this ->injectionClass , $ add ) === false ) {
1716+ $ this ->addCheckWarning (self ::WARNING , $ item ::class);
1717+ }
1718+
17181719 //$this->results['status'] = self::SUCCESS;
17191720 $ this ->results [$ item ::class] = $ newID ;
17201721
@@ -1751,8 +1752,12 @@ public function processAddOrUpdate()
17511752
17521753 $ values = $ this ->getValuesForItemtype ($ itemtype );
17531754 if ($ this ->lastCheckBeforeProcess ($ injectionClass )) {
1754- $ tmpID = $ this ->effectiveAddOrUpdate ($ injectionClass , $ item , $ values , $ add );
1755- $ this ->processAfterInsertOrUpdate ($ injectionClass , $ add );
1755+ $ tmpID = $ this ->effectiveAddOrUpdate ($ injectionClass , $ item , $ values , $ add );
1756+ if (!$ tmpID ) {
1757+ $ this ->addCheckWarning (self ::WARNING , $ itemtype );
1758+ } elseif ($ this ->processAfterInsertOrUpdate ($ injectionClass , $ add ) === false ) {
1759+ $ this ->addCheckWarning (self ::WARNING , $ itemtype );
1760+ }
17561761 }
17571762 }
17581763 }
@@ -1765,6 +1770,20 @@ public function processAddOrUpdate()
17651770 }
17661771
17671772
1773+ /**
1774+ * Flag the current line as partially injected and log the reason
1775+ *
1776+ * @param integer $code log label describing the reason
1777+ * @param string $itemtype itemtype that could not be written
1778+ **/
1779+ private function addCheckWarning (int $ code , string $ itemtype ): void
1780+ {
1781+ $ this ->results ['status ' ] = self ::WARNING ;
1782+ $ this ->results [self ::ACTION_CHECK ]['status ' ] = self ::WARNING ;
1783+ $ this ->results [self ::ACTION_CHECK ][] = [$ code , $ itemtype ];
1784+ }
1785+
1786+
17681787 /**
17691788 * Perform data injection into GLPI DB
17701789 *
@@ -1778,6 +1797,24 @@ public function processAddOrUpdate()
17781797 private function effectiveAddOrUpdate ($ injectionClass , $ item , $ values , $ add = true )
17791798 {
17801799
1800+ //The plugin acts as the front controller here: rights must be checked before writing.
1801+ //Skipped without a session, as the lib is also a programmatic entry point for scripts.
1802+ if (Session::getLoginUserID () !== false ) {
1803+ $ input = is_array ($ values ) ? $ values : [];
1804+ if ($ add ) {
1805+ //Passing the input to can() makes the check cover the target entity
1806+ if (!$ item ->can (-1 , CREATE , $ input )) {
1807+ $ this ->addCheckWarning (self ::ERROR_CANNOT_IMPORT , $ item ::class);
1808+ return 0 ;
1809+ }
1810+
1811+ //On the update path the target id is known, so the per-item check also covers the entity scope
1812+ } elseif (!isset ($ values ['id ' ]) || !$ item ->can ($ values ['id ' ], UPDATE )) {
1813+ $ this ->addCheckWarning (self ::ERROR_CANNOT_UPDATE , $ item ::class);
1814+ return 0 ;
1815+ }
1816+ }
1817+
17811818 //Insert data using the standard add() method
17821819 $ toinject = [];
17831820 $ options = $ injectionClass ->getOptions ();
@@ -1972,7 +2009,6 @@ private function manageRelations()
19722009 $ option ,
19732010 $ option ['linkfield ' ],
19742011 $ value ,
1975- true ,
19762012 );
19772013 }
19782014 }
@@ -2476,15 +2512,17 @@ public static function addTemplateSearchOptions($injectionClass, &$tab)
24762512 * @param PluginDatainjectionInjectionInterface $injectionClass the injection class to use
24772513 * @param $add true if an item is created, false if it's an update
24782514 *
2479- * @return void nothing
2515+ * @return bool false if the injection class rejected a post-processing step
24802516 **/
24812517 private function processAfterInsertOrUpdate ($ injectionClass , $ add = true )
24822518 {
24832519
24842520 //If itemtype implements special process after type injection
24852521 if (method_exists ($ injectionClass , 'processAfterInsertOrUpdate ' )) {
24862522 //Invoke it
2487- $ injectionClass ->processAfterInsertOrUpdate ($ this ->values , $ add , $ this ->rights );
2523+ return $ injectionClass ->processAfterInsertOrUpdate ($ this ->values , $ add , $ this ->rights ) !== false ;
24882524 }
2525+
2526+ return true ;
24892527 }
24902528}
0 commit comments