PDA

View Full Version : no_permission when creating user through mobile API


elieseif
04-13-2020, 05:30 PM
SOLVED: See posts #4 (https://vborg.vbsupport.ru/showpost.php?p=2602572&postcount=4) and #5 (https://vborg.vbsupport.ru/showpost.php?p=2602593&postcount=5)

The call to api.init generates the required access token, client id, secret, and api version, but the call to user.save is returning an no_permission error.
Using vBCloud 5.6.0

Here's the code snippet to api.init:
$requestparams = array(
'api_m' => 'api.init',
'clientname' => 'Client',
'clientversion' => '1.0',
'platformname' => 'Platform',
'platformversion' => '1.0',
'uniqueid' => 'XXXX'
);

// cURL
$url = 'https://myforum.com/api.php';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($requestparams));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$curl_response = curl_exec($ch);
curl_close($ch);

$curl_response_array = json_decode($curl_response,true);

// API
$apiaccesstoken = $curl_response_array['apiaccesstoken'];
$apiclientid = $curl_response_array['apiclientid'];
$apisecret = $curl_response_array['secret'];
$apiversion = $curl_response_array['apiversion'];

And the call to api.save:
// User
$user = array(
'username' => "Test",
'email' => "test@test.com",
'usergroupid' => "14"
);

// Sort GET params by key
ksort($user);

// The HTTP GET params for an API method
// (without api related params except api_m. see below)
$requestparams = array(
'api_m' => 'user.save',
'userid' => '0',
'password' => '123',
'user' => $user,
'options' => '',
'adminoptions' => '',
'userfield' => ''
);

// Sort GET params by key
ksort($requestparams);

// The correct signature is the md5 value of $data + accesstoken + clientid + secret + apikey
// (all can be fetched from api_init except apikey
// -- this is a value specific to the vB site you are trying to connect to and can be found in the admincp)
$requestparams_string = http_build_query($requestparams);
$apisignature = md5($requestparams_string.$apiaccesstoken.$apiclie ntid.$apisecret.$apikey);

$requestparams['api_s'] = $apiaccesstoken;
$requestparams['api_sig'] = $apisignature;
$requestparams['api_v'] = $apiversion;

// cURL
$url = 'https://myforum.com/api.php';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($requestparams));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$curl_response = curl_exec($ch);
curl_close($ch);

$curl_response_array = json_decode($curl_response,true);

Here's the generate query string for the api.save call (I've replaced the hash strings with XXX):
adminoptions=&api_m=user.save&options=&password=123&user%5Bemail%5D=test%40test.com&user%5Busergroupid%5D=14&user%5Busername%5D=Test&userfield=&userid=0&api_s=XXX&api_sig=XXX&api_v=560

Adding api_c to the user.save method call generates in invalid_api_signature. Otherwise, it's a no_permission error. Also tried logging in as administrator before creating a user and still got the no_permission error.

There's very little documentation on the API, any help would be appreciated?
Thanks

shka
04-13-2020, 08:50 PM
Without login?

Just a guess: api.init, user.login2,api.init (on first page of api docs is written - needed after .login, but after login2?), and then user.save

elieseif
04-13-2020, 09:11 PM
I tried logging in as Administrator after api.init and before api.save, and got both session and cpsession hashes so login was successful, but api.save still gives no_permission.
I also tried calling api.init again after user.login2, no change.

That said, whenever I include api_c in login2 or save method calls, I get "invalid_api_signature". If I remove api_c and keep api_s, api_sig and api_v, I am able to login, but user.save gives the no_permission error.

At this point, I'm out of ideas.

shka
04-15-2020, 12:28 PM
Yepp, api docs are really bad. Solution is the security token getting by login call.
Following example works in my local xammp dev enviroment. I've used loginSpecificUser but also login2 is possible. After login fetchCurrentUserinfo and get username (to check if correct login) and securitytoken.

After that an example for adding an post and adding a user.

You need to change apikey, urlapibase, userid and password for userid

<?php

$requestparams = array(
'api_m' => 'api.init',
'clientname' => 'Muschebuhbuh',
'clientversion' => '1.0',
'platformname' => 'Muschebuhbuh',
'platformversion' => '1.0',
'uniqueid' => 'test123'
);

$urlapibase = 'http://localhost/forum/api.php'; //replace with your url, but don't use .../core/api.php

// cURL
$url = $urlapibase;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($requestparams));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$curl_response = curl_exec($ch);
curl_close($ch);

$curl_response_array = json_decode($curl_response, true);
// API
$apiaccesstoken = $curl_response_array['apiaccesstoken'];
$apiclientid = $curl_response_array['apiclientid'];
$apisecret = $curl_response_array['secret'];
$apiversion = $curl_response_array['apiversion'];

$apikey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; //replace with your generated api key from admincp
echo '-------------- first init -----------------';
echo 'apiaccesstoken : ';
var_dump($apiaccesstoken);
//echo 'curl_response_array : ';
//var_dump($curl_response_array2);


// you can use also user.login or user.login2, but with other params
$requestparams = array(
'api_m' => 'user.loginSpecificUser',
'userid' => 1, // change userid for login
'passwords' => array(
'password' => 'xxxxxxx', // password for userid
'md5password' => md5('xxxxx'), //same password
'md5password_utf' => ''
),
'extraAuthInfo' => array(
'mfa_authcode' => ""
),
'logintype' => 'cplogin'
);
ksort($requestparams);
$requestparams_string = http_build_query($requestparams);
$url = $urlapibase.'?'.$requestparams_string;
$apisignature = md5($requestparams_string.$apiaccesstoken.$apiclie ntid.$apisecret.$apikey);

$requestparams['api_s'] = $apiaccesstoken;
$requestparams['api_sig'] = $apisignature;
$requestparams['api_v'] = $apiversion;
$requestparams['api_c'] = $apiclientid;

// cURL
define("COOKIE_FILE", "cookie.txt");

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_COOKIEJAR, COOKIE_FILE);
curl_setopt($ch, CURLOPT_COOKIEFILE, COOKIE_FILE);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($requestparams));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$curl_response = curl_exec($ch);
$curl_response_array = json_decode($curl_response, true);
curl_close($ch);


$remember_me = $curl_response_array['password'];
$sessionhash = $curl_response_array['sessionhash'];
$cpsession = $curl_response_array['cpsession'];

echo '-------------- login user -----------------';
echo 'curl_response_array : ';
var_dump($curl_response_array);
// echo 'remember_me : ';
// var_dump($remember_me);
// echo 'sessionhash : ';
// var_dump($sessionhash);
// echo 'cpsession : ';
// var_dump($cpsession);



// fetch User Info
$requestparams = array(
'api_m' => 'user.fetchCurrentUserinfo'
);
ksort($requestparams);
$url = $urlapibase.'?'.http_build_query($requestparams);
$requestparams_string = http_build_query($requestparams);
$apisignature = md5($requestparams_string.$apiaccesstoken.$apiclie ntid.$apisecret.$apikey);

$requestparams['api_s'] = $apiaccesstoken;
$requestparams['api_sig'] = $apisignature;
$requestparams['api_v'] = $apiversion;
$requestparams['api_c'] = $apiclientid;


// cURL
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($requestparams));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
$curl_response = curl_exec($ch);
$information = curl_getinfo($ch);
curl_close($ch);

$curl_response_array = json_decode($curl_response, true);
echo '--------------- fetch user info ----------------';
//echo 'header information : ';
//var_dump($information);
//echo 'curl_response_array : ';
//var_dump($curl_response_array);
echo 'username : (should be the logged in username)';
var_dump($curl_response_array['username']);
echo 'securitytoken : ';
var_dump($curl_response_array['securitytoken']);

$securitytoken = $curl_response_array['securitytoken'];



// Content add
$requestparams = array(
'api_m' => 'content_text.add',
'data' => array(
'rawtext' => "Content for Content_Title 14",
'title' => "Content_Title 14",
'parentid' => 3,
'userid' => 1
),
'options' => array()
);

ksort($requestparams);
$url = $urlapibase.'?'.http_build_query($requestparams);
$requestparams_string = http_build_query($requestparams);
$apisignature = md5($requestparams_string.$apiaccesstoken.$apiclie ntid.$apisecret.$apikey);

$requestparams['api_s'] = $apiaccesstoken;
$requestparams['api_sig'] = $apisignature;
$requestparams['api_v'] = $apiversion;
$requestparams['api_c'] = $apiclientid;
$requestparams['securitytoken'] = $securitytoken;

// cURL
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($requestparams));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
$curl_response = curl_exec($ch);
$information = curl_getinfo($ch);
curl_close($ch);

$curl_response_array = json_decode($curl_response, true);
echo '------------ content add -------------------';
//echo 'header information : ';
//var_dump($information);
echo 'curl_response_array : ';
var_dump($curl_response_array);



// User
$user = array(
'username' => "Test4",
'email' => "test4@test.com",
'usergroupid' => "2"
);

ksort($user);
$requestparams = array(
'api_m' => 'user.save',
'userid' => '0',
'password' => '123',
'user' => $user,
'options' => '',
'adminoptions' => '',
'userfield' => ''
);
ksort($requestparams);
$url = $urlapibase.'?'.http_build_query($requestparams);
$requestparams_string = http_build_query($requestparams);
$apisignature = md5($requestparams_string.$apiaccesstoken.$apiclie ntid.$apisecret.$apikey);

$requestparams['api_s'] = $apiaccesstoken;
$requestparams['api_sig'] = $apisignature;
$requestparams['api_v'] = $apiversion;
$requestparams['api_c'] = $apiclientid;
$requestparams['securitytoken'] = $securitytoken;

// cURL
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($requestparams));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
$curl_response = curl_exec($ch);
$information = curl_getinfo($ch);
curl_close($ch);

$curl_response_array = json_decode($curl_response, true);
echo '------------ add user -------------------';
//echo 'header information : ';
//var_dump($information);
echo 'curl_response_array : ';
var_dump($curl_response_array);

elieseif
04-17-2020, 08:47 AM
Many many thanks. I finally got it to work.

But for anyone who comes across this thread, here's what I discovered.
The call to the api works in GET mode, but not HTTP POST.
It only works in POST mode if you provide the full url with the query parameters in the url and not only as CURLOPT_POSTFIELDS

Both my version of the code and yours work when the HTTP call is modified accordingly, so there was need to fetch the admin and the security token after logging in. The sequence is api.init ---> api.login2 ---> api.save

This is clearly a bug in the api!