From 4726923228d810ea0cd1800b17a9244c6f0d8eef Mon Sep 17 00:00:00 2001 From: "mkanat%bugzilla.org" <> Date: Mon, 9 Nov 2009 19:15:28 +0000 Subject: Bug 525734: Allow WebService clients to authenticate using Bugzilla_login and Bugzilla_password Patch by Max Kanat-Alexander r=dkl, a=mkanat --- Bugzilla/Auth/Login/CGI.pm | 8 +++---- Bugzilla/Auth/Persist/Cookie.pm | 7 +++--- Bugzilla/CGI.pm | 33 +++++++++++++++++++++++++++++ Bugzilla/Hook.pm | 3 +++ Bugzilla/WebService.pm | 40 +++++++++++++++++++++++++++++++++++ Bugzilla/WebService/Server.pm | 3 ++- Bugzilla/WebService/Server/JSONRPC.pm | 11 +++++----- Bugzilla/WebService/Server/XMLRPC.pm | 5 ++++- Bugzilla/WebService/User.pm | 10 ++++----- 9 files changed, 99 insertions(+), 21 deletions(-) mode change 100755 => 100644 Bugzilla/WebService.pm (limited to 'Bugzilla') diff --git a/Bugzilla/Auth/Login/CGI.pm b/Bugzilla/Auth/Login/CGI.pm index a93bc3d3a..407582af4 100644 --- a/Bugzilla/Auth/Login/CGI.pm +++ b/Bugzilla/Auth/Login/CGI.pm @@ -40,12 +40,10 @@ use Bugzilla::Error; sub get_login_info { my ($self) = @_; - my $cgi = Bugzilla->cgi; - - my $username = trim($cgi->param("Bugzilla_login")); - my $password = $cgi->param("Bugzilla_password"); + my $params = Bugzilla->input_params; - $cgi->delete('Bugzilla_login', 'Bugzilla_password'); + my $username = trim(delete $params->{"Bugzilla_login"}); + my $password = delete $params->{"Bugzilla_password"}; if (!defined $username || !defined $password) { return { failure => AUTH_NODATA }; diff --git a/Bugzilla/Auth/Persist/Cookie.pm b/Bugzilla/Auth/Persist/Cookie.pm index 4458e31b5..1e1b3a871 100644 --- a/Bugzilla/Auth/Persist/Cookie.pm +++ b/Bugzilla/Auth/Persist/Cookie.pm @@ -48,9 +48,10 @@ sub persist_login { my ($self, $user) = @_; my $dbh = Bugzilla->dbh; my $cgi = Bugzilla->cgi; + my $input_params = Bugzilla->input_params; my $ip_addr; - if ($cgi->param('Bugzilla_restrictlogin')) { + if ($input_params->{'Bugzilla_restrictlogin'}) { $ip_addr = $cgi->remote_addr; # The IP address is valid, at least for comparing with itself in a # subsequent login @@ -80,8 +81,8 @@ sub persist_login { # or admin didn't forbid it and user told to remember. if ( Bugzilla->params->{'rememberlogin'} eq 'on' || (Bugzilla->params->{'rememberlogin'} ne 'off' && - $cgi->param('Bugzilla_remember') && - $cgi->param('Bugzilla_remember') eq 'on') ) + $input_params->{'Bugzilla_remember'} && + $input_params->{'Bugzilla_remember'} eq 'on') ) { # Not a session cookie, so set an infinite expiry $cookieargs{'-expires'} = 'Fri, 01-Jan-2038 00:00:00 GMT'; diff --git a/Bugzilla/CGI.pm b/Bugzilla/CGI.pm index 8c68f996c..bebff2d63 100644 --- a/Bugzilla/CGI.pm +++ b/Bugzilla/CGI.pm @@ -416,6 +416,39 @@ sub url_is_attachment_base { return ($self->self_url =~ $regex) ? 1 : 0; } +########################## +# Vars TIEHASH Interface # +########################## + +# Fix the TIEHASH interface (scalar $cgi->Vars) to return and accept +# arrayrefs. +sub STORE { + my $self = shift; + my ($param, $value) = @_; + if (defined $value and ref $value eq 'ARRAY') { + return $self->param(-name => $param, -value => $value); + } + return $self->SUPER::STORE(@_); +} + +sub FETCH { + my ($self, $param) = @_; + return $self if $param eq 'CGI'; # CGI.pm did this, so we do too. + my @result = $self->param($param); + return undef if !scalar(@result); + return $result[0] if scalar(@result) == 1; + return \@result; +} + +# For the Vars TIEHASH interface: the normal CGI.pm DELETE doesn't return +# the value deleted, but Perl's "delete" expects that value. +sub DELETE { + my ($self, $param) = @_; + my $value = $self->FETCH($param); + $self->delete($param); + return $value; +} + 1; __END__ diff --git a/Bugzilla/Hook.pm b/Bugzilla/Hook.pm index 51bce7fbe..69fa2f654 100644 --- a/Bugzilla/Hook.pm +++ b/Bugzilla/Hook.pm @@ -144,6 +144,9 @@ These params are accessible through L. That returns a hashref. Very frequently, if you want your hook to do anything, you have to modify these variables. +You may also want to use L to get parameters +that were passed to the current CGI script or WebService method. + =head2 Versioning Extensions Every extension must have a file in its root called F. diff --git a/Bugzilla/WebService.pm b/Bugzilla/WebService.pm old mode 100755 new mode 100644 index 75fcf6bc9..222923e70 --- a/Bugzilla/WebService.pm +++ b/Bugzilla/WebService.pm @@ -142,11 +142,51 @@ how this is implemented for those frontends. =head1 LOGGING IN +There are various ways to log in: + +=over + +=item C + You can use L to log in as a Bugzilla user. This issues standard HTTP cookies that you must then use in future calls, so your client must be capable of receiving and transmitting cookies. +=item C and C + +B + +You can specify C and C as arguments +to any WebService method, and you will be logged in as that user if your +credentials are correct. Here are the arguments you can specify to any +WebService method to perform a login: + +=over + +=item C (string) - A user's login name. + +=item C (string) - That user's password. + +=item C (boolean) - Optional. If true, +then your login will only be valid for your IP address. + +=item C (boolean) - Optional. If true, +then the cookie sent back to you with the method response will +not expire. + +=back + +The C and C options +are only used when you have also specified C and +C. + +Note that Bugzilla will return HTTP cookies along with the method +response when you use these arguments (just like the C method +above). + +=back + =head1 STABLE, EXPERIMENTAL, and UNSTABLE Methods are marked B if you can expect their parameters and diff --git a/Bugzilla/WebService/Server.pm b/Bugzilla/WebService/Server.pm index 2db182fd4..115c7df89 100644 --- a/Bugzilla/WebService/Server.pm +++ b/Bugzilla/WebService/Server.pm @@ -21,7 +21,8 @@ use strict; sub handle_login { my ($self, $class, $method, $full_method) = @_; eval "require $class"; - return if $class->login_exempt($method); + return if ($class->login_exempt($method) + and !defined Bugzilla->input_params->{Bugzilla_login}); Bugzilla->login(); } diff --git a/Bugzilla/WebService/Server/JSONRPC.pm b/Bugzilla/WebService/Server/JSONRPC.pm index e54387a6d..919370a2a 100644 --- a/Bugzilla/WebService/Server/JSONRPC.pm +++ b/Bugzilla/WebService/Server/JSONRPC.pm @@ -112,12 +112,6 @@ sub _argument_type_check { my $self = shift; my $params = $self->SUPER::_argument_type_check(@_); - # This is the best time to do login checks. - $self->handle_login(); - - # If there are no parameters, we don't need to parse them. - return $params if !ref $params; - # JSON-RPC 1.0 requires all parameters to be passed as an array, so # we just pull out the first item and assume it's an object. if (ref $params eq 'ARRAY') { @@ -144,6 +138,11 @@ sub _argument_type_check { } } + Bugzilla->input_params($params); + + # This is the best time to do login checks. + $self->handle_login(); + # Bugzilla::WebService packages call internal methods like # $self->_some_private_method. So we have to inherit from # that class as well as this Server class. diff --git a/Bugzilla/WebService/Server/XMLRPC.pm b/Bugzilla/WebService/Server/XMLRPC.pm index b2a50712a..cbfb1b7f2 100644 --- a/Bugzilla/WebService/Server/XMLRPC.pm +++ b/Bugzilla/WebService/Server/XMLRPC.pm @@ -78,6 +78,7 @@ sub deserialize { $som->{_bz_do_taint} = 1; } bless $som, 'Bugzilla::XMLRPC::SOM'; + Bugzilla->input_params($som->paramsin); return $som; } @@ -146,11 +147,13 @@ use Bugzilla::WebService::Util qw(taint_data); sub paramsin { my $self = shift; + return $self->{bz_params_in} if $self->{bz_params_in}; my $params = $self->SUPER::paramsin(@_); if ($self->{_bz_do_taint}) { taint_data($params); } - return $params; + $self->{bz_params_in} = $params; + return $self->{bz_params_in}; } 1; diff --git a/Bugzilla/WebService/User.pm b/Bugzilla/WebService/User.pm index ba899cd4d..67a4720de 100644 --- a/Bugzilla/WebService/User.pm +++ b/Bugzilla/WebService/User.pm @@ -61,12 +61,12 @@ sub login { } # Make sure the CGI user info class works if necessary. - my $cgi = Bugzilla->cgi; - $cgi->param('Bugzilla_login', $params->{login}); - $cgi->param('Bugzilla_password', $params->{password}); - $cgi->param('Bugzilla_remember', $remember); + my $input_params = Bugzilla->input_params; + $input_params->{'Bugzilla_login'} = $params->{login}; + $input_params->{'Bugzilla_password'} = $params->{password}; + $input_params->{'Bugzilla_remember'} = $remember; - Bugzilla->login; + Bugzilla->login(); return { id => $self->type('int', Bugzilla->user->id) }; } -- cgit v1.2.3-24-g4f1b