Skip to content

Commit a0f4038

Browse files
authored
AAP-49728 Allow absolute paths for LOGIN_REDIRECT_OVERRIDE (#784)
LOGIN_REDIRECT_OVERRIDE can be an absolute path or a URL.
1 parent ed32cac commit a0f4038

File tree

3 files changed

+46
-11
lines changed

3 files changed

+46
-11
lines changed

ansible_base/authentication/views/ui_auth.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
from typing import Union
23

34
from django.conf import settings
45
from django.utils.translation import gettext_lazy as _
@@ -8,7 +9,7 @@
89
from ansible_base.authentication.models import Authenticator
910
from ansible_base.authentication.serializers import UIAuthResponseSerializer
1011
from ansible_base.lib.utils.settings import get_setting, is_aoc_instance
11-
from ansible_base.lib.utils.validation import validate_image_data, validate_url
12+
from ansible_base.lib.utils.validation import validate_absolute_path, validate_image_data, validate_url
1213
from ansible_base.lib.utils.views.django_app_api import AnsibleBaseDjangoAppApiView
1314

1415
logger = logging.getLogger('ansible_base.authentication.views.ui_auth')
@@ -39,6 +40,23 @@ def get(self):
3940
return self._get()
4041

4142

43+
def _validate_and_get_login_redirect_override() -> Union[str, None]:
44+
try:
45+
login_redirect_override = get_setting('LOGIN_REDIRECT_OVERRIDE', '')
46+
# ignore validation if login_redirect_override is None or empty string
47+
if login_redirect_override is not None and login_redirect_override != '':
48+
validate_url(url=login_redirect_override, schemes=['https', 'http'], allow_plain_hostname=True)
49+
return login_redirect_override
50+
except ValidationError:
51+
# login_redirect_override can also be an absolute path
52+
try:
53+
validate_absolute_path(path=login_redirect_override)
54+
return login_redirect_override
55+
except ValidationError:
56+
logger.error('LOGIN_REDIRECT_OVERRIDE was set but was not a valid URL or absolute path, ignoring')
57+
return None
58+
59+
4260
def generate_ui_auth_data():
4361
authenticators = Authenticator.objects.filter(enabled=True)
4462
response = {
@@ -68,14 +86,9 @@ def generate_ui_auth_data():
6886
else:
6987
logger.error(f"Don't know how to handle authenticator of type {authenticator.type}")
7088

71-
try:
72-
login_redirect_override = get_setting('LOGIN_REDIRECT_OVERRIDE', '')
73-
# ignore validation if login_redirect_override is None or empty string
74-
if login_redirect_override is not None and login_redirect_override != '':
75-
validate_url(url=login_redirect_override, allow_plain_hostname=True)
76-
response['login_redirect_override'] = login_redirect_override
77-
except ValidationError:
78-
logger.error('LOGIN_REDIRECT_OVERRIDE was set but was not a valid URL, ignoring')
89+
login_redirect_override = _validate_and_get_login_redirect_override()
90+
if login_redirect_override:
91+
response['login_redirect_override'] = login_redirect_override
7992

8093
custom_login_info = get_setting('custom_login_info', '')
8194
if isinstance(custom_login_info, str):

ansible_base/lib/utils/validation.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import binascii
33
import re
44
import secrets
5+
from pathlib import Path
56
from urllib.parse import urlparse, urlunsplit
67

78
from cryptography.exceptions import InvalidSignature
@@ -32,6 +33,12 @@ def validate_url_list(urls: list, schemes: list = ['https'], allow_plain_hostnam
3233
raise ValidationError(', '.join(errors))
3334

3435

36+
def validate_absolute_path(path: str) -> None:
37+
path = Path(path)
38+
if not path.is_absolute():
39+
raise ValidationError(f"{path} is not an absolute path")
40+
41+
3542
def validate_url(url: str, schemes: list = ['https'], allow_plain_hostname: bool = False) -> None:
3643
if type(url) is not str:
3744
raise ValidationError(VALID_STRING)

test_app/tests/authentication/views/test_ui_auth.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@ def test_generate_ui_auth_data_no_authenticators_or_settings():
2424

2525
@override_settings(LOGIN_REDIRECT_OVERRIDE='https://example.com')
2626
@pytest.mark.django_db
27-
def test_generate_ui_auth_data_valid_login_redirect():
27+
def test_generate_ui_auth_data_valid_login_redirect_url():
28+
response = generate_ui_auth_data()
29+
assert response['login_redirect_override'] == settings.LOGIN_REDIRECT_OVERRIDE
30+
31+
32+
@override_settings(LOGIN_REDIRECT_OVERRIDE='/an/absolute/path')
33+
@pytest.mark.django_db
34+
def test_generate_ui_auth_data_valid_login_redirect_path():
2835
response = generate_ui_auth_data()
2936
assert response['login_redirect_override'] == settings.LOGIN_REDIRECT_OVERRIDE
3037

@@ -34,7 +41,15 @@ def test_generate_ui_auth_data_valid_login_redirect():
3441
@pytest.mark.django_db
3542
def test_generate_ui_auth_data_invalid_login_redirect_function(logger):
3643
generate_ui_auth_data()
37-
logger.error.assert_called_with('LOGIN_REDIRECT_OVERRIDE was set but was not a valid URL, ignoring')
44+
logger.error.assert_called_with('LOGIN_REDIRECT_OVERRIDE was set but was not a valid URL or absolute path, ignoring')
45+
46+
47+
@mock.patch("ansible_base.authentication.views.ui_auth.logger")
48+
@override_settings(LOGIN_REDIRECT_OVERRIDE='a/relative/path')
49+
@pytest.mark.django_db
50+
def test_generate_ui_auth_invalid_path_login_redirect_function(logger):
51+
generate_ui_auth_data()
52+
logger.error.assert_called_with('LOGIN_REDIRECT_OVERRIDE was set but was not a valid URL or absolute path, ignoring')
3853

3954

4055
@override_settings(custom_login_info='Login with your username and password')

0 commit comments

Comments
 (0)