From 65008b4c12e95bfcc7870e0bdb8f8f10500eceda Mon Sep 17 00:00:00 2001 From: Alexander Saprykin Date: Tue, 9 Apr 2024 15:03:33 +0200 Subject: [PATCH] [AAP-22023] Return 401 Unauthorized for session auth No-Issue --- dev/standalone-community/galaxy_ng.env | 2 +- docs/config/options.md | 2 +- docs/integration/ldap.md | 2 +- docs/usage_guide/installation.md | 2 +- galaxy_ng/app/auth/session.py | 13 +++++++++++++ galaxy_ng/app/dynaconf_hooks.py | 8 ++++---- galaxy_ng/app/settings.py | 2 +- galaxy_ng/tests/integration/api/test_auth.py | 6 +++--- galaxy_ng/tests/unit/api/test_api_ui_auth_views.py | 4 ++-- galaxy_ng/tests/unit/api/test_api_v3_auth_views.py | 8 ++++---- galaxy_ng/tests/unit/api/test_view_only_access.py | 4 ++-- profiles/community/pulp_config.env | 2 +- profiles/dab/pulp_config.env | 2 +- profiles/keycloak/pulp_config.env | 2 +- 14 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 galaxy_ng/app/auth/session.py diff --git a/dev/standalone-community/galaxy_ng.env b/dev/standalone-community/galaxy_ng.env index 399925218f..f77f6980c1 100644 --- a/dev/standalone-community/galaxy_ng.env +++ b/dev/standalone-community/galaxy_ng.env @@ -1,7 +1,7 @@ PULP_CONTENT_PATH_PREFIX=/api/v3/artifacts/collections/ PULP_GALAXY_API_PATH_PREFIX=/api/ -PULP_GALAXY_AUTHENTICATION_CLASSES=['rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.BasicAuthentication', 'django.contrib.auth.backends.ModelBackend'] +PULP_GALAXY_AUTHENTICATION_CLASSES=['galaxy_ng.app.auth.session.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.BasicAuthentication', 'django.contrib.auth.backends.ModelBackend'] PULP_GALAXY_DEPLOYMENT_MODE=standalone PULP_GALAXY_REQUIRE_CONTENT_APPROVAL=false PULP_GALAXY_AUTO_SIGN_COLLECTIONS=false diff --git a/docs/config/options.md b/docs/config/options.md index 70156d6c78..d3cffc4615 100644 --- a/docs/config/options.md +++ b/docs/config/options.md @@ -113,7 +113,7 @@ Assuming that on `galaxy_ng.app.settings` there is the default ```py title="Galaxy internal default config" GALAXY_AUTHENTICATION_CLASSES = [ - "rest_framework.authentication.SessionAuthentication", + "galaxy_ng.app.auth.session.SessionAuthentication", "rest_framework.authentication.TokenAuthentication", "rest_framework.authentication.BasicAuthentication", ] diff --git a/docs/integration/ldap.md b/docs/integration/ldap.md index 74ad728d3d..d7a0a7d53d 100644 --- a/docs/integration/ldap.md +++ b/docs/integration/ldap.md @@ -50,7 +50,7 @@ Authentication class and deployment mode by default is already set tho the follo You don't need to change it, **just confirm this is the setting you have in place.** ```bash -PULP_GALAXY_AUTHENTICATION_CLASSES=['rest_framework.authentication.SessionAuthentication','rest_framework.authentication.TokenAuthentication','rest_framework.authentication.BasicAuthentication'] +PULP_GALAXY_AUTHENTICATION_CLASSES=['galaxy_ng.app.auth.session.SessionAuthentication','rest_framework.authentication.TokenAuthentication','rest_framework.authentication.BasicAuthentication'] PULP_GALAXY_DEPLOYMENT_MODE=standalone ``` diff --git a/docs/usage_guide/installation.md b/docs/usage_guide/installation.md index faeaa93a4c..1a98bca1b3 100644 --- a/docs/usage_guide/installation.md +++ b/docs/usage_guide/installation.md @@ -62,7 +62,7 @@ PULP_ANSIBLE_API_HOSTNAME=http://localhost:8080 PULP_GALAXY_API_PATH_PREFIX=/api/galaxy/ PULP_ANSIBLE_CONTENT_HOSTNAME=http://localhost:8080/pulp/content/api/galaxy/v3/artifacts/collections/ PULP_CONTENT_PATH_PREFIX=/pulp/content/api/galaxy/v3/artifacts/collections/ -PULP_GALAXY_AUTHENTICATION_CLASSES=['rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.BasicAuthentication', 'django.contrib.auth.backends.ModelBackend'] +PULP_GALAXY_AUTHENTICATION_CLASSES=['galaxy_ng.app.auth.session.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.BasicAuthentication', 'django.contrib.auth.backends.ModelBackend'] PULP_GALAXY_REQUIRE_CONTENT_APPROVAL=true PULP_GALAXY_DEPLOYMENT_MODE=standalone PULP_GALAXY_AUTO_SIGN_COLLECTIONS=false diff --git a/galaxy_ng/app/auth/session.py b/galaxy_ng/app/auth/session.py new file mode 100644 index 0000000000..5eedbee076 --- /dev/null +++ b/galaxy_ng/app/auth/session.py @@ -0,0 +1,13 @@ +from rest_framework.authentication import SessionAuthentication as _SessionAuthentication + + +class SessionAuthentication(_SessionAuthentication): + """Custom session authentication class. + + This is a workaround for DRF returning 403 Forbidden status code instead + of 401 Unauthorized for session authentication, that does not define + an appropriate `WWW-Authenticate` header value. + """ + + def authenticate_header(self, request): + return "Session" diff --git a/galaxy_ng/app/dynaconf_hooks.py b/galaxy_ng/app/dynaconf_hooks.py index 9e07498b01..7263a08a2b 100755 --- a/galaxy_ng/app/dynaconf_hooks.py +++ b/galaxy_ng/app/dynaconf_hooks.py @@ -165,7 +165,7 @@ def configure_keycloak(settings: Dynaconf) -> Dict[str, Any]: # Replace AUTH CLASSES data["GALAXY_AUTHENTICATION_CLASSES"] = [ - "rest_framework.authentication.SessionAuthentication", + "galaxy_ng.app.auth.session.SessionAuthentication", "galaxy_ng.app.auth.token.ExpiringTokenAuthentication", "galaxy_ng.app.auth.keycloak.KeycloakBasicAuth" ] @@ -232,19 +232,19 @@ def configure_socialauth(settings: Dynaconf) -> Dict[str, Any]: data["GALAXY_AUTHENTICATION_BACKENDS"] = backends data['DEFAULT_AUTHENTICATION_CLASSES'] = [ - "rest_framework.authentication.SessionAuthentication", + "galaxy_ng.app.auth.session.SessionAuthentication", "rest_framework.authentication.TokenAuthentication", "rest_framework.authentication.BasicAuthentication", ] data['GALAXY_AUTHENTICATION_CLASSES'] = [ - "rest_framework.authentication.SessionAuthentication", + "galaxy_ng.app.auth.session.SessionAuthentication", "rest_framework.authentication.TokenAuthentication", "rest_framework.authentication.BasicAuthentication", ] data['REST_FRAMEWORK_AUTHENTICATION_CLASSES'] = [ - "rest_framework.authentication.SessionAuthentication", + "galaxy_ng.app.auth.session.SessionAuthentication", "rest_framework.authentication.TokenAuthentication", "rest_framework.authentication.BasicAuthentication", ] diff --git a/galaxy_ng/app/settings.py b/galaxy_ng/app/settings.py index 57dfc83449..60a0a49e2d 100644 --- a/galaxy_ng/app/settings.py +++ b/galaxy_ng/app/settings.py @@ -75,7 +75,7 @@ # Galaxy authentication classes are used to set REST_FRAMEWORK__DEFAULT_AUTHENTICATION_CLASSES GALAXY_AUTHENTICATION_CLASSES = [ - "rest_framework.authentication.SessionAuthentication", + "galaxy_ng.app.auth.session.SessionAuthentication", "rest_framework.authentication.TokenAuthentication", "rest_framework.authentication.BasicAuthentication", ] diff --git a/galaxy_ng/tests/integration/api/test_auth.py b/galaxy_ng/tests/integration/api/test_auth.py index ac1ede5dba..ab8ff96729 100644 --- a/galaxy_ng/tests/integration/api/test_auth.py +++ b/galaxy_ng/tests/integration/api/test_auth.py @@ -29,7 +29,7 @@ def test_token_auth(profile, galaxy_client): with pytest.raises(GalaxyClientError) as ctx: gc.get("v3/collections/") - assert ctx.value.response.status_code == 403 + assert ctx.value.response.status_code == 401 gc = galaxy_client(profile, ignore_cache=True) resp = gc.get("") assert "available_versions" in resp @@ -46,7 +46,7 @@ def test_auth_admin(galaxy_client): remove_from_cache("admin") with pytest.raises(GalaxyClientError) as ctx: gc.get("v3/collections/") - assert ctx.value.response.status_code == 403 + assert ctx.value.response.status_code == 401 @pytest.mark.deployment_standalone @@ -60,7 +60,7 @@ def test_auth_exception(galaxy_client): remove_from_cache("basic_user") with pytest.raises(GalaxyClientError) as ctx: gc.get("v3/collections/") - assert ctx.value.response.status_code == 403 + assert ctx.value.response.status_code == 401 @pytest.mark.deployment_standalone diff --git a/galaxy_ng/tests/unit/api/test_api_ui_auth_views.py b/galaxy_ng/tests/unit/api/test_api_ui_auth_views.py index fca0338601..f66eb87f48 100644 --- a/galaxy_ng/tests/unit/api/test_api_ui_auth_views.py +++ b/galaxy_ng/tests/unit/api/test_api_ui_auth_views.py @@ -58,7 +58,7 @@ def test_login_invalid_password(self): self.assertEqual(response.status_code, http_code.HTTP_403_FORBIDDEN) response: Response = self.client.get(self.me_url) - self.assertEqual(response.status_code, http_code.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, http_code.HTTP_401_UNAUTHORIZED) def test_login_wrong_password(self): response: Response = self.client.post( @@ -112,7 +112,7 @@ def test_logout(self): self.assertEqual(response.status_code, http_code.HTTP_204_NO_CONTENT) response: Response = self.client.get(self.me_url) - self.assertEqual(response.status_code, http_code.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, http_code.HTTP_401_UNAUTHORIZED) def _test_login(self, username, password, client=None): client = client or self.client diff --git a/galaxy_ng/tests/unit/api/test_api_v3_auth_views.py b/galaxy_ng/tests/unit/api/test_api_v3_auth_views.py index 98724c007a..a25fa75be7 100644 --- a/galaxy_ng/tests/unit/api/test_api_v3_auth_views.py +++ b/galaxy_ng/tests/unit/api/test_api_v3_auth_views.py @@ -71,14 +71,14 @@ def test_token_auth_missing_token(self): new_client = APIClient() response: Response = new_client.get(self.me_url) - self.assertEqual(response.status_code, http_code.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, http_code.HTTP_401_UNAUTHORIZED) self.assertEqual( response.data, { "errors": [ { "code": "not_authenticated", - "status": "403", + "status": "401", "title": "Authentication credentials were not provided.", } ] @@ -90,7 +90,7 @@ def test_token_auth_invalid_token(self): new_client.credentials(HTTP_AUTHORIZATION="Token c451947e96372bc215c1a9e9e9d01eca910cd144") response: Response = new_client.get(self.me_url) - self.assertEqual(response.status_code, http_code.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, http_code.HTTP_401_UNAUTHORIZED) self.assertEqual( response.data, { @@ -98,7 +98,7 @@ def test_token_auth_invalid_token(self): { "detail": "Invalid token.", "code": "authentication_failed", - "status": "403", + "status": "401", "title": "Incorrect authentication credentials.", } ] diff --git a/galaxy_ng/tests/unit/api/test_view_only_access.py b/galaxy_ng/tests/unit/api/test_view_only_access.py index 3c154a587b..fc3ca19d02 100644 --- a/galaxy_ng/tests/unit/api/test_view_only_access.py +++ b/galaxy_ng/tests/unit/api/test_view_only_access.py @@ -80,7 +80,7 @@ def setUp(self): def test_unauthenticated_access_to_collections(self): response = self.client.get(self.collections_detail_url) - self.assertEqual(response.data['errors'][0]['status'], '403') + self.assertEqual(response.data['errors'][0]['status'], '401') with self.settings(GALAXY_ENABLE_UNAUTHENTICATED_COLLECTION_ACCESS=True): response = self.client.get(self.collections_detail_url) self.assertEqual(response.data['name'], self.collection.name) @@ -92,7 +92,7 @@ def test_unauthenticated_access_to_collections(self): def test_unauthenticated_access_to_namespace(self): response = self.client.get(self.ns_detail_url) - self.assertEqual(response.data['errors'][0]['status'], '403') + self.assertEqual(response.data['errors'][0]['status'], '401') with self.settings(GALAXY_ENABLE_UNAUTHENTICATED_COLLECTION_ACCESS=True): response = self.client.get(self.ns_detail_url) self.assertEqual(response.data['name'], self.namespace.name) diff --git a/profiles/community/pulp_config.env b/profiles/community/pulp_config.env index 158874200d..bc1a55beb6 100644 --- a/profiles/community/pulp_config.env +++ b/profiles/community/pulp_config.env @@ -1,7 +1,7 @@ PULP_CONTENT_PATH_PREFIX=/api/v3/artifacts/collections/ PULP_GALAXY_API_PATH_PREFIX=/api/ -PULP_GALAXY_AUTHENTICATION_CLASSES=['rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.BasicAuthentication', 'django.contrib.auth.backends.ModelBackend'] +PULP_GALAXY_AUTHENTICATION_CLASSES=['galaxy_ng.app.auth.session.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.BasicAuthentication', 'django.contrib.auth.backends.ModelBackend'] PULP_GALAXY_REQUIRE_CONTENT_APPROVAL=false PULP_GALAXY_AUTO_SIGN_COLLECTIONS=false diff --git a/profiles/dab/pulp_config.env b/profiles/dab/pulp_config.env index a5256a3484..6cf40b70ab 100644 --- a/profiles/dab/pulp_config.env +++ b/profiles/dab/pulp_config.env @@ -1,4 +1,4 @@ -PULP_GALAXY_AUTHENTICATION_CLASSES="['ansible_base.jwt_consumer.hub.auth.HubJWTAuth', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.BasicAuthentication']" +PULP_GALAXY_AUTHENTICATION_CLASSES="['galaxy_ng.app.auth.session.SessionAuthentication', 'ansible_base.jwt_consumer.hub.auth.HubJWTAuth', 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.BasicAuthentication']" PULP_ANSIBLE_BASE_JWT_VALIDATE_CERT=false PULP_ANSIBLE_BASE_JWT_KEY=https://localhost diff --git a/profiles/keycloak/pulp_config.env b/profiles/keycloak/pulp_config.env index e2839dad62..78091c9a90 100644 --- a/profiles/keycloak/pulp_config.env +++ b/profiles/keycloak/pulp_config.env @@ -1,4 +1,4 @@ -PULP_GALAXY_AUTHENTICATION_CLASSES=['rest_framework.authentication.SessionAuthentication', 'galaxy_ng.app.auth.token.ExpiringTokenAuthentication', 'galaxy_ng.app.auth.keycloak.KeycloakBasicAuth'] +PULP_GALAXY_AUTHENTICATION_CLASSES=['galaxy_ng.app.auth.session.SessionAuthentication', 'galaxy_ng.app.auth.token.ExpiringTokenAuthentication', 'galaxy_ng.app.auth.keycloak.KeycloakBasicAuth'] PULP_GALAXY_DEPLOYMENT_MODE=standalone PULP_SOCIAL_AUTH_KEYCLOAK_KEY=automation-hub