123 lines
6.2 KiB
XML
123 lines
6.2 KiB
XML
|
<chapter id="ljp.csp.auth">
|
||
|
<title>Authentication in the Client Server Protocol</title>
|
||
|
<section id="ljp.csp.auth.clear">
|
||
|
<title>Clear</title>
|
||
|
<warning><simpara>Although this method is still supported, it is DEPRECATED and should not be used. Client authors
|
||
|
SHOULD use another authentication method if it is available to them.</simpara></warning>
|
||
|
<para>The default authentication method is known as <quote>clear</quote>, which refers to the fact that <literal>password</literal>s
|
||
|
are being sent as plain-text (<quote>in the clear</quote>). Though clients have the ability to encrypt passwords
|
||
|
in a one way hash function (MD5) and send them to the server (as <literal>hpassword</literal>), they are still
|
||
|
vulnerable to replay attacks if the hashed password becomes known.</para>
|
||
|
<para><quote>Clear</quote> authentication occurs when a <literal>username</literal> and either <literal>password</literal>
|
||
|
or <literal>hpassword</literal> is passed to any client server protocol method.</para>
|
||
|
</section>
|
||
|
<section id="ljp.csp.auth.cookies">
|
||
|
<title>HTTP Cookies</title>
|
||
|
<para>If you specify <parameter>auth_method</parameter> with the value of <quote>cookie</quote>, you can use
|
||
|
session cookies generated by the server in your client. To prevent against the usage of modified forms to perform
|
||
|
actions without the consent of the user, we require the <abbrev>HTTP</abbrev> header <literal>X-LJ-Auth</literal>
|
||
|
be set to <quote>cookie</quote> as well.</para>
|
||
|
<example>
|
||
|
<title>Using Wget 1.9 with <literal>auth_method=cookie</literal> in flat protocol</title>
|
||
|
<screen><prompt>$</prompt> <command>wget</command> <option>--post-data "mode=login&user=test&auth_method=cookie"</option> <option>--header "X-LJ-Auth: cookie"</option> <option>--header "Cookie: ljsession=<replaceable>cookieval</replaceable></option> &siteroot;/interface/flat</screen>
|
||
|
</example>
|
||
|
</section>
|
||
|
<section id="ljp.csp.auth.challresp">
|
||
|
<title>Challenge / Response</title>
|
||
|
<para>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 <parameter>auth_method</parameter> <quote>challenge</quote>.</para>
|
||
|
<para>Essentially, you generate a challenge by issuing a blank request to the <methodname>getchallenge</methodname> method. If your
|
||
|
method call is successful you're given:</para>
|
||
|
<variablelist>
|
||
|
<varlistentry>
|
||
|
<term><type>string</type> <returnvalue>auth_scheme</returnvalue></term>
|
||
|
<listitem><simpara>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."</simpara></listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term><type>string</type> <returnvalue>challenge</returnvalue></term>
|
||
|
<listitem><simpara><returnvalue>challenge</returnvalue> is an opaque cookie, as generated by
|
||
|
<xref linkend="ljp.api.lj.get_challenge" />. Challenges may only be used once.</simpara></listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term><type>int</type> <returnvalue>expire_time</returnvalue></term>
|
||
|
<listitem><simpara><returnvalue>expire_time</returnvalue> is the expiration time for the challenge
|
||
|
as measured in seconds since the Unix epoch.</simpara></listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term><type>int</type> <returnvalue>server_time</returnvalue></term>
|
||
|
<listitem><simpara><returnvalue>servertime</returnvalue> is the time of when the challenge was generated,
|
||
|
as measured in seconds since the Unix epoch. The formula (<returnvalue>server_time</returnvalue> -
|
||
|
<returnvalue>expire_time</returnvalue>) is the life span of the challenge, in seconds.</simpara></listitem>
|
||
|
</varlistentry>
|
||
|
</variablelist>
|
||
|
<para>For your response, you then build a MD5 hex digest of the formula (<returnvalue>challenge</returnvalue>
|
||
|
+ MD5_hex(<literal>password</literal>)). To authenticate your client now, you simply send back the following 3
|
||
|
parameters, along with your username:</para>
|
||
|
<variablelist>
|
||
|
<varlistentry>
|
||
|
<term><type>string</type> <parameter>auth_method</parameter></term>
|
||
|
<listitem><simpara>Set to <quote>challenge</quote></simpara></listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term><type>string</type> <parameter>auth_challenge</parameter></term>
|
||
|
<listitem><simpara>The challenge issued by the server</simpara></listitem>
|
||
|
</varlistentry>
|
||
|
<varlistentry>
|
||
|
<term><type>string</type> <parameter>auth_response</parameter></term>
|
||
|
<listitem><simpara>MD5_hex(<returnvalue>challenge</returnvalue> + MD5_hex(<literal>password</literal>))</simpara></listitem>
|
||
|
</varlistentry>
|
||
|
</variablelist>
|
||
|
<example>
|
||
|
<title>Sample Perl script using <methodname>getchallenge</methodname></title>
|
||
|
<programlisting><![CDATA[
|
||
|
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;
|
||
|
}]]>
|
||
|
</programlisting>
|
||
|
</example>
|
||
|
</section>
|
||
|
</chapter>
|
||
|
<!--
|
||
|
Local Variables:
|
||
|
mode:sgml
|
||
|
sgml-parent-document: ("index.xml" "book" "part")
|
||
|
End:
|
||
|
-->
|