Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
bugzilla
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
etersoft
bugzilla
Commits
5bb84b3c
Commit
5bb84b3c
authored
Apr 22, 2010
by
Max Kanat-Alexander
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bug 550732: Allow read-only JSON-RPC methods to be called with GET
r=dkl, a=mkanat
parent
d8e899ba
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
219 additions
and
29 deletions
+219
-29
Login.pm
Bugzilla/Auth/Login.pm
+9
-0
Cookie.pm
Bugzilla/Auth/Login/Cookie.pm
+1
-0
Env.pm
Bugzilla/Auth/Login/Env.pm
+1
-0
Stack.pm
Bugzilla/Auth/Login/Stack.pm
+5
-0
WebService.pm
Bugzilla/WebService.pm
+4
-0
Bug.pm
Bugzilla/WebService/Bug.pm
+10
-0
Bugzilla.pm
Bugzilla/WebService/Bugzilla.pm
+7
-0
Constants.pm
Bugzilla/WebService/Constants.pm
+5
-4
Product.pm
Bugzilla/WebService/Product.pm
+7
-0
JSONRPC.pm
Bugzilla/WebService/Server/JSONRPC.pm
+154
-23
User.pm
Bugzilla/WebService/User.pm
+4
-0
user-error.html.tmpl
template/en/default/global/user-error.html.tmpl
+12
-2
No files found.
Bugzilla/Auth/Login.pm
View file @
5bb84b3c
...
...
@@ -27,6 +27,7 @@ use constant can_login => 1;
use
constant
requires_persistence
=>
1
;
use
constant
requires_verification
=>
1
;
use
constant
user_can_create_account
=>
0
;
use
constant
is_automatic
=>
0
;
sub
new
{
my
(
$class
)
=
@_
;
...
...
@@ -122,4 +123,12 @@ got from this login method. Defaults to C<true>.
Whether or not users can create accounts, if this login method is
currently being used by the system. Defaults to C<false>.
=item C<is_automatic>
True if this login method requires no interaction from the user within
Bugzilla. (For example, C<Env> auth is "automatic" because the webserver
just passes us an environment variable on most page requests, and does not
ask the user for authentication information directly in Bugzilla.) Defaults
to C<false>.
=back
Bugzilla/Auth/Login/Cookie.pm
View file @
5bb84b3c
...
...
@@ -27,6 +27,7 @@ use List::Util qw(first);
use
constant
requires_persistence
=>
0
;
use
constant
requires_verification
=>
0
;
use
constant
can_login
=>
0
;
use
constant
is_automatic
=>
1
;
# Note that Cookie never consults the Verifier, it always assumes
# it has a valid DB account or it fails.
...
...
Bugzilla/Auth/Login/Env.pm
View file @
5bb84b3c
...
...
@@ -31,6 +31,7 @@ use constant can_logout => 0;
use
constant
can_login
=>
0
;
use
constant
requires_persistence
=>
0
;
use
constant
requires_verification
=>
0
;
use
constant
is_automatic
=>
1
;
sub
get_login_info
{
my
(
$self
)
=
@_
;
...
...
Bugzilla/Auth/Login/Stack.pm
View file @
5bb84b3c
...
...
@@ -52,6 +52,11 @@ sub get_login_info {
my
$self
=
shift
;
my
$result
;
foreach
my
$object
(
@
{
$self
->
{
_stack
}})
{
# See Bugzilla::WebService::Server::JSONRPC for where and why
# auth_no_automatic_login is used.
if
(
Bugzilla
->
request_cache
->
{
auth_no_automatic_login
})
{
next
if
$object
->
is_automatic
;
}
$result
=
$object
->
get_login_info
(
@_
);
$self
->
{
successful
}
=
$object
;
last
if
!
$result
->
{
failure
};
...
...
Bugzilla/WebService.pm
View file @
5bb84b3c
...
...
@@ -29,6 +29,10 @@ use constant DATE_FIELDS => {};
# For some methods, we shouldn't call Bugzilla->login before we call them
use
constant
LOGIN_EXEMPT
=>
{
};
# Used to allow methods to be called in the JSON-RPC WebService via GET.
# Methods that can modify data MUST not be listed here.
use
constant
READ_ONLY
=>
();
sub
login_exempt
{
my
(
$class
,
$method
)
=
@_
;
return
$class
->
LOGIN_EXEMPT
->
{
$method
};
...
...
Bugzilla/WebService/Bug.pm
View file @
5bb84b3c
...
...
@@ -48,6 +48,16 @@ use constant DATE_FIELDS => {
search
=>
[
'last_change_time'
,
'creation_time'
],
};
use
constant
READ_ONLY
=>
qw(
attachments
comments
fields
get
history
legal_values
search
)
;
######################################################
# Add aliases here for old method name compatibility #
######################################################
...
...
Bugzilla/WebService/Bugzilla.pm
View file @
5bb84b3c
...
...
@@ -31,6 +31,13 @@ use constant LOGIN_EXEMPT => {
version
=>
1
,
};
use
constant
READ_ONLY
=>
qw(
extensions
timezone
time
version
)
;
sub
version
{
my
$self
=
shift
;
return
{
version
=>
$self
->
type
(
'string'
,
BUGZILLA_VERSION
)
};
...
...
Bugzilla/WebService/Constants.pm
View file @
5bb84b3c
...
...
@@ -120,10 +120,11 @@ use constant WS_ERROR_CODE => {
user_access_by_id_denied
=>
505
,
user_access_by_match_denied
=>
505
,
# RPC Server Errors. See the following URL:
# http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
xmlrpc_invalid_value
=>
-
32600
,
unknown_method
=>
-
32601
,
# Errors thrown by the WebService itself. The ones that are negative
# conform to http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
xmlrpc_invalid_value
=>
-
32600
,
unknown_method
=>
-
32601
,
json_rpc_post_only
=>
32610
,
};
# These are the fallback defaults for errors not in ERROR_CODE.
...
...
Bugzilla/WebService/Product.pm
View file @
5bb84b3c
...
...
@@ -23,6 +23,13 @@ use Bugzilla::Product;
use
Bugzilla::
User
;
use
Bugzilla::WebService::
Util
qw(validate)
;
use
constant
READ_ONLY
=>
qw(
get
get_accessible_products
get_enterable_products
get_selectable_products
)
;
##################################################
# Add aliases here for method name compatibility #
##################################################
...
...
Bugzilla/WebService/Server/JSONRPC.pm
View file @
5bb84b3c
...
...
@@ -28,6 +28,12 @@ use Bugzilla::Error;
use
Bugzilla::WebService::
Constants
;
use
Bugzilla::WebService::
Util
qw(taint_data)
;
use
Bugzilla::
Util
qw(correct_urlbase)
;
#####################################
# Public JSON::RPC Method Overrides #
#####################################
sub
new
{
my
$class
=
shift
;
my
$self
=
$class
->
SUPER::
new
(
@_
);
...
...
@@ -71,6 +77,81 @@ sub response {
print
$response
->
content
;
}
# The JSON-RPC 1.1 GET specification is not so great--you can't specify
# data structures as parameters. However, the JSON-RPC 2.0 "JSON-RPC over
# HTTP" spec is excellent, so we are using that for GET requests, instead.
# Spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
#
# The one exception is that we don't require the "params" argument to be
# Base64 encoded, because that is ridiculous and obnoxious for JavaScript
# clients.
sub
retrieve_json_from_get
{
my
$self
=
shift
;
my
$cgi
=
$self
->
cgi
;
my
%
input
;
# Both version and id must be set before any errors are thrown.
if
(
$cgi
->
param
(
'version'
))
{
$self
->
version
(
scalar
$cgi
->
param
(
'version'
));
$input
{
version
}
=
$cgi
->
param
(
'version'
);
}
else
{
$self
->
version
(
'1.0'
);
}
# The JSON-RPC 2.0 spec says that any request that omits an id doesn't
# want a response. However, in an HTTP GET situation, it's stupid to
# expect all clients to specify some id parameter just to get a response,
# so we don't require it.
my
$id
;
if
(
defined
$cgi
->
param
(
'id'
))
{
$id
=
$cgi
->
param
(
'id'
);
}
# However, JSON::RPC does require that an id exist in most cases, in
# order to throw proper errors. We use the installation's urlbase as
# the id, in this case.
else
{
$id
=
correct_urlbase
();
}
# Setting _bz_request_id here is required in case we throw errors early,
# before _handle.
$self
->
{
_bz_request_id
}
=
$input
{
id
}
=
$id
;
if
(
!
$cgi
->
param
(
'method'
))
{
ThrowUserError
(
'json_rpc_get_method_required'
);
}
$input
{
method
}
=
$cgi
->
param
(
'method'
);
my
$params
;
if
(
defined
$cgi
->
param
(
'params'
))
{
local
$@
;
$params
=
eval
{
$self
->
json
->
decode
(
scalar
$cgi
->
param
(
'params'
))
};
if
(
$@
)
{
ThrowUserError
(
'json_rpc_invalid_params'
,
{
params
=>
scalar
$cgi
->
param
(
'params'
),
err_msg
=>
$@
});
}
}
elsif
(
!
$self
->
version
or
$self
->
version
ne
'1.1'
)
{
$params
=
[]
;
}
else
{
$params
=
{};
}
$input
{
params
}
=
$params
;
my
$json
=
$self
->
json
->
encode
(
\%
input
);
return
$json
;
}
#######################################
# Bugzilla::WebService Implementation #
#######################################
sub
type
{
my
(
$self
,
$type
,
$value
)
=
@_
;
...
...
@@ -108,6 +189,35 @@ sub datetime_format_outbound {
return
$self
->
SUPER::
datetime_format_outbound
(
@_
)
.
'Z'
;
}
sub
handle_login
{
my
$self
=
shift
;
# If we're being called using GET, we don't allow cookie-based or Env
# login, because GET requests can be done cross-domain, and we don't
# want private data showing up on another site unless the user
# explicitly gives that site their username and password. (This is
# particularly important for JSONP, which would allow a remote site
# to use private data without the user's knowledge, unless we had this
# protection in place.)
if
(
$self
->
request
->
method
ne
'POST'
)
{
# XXX There's no particularly good way for us to get a parameter
# to Bugzilla->login at this point, so we pass this information
# around using request_cache, which is a bit of a hack. The
# implementation of it is in Bugzilla::Auth::Login::Stack.
Bugzilla
->
request_cache
->
{
auth_no_automatic_login
}
=
1
;
}
my
$path
=
$self
->
path_info
;
my
$class
=
$self
->
{
dispatch_path
}
->
{
$path
};
my
$full_method
=
$self
->
_bz_method_name
;
$full_method
=~
/^\S+\.(\S+)/
;
my
$method
=
$1
;
$self
->
SUPER::
handle_login
(
$class
,
$method
,
$full_method
);
}
######################################
# Private JSON::RPC Method Overrides #
######################################
# Store the ID of the current call, because Bugzilla::Error will need it.
sub
_handle
{
...
...
@@ -154,21 +264,11 @@ sub _error {
return
$json
;
}
##################
# Login Handling #
##################
# This handles dispatching our calls to the appropriate class based on
# the name of the method.
sub
_find_procedure
{
my
$self
=
shift
;
# This is also a good place to deny GET requests, since we can
# safely call ThrowUserError at this point.
if
(
$self
->
request
->
method
ne
'POST'
)
{
ThrowUserError
(
'json_rpc_post_only'
);
}
my
$method
=
shift
;
$self
->
{
_bz_method_name
}
=
$method
;
...
...
@@ -217,6 +317,16 @@ sub _argument_type_check {
Bugzilla
->
input_params
(
$params
);
if
(
$self
->
request
->
method
ne
'POST'
)
{
# When being called using GET, we don't allow calling
# methods that can change data. This protects us against cross-site
# request forgeries.
if
(
!
grep
(
$_
eq
$method
,
$pkg
->
READ_ONLY
))
{
ThrowUserError
(
'json_rpc_post_only'
,
{
method
=>
$self
->
_bz_method_name
});
}
}
# This is the best time to do login checks.
$self
->
handle_login
();
...
...
@@ -235,17 +345,6 @@ sub _argument_type_check {
return
$params
;
}
sub
handle_login
{
my
$self
=
shift
;
my
$path
=
$self
->
path_info
;
my
$class
=
$self
->
{
dispatch_path
}
->
{
$path
};
my
$full_method
=
$self
->
_bz_method_name
;
$full_method
=~
/^\S+\.(\S+)/
;
my
$method
=
$1
;
$self
->
SUPER::
handle_login
(
$class
,
$method
,
$full_method
);
}
# _bz_method_name is stored by _find_procedure for later use.
sub
_bz_method_name
{
return
$_
[
0
]
->
{
_bz_method_name
};
...
...
@@ -285,8 +384,40 @@ your Bugzilla installation. For example, if your Bugzilla is at
C<bugzilla.yourdomain.com>, then your JSON-RPC client would access the
API via: C<http://bugzilla.yourdomain.com/jsonrpc.cgi>
Bugzilla only allows JSON-RPC requests over C<POST>. C<GET> requests
(or any other type of request, such as C<HEAD>) will be denied.
=head2 Connecting via GET
The most powerful way to access the JSON-RPC interface is by HTTP POST.
However, for convenience, you can also access certain methods by using GET
(a normal webpage load). Methods that modify the database or cause some
action to happen in Bugzilla cannot be called over GET. Only methods that
simply return data can be used over GET.
For security reasons, when you connect over GET, cookie authentication
is not accepted. If you want to authenticate using GET, you have to
use the C<Bugzilla_login> and C<Bugzilla_password> method described at
L<Bugzilla::WebService/LOGGING IN>.
To connect over GET, simply send the values that you'd normally send for
each JSON-RPC argument as URL parameters, with the C<params> item being
a JSON string.
The simplest example is a call to C<Bugzilla.time>:
jsonrpc.cgi?method=Bugzilla.time
Here's a call to C<User.get>, with several parameters:
jsonrpc.cgi?method=User.get¶ms=[ { "ids": [1,2], "names": ["user@domain.com"] } ]
Although in reality you would url-encode the C<params> argument, so it would
look more like this:
jsonrpc.cgi?method=User.get¶ms=%5B+%7B+%22ids%22%3A+%5B1%2C2%5D%2C+%22names%22%3A+%5B%22user%40domain.com%22%5D+%7D+%5D
You can also specify C<version> as a URL parameter, if you want to specify
what version of the JSON-RPC protocol you're using, and C<id> as a URL
parameter if you want there to be a specific C<id> value in the returned
JSON-RPC response.
=head1 PARAMETERS
...
...
Bugzilla/WebService/User.pm
View file @
5bb84b3c
...
...
@@ -36,6 +36,10 @@ use constant LOGIN_EXEMPT => {
offer_account_by_email
=>
1
,
};
use
constant
READ_ONLY
=>
qw(
get
)
;
##############
# User Login #
##############
...
...
template/en/default/global/user-error.html.tmpl
View file @
5bb84b3c
...
...
@@ -979,9 +979,19 @@
[%+ constants.LOGIN_LOCKOUT_INTERVAL FILTER html %] minutes.
[% END %]
[% ELSIF error == "json_rpc_get_method_required" %]
When using JSON-RPC over GET, you must specify a 'method'
parameter. See the documentation at
[%+ docs_urlbase FILTER html %]api/Bugzilla/WebService/Server/JSONRPC.html
[% ELSIF error == "json_rpc_invalid_params" %]
Could not parse the 'params' argument as valid JSON.
Error: [% err_msg FILTER html %]
Value: [% params FILTER html %]
[% ELSIF error == "json_rpc_post_only" %]
For security reasons, you may only
use JSON-RPC with the POST
HTTP method
.
For security reasons, you may only
call the '[% method FILTER html %]'
method via HTTP POST
.
[% ELSIF error == "keyword_already_exists" %]
[% title = "Keyword Already Exists" %]
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment