]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 525734: Allow WebService clients to authenticate using Bugzilla_login and Bugzill...
authormkanat%bugzilla.org <>
Mon, 9 Nov 2009 19:15:28 +0000 (19:15 +0000)
committermkanat%bugzilla.org <>
Mon, 9 Nov 2009 19:15:28 +0000 (19:15 +0000)
Patch by Max Kanat-Alexander <mkanat@bugzilla.org> r=dkl, a=mkanat

Bugzilla.pm
Bugzilla/Auth/Login/CGI.pm
Bugzilla/Auth/Persist/Cookie.pm
Bugzilla/CGI.pm
Bugzilla/Hook.pm
Bugzilla/WebService.pm [changed mode: 0755->0644]
Bugzilla/WebService/Server.pm
Bugzilla/WebService/Server/JSONRPC.pm
Bugzilla/WebService/Server/XMLRPC.pm
Bugzilla/WebService/User.pm

index a373aa801e2a18b1d1d48cf4d909e873500c31bc..666b1ec1579b96ba498c64ed661dec3b9cd7af6d 100644 (file)
@@ -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
index a93bc3d3a33b3f8d44b0f37b84c65b14a96a98ee..407582af4fc10b639a208d81db694a27964ebd97 100644 (file)
@@ -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 };
index 4458e31b5a08442ecaff4a756e1d97cc2646dfee..1e1b3a87178253feb0faa5fb7fba2f7fc3b04d6b 100644 (file)
@@ -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';
index 8c68f996c23c884416a43f74b0d575dc3435042f..bebff2d6304a93f0ef40ab193f32bd2b80f3b90e 100644 (file)
@@ -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__
index 51bce7fbeb92c4bee857c7f7348ec7cf9799f5c3..69fa2f6544c1834ee70028e5ca6c7cecbc3e2506 100644 (file)
@@ -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>.
old mode 100755 (executable)
new mode 100644 (file)
index 75fcf6b..222923e
@@ -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
index 2db182fd44f196234ccedb61a8d063f126c106c5..115c7df8962fe3de64516a5451c193091939145a 100644 (file)
@@ -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();
 }
 
index e54387a6d9a322c848ce0d45b46697d8acee70b0..919370a2a23b27313048c57bd2e9b94579ce0c45 100644 (file)
@@ -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.
index b2a50712ae415ab8a00d645b1e8b99d3a3a0583d..cbfb1b7f2a1b12df56cb16d7c4178b12c1f85e00 100644 (file)
@@ -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;
index ba899cd4dbfb164e404aef5164604929b9289f43..67a4720deb8241370ff6ea714992c789d96848d6 100644 (file)
@@ -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) };
 }