»3. Challenge / Response

Another way to authenticate your client is to build a hex digest consisting of the user's password and a challenge as issued by the server. This is currently known as auth_method “challenge”.

Essentially, you generate a challenge by issuing a blank request to the getchallenge method. If your method call is successful you're given:

string auth_scheme
You can ignore this for now. By default this is the highest version of our authentication schemes, if in the future if we implement other auth schemes or change the default. In that case we'd add a new capabilities exchange: your client could say, "I know c0 and c1", and our server would then say, "Use c1, it's the best."
string challenge
challenge is an opaque cookie, as generated by ???. Challenges may only be used once.
int expire_time
expire_time is the expiration time for the challenge as measured in seconds since the Unix epoch.
int server_time
servertime is the time of when the challenge was generated, as measured in seconds since the Unix epoch. The formula (server_time - expire_time) is the life span of the challenge, in seconds.

For your response, you then build a MD5 hex digest of the formula (challenge + MD5_hex(password)). To authenticate your client now, you simply send back the following 3 parameters, along with your username:

string auth_method
Set to ‘challenge’
string auth_challenge
The challenge issued by the server
string auth_response
MD5_hex(challenge + MD5_hex(password))

Example 9.2. Sample Perl script using getchallenge

use strict;
use Fcntl;
use XMLRPC::Lite;
use Data::Dumper;
use Digest::MD5 qw(md5_hex);

my $xmlrpc = new XMLRPC::Lite;
$xmlrpc->proxy("http://www.lj.com/interface/xmlrpc");
my $get_chal = xmlrpc_call("LJ.XMLRPC.getchallenge");
my $chal = $get_chal->{'challenge'};

my $user = "test";
my $pass = "pass";
print "chal: $chal\n";

my $response = md5_hex($chal . md5_hex($pass));

my $login = xmlrpc_call('LJ.XMLRPC.login', {
        'username' => $user,
        'auth_method' => 'challenge',
        'auth_challenge' => $chal,
        'auth_response' => $response,
});

print Dumper($login);

sub xmlrpc_call {
    my ($method, $req) = @_;
    my $res = $xmlrpc->call($method, $req);
    if ($res->fault) {
        print STDERR "Error:\n".
        " String: " . $res->faultstring . "\n" .
        " Code: " . $res->faultcode . "\n";
        exit 1;
    }
    return $res->result;
}