mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge pull request #14057 from mvdbeek/backport_session_fix
[21.09][Backport] Add sessioncookie with ``SameSite=None; secure`` for tool_runner path
This commit is contained in:
@@ -1245,6 +1245,12 @@ class NavigatesGalaxy(HasDriver):
|
||||
self.driver.execute_script("arguments[0].scrollIntoView(true);", tool_element)
|
||||
tool_link.wait_for_and_click()
|
||||
|
||||
def datasource_tool_open(self, tool_id):
|
||||
tool_link = self.components.tool_panel.data_source_tool_link(tool_id=tool_id)
|
||||
tool_element = tool_link.wait_for_present()
|
||||
self.driver.execute_script("arguments[0].scrollIntoView(true);", tool_element)
|
||||
tool_link.wait_for_and_click()
|
||||
|
||||
def tool_parameter_div(self, expanded_parameter_id):
|
||||
return self.components.tool_form.parameter_div(parameter=expanded_parameter_id).wait_for_clickable()
|
||||
|
||||
|
||||
@@ -229,7 +229,7 @@ history_panel:
|
||||
refresh_button: '.history-refresh-button'
|
||||
name: '.title .name'
|
||||
name_beta: '.history-title span:last-child'
|
||||
name_edit_input:
|
||||
name_edit_input:
|
||||
selector: 'name input'
|
||||
type: data-description
|
||||
contents: '#current-history-panel .history-content'
|
||||
@@ -274,7 +274,7 @@ history_panel:
|
||||
selector: '//button[contains(span, "Return to legacy history panel")]'
|
||||
|
||||
collection_menu_button: '.collection-menu'
|
||||
collection_menu_edit_attributes:
|
||||
collection_menu_edit_attributes:
|
||||
type: xpath
|
||||
selector: '//button[@title="Edit attributes"]'
|
||||
new_history_button: '.history-new-button'
|
||||
@@ -316,10 +316,10 @@ edit_dataset_attributes:
|
||||
|
||||
edit_collection_attributes:
|
||||
selectors:
|
||||
database_genome_tab:
|
||||
database_genome_tab:
|
||||
type: xpath
|
||||
selector: '//a[contains(text(), "Database/Build")]'
|
||||
database_value:
|
||||
database_value:
|
||||
type: xpath
|
||||
selector: '//span[contains(text(), "${dbkey}")]'
|
||||
save_btn: '.save-collection-edit'
|
||||
@@ -331,6 +331,7 @@ tool_panel:
|
||||
selectors:
|
||||
tool_link: 'a[href$$="tool_runner?tool_id=${tool_id}"]'
|
||||
outer_tool_link: '.toolTitle a[href$$="tool_runner?tool_id=${tool_id}"]'
|
||||
data_source_tool_link: 'a[href$$="tool_runner/data_source_redirect?tool_id=${tool_id}"]'
|
||||
search: '.search-query'
|
||||
workflow_names: '#internal-workflows .toolTitle'
|
||||
views_button: '.tool-panel-dropdown'
|
||||
|
||||
@@ -9,7 +9,10 @@ import socket
|
||||
import string
|
||||
import time
|
||||
from http.cookies import CookieError
|
||||
from typing import Any, Dict
|
||||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
)
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import mako.lookup
|
||||
@@ -63,6 +66,8 @@ UCSC_SERVERS = (
|
||||
'hgw8.soe.ucsc.edu',
|
||||
)
|
||||
|
||||
TOOL_RUNNER_SESSION_COOKIE = "galaxytoolrunnersession"
|
||||
|
||||
|
||||
class WebApplication(base.WebApplication):
|
||||
"""
|
||||
@@ -379,14 +384,40 @@ class GalaxyWebTransaction(base.DefaultWebTransaction, context.ProvidesHistoryCo
|
||||
if name in self.response.cookies:
|
||||
return self.response.cookies[name].value
|
||||
else:
|
||||
if name not in self.request.cookies and TOOL_RUNNER_SESSION_COOKIE in self.request.cookies:
|
||||
# TOOL_RUNNER_SESSION_COOKIE value is the encoded galaxysession cookie.
|
||||
# We decode it here and pretend it's the galaxysession
|
||||
tool_runner_path = url_for(controller="tool_runner")
|
||||
if self.request.path.startswith(tool_runner_path):
|
||||
return self.security.decode_guid(self.request.cookies[TOOL_RUNNER_SESSION_COOKIE].value)
|
||||
return self.request.cookies[name].value
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def set_cookie(self, value, name='galaxysession', path='/', age=90, version='1'):
|
||||
def set_cookie(self, value, name="galaxysession", path="/", age=90, version="1"):
|
||||
self._set_cookie(value, name=name, path=path, age=age, version=version)
|
||||
if name == "galaxysession":
|
||||
# Set an extra sessioncookie that will only be sent and be accepted on the tool_runner path.
|
||||
# Use the id_secret to encode the sessioncookie, so if a malicious site
|
||||
# obtains the sessioncookie they can only run tools.
|
||||
self._set_cookie(
|
||||
value,
|
||||
name=TOOL_RUNNER_SESSION_COOKIE,
|
||||
path=url_for(controller="tool_runner"),
|
||||
age=age,
|
||||
version=version,
|
||||
encode_value=True,
|
||||
)
|
||||
tool_runner_cookie = self.response.cookies[TOOL_RUNNER_SESSION_COOKIE]
|
||||
tool_runner_cookie["SameSite"] = "None"
|
||||
tool_runner_cookie["secure"] = True
|
||||
|
||||
def _set_cookie(self, value, name="galaxysession", path="/", age=90, version="1", encode_value=False):
|
||||
"""Convenience method for setting a session cookie"""
|
||||
# The galaxysession cookie value must be a high entropy 128 bit random number encrypted
|
||||
# using a server secret key. Any other value is invalid and could pose security issues.
|
||||
if encode_value:
|
||||
value = self.security.encode_guid(value)
|
||||
self.response.cookies[name] = unicodify(value)
|
||||
self.response.cookies[name]['path'] = path
|
||||
self.response.cookies[name]['max-age'] = 3600 * 24 * age # 90 days
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import base64
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from requests import get
|
||||
|
||||
@@ -27,3 +28,29 @@ class AuthenticationApiTestCase(ApiTestCase):
|
||||
random_api_url = self._api_url("users", use_key=False)
|
||||
random_api_response = get(random_api_url, params=dict(key=auth_dict["api_key"]))
|
||||
self._assert_status_code_is(random_api_response, 200)
|
||||
|
||||
def test_tool_runner_session_cookie_handling(self):
|
||||
response = get(self.url)
|
||||
tool_runner_session_cookie = response.cookies["galaxytoolrunnersession"]
|
||||
galaxy_session_cookie = response.cookies["galaxysession"]
|
||||
assert tool_runner_session_cookie != galaxy_session_cookie
|
||||
root_response = get(self.url, cookies={"galaxytoolrunnersession": tool_runner_session_cookie})
|
||||
root_response.raise_for_status()
|
||||
# Browser will only send cookie to /tool_runner path, but let's make sure it isn't accepted.
|
||||
# Galaxy responds with a new session and sessioncookie in that case.
|
||||
# (We might want to redirect to the login page instead if require_login is set?)
|
||||
assert root_response.cookies["galaxysession"] != galaxy_session_cookie
|
||||
tool_runner_response = get(
|
||||
urljoin(self.url, "tool_runner?tool_id=test_data_source"),
|
||||
cookies={"galaxytoolrunnersession": tool_runner_session_cookie},
|
||||
)
|
||||
tool_runner_response.raise_for_status()
|
||||
# Verify that we're not returning the sessioncookie
|
||||
assert "galaxysession" not in tool_runner_response.cookies
|
||||
# Make sure history for original session received job
|
||||
current_history_json_response = get(
|
||||
urljoin(self.url, "history/current_history_json"), cookies={"galaxysession": galaxy_session_cookie}
|
||||
)
|
||||
current_history_json_response.raise_for_status()
|
||||
current_history = current_history_json_response.json()
|
||||
assert current_history["contents_active"]["active"] == 1
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
from galaxy_test.base.populators import skip_if_site_down
|
||||
from .framework import (
|
||||
managed_history,
|
||||
selenium_test,
|
||||
SeleniumTestCase,
|
||||
UsesHistoryItemAssertions,
|
||||
)
|
||||
|
||||
|
||||
class DataSourceTestCase(SeleniumTestCase, UsesHistoryItemAssertions):
|
||||
|
||||
ensure_registered = True
|
||||
|
||||
@selenium_test
|
||||
@managed_history
|
||||
@skip_if_site_down("https://genome.ucsc.edu/cgi-bin/hgTables")
|
||||
def test_ucsc_table_direct1_data_source(self):
|
||||
self.home()
|
||||
self.datasource_tool_open("ucsc_table_direct1")
|
||||
self.screenshot("ucsc_table_browser_first_page")
|
||||
checkbox = self.wait_for_selector("#checkboxGalaxy")
|
||||
assert checkbox.get_attribute("checked") == "true"
|
||||
submit_button = self.wait_for_selector("#hgta_doTopSubmit")
|
||||
submit_button.click()
|
||||
self.screenshot("ucsc_table_browser_second_page")
|
||||
self.wait_for_selector("#hgta_doGalaxyQuery").click()
|
||||
self.history_panel_wait_for_hid_ok(1)
|
||||
# Make sure we're still logged in (xref https://github.com/galaxyproject/galaxy/issues/11374)
|
||||
self.components.masthead.logged_in_only.wait_for_visible()
|
||||
@@ -8,6 +8,7 @@
|
||||
<tool file="param_text_option.xml" />
|
||||
<tool file="column_param.xml" />
|
||||
</section>
|
||||
<tool file="ucsc_tablebrowser.xml"/>
|
||||
<tool file="test_data_source.xml"/>
|
||||
<tool file="simple_constructs.xml" />
|
||||
<tool file="color_param.xml" />
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
../../../lib/galaxy/tools/bundled/data_source/ucsc_tablebrowser.xml
|
||||
Reference in New Issue
Block a user