Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow DELETE HTTP method for journalist interface #4023

Merged
merged 4 commits into from
Mar 29, 2019

Conversation

emkll
Copy link
Contributor

@emkll emkll commented Jan 8, 2019

Status

Ready for review

Description of Changes

Fixes #3977 , #3877

Certain Journalist API operations require DELETE (e.g. delete or unstar a source). This will ensure that Apache allows the DELETE operation for new installs (or existing installs after an Ansible run).

Furthermore, this will disable Apache stripping Etag headers on the journalist interface in order to receive Etag information from the API (containing sha256 sum of file for integrity). Currently all Etag headers should be sha256sum:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 due to a bug tracked in #4032 .

From the test plan below, it is very clear that we need some integration tests in order to validate these configurations (tracked #4030)

Testing

Clean install scenario

  • Check out this branch
  • ./securedrop-admin install
  • install completed without error
  • /etc/apache2/sites-enabled/journalist.conf contains expected changes (or run testinfra suite)
  • Create admin user for the app
  • Navigate to the source interface and submit a document/message
  • Attempt to delete source via API (see below for example commands)
  • The deletion was successful, DELETE method was allowed by Apache.

Upgrade scenario

  • Install SecureDrop 0.12.1
  • Check out this branch
  • ./securedrop-admin install
  • install completed without error
  • /etc/apache2/sites-enabled/journalist.conf contains expected changes (or run testinfra suite)
  • Create admin user for the app
  • Navigate to the source interface and submit a document/message
  • Attempt to delete source via API

Example test commands for api (curl)

  1. Ensure aths token is in torrc
  2. Get auth token:
torify curl -X POST \
  http://$JOURNALIST_INTERFACE.onion/api/v1/token \
  -H 'Content-Type: application/json' \
  -d '{
    "username": "$USERNAME", 
    "passphrase": "$PASSPHRASE", 
    "one_time_code": "$TOTP"
}'
  1. Use the above token to get list of sources (to obtain source_uuid):
torify curl -X GET \
  http://$JOURNALIST_INTERFACE.onion/api/v1/sources \
  -H 'Authorization: Bearer $YOUR_TOKEN_GOES_HERE' \
  -H 'Content-Type: application/json' 
  1. Get the source based on source_uuid obtained above:
torify curl -X GET \
  http://$JOURNALIST_INTERFACE.onion/api/v1/sources/$SOURCE_UUID \
  -H 'Authorization: Bearer $YOUR_TOKEN_GOES_HERE' \
  -H 'Content-Type: application/json' 
  1. Get the download URL of a file from thesource_uuid :
torify curl -O \
  http://$JOURNALIST_INTERFACE.onion/api/v1/sources/$SOURCE_UUID/submissions/$SUBMISSION_UUID/download \
  -H 'Authorization: Bearer $YOUR_TOKEN_GOES_HERE' \
  -H 'Content-Type: application/json' 
  1. Get the headers/Etag value :
torify curl -I \
  http://$JOURNALIST_INTERFACE.onion/api/v1/sources/$SOURCE_UUID/submissions/$SUBMISSION_UUID/download \
  -H 'Authorization: Bearer $YOUR_TOKEN_GOES_HERE' \
  -H 'Content-Type: application/json' 

Should return the expected Etag value in the headers:

HTTP/1.1 200 OK
Date: Mon, 14 Jan 2019 19:22:02 GMT
Server: Apache
Content-Disposition: attachment; filename=1-better_wrap-msg.gpg
Cache-Control: public, max-age=43200
Expires: Tue, 15 Jan 2019 07:22:02 GMT
X-Frame-Options: DENY
Etag: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
Cache-Control: no-store
Referrer-Policy: no-referrer
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Content-Security-Policy: default-src 'self'
Content-Security-Policy: default-src 'self'
Last-Modified: Mon, 14 Jan 2019 18:54:00 GMT
Content-Length: 592
Content-Type: application/pgp-encrypted
  1. Delete the source:
curl -X DELETE \
  http://$JOURNALIST_INTERFACE.onion/api/v1/sources/$SOURCE_UUID \
  -H 'Authorization: Bearer $YOUR_TOKEN_GOES_HERE' \
  -H 'Content-Type: application/json' 
  1. Ensure the source is deleted:
curl -X GET \
  http://$JOURNALIST_INTERFACE.onion/api/v1/sources \
  -H 'Authorization: Bearer $YOUR_TOKEN_GOES_HERE' \
  -H 'Content-Type: application/json' 

Deployment

Due to the risks associated with modifying the Apache configuration and due to this change being opt-in for users of the SecureDrop Workstation, this change will initially require an Ansible run to be applied.

  1. New installs: Via Ansible / securedrop-admin install
  2. Existing installs/upgrades: Via Ansible / securedrop-admin install

Checklist

If you made changes to the system configuration:

If you made non-trivial code changes:

  • I have written a test plan and validated it for this PR

@@ -53,11 +53,11 @@ ErrorDocument 500 /error
<Directory /var/www/>
Options {{ apache_dir_options | default('None') }}
AllowOverride None
<Limit GET POST HEAD>
<Limit GET POST HEAD DELETE>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should remove the ErrorDocument directives above as part of this ticket. I'm advocating this because they override the API error handlers we have implemented in the application code. Recall these Apache directives in the journalist config are why we saw redirects in #3977 instead of nice JSON responses. Let me know if you see a reason to keep them in the Apache config?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After taking a look at the removal of the ErrorDocument directives, the default Apache pages for errors do not return the security headers that are configured for the journalist interface (i.e.: x-xss-protection referrer-policy ...) While these error pages are static, I think we should still provide the headers for those pages. However, this meas we will need to provide ErrorDocuments for each error (400, 401, 403, 404 and 500)

@emkll emkll force-pushed the 3977-allow-delete-for-journalist-interface branch from ec5466e to bbff078 Compare January 10, 2019 19:11
@codecov-io
Copy link

codecov-io commented Jan 10, 2019

Codecov Report

Merging #4023 into develop will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           develop   #4023   +/-   ##
=======================================
  Coverage     84.7%   84.7%           
=======================================
  Files           43      43           
  Lines         2765    2765           
  Branches       300     300           
=======================================
  Hits          2342    2342           
  Misses         355     355           
  Partials        68      68

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1c877f7...bbff078. Read the comment docs.

@conorsch
Copy link
Contributor

Summarizing discussion today among @emkll, @redshiftzero, and myself: outstanding work here prior to merge is:

@emkll emkll requested a review from heartsucker as a code owner January 10, 2019 23:52
@redshiftzero
Copy link
Contributor

The automated (unit tests since functional tests need to get done in a followup) tests we need for the error handlers are in 9625c4c, one can verify that these tests work by commenting out the registration of the error handlers here and here.

@redshiftzero
Copy link
Contributor

While I don't want to increase the scope of this PR further, we should also resolve #3877 with this PR. The reason is that this is another API bug that we have worked around for now on the SDK/client side, but we should resolve while we are requesting a securedrop-admin install run to enable the API.

@emkll
Copy link
Contributor Author

emkll commented Jan 15, 2019

Thanks for the tests @redshiftzero these look good, and thanks for opening the much-needed #4030 .I agree, let's expose Etags for Journalist interface. I have pushed a commit, tested, and updated the test plan accordingly. I've opened #4032 to track an issue with Etags.

This PR should now be ready for re-review.

@emkll emkll force-pushed the 3977-allow-delete-for-journalist-interface branch from 3575957 to ce48126 Compare January 18, 2019 14:43
@emkll
Copy link
Contributor Author

emkll commented Jan 18, 2019

Rebased on latest develop, this is ready for another review.

@rmol
Copy link
Contributor

rmol commented Mar 19, 2019

👍 I ran through both scenarios -- fresh install and upgrade (though I started at 0.12.0, not 0.11.0) -- and was able to verify the Etag hashes and delete a source through the API.

One note for anyone else testing this: since this PR was filed, we've started requiring Authorization: Token instead of Authorization: Bearer.

@emkll emkll force-pushed the 3977-allow-delete-for-journalist-interface branch from ce48126 to 3ed7208 Compare March 20, 2019 17:15
@emkll
Copy link
Contributor Author

emkll commented Mar 20, 2019

rebased on latest develop

@redshiftzero
Copy link
Contributor

The testinfra failure here looks legit (test_apache_journalist_interface_vhost)

@rmol
Copy link
Contributor

rmol commented Mar 21, 2019

The testinfra failure here looks legit (test_apache_journalist_interface_vhost)

Yep. Just needs a space removed in the expected snippet:

diff --git a/molecule/testinfra/staging/app/apache/test_apache_journalist_interface.py b/molecule/testinfra/staging/app/apache/test_apache_journalist_interface.py
index 1249b2c08..cc1a5341a 100644
--- a/molecule/testinfra/staging/app/apache/test_apache_journalist_interface.py
+++ b/molecule/testinfra/staging/app/apache/test_apache_journalist_interface.py
@@ -63,7 +63,7 @@ common_apache2_directory_declarations = """
 <Directory {securedrop_code}>
   Options None
   AllowOverride None
-   <Limit GET POST HEAD DELETE>
+  <Limit GET POST HEAD DELETE>
     Order allow,deny
     allow from {apache_allow_from}
   </Limit>

emkll and others added 4 commits March 21, 2019 10:01
Certain Journalist API operations require DELETE (e.g. delete or unstar a source). This will ensure that Apache allows the DELETE operation for new installs (or existing installs after an Ansible run).
These directives were returning incorrect values for the Journalist API. Errors should be handled in the application to ensure headers are sent. The API should return appropirate error codes, and the web interface should always redirect to the login page.
The status codes in here are to ensure that the cases the
ErrorDocument directives previously in the Apache journalist
configuration are handled in the application code.
ETags are useful to the journalist API to ensure file integrity, and in the future would allow file download resumption. Disabling ETags is a defense against information leakage https://nvd.nist.gov/vuln/detail/CVE-2003-1418. Since inodes are no longer included by Apache by default, since 2.3.14, that Apache only exposes filesize and MTime by default (information readily available on the Journalist interface, that the Journalist Interface is behind ATHS, it should be safe to re-enable ETags on the journalist interface only.
@emkll emkll force-pushed the 3977-allow-delete-for-journalist-interface branch from 3ed7208 to febee2b Compare March 21, 2019 14:29
@emkll
Copy link
Contributor Author

emkll commented Mar 21, 2019

Thanks for the reviews/comments, I've addressed the test failure described above.
@conorsch would you mind doing a visual review of this (specifically removal of the ErrorDocument directives).

@conorsch
Copy link
Contributor

Changes look good. Based on the diff of the ErrorDocument removal, I'm inclined to agree with @emkll:

While these error pages are static, I think we should still provide the headers for those pages. However, this meas we will need to provide ErrorDocuments for each error (400, 401, 403, 404 and 500)

Let's revisit the error routes when we add new tests validating that the headers are set, even on error. Some of the functional testing work you've been doing in other contexts is relevant here, @emkll, although we could certainly get away with some barebones curl checks to cover our bases. More important, the ErrorDocument directive will likely never work for our needs, given the Client's expectation of full JSON results.

Since the changes are written affect only the Journalist Interface, no concerns with these changes going in as presented. Doing so will unblock pending work on the Client, and we can shore up the functional testing of the server side components post merge of the long-standing TBB work, when all of our functional tests will be running outside the VMs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants