summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormkanat%bugzilla.org <>2009-11-09 20:15:28 +0100
committermkanat%bugzilla.org <>2009-11-09 20:15:28 +0100
commit4726923228d810ea0cd1800b17a9244c6f0d8eef (patch)
tree2d3fea848aa7e514a56b4f31dcd9453c2deeba77
parenta90df29f99bf1aa3a1835d0aa04e1602e5523096 (diff)
downloadbugzilla-4726923228d810ea0cd1800b17a9244c6f0d8eef.tar.gz
bugzilla-4726923228d810ea0cd1800b17a9244c6f0d8eef.tar.xz
Bug 525734: Allow WebService clients to authenticate using Bugzilla_login and Bugzilla_password
Patch by Max Kanat-Alexander <mkanat@bugzilla.org> r=dkl, a=mkanat
-rw-r--r--Bugzilla.pm36
-rw-r--r--Bugzilla/Auth/Login/CGI.pm8
-rw-r--r--Bugzilla/Auth/Persist/Cookie.pm7
-rw-r--r--Bugzilla/CGI.pm33
-rw-r--r--Bugzilla/Hook.pm3
-rw-r--r--[-rwxr-xr-x]Bugzilla/WebService.pm40
-rw-r--r--Bugzilla/WebService/Server.pm3
-rw-r--r--Bugzilla/WebService/Server/JSONRPC.pm11
-rw-r--r--Bugzilla/WebService/Server/XMLRPC.pm5
-rw-r--r--Bugzilla/WebService/User.pm10
10 files changed, 135 insertions, 21 deletions
diff --git a/Bugzilla.pm b/Bugzilla.pm
index a373aa801..666b1ec15 100644
--- a/Bugzilla.pm
+++ b/Bugzilla.pm
@@ -234,6 +234,22 @@ sub cgi {
return $class->request_cache->{cgi};
}
+sub input_params {
+ my ($class, $params) = @_;
+ my $cache = $class->request_cache;
+ # This is how the WebService and other places set input_params.
+ if (defined $params) {
+ $cache->{input_params} = $params;
+ }
+ return $cache->{input_params} if defined $cache->{input_params};
+
+ # Making this scalar makes it a tied hash to the internals of $cgi,
+ # so if a variable is changed, then it actually changes the $cgi object
+ # as well.
+ $cache->{input_params} = $class->cgi->Vars;
+ return $cache->{input_params};
+}
+
sub localconfig {
my $class = shift;
$class->request_cache->{localconfig} ||= read_localconfig();
@@ -647,6 +663,26 @@ The current C<cgi> object. Note that modules should B<not> be using this in
general. Not all Bugzilla actions are cgi requests. Its useful as a convenience
method for those scripts/templates which are only use via CGI, though.
+=item C<input_params>
+
+When running under the WebService, this is a hashref containing the arguments
+passed to the WebService method that was called. When running in a normal
+script, this is a hashref containing the contents of the CGI parameters.
+
+Modifying this hashref will modify the CGI parameters or the WebService
+arguments (depending on what C<input_params> currently represents).
+
+This should be used instead of L</cgi> in situations where your code
+could be being called by either a normal CGI script or a WebService method,
+such as during a code hook.
+
+B<Note:> When C<input_params> represents the CGI parameters, any
+parameter specified more than once (like C<foo=bar&foo=baz>) will appear
+as an arrayref in the hash, but any value specified only once will appear
+as a scalar. This means that even if a value I<can> appear multiple times,
+if it only I<does> appear once, then it will be a scalar in C<input_params>,
+not an arrayref.
+
=item C<user>
C<undef> if there is no currently logged in user or if the login code has not
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<Bugzilla/hook_args>.
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<Bugzilla/input_params> 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<info.pl>.
diff --git a/Bugzilla/WebService.pm b/Bugzilla/WebService.pm
index 75fcf6bc9..222923e70 100755..100644
--- 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<User.login>
+
You can use L<Bugzilla::WebService::User/login> 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<Bugzilla_login> and C<Bugzilla_password>
+
+B<Added in Bugzilla 3.6>
+
+You can specify C<Bugzilla_login> and C<Bugzilla_password> 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<Bugzilla_login> (string) - A user's login name.
+
+=item C<Bugzilla_password> (string) - That user's password.
+
+=item C<Bugzilla_restrictlogin> (boolean) - Optional. If true,
+then your login will only be valid for your IP address.
+
+=item C<Bugzilla_rememberlogin> (boolean) - Optional. If true,
+then the cookie sent back to you with the method response will
+not expire.
+
+=back
+
+The C<Bugzilla_restrictlogin> and C<Bugzilla_rememberlogin> options
+are only used when you have also specified C<Bugzilla_login> and
+C<Bugzilla_password>.
+
+Note that Bugzilla will return HTTP cookies along with the method
+response when you use these arguments (just like the C<User.login> method
+above).
+
+=back
+
=head1 STABLE, EXPERIMENTAL, and UNSTABLE
Methods are marked B<STABLE> 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) };
}