[livejournal] r22252: LJSUP-12247: Implement requested scopes/...
Committer: nnikulochkina
LJSUP-12247: Implement requested scopes/permissions mapping for XML-RPC functionsU trunk/cgi-bin/Apache/LiveJournal.pm U trunk/cgi-bin/ljprotocol.pl
Modified: trunk/cgi-bin/Apache/LiveJournal.pm
===================================================================
--- trunk/cgi-bin/Apache/LiveJournal.pm 2012-06-15 07:39:06 UTC (rev 22251)
+++ trunk/cgi-bin/Apache/LiveJournal.pm 2012-06-15 07:40:52 UTC (rev 22252)
@@ -2416,26 +2416,13 @@
shift; # get rid of package name that dispatcher includes.
my $req = shift;
- # For specified methods
- if ($LJ::XMLRPC_VALIDATION_METHOD{$method}) {
- # Deny access for accounts that have not validated their email
- my $u = LJ::load_user($req->{'username'});
- unless ($u){
- die SOAP::Fault
- ->faultstring("Unknown username.");
- }
- unless ($u->is_validated) {
- die SOAP::Fault
- ->faultstring("Account not validated.");
- }
- }
-
if (@_) {
# don't allow extra arguments
die SOAP::Fault
->faultstring(LJ::Protocol::error_message(202))
->faultcode(202);
}
+
my $error = 0;
## All our functions take signle hashref as an argument.
@@ -2512,10 +2499,7 @@
## They are useless for Ops, but, yes, they can be useful for engineering debug.
##
warn "LJ::XMLRPC::$method died: $@"
- if $@ !~ /^\d+?\s*:/
- and $@ !~ m/\s*:\s*Account not validated./
- and $@ !~ "Unknown username.";
-
+ if $@ !~ /^\d+?\s*:/;
die $@;
}
Modified: trunk/cgi-bin/ljprotocol.pl
===================================================================
--- trunk/cgi-bin/ljprotocol.pl 2012-06-15 07:39:06 UTC (rev 22251)
+++ trunk/cgi-bin/ljprotocol.pl 2012-06-15 07:40:52 UTC (rev 22252)
@@ -22,6 +22,7 @@
LJ::PersistentQueue
LJ::PersonalStats::Ratings::Posts
LJ::PersonalStats::Ratings::Journals
+ LJ::API::RateLimiter
);
use LJ::TimeUtil;
@@ -29,6 +30,8 @@
LJ::Config->load;
+
+
use lib "$ENV{LJHOME}/cgi-bin";
require "taglib.pl";
@@ -126,7 +129,13 @@
"328" => E_PERM,
"329" => E_PERM,
"330" => E_PERM,
-
+ "331" => E_TEMP,
+ "332" => E_TEMP,
+ "333" => E_PERM,
+ "334" => E_PERM,
+ "335" => E_PERM,
+ "336" => E_TEMP,
+
# Limit errors
"402" => E_TEMP,
"404" => E_TEMP,
@@ -138,6 +147,7 @@
"410" => E_PERM,
"411" => E_TEMP,
"412" => E_TEMP,
+ "413" => E_TEMP,
# Server Errors
"500" => E_TEMP,
@@ -317,7 +327,7 @@
sub getpoll
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getpoll');
my $u = $flags->{'u'};
# check arguments
@@ -414,7 +424,7 @@
sub editpoll
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'editpoll');
my $u = $flags->{'u'};
# check arguments
@@ -453,7 +463,7 @@
sub votepoll
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'votepoll');
my $u = $flags->{'u'}; # remote_id
# check pollid
@@ -491,7 +501,7 @@
sub checksession {
my ($req, $err, $flags) = @_;
return undef
- unless authenticate($req, $err, $flags);
+ unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'checksession');
my $u = $flags->{'u'};
@@ -511,7 +521,7 @@
sub addcomment
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'addcomment');
my $u = $flags->{'u'};
return fail($err,200,"body") unless($req->{body});
@@ -574,7 +584,7 @@
$flags->{allow_anonymous} = 1;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getcomments');
my $u = $flags->{'u'};
my $journal;
@@ -785,7 +795,7 @@
=cut
sub deletecomments {
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'deletecomments');
my $u = $flags->{'u'};
my $journal;
@@ -913,7 +923,7 @@
sub updatecomments {
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'updatecomments');
my $u = $flags->{'u'};
my $journal;
@@ -1110,7 +1120,7 @@
=cut
sub editcomment {
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'editcomment');
my $remote = $flags->{'u'};
return fail($err, 318) if $remote && $remote->is_readonly;
@@ -1162,7 +1172,7 @@
sub getrecentcomments {
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getrecentcomments');
my $u = $flags->{'u'};
my $journal;
@@ -1240,7 +1250,7 @@
sub getfriendspage
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getfriendspage');
my $u = $flags->{'u'};
my $itemshow = (defined $req->{itemshow}) ? $req->{itemshow} : 100;
@@ -1385,7 +1395,7 @@
sub getinbox
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getinbox');
my $u = $flags->{'u'};
my $itemshow = (defined $req->{itemshow}) ? $req->{itemshow} : 100;
@@ -1490,7 +1500,7 @@
sub setmessageread {
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'setmessageread');
my $u = $flags->{'u'};
@@ -1542,7 +1552,7 @@
return fail($err, 315) if $LJ::DISABLED{user_messaging};
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'sendmessage');
my $u = $flags->{'u'};
return fail($err, 305) if $u->statusvis eq 'S'; # suspended cannot send private messages
@@ -1615,7 +1625,7 @@
sub login
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'login');
return undef unless check_altusage($req, $err, $flags);
my $u = $flags->{'u'};
@@ -1711,6 +1721,7 @@
$res->{'fastserver'} = 1 if LJ::get_cap($uowner, "fastserver");
## user info
+ $res->{'username'} = $uowner->{'user'};
$res->{'userid'} = $uowner->{'userid'};
$res->{'fullname'} = $uowner->{'name'};
LJ::text_out(\$res->{'fullname'}) if $ver >= 1;
@@ -1752,7 +1763,7 @@
sub getfriendgroups
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getfriendgroups');
my $u = $flags->{'u'};
my $res = {
xc3 => {
@@ -1774,7 +1785,7 @@
sub getusertags
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getusertags');
return undef unless check_altusage($req, $err, $flags);
my $u = $flags->{'u'};
@@ -1795,7 +1806,7 @@
my ($req, $err, $flags) = @_;
$flags->{'allow_anonymous'} = 1;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getuserpics');
$flags->{'ignorecanuse'} = 1; # function return public info
return undef unless check_altusage($req, $err, $flags);
@@ -1831,7 +1842,8 @@
sub getfriends
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getfriends');
+
return fail($req,502) unless LJ::get_db_reader();
my $u = $flags->{'u'};
my $res = {
@@ -1874,7 +1886,7 @@
sub friendof
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'friendof');
return fail($req,502) unless LJ::get_db_reader();
my $u = $flags->{'u'};
my $res = {
@@ -1898,7 +1910,7 @@
sub checkfriends
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'checkfriends');
my $u = $flags->{'u'};
my $res = {
xc3 => {
@@ -1981,7 +1993,7 @@
sub getdaycounts
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getdaycounts');
return undef unless check_altusage($req, $err, $flags);
my $u = $flags->{'u'};
@@ -2178,8 +2190,8 @@
un_utf8_request($req);
my $post_noauth = LJ::run_hook('post_noauth', $req);
- return undef unless $post_noauth || authenticate($req, $err, $flags);
+ return undef unless $post_noauth || authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'postevent');
my $spam = 0;
LJ::run_hook('spam_detector', $req, \$spam);
return fail($err,320) if $spam;
@@ -2938,7 +2950,7 @@
my ($req, $err, $flags) = @_;
un_utf8_request($req);
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'editevent');
my $spam = 0;
return undef unless LJ::run_hook('spam_detector', $req, \$spam);
@@ -3451,7 +3463,7 @@
my ($req, $err, $flags) = @_;
$flags->{allow_anonymous} = 1;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getevents');
$flags->{'ignorecanuse'} = 1; # later we will check security levels, so allow some access to communities
return undef unless check_altusage($req, $err, $flags);
@@ -4124,7 +4136,7 @@
sub editfriends
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'editfriends');
my $u = $flags->{'u'};
my $userid = $u->{'userid'};
@@ -4340,7 +4352,7 @@
sub editfriendgroups
{
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'editfriendgroups');
my $u = $flags->{'u'};
my $userid = $u->{'userid'};
@@ -4517,7 +4529,7 @@
sub sessionexpire {
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'sessionexpire');
my $u = $flags->{u};
my $res = {
xc3 => {
@@ -4545,7 +4557,7 @@
sub sessiongenerate {
# generate a session
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'sessiongenerate');
# sanitize input
$req->{expiration} = 'short' unless $req->{expiration} eq 'long';
@@ -4673,7 +4685,7 @@
sub syncitems {
my ($req, $err, $flags) = @_;
- return undef unless authenticate($req, $err, $flags);
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'syncitems');
return undef unless check_altusage($req, $err, $flags);
return fail($err, 506) if $LJ::DISABLED{'syncitems'};
@@ -4779,7 +4791,7 @@
my ($req, $err, $flags) = @_;
# logging in isn't necessary, but most console commands do require it
- LJ::set_remote($flags->{'u'}) if authenticate($req, $err, $flags);
+ LJ::set_remote($flags->{'u'}) if authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'consolecommand');
my $res = {
xc3 => {
@@ -5025,40 +5037,43 @@
{
my ($req, $err, $flags) = @_;
- my $username = $req->{'username'};
+ my $u;
- # add flag to avoid authentication
- if (!$username && $flags->{'allow_anonymous'}) {
- undef $flags->{'u'};
+ my $auth_meth = $req->{'auth_method'} || "clear";
+ my $username = $req->{'username'} || '';
+
+ my $check_user = sub {
+ return fail($err,100) unless $u;
+ return fail($err,100) if ($u->{'statusvis'} eq "X");
+ return fail($err,505) unless $u->{'clusterid'};
return 1;
- }
+ };
- return fail($err,200) unless $username;
- return fail($err,100) unless LJ::canonical_username($username);
+ unless ($auth_meth eq "oauth") {
+
+ # add flag to avoid authentication
+ if (!$username && $flags->{'allow_anonymous'}) {
+ undef $flags->{'u'};
+ return 1;
+ }
- my $u = $flags->{'u'};
- unless ($u) {
- my $dbr = LJ::get_db_reader();
- return fail($err,502) unless $dbr;
- $u = LJ::load_user($username);
- }
+ return fail($err,200) unless $username;
+ return fail($err,100) unless LJ::canonical_username($username);
- return fail($err,100) unless $u;
- return fail($err,100) if ($u->{'statusvis'} eq "X");
- return fail($err,505) unless $u->{'clusterid'};
+ $u = $flags->{'u'};
+ unless ($u) {
+ my $dbr = LJ::get_db_reader();
+ return fail($err,502) unless $dbr;
+ $u = LJ::load_user($username);
+ }
- my $ip;
- if (LJ::Request->is_inited) {
- LJ::Request->notes("ljuser" => $u->{'user'}) unless LJ::Request->notes("ljuser");
- LJ::Request->notes("journalid" => $u->{'userid'}) unless LJ::Request->notes("journalid");
- $ip = LJ::Request->connection->remote_ip;
+ return unless $check_user->();
}
my $ip_banned = 0;
my $chal_expired = 0;
my $auth_check = sub {
- my $auth_meth = $req->{'auth_method'} || "clear";
if ($auth_meth eq "clear") {
my $res = LJ::auth_okay($u,
$req->{'password'},
@@ -5089,26 +5104,90 @@
my $remote = LJ::get_remote();
return $remote && $remote->{'user'} eq $username ? 1 : 0;
}
+ if ($auth_meth eq "oauth"){
+ my $rate_limiter = LJ::Request->is_inited ?
+ LJ::API::RateLimiter->new(LJ::Request->request) :
+ LJ::API::RateLimiter->new();
+
+ my $oauth = LJ::OAuth->new(rate_limiter => $rate_limiter);
+
+ my $result = $oauth->have_access;
+ unless ($result->{http_status} == 200) {
+ return fail($err,331,$result->{oauth_problem}) if $result->{http_status} == 400;
+ return fail($err,332,$result->{oauth_problem}) if $result->{http_status} == 401;
+ return fail($err,334,$result->{oauth_problem}) if $result->{http_status} == 403;
+ return fail($err,413,$result->{oauth_problem}) if $result->{http_status} == 503;
+ return fail($err,101);
+ }
+ $u = $result->{user};
+ return unless $check_user->();
+ $flags->{'user_access'} = $result->{access};
+ LJ::Session->record_login($u);
+ }
};
unless ($flags->{'nopassword'} ||
$flags->{'noauth'} ||
$auth_check->() )
{
+ return undef if $$err;
return fail($err,402) if $ip_banned;
return fail($err,105) if $chal_expired;
return fail($err,101);
}
+ return 1 if ($flags->{'allow_anonymous'} && !$u);
+
# if there is a require TOS revision, check for it now
return fail($err, 156) unless $u->tosagree_verify;
# remember the user record for later.
$flags->{'u'} = $u;
+
+ if (LJ::Request->is_inited) {
+ LJ::Request->notes("ljuser" => $u->{'user'}) unless LJ::Request->notes("ljuser");
+ LJ::Request->notes("journalid" => $u->{'userid'}) unless LJ::Request->notes("journalid");
+ }
+
return 1;
}
+sub authorize
+{
+ my ($req, $err, $flags, $method) = @_;
+
+ my $auth_method = $req->{'auth_method'};
+ return 1 if ($flags->{noauth});
+
+ if ($auth_method eq 'oauth') {
+
+ return fail($err,333) unless $flags->{'user_access'};
+ return fail($err,333) unless defined $LJ::XMLRPC_USER_ACCESS{$method};
+
+ my $access_required = ref $LJ::XMLRPC_USER_ACCESS{$method} ? $LJ::XMLRPC_USER_ACCESS{$method} : [$LJ::XMLRPC_USER_ACCESS{$method}];
+
+ my %user_access = map {$_ => 1} @{$flags->{'user_access'}};
+
+ foreach my $p (@$access_required){
+ return fail($err,333) unless ( $user_access{$p} || ($p =~ /(.+)_ro$/) && $user_access{"$1_rw"} );
+ }
+ }
+
+ if ($LJ::XMLRPC_VALIDATION_METHOD{$method}) {
+ # Deny access for accounts that have not validated their email
+ my $u = $flags->{'u'} || LJ::load_user($req->{'username'});
+ unless ($u){
+ return fail($err,335);
+ }
+ unless ($u->is_validated) {
+ return fail($err,336);
+ }
+ }
+
+ return 1;
+}
+
sub fail
{
my $err = shift;
@@ -5182,7 +5261,7 @@
my ($req, $err, $flags) = @_;
return undef
- unless authenticate($req, $err, $flags);
+ unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'registerpush');
my $u = $flags->{u};
@@ -5207,7 +5286,7 @@
sub unregisterpush {
my ($req, $err, $flags) = @_;
return undef
- unless authenticate($req, $err, $flags);
+ unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'unregisterpush');
my $u = $flags->{u};
@@ -5225,7 +5304,7 @@
sub pushsubscriptions {
my ($req, $err, $flags) = @_;
return undef
- unless authenticate($req, $err, $flags);
+ unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'pushsubscriptions');
my $u = $flags->{u};
my @errors;
@@ -5260,7 +5339,7 @@
sub resetpushcounter {
my ($req, $err, $flags) = @_;
return undef
- unless authenticate($req, $err, $flags);
+ unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'resetpushcounter');
my $u = $flags->{u};
@@ -5282,7 +5361,7 @@
sub getpushlist {
my ($req, $err, $flags) = @_;
return undef
- unless authenticate($req, $err, $flags);
+ unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getpushlist');
my $u = $flags->{u};
@@ -5327,7 +5406,9 @@
sub geteventsrating {
my ($req, $err, $flags) = @_;
- authenticate($req, $err, {%$flags, allow_anonymous => 1});
+ $flags->{allow_anonymous} = 1;
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'geteventsrating');
+
my $user_id = $flags->{u} ? $flags->{u}->id : 0;
return fail($err, 200, 'region') unless $req->{region};
@@ -5426,7 +5507,9 @@
sub getusersrating {
my ($req, $err, $flags) = @_;
- authenticate($req, $err, {%$flags, allow_anonymous => 1});
+ $flags->{allow_anonymous} = 1;
+ return undef unless authenticate($req, $err, $flags) && authorize($req, $err, $flags, 'getusersrating');
+
my $user_id = $flags->{u} ? $flags->{u}->id : 0;
return fail($err, 200, 'region') unless $req->{region};
