We have moved to Github. Please open tickets there.

Opened 4 years ago

Closed 4 years ago

#1114 closed Defect (fixed)

REST api: POST to REST API

Reported by: thomas Owned by:
Priority: high Milestone:
Component: API Version: 1.5
Severity: major Keywords: rest api post
Cc: ben, ticean@…, cash.costello.nospam@… Difficulty:

Description

Hello,

yesterday I tested the REST-API with GET-parameters. It works gerat. Now im trying to handle POST-Data with the REST-API.

I implemented this function:

expose_function("myapi.test", "test_import", array(
"username" => array(type => "string", required => false),
"password" => array(type => "string", required => false),
"email" => array(type => "string", required => false)
), "imports an profile", "POST", false, true);

function test_import($username, $password, $email) {

do something

}

But the Api will only return "Missing parameter username in method myapi.test exception 'APIException' with message..."

But the Data is available in $_POST[] and also get_input(). So in my opinion there are two Bugs

  1. I set required to true, and then the parameter was optional.
  2. POST-Data is not prcessed correctly.

Change History (20)

comment:1 Changed 4 years ago by twall

Consider this a vote to fix. Apparently no one is using POST with the REST API and there are likely no tests for it.

I ran into the same issue; digging further it seemed that get_input() does not have the $_POST parameters available at the time the method is dispatched and the error generated. This is likely due to the pagehandler trampoline improperly forwarding all inputs (a related bug has the pagehandler dropping all array inputs).

comment:2 Changed 4 years ago by twall

The problem is that the parameters are obtained via get_parameters_from_method in api.php, which looks at $CONFIG->input for its parameters. $CONFIG->input does not contain any of the $_POST parameters (nor apparently is it intended to, since get_input() falls back to checking $_REQUEST if a requested input is not found in $CONFIG->input).

In the context of the REST API, it might make sense to call get_input() with the set of parameters defined by the method, rather than the set of inputs contained in $CONFIG->input.

comment:3 Changed 4 years ago by twall

Replace $CONFIG->input with $METHODS[$method]parameters? in line 325 of api.php

comment:4 Changed 4 years ago by tbenn

I am having the exact same issues. GET params work fine, but POST always fails. I have tried changing the code as indicated in the ticket notes with no success.

Thomas were you able to get this working? Any help is much appreciated.

comment:5 Changed 4 years ago by tbenn

  • Cc ticean@… added

comment:6 Changed 4 years ago by twall

I replaced the line in engine/api.php:get_parameters_for_method:

foreach ($CONFIG->input as $k => $v)

with:

$params = $CONFIG->input;
if (is_array($METHODS[$method]['parameters']))
  $params = $METHODS[$method]['parameters'];
foreach ($params as $k => $v)

and POSTs to the REST API no longer fail with an arguments missing error.

comment:7 Changed 4 years ago by tbenn

Thanks, twall. That worked.

I would like to submit another vote to fix. This is a real landmine for anyone wishing to use POST with the API.

comment:8 Changed 4 years ago by cash

  • Cc cash.costello.nospam@… added

comment:9 Changed 4 years ago by cash

Are you using only anonymous methods? Your modifications to get_parameters_for_method() should break user authentication and api authentication. The hmac check needs the method name in the parameter list and user authentication needs the token. Neither of those will be in $METHODS[$method]parameters?

comment:10 Changed 4 years ago by twall

No, they are not anonymous, but they *are* being called via AJAX, so the auth information is probably being obtained from the user's browser session.

comment:11 Changed 4 years ago by cash

Makes sense. pam_auth_session() is used for authentication in your case. Anyone who is trying to use pam_auth_hmac() or pam_auth_usertoken() will need a different fix.

The above fix also breaks optional parameters that have a default value set in the function declaration. This is independent of authentication method.

comment:12 Changed 4 years ago by tbenn

I am using pam_auth_hmac() and it is definitely breaking.

I am submitting to the API via a Flash SWF that will be on an Elgg page. HMAC is actually not the best authentication in my case anyway, and I would rather have user or session authentication, but I'm not sure how to submit those via Flash. Asking for user credentials on submit is out of the question.

Any suggestions, or alternative solutions?

comment:13 Changed 4 years ago by twall

Perhaps the following (replacing $_POST with $_GET if the method type demands it). POST parameters take priority over cookies, and explicitly set input (via set_input) overrides any POST parameters. Alternatively, if the request_order setting is important, then the merge should be done according to that.

$params = array_merge($_COOKIE, $_POST, $CONFIG->input);

comment:14 Changed 4 years ago by cash

No, the reason it is breaking is because hmac requires the method name be included in the parameter array created by get_parameters_for_method(). The fix up above excludes the method name.

I know nothing about Flash so I can't help much there. pam_auth_session() uses the PHP session cookie to validate against (though the isloggedin() function).

Basing it off pam_auth_usertoken() seems reasonable. Normally you pass in username and password and get back a token that can be used using the auth.gettoken REST call. You'd have to create a new method for generating the token and giving it to your flash code. Then pass that token in as a parameter (POST or GET).

comment:15 Changed 4 years ago by tbenn

OK. Thanks Cash. I created a plugin to generate a auth token automatically when a user logs into the site. This is passed in the Flash request.

This works great, only it seems that when the login is performed it kills the user's existing browser session. Can you think of any way that I can link the API session and the browser session?

I apologize, I know this isn't a forum but there's not much info available elsewhere.

comment:16 Changed 4 years ago by twall

I've actually run into a similar situation where I effectively need to "copy" credentials to another client. I'm also interested in a solution that doesn't destroy the original session.

comment:17 Changed 4 years ago by cash

Forgot about Elgg's session handling quirks. I think Elgg is misusing the session code parameter when people aren't clicking "remember me" in the login box. I keep intending to submit something on this and never get around to it. Let's assume that doesn't get fixed.

Do you need the user to be logged in on the receiving side of the Flash calls? If not, you could implement your own authentication handler and base it on pam_auth_usertoken but not log the user in. Just use it to authenticate that specific session and attach the session variable to the user as metadata.

If you need the user logged in, you need to maintain the same session. This means you need to pass the cookie that has the PHPSESSID parameter (or as a GET parameter if your hosting setup allows that). The HTTP_USER_AGENT has to be maintained also. I think that's it.

comment:18 Changed 4 years ago by cash

  • Summary changed from POST to REST API to REST api: POST to REST API

Adding REST api to the title of all REST related tickets so they are easier to find.

comment:19 Changed 4 years ago by cash

Tim and others: please check out my survey on REST here: http://groups.google.com/group/elgg-development/browse_thread/thread/419de9d6cfa6ef06

If all goes well we should have a new REST implementation in a few weeks.

comment:20 Changed 4 years ago by cash

  • Resolution set to fixed
  • Status changed from new to closed

Fixed in [svn:3562] - post parameters now loaded into $CONFIG->input

Note: See TracTickets for help on using tickets.