ljr/livejournal/doc/raw/ljp.book/csp/auth.xml

123 lines
6.2 KiB
XML
Raw Normal View History

2019-02-05 21:49:12 +00:00
<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&amp;user=test&amp;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:
-->