This commit is contained in:
Jason Robbins 2022-09-12 10:52:53 -07:00 коммит произвёл GitHub
Родитель e7eb6b255d
Коммит 772225dbb3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 67 добавлений и 2 удалений

Просмотреть файл

@ -427,6 +427,22 @@ class FlaskHandler(BaseHandler):
self.abort(403, msg=('Lacking X-AppEngine-QueueName or '
'incorrect X-Appengine-Inbound-Appid headers'))
def require_cron_header(self):
"""Abort if this is not a GAE cron request or from a site admin."""
if settings.UNIT_TEST_MODE or settings.DEV_MODE:
return
if 'X-AppEngine-Cron' in self.request.headers:
return
user = self.get_current_user(required=True)
if permissions.can_admin_site(user):
return
logging.info('non-admin and headers lack X-AppEngine-Cron:')
for k, v in self.request.headers:
logging.info('%r: %r', k, v)
self.abort(403, msg='Lacking X-AppEngine-Cron or admin account')
def split_input(self, field_name, delim='\\r?\\n'):
"""Split the input lines, strip whitespace, and skip blank lines."""
input_text = flask.request.form.get(field_name) or ''

Просмотреть файл

@ -666,6 +666,50 @@ class FlaskHandlerTests(testing_config.CustomTestCase):
with self.assertRaises(werkzeug.exceptions.Forbidden):
self.handler.require_task_header()
def test_require_cron_header__while_testing(self):
"""During unit testing of cron handlers, we allow it."""
with test_app.test_request_context('/test'):
self.handler.require_cron_header()
@mock.patch('settings.UNIT_TEST_MODE', False)
def test_require_cron_header__normal(self):
"""If the incoming request is from GCT, we allow it."""
headers = {'X-AppEngine-Cron': 'true'}
with test_app.test_request_context('/test', headers=headers):
self.handler.require_cron_header()
@mock.patch('settings.UNIT_TEST_MODE', False)
@mock.patch('framework.basehandlers.BaseHandler.get_current_user')
@mock.patch('framework.permissions.can_admin_site')
def test_require_cron_header__admin(
self, mock_can_admin_site, mock_get_current_user):
"""If the incoming request is from an admin, we allow it."""
mock_can_admin_site.return_value = True
# Also mock get_current_user because it will not use the usual
# unit test configuration if we have UNIT_TEST_MODE == False.
mock_get_current_user.return_value = users.User('admin@example.com', 111)
with test_app.test_request_context('/test'):
self.handler.require_cron_header()
@mock.patch('settings.UNIT_TEST_MODE', False)
@mock.patch('framework.basehandlers.BaseHandler.get_current_user')
def test_require_cron_header__missing_nonadmin(self, mock_get_current_user):
"""If the incoming request is not from GAE, abort."""
# Also mock get_current_user because it will not use the usual
# unit test configuration if we have UNIT_TEST_MODE == False.
mock_get_current_user.return_value = users.User('user1@example.com', 111)
with test_app.test_request_context('/test'):
with self.assertRaises(werkzeug.exceptions.Forbidden):
self.handler.require_cron_header()
@mock.patch('settings.UNIT_TEST_MODE', False)
def test_require_cron_header__missing_anon(self):
"""If the incoming request is not from GAE, abort."""
testing_config.sign_out()
with test_app.test_request_context('/test'):
with self.assertRaises(werkzeug.exceptions.Forbidden):
self.handler.require_cron_header()
@mock.patch('settings.UNIT_TEST_MODE', False)
@mock.patch('framework.users.get_current_user')
def test_require_xsrf_token__normal(self, mock_get_user):

Просмотреть файл

@ -33,6 +33,7 @@ class BackupExportHandler(basehandlers.FlaskHandler):
"""Triggers a new Datastore export."""
def get_template_data(self):
self.require_cron_header()
bucket = f'gs://{settings.BACKUP_BUCKET}'
# The default cache (file_cache) is unavailable when using oauth2client >= 4.0.0 or google-auth,
# and it will log worrisome messages unless given another interface to use.

Просмотреть файл

@ -8,6 +8,7 @@ class WriteStandardMaturityHandler(FlaskHandler):
def get_template_data(self):
"""Writes standard_maturity field from the old standardization field."""
self.require_cron_header()
q = Feature.query()
features = q.fetch()
update_count = 0
@ -17,7 +18,7 @@ class WriteStandardMaturityHandler(FlaskHandler):
update_count += 1
feature.standard_maturity = STANDARD_MATURITY_BACKFILL[feature.standardization]
feature.put(notify=False)
logging.info(
f'{update_count} features updated with standard_maturity field.')
return 'Success'

Просмотреть файл

@ -186,6 +186,7 @@ class YesterdayHandler(basehandlers.FlaskHandler):
filename: The filename for the data file to be loaded.
today: date passed in for testing, defaults to today.
"""
self.require_cron_header()
days = []
date_str = self.request.args.get('date')
if date_str:
@ -244,6 +245,7 @@ class HistogramsHandler(basehandlers.FlaskHandler):
)
def get_template_data(self):
self.require_cron_header()
# Attempt to fetch enums mapping file.
response = requests.get(HISTOGRAMS_URL, timeout=60)
@ -278,5 +280,6 @@ class HistogramsHandler(basehandlers.FlaskHandler):
class BlinkComponentHandler(basehandlers.FlaskHandler):
"""Updates the list of Blink components in the db."""
def get_template_data(self):
self.require_cron_header()
user_models.BlinkComponent.update_db()
return 'Blink components updated'

Просмотреть файл

@ -279,7 +279,7 @@ class FeatureAccuracyHandler(basehandlers.FlaskHandler):
def get_template_data(self):
"""Sends notifications to users requesting feature updates for accuracy."""
self.require_cron_header()
features_to_notify = self._determine_features_to_notify()
email_tasks = self._build_email_tasks(features_to_notify)
send_emails(email_tasks)