Calling API from skin

CyberAlien

Verified User
Joined
Oct 28, 2003
Messages
229
Location
Mars
Hello,

I tried to call API from skin. Instead of authorization i tried to use cookie from current session (used $_ENV['HTTP_COOKIE']) and of course it didn't work because remote ip is different (i got "HTTP/1.1 401 Unauthorized" in reply).

Is there a way to run API commands from skin without knowing user's password?
 
Hello,

Php isn't run like it is via apache. DA is runing the php binary as a person would when using a shell script. DA does pass a few env variables (DOCUMENT_ROOT, USERNAME, USER (same as USERNAME), HOME and SCRIPT_FILENAME), but that's it. You can however get other data from the standard tokens. (|SESSION_ID|)

I believe that CMD_API_GET_SESSION is the only way to get a password right now, and no, there is no way to do it without the password.

John
 
I had asked for a login key we could use in place of a users password. This key would obviously only work when the APIs are used in a skin (when the user has an active session), and the key needs to change for every session.

You'd do something like:

$fsock->set_login($_SERVER['USER'],$_SERVER['LOGINKEY']);

Whereby 'LOGINKEY' is the ENV variable containing our login key.
 
l0rdphi1 said:
I had asked for a login key we could use in place of a users password. This key would obviously only work when the APIs are used in a skin (when the user has an active session), and the key needs to change for every session.

You'd do something like:

$fsock->set_login($_SERVER['USER'],$_SERVER['LOGINKEY']);

Whereby 'LOGINKEY' is the ENV variable containing our login key.
Great idea :)
But instead of using it as password it should be used as some other HTTP header to avoid confusion. And for security reasons i suggest to make it valid for only a minute or so after it was added to ENV and accept it only from localhost.
 
I like the expiration idea. That's good.

But, I don't see why it'd need to be a different header: [pseudocode]

if ( enc(incomging_password) == stored_encpassword )
{ return PASS; }
else if ( enc(incoming_password) == stored_encloginkey )
{ return PASS; }
else { reuturn FAIL; }

There's no case where that breaks.
 
Also, John, can I have an 'SSL' ENV, so I can easily determine whether the user is running DA over an SSL connection?

Can be as simple as: [pseudocode]
%ENV{SSL} = 0 // no ssl
%ENV{SSL} = 1 // ssl

Thanks. ;)
 
Hello,

I just added the SSL=1 or SSL=0 into the env for skins.

I'll look into adding some sort of key system where the key will be passed through the env, and then you pass the session id/key back through the headers. It would only be valid through 127.0.0.1. Not sure how the expiry would work. If it was 1 key per session, then we'd just leave it till the session died. If it were a list of keys, one per command, then we could more easily just expire them as needed (becomes an issue if you have more than 1 command running at once through a few people).

http://www.directadmin.com/features.php?id=362

John
 
Works perfectly with DirectAdmin 1.21.3. Thanks a lot for this feature!

And for people who are interested in using this feature here is simple php function that will do it. First parameter is command like '/CMD_API_SHOW_DOMAINS' (should start with /). Second parameter is array of POST data or false if request is GET. Function will return false on error or message text on success.

Code:
function api_get($cmd, $post = false)
{
	// check post
	if(is_array($post))
	{
		$is_post = true;
		$str = '';
		foreach($post as $var => $value)
		{
			if(strlen($str) > 0)
			{
				$str .= '&';
			}
			$str .= $var . '=' . urlencode($value);
		}
		$post = $str;
	}
	else
	{
		$is_post = false;
	}
	// set headers
	$headers = array();
	$headers['Host'] = '127.0.0.1:' . $_ENV['SERVER_PORT'];
	$headers['Cookie'] = 'session=' . $_ENV['SESSION_ID'] . '; key=' . $_ENV['SESSION_KEY'];
	// add get/post header
	if($is_post)
	{
		$headers['Content-type'] = 'application/x-www-form-urlencoded';
		$headers['Content-length'] = strlen($post);
	}
	// prepare headers
	$send = ($is_post ? 'POST ' : 'GET ') . $cmd . " HTTP/1.1\r\n";
	foreach($headers as $var => $value)
	{
		$send .= $var . ': ' . $value . "\r\n";
	}
	$send .= "\r\n";
	if($is_post && strlen($post) > 0)
	{
		$send .= $post . "\r\n\r\n";
	}
	// connect
	$res = @fsockopen('127.0.0.1', $_SERVER['SERVER_PORT'], &$sock_errno, &$sock_errstr, 3);
	if($sock_errno || $sock_errstr)
	{
		return false;
	}
	// send query
	fputs($res, $send, strlen($send));
	// get reply
	$result = '';
	while(!feof($res))
	{
		$result .= fgets($res, 32768);
	}
	@fclose($res);
	// remove header
	$data = explode("\r\n\r\n", $result, 2);
	if(count($data) == 2)
	{
		return $data[1];
	}
	return false;
}
 
Sorry, didn't see it. But with this function user has to type only one line instead of creating whole class.
 
Back
Top