source: subversion/sites/rails_port/test/functional/node_controller_test.rb @ 14784

Last change on this file since 14784 was 14784, checked in by Shaun McDonald, 10 years ago

Fix the node and relation tests from when the users with data public=false were disallowed from editing. Needed extra fixtures.

File size: 17.2 KB
Line 
1require File.dirname(__FILE__) + '/../test_helper'
2
3class NodeControllerTest < ActionController::TestCase
4  api_fixtures
5
6  def test_create
7    # cannot read password from fixture as it is stored as MD5 digest
8    ## First try with no auth
9   
10    # create a node with random lat/lon
11    lat = rand(100)-50 + rand
12    lon = rand(100)-50 + rand
13    # normal user has a changeset open, so we'll use that.
14    changeset = changesets(:normal_user_first_change)
15    # create a minimal xml file
16    content("<osm><node lat='#{lat}' lon='#{lon}' changeset='#{changeset.id}'/></osm>")
17    assert_difference('OldNode.count', 0) do
18      put :create
19    end
20    # hope for unauthorized
21    assert_response :unauthorized, "node upload did not return unauthorized status"
22
23   
24   
25    ## Now try with the user which doesn't have their data public
26    basic_authorization(users(:normal_user).email, "test")
27   
28    # create a node with random lat/lon
29    lat = rand(100)-50 + rand
30    lon = rand(100)-50 + rand
31    # normal user has a changeset open, so we'll use that.
32    changeset = changesets(:normal_user_first_change)
33    # create a minimal xml file
34    content("<osm><node lat='#{lat}' lon='#{lon}' changeset='#{changeset.id}'/></osm>")
35    assert_difference('Node.count', 0) do
36      put :create
37    end
38    # hope for success
39    assert_require_public_data "node create did not return forbidden status"
40
41
42   
43    ## Now try with the user that has the public data
44    basic_authorization(users(:public_user).email, "test")
45   
46    # create a node with random lat/lon
47    lat = rand(100)-50 + rand
48    lon = rand(100)-50 + rand
49    # normal user has a changeset open, so we'll use that.
50    changeset = changesets(:public_user_first_change)
51    # create a minimal xml file
52    content("<osm><node lat='#{lat}' lon='#{lon}' changeset='#{changeset.id}'/></osm>")
53    put :create
54    # hope for success
55    assert_response :success, "node upload did not return success status"
56
57    # read id of created node and search for it
58    nodeid = @response.body
59    checknode = Node.find(nodeid)
60    assert_not_nil checknode, "uploaded node not found in data base after upload"
61    # compare values
62    assert_in_delta lat * 10000000, checknode.latitude, 1, "saved node does not match requested latitude"
63    assert_in_delta lon * 10000000, checknode.longitude, 1, "saved node does not match requested longitude"
64    assert_equal changesets(:public_user_first_change).id, checknode.changeset_id, "saved node does not belong to changeset that it was created in"
65    assert_equal true, checknode.visible, "saved node is not visible"
66  end
67
68  def test_create_invalid_xml
69    ## Only test public user here, as test_create should cover what's the forbiddens
70    ## that would occur here
71    # Initial setup
72    basic_authorization(users(:public_user).email, "test")
73    # normal user has a changeset open, so we'll use that.
74    changeset = changesets(:public_user_first_change)
75    lat = 3.434
76    lon = 3.23
77   
78    # test that the upload is rejected when no lat is supplied
79    # create a minimal xml file
80    content("<osm><node lon='#{lon}' changeset='#{changeset.id}'/></osm>")
81    put :create
82    # hope for success
83    assert_response :bad_request, "node upload did not return bad_request status"
84    assert_equal "Cannot parse valid node from xml string <node lon=\"3.23\" changeset=\"#{changeset.id}\"/>. lat missing", @response.body
85
86    # test that the upload is rejected when no lon is supplied
87    # create a minimal xml file
88    content("<osm><node lat='#{lat}' changeset='#{changeset.id}'/></osm>")
89    put :create
90    # hope for success
91    assert_response :bad_request, "node upload did not return bad_request status"
92    assert_equal "Cannot parse valid node from xml string <node lat=\"3.434\" changeset=\"#{changeset.id}\"/>. lon missing", @response.body
93
94  end
95
96  def test_read
97    # check that a visible node is returned properly
98    get :read, :id => current_nodes(:visible_node).id
99    assert_response :success
100
101    # check that an invisible node is not returned
102    get :read, :id => current_nodes(:invisible_node).id
103    assert_response :gone
104
105    # check chat a non-existent node is not returned
106    get :read, :id => 0
107    assert_response :not_found
108  end
109
110  # this tests deletion restrictions - basic deletion is tested in the unit
111  # tests for node!
112  def test_delete
113    ## first try to delete node without auth
114    delete :delete, :id => current_nodes(:visible_node).id
115    assert_response :unauthorized
116   
117   
118    ## now set auth for the non-data public user
119    basic_authorization(users(:normal_user).email, "test"); 
120
121    # try to delete with an invalid (closed) changeset
122    content update_changeset(current_nodes(:visible_node).to_xml,
123                             changesets(:normal_user_closed_change).id)
124    delete :delete, :id => current_nodes(:visible_node).id
125    assert_require_public_data("non-public user shouldn't be able to delete node")
126
127    # try to delete with an invalid (non-existent) changeset
128    content update_changeset(current_nodes(:visible_node).to_xml,0)
129    delete :delete, :id => current_nodes(:visible_node).id
130    assert_require_public_data("shouldn't be able to delete node, when user's data is private")
131
132    # valid delete now takes a payload
133    content(nodes(:visible_node).to_xml)
134    delete :delete, :id => current_nodes(:visible_node).id
135    assert_require_public_data("shouldn't be able to delete node when user's data isn't public'")
136
137    # this won't work since the node is already deleted
138    content(nodes(:invisible_node).to_xml)
139    delete :delete, :id => current_nodes(:invisible_node).id
140    assert_require_public_data
141
142    # this won't work since the node never existed
143    delete :delete, :id => 0
144    assert_require_public_data
145
146    ## these test whether nodes which are in-use can be deleted:
147    # in a way...
148    content(nodes(:used_node_1).to_xml)
149    delete :delete, :id => current_nodes(:used_node_1).id
150    assert_require_public_data
151       "shouldn't be able to delete a node used in a way (#{@response.body})"
152
153    # in a relation...
154    content(nodes(:node_used_by_relationship).to_xml)
155    delete :delete, :id => current_nodes(:node_used_by_relationship).id
156    assert_require_public_data
157       "shouldn't be able to delete a node used in a relation (#{@response.body})"
158
159   
160
161    ## now set auth for the public data user
162    basic_authorization(users(:public_user).email, "test"); 
163
164    # try to delete with an invalid (closed) changeset
165    content update_changeset(current_nodes(:visible_node).to_xml,
166                             changesets(:normal_user_closed_change).id)
167    delete :delete, :id => current_nodes(:visible_node).id
168    assert_response :conflict
169
170    # try to delete with an invalid (non-existent) changeset
171    content update_changeset(current_nodes(:visible_node).to_xml,0)
172    delete :delete, :id => current_nodes(:visible_node).id
173    assert_response :conflict
174
175    # valid delete now takes a payload
176    content(nodes(:public_visible_node).to_xml)
177    delete :delete, :id => current_nodes(:public_visible_node).id
178    assert_response :success
179
180    # valid delete should return the new version number, which should
181    # be greater than the old version number
182    assert @response.body.to_i > current_nodes(:public_visible_node).version,
183       "delete request should return a new version number for node"
184
185    # this won't work since the node is already deleted
186    content(nodes(:invisible_node).to_xml)
187    delete :delete, :id => current_nodes(:invisible_node).id
188    assert_response :gone
189
190    # this won't work since the node never existed
191    delete :delete, :id => 0
192    assert_response :not_found
193
194    ## these test whether nodes which are in-use can be deleted:
195    # in a way...
196    content(nodes(:used_node_1).to_xml)
197    delete :delete, :id => current_nodes(:used_node_1).id
198    assert_response :precondition_failed,
199       "shouldn't be able to delete a node used in a way (#{@response.body})"
200
201    # in a relation...
202    content(nodes(:node_used_by_relationship).to_xml)
203    delete :delete, :id => current_nodes(:node_used_by_relationship).id
204    assert_response :precondition_failed,
205       "shouldn't be able to delete a node used in a relation (#{@response.body})"
206  end
207
208  ##
209  # tests whether the API works and prevents incorrect use while trying
210  # to update nodes.
211  def test_update
212    ## First test with no user credentials
213    # try and update a node without authorisation
214    # first try to delete node without auth
215    content current_nodes(:visible_node).to_xml
216    put :update, :id => current_nodes(:visible_node).id
217    assert_response :unauthorized
218   
219   
220   
221    ## Second test with the private user
222   
223    # setup auth
224    basic_authorization(users(:normal_user).email, "test")
225
226    ## trying to break changesets
227
228    # try and update in someone else's changeset
229    content update_changeset(current_nodes(:visible_node).to_xml,
230                             changesets(:public_user_first_change).id)
231    put :update, :id => current_nodes(:visible_node).id
232    assert_require_public_data "update with other user's changeset should be forbidden when date isn't public"
233
234    # try and update in a closed changeset
235    content update_changeset(current_nodes(:visible_node).to_xml,
236                             changesets(:normal_user_closed_change).id)
237    put :update, :id => current_nodes(:visible_node).id
238    assert_require_public_data "update with closed changeset should be forbidden, when data isn't public"
239
240    # try and update in a non-existant changeset
241    content update_changeset(current_nodes(:visible_node).to_xml, 0)
242    put :update, :id => current_nodes(:visible_node).id
243    assert_require_public_data("update with changeset=0 should be forbidden, when data isn't public")
244
245    ## try and submit invalid updates
246    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lat', 91.0);
247    put :update, :id => current_nodes(:visible_node).id
248    assert_require_public_data "node at lat=91 should be forbidden, when data isn't public"
249
250    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lat', -91.0);
251    put :update, :id => current_nodes(:visible_node).id
252    assert_require_public_data "node at lat=-91 should be forbidden, when data isn't public"
253   
254    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lon', 181.0);
255    put :update, :id => current_nodes(:visible_node).id
256    assert_require_public_data "node at lon=181 should be forbidden, when data isn't public"
257
258    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lon', -181.0);
259    put :update, :id => current_nodes(:visible_node).id
260    assert_require_public_data "node at lon=-181 should be forbidden, when data isn't public"
261   
262    ## finally, produce a good request which should work
263    content current_nodes(:visible_node).to_xml
264    put :update, :id => current_nodes(:visible_node).id
265    assert_require_public_data "should have failed with a forbidden when data isn't public"
266
267   
268   
269   
270    ## Finally test with the public user
271   
272    # try and update a node without authorisation
273    # first try to delete node without auth
274    content current_nodes(:visible_node).to_xml
275    put :update, :id => current_nodes(:visible_node).id
276    assert_response :forbidden
277   
278    # setup auth
279    basic_authorization(users(:public_user).email, "test")
280
281    ## trying to break changesets
282
283    # try and update in someone else's changeset
284    content update_changeset(current_nodes(:visible_node).to_xml,
285                              changesets(:normal_user_first_change).id)
286    put :update, :id => current_nodes(:visible_node).id
287    assert_response :conflict, "update with other user's changeset should be rejected"
288
289    # try and update in a closed changeset
290    content update_changeset(current_nodes(:visible_node).to_xml,
291                             changesets(:normal_user_closed_change).id)
292    put :update, :id => current_nodes(:visible_node).id
293    assert_response :conflict, "update with closed changeset should be rejected"
294
295    # try and update in a non-existant changeset
296    content update_changeset(current_nodes(:visible_node).to_xml, 0)
297    put :update, :id => current_nodes(:visible_node).id
298    assert_response :conflict, "update with changeset=0 should be rejected"
299
300    ## try and submit invalid updates
301    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lat', 91.0);
302    put :update, :id => current_nodes(:visible_node).id
303    assert_response :bad_request, "node at lat=91 should be rejected"
304
305    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lat', -91.0);
306    put :update, :id => current_nodes(:visible_node).id
307    assert_response :bad_request, "node at lat=-91 should be rejected"
308   
309    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lon', 181.0);
310    put :update, :id => current_nodes(:visible_node).id
311    assert_response :bad_request, "node at lon=181 should be rejected"
312
313    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lon', -181.0);
314    put :update, :id => current_nodes(:visible_node).id
315    assert_response :bad_request, "node at lon=-181 should be rejected"
316
317    ## next, attack the versioning
318    current_node_version = current_nodes(:visible_node).version
319
320    # try and submit a version behind
321    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 
322                             'version', current_node_version - 1);
323    put :update, :id => current_nodes(:visible_node).id
324    assert_response :conflict, "should have failed on old version number"
325   
326    # try and submit a version ahead
327    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 
328                             'version', current_node_version + 1);
329    put :update, :id => current_nodes(:visible_node).id
330    assert_response :conflict, "should have failed on skipped version number"
331
332    # try and submit total crap in the version field
333    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 
334                             'version', 'p1r4t3s!');
335    put :update, :id => current_nodes(:visible_node).id
336    assert_response :conflict, 
337       "should not be able to put 'p1r4at3s!' in the version field"
338   
339    ## finally, produce a good request which should work
340    content current_nodes(:public_visible_node).to_xml
341    put :update, :id => current_nodes(:public_visible_node).id
342    assert_response :success, "a valid update request failed"
343  end
344
345  ##
346  # test adding tags to a node
347  def test_duplicate_tags
348    # setup auth
349    basic_authorization(users(:public_user).email, "test")
350
351    # add an identical tag to the node
352    tag_xml = XML::Node.new("tag")
353    tag_xml['k'] = current_node_tags(:public_v_t1).k
354    tag_xml['v'] = current_node_tags(:public_v_t1).v
355
356    # add the tag into the existing xml
357    node_xml = current_nodes(:public_visible_node).to_xml
358    node_xml.find("//osm/node").first << tag_xml
359
360    # try and upload it
361    content node_xml
362    put :update, :id => current_nodes(:public_visible_node).id
363    assert_response :bad_request, 
364      "adding duplicate tags to a node should fail with 'bad request'"
365    assert_equal "Element node/#{current_nodes(:public_visible_node).id} has duplicate tags with key #{current_node_tags(:t1).k}.", @response.body
366  end
367
368  # test whether string injection is possible
369  def test_string_injection
370    ## First try with the non-data public user
371    basic_authorization(users(:normal_user).email, "test")
372    changeset_id = changesets(:normal_user_first_change).id
373
374    # try and put something into a string that the API might
375    # use unquoted and therefore allow code injection...
376    content "<osm><node lat='0' lon='0' changeset='#{changeset_id}'>" +
377      '<tag k="#{@user.inspect}" v="0"/>' +
378      '</node></osm>'
379    put :create
380    assert_require_public_data "Shouldn't be able to create with non-public user"
381   
382   
383    ## Then try with the public data user
384    basic_authorization(users(:public_user).email, "test")
385    changeset_id = changesets(:public_user_first_change).id
386
387    # try and put something into a string that the API might
388    # use unquoted and therefore allow code injection...
389    content "<osm><node lat='0' lon='0' changeset='#{changeset_id}'>" +
390      '<tag k="#{@user.inspect}" v="0"/>' +
391      '</node></osm>'
392    put :create
393    assert_response :success
394    nodeid = @response.body
395
396    # find the node in the database
397    checknode = Node.find(nodeid)
398    assert_not_nil checknode, "node not found in data base after upload"
399   
400    # and grab it using the api
401    get :read, :id => nodeid
402    assert_response :success
403    apinode = Node.from_xml(@response.body)
404    assert_not_nil apinode, "downloaded node is nil, but shouldn't be"
405   
406    # check the tags are not corrupted
407    assert_equal checknode.tags, apinode.tags
408    assert apinode.tags.include?('#{@user.inspect}')
409  end
410
411  def basic_authorization(user, pass)
412    @request.env["HTTP_AUTHORIZATION"] = "Basic %s" % Base64.encode64("#{user}:#{pass}")
413  end
414
415  def content(c)
416    @request.env["RAW_POST_DATA"] = c.to_s
417  end
418
419  ##
420  # update the changeset_id of a node element
421  def update_changeset(xml, changeset_id)
422    xml_attr_rewrite(xml, 'changeset', changeset_id)
423  end
424
425  ##
426  # update an attribute in the node element
427  def xml_attr_rewrite(xml, name, value)
428    xml.find("//osm/node").first[name] = value.to_s
429    return xml
430  end
431
432  ##
433  # parse some xml
434  def xml_parse(xml)
435    parser = XML::Parser.string(xml)
436    parser.parse
437  end
438end
Note: See TracBrowser for help on using the repository browser.