The OData Server module integrates a third-party library called the OData PHP Producer, along with Drupal's Field API to expose all Drupal entities via an OData v2 compliant web service. Installation procedures are noted in README.txt.

OData, for those unfamiliar, is a specification for RESTful web services: http://www.odata.org/

The OData Server module is designed to expose all entities and all core fields (and a few contrib fields like Date) using the OData PHP Producer library to parse requests according to the OData specification, at which point requests are translated into EntityFieldQueries. Results are then serialized and delivered by the OData PHP Producer library.

An administration screen under admin/config/development/odata allows administrators to select precisely which bundles, properties, and fields to expose.

Project Page: http://drupal.org/sandbox/r2integrated/1561302

Git:

git clone --recursive --branch 7.x-1.x http://git.drupal.org/sandbox/r2integrated/1561302.git odata_server
cd odata_server
CommentFileSizeAuthor
#9 drupalcs-result.txt12.01 KBklausi
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Eyal Shalev’s picture

Status: Needs review » Needs work

@r2integrated,

There is a sum of Drupal coding standards errors found using ventral.org you can view them with this link.

Things I recommend fixing first (by priority):

  1. test_candidate/classes/ODataServer.php: line 64, "Using eval() or drupal_eval() in your module's code could have a security risk if the PHP input provided to the function contains malicious code."
  2. classes/entities_template.inc: The "?>" PHP delimiter at the end of files is discouraged, see http://drupal.org/node/318#phptags
  3. It seems that your not using short function descriptions. These comments can be very helpful later on when you need to debug something and don't remember what every single function do. see Doxygen and comment formatting conventions
r2integrated’s picture

@Eyal Shalev

Thanks for checking things out - I have (before submitting the project for review) run the module through the PAreview script and can confirm I have seen item 2 in the past, however I believe the review script is incorrect, which I've noted below.

  1. This is part of the dynamic code generation system that builds classes that the OData PHP Producer library uses. The library needs real, defined classes with which to work, which therefore means using eval(). The code being passed to eval(), however, contains only machine-generated content (with the exception of the bundle and field names, which must follow strict naming conventions anyway), so I don't see any security issues.
  2. There is, in fact, no closing "?>" tag at the *end* of the file. There are closing tags throughout the middle of the file though. These closing tags are necessary for this particular functionality to work as designed.
  3. I'm not using the short form because I'm using the long form to provide more documentation than the short form would. Not sure why this is listed as an issue.

Please let me know if I have misunderstood any of the issues you posted or if you find any other issues. Thank you very much for helping this get through the review process!

Patrick

r2integrated’s picture

Status: Needs work » Needs review
vaibhavjain’s picture

Status: Needs review » Needs work

please rectify the issues stated in automation testing - http://ventral.org/pareview/httpgitdrupalorgsandboxr2integrated1561302git

patrickd’s picture

Status: Needs work » Needs review

fixing all coding standard issues is NOT mandatory - DON'T change to needs work without explanation/major issues

r2integrated’s picture

Priority: Normal » Major

Elevating priority in accordance with guidelines on http://drupal.org/node/539608

klausi’s picture

Assigned: Unassigned » klausi
dman’s picture

Status: Needs review » Needs work

Good clear introduction and summary of what the module does and how. It's surprising how many applications leave us guessing from the beginning :-)

/**
  * Make sure SDK is installed properly, and if not, inform the user additional
  * actions are required.
  */
function odata_server_enable() {

.. This can and should be done using the hook_requirements() instead. When used, this allows the enable process to prevent installation (if that's what you are trying to do), and also helps by providing status reports as well, that confirm when things are good, even if you move servers etc later.
Good on you for checking though!

Thanks for using the libraries API, it's a good way to be doing this.

I can't fully evaluate all the functionality of the code by tracing it in my head and also understanding the API you are interacting with, but it looks well structured, very well documented and very consistent.

It's not clear to me where, how, or if, access controls are checked. Does this respect field privacy, unpublished content and restriction by role? This is the first security concern in the service as described.

Looking at things like DrupalQueryProvider.php, I can tell you've taken a very robust approach, and clearly know what you are doing there. Perhaps a summary of the extent to which this service respects normal Drupal access controls would be helpful. Is there any expected authentication to read from this service? I see no API key code or anything except

'access arguments' => array('access content'),

in that respect. Maybe I just can't see where to look for that.
If "security" is totally out-of-scope, please make that very clear. We can't have modules that inadvertently make private information public when enabled.

...

Small niggles :

I get the feeling there are cleaner ways of doing this though: ( odata_server_settings() )

     require_once drupal_get_path('module', 'odata_server') . '/classes/ODataServer/Utils/ClassAutoLoader.php';
     ClassAutoLoader::register(array(
         __DIR__ . '/../classes',
         DRUPAL_ROOT . '/../' . $library['library path'] . '/library')
     );

This (and things like it) should be passed through t() as a matter of course. Preferably without markup.

$form['permissions']['info'] = array(
  '#markup' => '<p>Pick which bundles, properties, fields, and references should be exposed through the OData server.</p>',
);
  '#markup' => '<p>' . t('Pick which bundles, properties, fields, and references should be exposed through the OData server.' . '</p>'),

I'd be interested in really trying this whole out, but it looks like a large job to spin up. Is there a way to test it, or a demo you could recommend as an example of how this odata works, or can you describe how you are using it currently?

Code-review-wise:
It's just important If you can let us know what's happening (or not) with security and/or maybe provide *some* sort of authentication layer (Drupal roles probably won't be appropriate for REST, so maybe an API key or IP lock)

klausi’s picture

Assigned: klausi » Unassigned
Priority: Major » Normal
FileSize
12.01 KB

Review of the 7.x-1.x branch:

This automated report was generated with PAReview.sh, your friendly project application review script. You can also use the online version to check your project. You have to get a review bonus to get a review from me.

manual review:

  1. odata_server_enable(): that should be hook_requirements().
  2. odata_server_libraries_info(): example.com?
  3. "'access arguments' => array('access administration pages'),": The administration menu callback should probably use "administer site configuration" - which implies the user can change something - rather than "access administration pages" which is about viewing but not changing configurations. Or use your own permission.
  4. " module_load_include('inc', 'odata_server', 'inc/odata_server_odata_field_info');": Also, no need to use module_load_inlcude as you are including files from your own module which you already know where they are. Use something like require_once 'mymodule.inc';. Also elsewhere.
r2integrated’s picture

Thanks guys, tons of feedback! @dman, I'll need to take some time reviewing everything, but off the bat, I'm having difficulties with your suggestion of using hook_requirements. The libraries module is not picking up on my hook_libraries_info implementation and so I can't check for the odata library during the install phase in hook_requirements. Apparently module_implements doesn't work during this phase of the bootstrap if the module has not been installed? I can still use it during the runtime phase, but I believe I need to leave my hook_enable implementation, unless I'm missing something. Any ideas?

dman’s picture

Yeah, I guess I can see why the library func would not be available before the module is activated.
A reasonably common pattern is for a .install hook to module_load_include() its own module file when needed (during the first .install, the .module isn't loaded yet) and then usually that has any requirements check function needed there.
BUT ... yeah, it's not going to work well on a library (under libraries API) that the module provides itself. It's a puzzler.
Will work fine if doing hook_requirements(runtime) I'd imagine, but install-time... may have to do a work-around of some type. I can't think of a short answer.
Maybe they will have an idea or example in the libraries issue queue.

r2integrated’s picture

So, I've checked the Libraries API issue queue and it would seem that this is a known issue which is still not fixed as of the stable 7.x-2.0 release (issue was discovered last year). I'm tempted to only check the library's presence during the runtime bootstrap phase in hook_requirements(). I could also issue a drupal_set_message() to indicate to the user that something isn't working right. Any thoughts?

r2integrated’s picture

Status: Needs work » Needs review

I've committed my latest, fixing issues identified by @klausi and @dman. Known remaining issues:

  • "The "?>" PHP delimiter at the end of files is discouraged" will continue to show in a Drupal CS run (this is a bug in Drupal CS IMO).
  • hook_requirements() will only check for library installation at runtime, not during install. This is a limitation with the Libraries API module.

Regarding security, this module is designed to be as generic as possible. It therefore doesn't make any assumptions about node visibility. "Status" is just another property to this module, so unpublished and published nodes will be visible. Ultimately, admins are responsible for exposing only the entities/bundles, properties, and fields that are appropriate. I think the idea of an API key is excellent and fully intend on exploring that and other options for 7.x-2.0. That said, I consider 7.x-1.0 to be feature complete. In the README I have a brief discussion of security considerations but would be more than happy to expand on it or explain in other locations the module's security impact.

dman’s picture

Sounds like a runtime requirements check is the most practical at this time. Thanks for looking in to it.

It's good you are considering the security aspect. Personally, I think that the built-in access controls we expect to work - "published" and "role can view content" MUST be respected by default. Any module that was found in the repository that failed to do so would have a security issue raised against it immediately. So a note on the README is not enough. The project page must loudly announce that installing this module would make previously private data public. Sorry, but it is a big deal, so make a clear disclaimer - and in the interim until this can be applied, mark the current release as "requires bad_judgement" Thats what bad_judgement is for - to mark a module as an insecure thing that you probably should not put on a real live site as-is

r2integrated’s picture

Hrmm, I'm thinking that given the choices of either respecting the status property on nodes OR going out of my way to scare potential users of the module, I think it's more desirable to just respect the status property ;)

I'll implement this special case shortly. Can you think of any other entities I should handle specially? Should I also respect the status property on users? I'm thinking yes, for consistency's sake at least.

dman’s picture

There are a number of access check APIs for the core entities - node_access() etc which are the ones to use. When using Drupal like a data service without authentication, the default will be what is available to the anon user. Don't check the published yourself, but use these if possible. Access permissions rapidly can be modified by other processes, so this API func is the one to trust. I don't know if any support for other new entities is available.

r2integrated’s picture

Excellent point on node_access(), but I'm not sure the query system can directly use this as it would interfere with result pagination. In this module we're using EntityFieldQuery, and I believe there are some permissions checks at this level at least for node entities.

chx’s picture

Do you need help with EntityFieldQuery?

r2integrated’s picture

@chx - I would love some feedback and guidance, thanks! The outstanding issue it would seem is node_access compliance. I'm not sure that queries done at such a low level, like in this module, can benefit from this hook. Any thoughts?

a_thakur’s picture

Status: Needs review » Needs work

Manual Review:
# README.txt: looks good
# odata_server.info: Why a blank line on line#6.
There are not a blockers.

# But in the file odata_server.admin.inc

function odata_server_settings($form, &$form_state) {

}

At various places in this file, you have used variable_get() to asssign #default_value to form elements, so these variables would be stored in the database, but these variables have to be deleted when the module is uninstalled, so the implementation of hook_uninstall() is required in the odata_server.install file which would use variable_del() to delete these variables.

/**
 * Implements hook_uninstall().
 */
function odata_server_uninstall() {
  $vars = db_query("SELECT name FROM {variable} WHERE name LIKE 'odataserver- permissions-%'")->fetchCol();
  foreach ($vars as $var) {
    variable_del($var);
  }
}

This would delete all the variables created.

More review..need some time to understand the code a bit more..

r2integrated’s picture

Status: Needs work » Closed (fixed)

Thanks @a__thakur, please follow development on the issue tracker for the sandbox project. I'm closing this issue as we've successfully completed a review for another module of ours.

a_thakur’s picture

Please make sure to change the status in that case, as reviewers usually pick up the issues which have "need review" status..