Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix(Core): Add entities_id and is_recursive fields to correctly filter data from the API #858

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

stonebuzz
Copy link
Contributor

@stonebuzz stonebuzz commented Nov 19, 2024

Checklist before requesting a review

Please delete options that are not relevant.

  • I have performed a self-review of my code.
  • I have added tests (when available) that prove my fix is effective or that my feature works.
  • This change requires a documentation update.

Description

This PR corrects a behaviour identified in the fields plugin. Until now, when calling the API to retrieve one or more containers (https://<FQDN>/apirest.php/PluginFields<BlockName>), the plugin did not correctly check the associated access rights and return all data.

This update introduces a systematic rights check for each container retrieved.

Before checl :

curl -X GET \
-H 'Content-Type: application/json' \
-H "Session-Token: qcs67di01ckfifaktuenldsu3c" \
-H "App-Token: OtWWECjVh4XjCXtxb0qU1yNF9cA3E5xtl8BOMuHx" \
'http://glpi10bf.local/apirest.php/PluginFieldsTickettest/1?expand_dropdowns=true'
{"id":1,"items_id":"Related ticket","itemtype":"Ticket","plugin_fields_containers_id":"test","texttestfield":"test","links":[{"rel":"Ticket","href":"http://glpi10bf.local/api/Ticket/94"},{"rel":"PluginFieldsContainer","href":"http://glpi10bf.local/api/PluginFieldsContainer/3"}]}%  

After :

curl -X GET \
-H 'Content-Type: application/json' \
-H "Session-Token: qcs67di01ckfifaktuenldsu3c" \
-H "App-Token: OtWWECjVh4XjCXtxb0qU1yNF9cA3E5xtl8BOMuHx" \
'http://glpi10bf.local/apirest.php/PluginFieldsTickettest/1?expand_dropdowns=true'
["ERROR_RIGHT_MISSING","You don't have permission to perform this action."]%       
  • It fixes !35164

Screenshots (if appropriate):

@stonebuzz stonebuzz self-assigned this Nov 19, 2024
@stonebuzz stonebuzz added the bug label Nov 19, 2024
Copy link
Contributor

@orthagh orthagh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems ok.
Are you sure this doesn't break anything in the UI ?

@stonebuzz
Copy link
Contributor Author

Sorry, I forgot an important point about PR

Check that the current user has access to the entity of the main itemtype linked to the fields

The first commit only checks read / update rights

The latter also takes into account the entity of the main itemtype and checks whether the current user has rights to the entity.

From the GUI this part is delegated to GLPI (If I have the right to see the ticket, I therefore have the right to see the associated fields), but from the API the entry point is not the Ticket (http://.../apirest.php/Ticket/<ID_Ticket>) but the container (https://<FQDN>/apirest.php/PluginFields<BlockName>) so we need to check whether the current user has the right to see the associated fields.

@AdrienClairembault
Copy link
Contributor

You don't need any rights to purge outside of API ?

@stonebuzz
Copy link
Contributor Author

stonebuzz commented Nov 19, 2024

You don't need any rights to purge outside of API ?

No because there is no dedicated interface via GLPI, fields are accessed via the main itemtype.

Fields are purged when the main item type is purged.

@AdrienClairembault
Copy link
Contributor

Maybe it should return false then if the action is never possible, it avoid potential mistakes.

@stonebuzz
Copy link
Contributor Author

Maybe it should return false then if the action is never possible, it avoid potential mistakes.

indeed, it's work like a charm

@AdrienClairembault
Copy link
Contributor

A bit late to change that but maybe it should have been an CommonDBChild ? Checking that the parent entity is visible is something that it can handle without extra code.

@stonebuzz
Copy link
Contributor Author

Major changes :

canUpdateItem and canViewItem works well when API do an getItem() (when the ID is specified in the API call)

But when the API doesn't receive a specific ID

curl -X GET \
 -H 'Content-Type: application/json' \
 -H "Session-Token: tsjhf16rgf68v7e1j7sap27kec" \
 -H "App-Token: eKVwtoTF4rMhg1m8rSAEuvOMcZNmneMNPM08D4P2" \
'http://127.0.0.1/GLPI/10.0-bugfixes/apirest.php/PluginFieldsTickettest' | jq

a getItems is performed (find()) and GLPI only check canView (static method) (in my case, I do have rights to the tickets (but not to the root entity))

as I haven't found a way to deal with this case in detail, I suggest looking at
$_SERVER['PATH_INFO'] if an ID is specified (and if I'm calling from the API) in order to refuse the display of all container entries.

I agree it's not “clean”, but I don't see any other solution.

@stonebuzz
Copy link
Contributor Author

Another major change (hopefully the last)

1. Change in Class Inheritance

Before: The PluginFieldsAbstractContainerInstance class extended CommonDBTM.
After: The class now extends CommonDBChild.

This allows data to be filtered automatically via the GLPI API, taking into account authorizations on the parent (entity / right).


2. Overloads of the addNeededInfoToInput Method

Native function relies on the static property static::$plugins_forward_entity,
which should be populated using the following method (from setup.php):

Plugin::registerClass(
    PluginFields<Itemtype><name>,
    ['forwardentityfrom' => <Itemtype>]
);

However, the order in which plugins are loaded can affect the behavior.
For example, if a container is defined on a GenericObject itemtype and
the Fields plugin initializes before the GenericObject plugin, the
itemtype for the container will not yet exist, leading to potential issues.

Modification of this function to meet specific requirements.


3. Database Migrations for entities_id and is_recursive from the template (container.class.tpl)

  • Two new fields are added to the database:
    1. entities_id: A foreign key representing entity assignment.
    2. is_recursive: A boolean field indicating if the relationship is recursive.
  • These fields are added conditionally:
    • entities_id is added only if the associated item type requires entity assignment (isEntityAssign()).
    • is_recursive is added only if the item type supports recursive behavior (maybeRecursive()).
  • Both fields are populated using data migration logic, ensuring consistency with existing records.

@stonebuzz stonebuzz changed the title Fix(Core): check UPDATE / VIEW right from API Fix(Core): Add entities_id and is_recursive fields to correctly filter data from the API Nov 22, 2024
@stonebuzz
Copy link
Contributor Author

Here’s a summary of the three API calls and their behaviors:

1. First API Call

curl -X GET \
 -H 'Content-Type: application/json' \
 -H "Session-Token: dhkc65d0ajq1rfbvnlnedo4meu" \
 -H "App-Token: eKVwtoTF4rMhg1m8rSAEuvOMcZNmneMNPM08D4P2" \
'http://127.0.0.1/GLPI/10.0-bugfixes/apirest.php/PluginFieldsComputertata' | jq

This call retrieves a list of all items in the PluginFieldsComputertata resource.
It only returns the items that the user has access to.

[
  {
    "id": 15,
    "items_id": 77,
    "itemtype": "Computer",
    "plugin_fields_containers_id": 8,
    "entities_id": 2,
    "is_recursive": 1,
    "testfieldthree": "sdfsdfsdf",
    "links": [
      {
        "rel": "Computer",
        "href": "http://127.0.0.1/GLPI/10.0-bugfixes/api/Computer/77"
      },
      {
        "rel": "PluginFieldsContainer",
        "href": "http://127.0.0.1/GLPI/10.0-bugfixes/api/PluginFieldsContainer/8"
      },
      {
        "rel": "Entity",
        "href": "http://127.0.0.1/GLPI/10.0-bugfixes/api/Entity/2"
      }
    ]
  }
]

2. Second API Call

curl -X GET \
 -H 'Content-Type: application/json' \
 -H "Session-Token: dhkc65d0ajq1rfbvnlnedo4meu" \
 -H "App-Token: eKVwtoTF4rMhg1m8rSAEuvOMcZNmneMNPM08D4P2" \
'http://127.0.0.1/GLPI/10.0-bugfixes/apirest.php/PluginFieldsComputertata/15' | jq
  • Description: This call fetches a specific item (id: 15) from the PluginFieldsComputertata resource.
  • Behavior: The API successfully returns the details of the requested item since it belongs to an entity the user has permission to access (entities_id: 2).
{
  "id": 15,
  "items_id": 77,
  "itemtype": "Computer",
  "plugin_fields_containers_id": 8,
  "entities_id": 2,
  "is_recursive": 1,
  "testfieldthree": "sdfsdfsdf",
  "links": [
    {
      "rel": "Computer",
      "href": "http://127.0.0.1/GLPI/10.0-bugfixes/api/Computer/77"
    },
    {
      "rel": "PluginFieldsContainer",
      "href": "http://127.0.0.1/GLPI/10.0-bugfixes/api/PluginFieldsContainer/8"
    },
    {
      "rel": "Entity",
      "href": "http://127.0.0.1/GLPI/10.0-bugfixes/api/Entity/2"
    }
  ]
}

3. Third API Call

curl -X GET \
 -H 'Content-Type: application/json' \
 -H "Session-Token: dhkc65d0ajq1rfbvnlnedo4meu" \
 -H "App-Token: eKVwtoTF4rMhg1m8rSAEuvOMcZNmneMNPM08D4P2" \
'http://127.0.0.1/GLPI/10.0-bugfixes/apirest.php/PluginFieldsComputertata/16' | jq
  • Description: This call attempts to retrieve another specific item (id: 16).
  • Behavior: The API returns an error:
[
  "ERROR_RIGHT_MISSING",
  "You don't have permission to perform this action."
] 

This indicates that the item (id: 16) belongs to an entity the user does not have access to, so it is not visible.

@AdrienClairembault
Copy link
Contributor

Are the new entities_id and is_recursive fields just a copy of the value form the container table ?
What happens if the value in the container table change ?

@stonebuzz
Copy link
Contributor Author

the new entities_id and is_recursive fields are simply a copy of the corresponding itemtype value

@flegastelois
Copy link
Contributor

@stonebuzz I get these errors when I try to add a computer with a fields.

[2024-11-26 14:38:55] glpiphplog.WARNING:   *** PHP Warning (2): Trying to access array offset on false in 10bf/htdocs/marketplace/fields/inc/container.class.php at line 1248
  Backtrace :
  marketplace/fields/inc/container.class.php:1616    PluginFieldsContainer->updateFieldsValues()
  src/Plugin.php:1713                                PluginFieldsContainer::postItemAdd()
  src/CommonDBTM.php:1397                            Plugin::doHook()
  front/computer.form.php:54                         CommonDBTM->add()
  public/index.php:82                                require()
  
[2024-11-26 14:38:55] glpiphplog.CRITICAL:   *** Uncaught Exception TypeError: array_diff_key(): Argument #1 ($array) must be of type array, false given in 10bf/htdocs/marketplace/fields/inc/container.class.php at line 1325
  Backtrace :
  marketplace/fields/inc/container.class.php:1325    array_diff_key()
  marketplace/fields/inc/container.class.php:1247    PluginFieldsContainer::constructHistory()
  marketplace/fields/inc/container.class.php:1616    PluginFieldsContainer->updateFieldsValues()
  src/Plugin.php:1713                                PluginFieldsContainer::postItemAdd()
  src/CommonDBTM.php:1397                            Plugin::doHook()
  front/computer.form.php:54                         CommonDBTM->add()
  public/index.php:82                                require()

templates/container.class.tpl Show resolved Hide resolved
templates/container.class.tpl Show resolved Hide resolved
stonebuzz and others added 2 commits December 3, 2024 11:33
Co-authored-by: Cédric Anne <[email protected]>
Co-authored-by: Cédric Anne <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants