authentik.admin.files.tests.test_validation

  1from django.core.exceptions import ValidationError
  2from django.test import TestCase
  3
  4from authentik.admin.files.validation import (
  5    MAX_FILE_NAME_LENGTH,
  6    MAX_PATH_COMPONENT_LENGTH,
  7    validate_file_name,
  8)
  9
 10
 11class TestSanitizeFilePath(TestCase):
 12    """Test validate_file_name function"""
 13
 14    def test_sanitize_valid_filename(self):
 15        """Test sanitizing valid filename"""
 16        validate_file_name("test.png")
 17
 18    def test_sanitize_valid_path_with_directory(self):
 19        """Test sanitizing valid path with directory"""
 20        validate_file_name("images/test.png")
 21
 22    def test_sanitize_valid_path_with_nested_dirs(self):
 23        """Test sanitizing valid path with nested directories"""
 24        validate_file_name("dir1/dir2/dir3/test.png")
 25
 26    def test_sanitize_with_hyphens(self):
 27        """Test sanitizing filename with hyphens"""
 28        validate_file_name("test-file-name.png")
 29
 30    def test_sanitize_with_underscores(self):
 31        """Test sanitizing filename with underscores"""
 32        validate_file_name("test_file_name.png")
 33
 34    def test_sanitize_with_dots(self):
 35        """Test sanitizing filename with multiple dots"""
 36        validate_file_name("test.file.name.png")
 37
 38    def test_sanitize_strips_whitespace(self):
 39        """Test sanitizing filename strips whitespace"""
 40        with self.assertRaises(ValidationError):
 41            validate_file_name("  test.png  ")
 42
 43    def test_sanitize_removes_duplicate_slashes(self):
 44        """Test sanitizing path removes duplicate slashes"""
 45        with self.assertRaises(ValidationError):
 46            validate_file_name("dir1//dir2///test.png")
 47
 48    def test_sanitize_empty_path_raises(self):
 49        """Test sanitizing empty path raises ValidationError"""
 50        with self.assertRaises(ValidationError):
 51            validate_file_name("")
 52
 53    def test_sanitize_whitespace_only_raises(self):
 54        """Test sanitizing whitespace-only path raises ValidationError"""
 55        with self.assertRaises(ValidationError):
 56            validate_file_name("   ")
 57
 58    def test_sanitize_invalid_characters_raises(self):
 59        """Test sanitizing path with invalid characters raises ValidationError"""
 60        invalid_paths = [
 61            "test file.png",  # space
 62            "test@file.png",  # @
 63            "test#file.png",  # #
 64            "test$file.png",  # $
 65            "test%file.png",  # % (but %(theme)s is allowed)
 66            "test&file.png",  # &
 67            "test*file.png",  # *
 68            "test(file).png",  # parentheses (but %(theme)s is allowed)
 69            "test[file].png",  # brackets
 70            "test{file}.png",  # braces
 71        ]
 72
 73        for path in invalid_paths:
 74            with self.assertRaises(ValidationError):
 75                validate_file_name(path)
 76
 77    def test_sanitize_absolute_path_raises(self):
 78        """Test sanitizing absolute path raises ValidationError"""
 79        with self.assertRaises(ValidationError):
 80            validate_file_name("/absolute/path/test.png")
 81
 82    def test_sanitize_parent_directory_raises(self):
 83        """Test sanitizing path with parent directory reference raises ValidationError"""
 84        with self.assertRaises(ValidationError):
 85            validate_file_name("../test.png")
 86
 87    def test_sanitize_nested_parent_directory_raises(self):
 88        """Test sanitizing path with nested parent directory reference raises ValidationError"""
 89        with self.assertRaises(ValidationError):
 90            validate_file_name("dir1/../test.png")
 91
 92    def test_sanitize_starts_with_dot_raises(self):
 93        """Test sanitizing path starting with dot raises ValidationError"""
 94        with self.assertRaises(ValidationError):
 95            validate_file_name(".hidden")
 96
 97    def test_sanitize_too_long_path_raises(self):
 98        """Test sanitizing too long path raises ValidationError"""
 99        long_path = "a" * (MAX_FILE_NAME_LENGTH + 1) + ".png"
100
101        with self.assertRaises(ValidationError):
102            validate_file_name(long_path)
103
104    def test_sanitize_too_long_component_raises(self):
105        """Test sanitizing path with too long component raises ValidationError"""
106        long_component = "a" * (MAX_PATH_COMPONENT_LENGTH + 1)
107        path = f"dir/{long_component}.png"
108
109        with self.assertRaises(ValidationError):
110            validate_file_name(path)
111
112    def test_sanitize_theme_variable_valid(self):
113        """Test sanitizing filename with %(theme)s variable"""
114        # These should all be valid
115        validate_file_name("logo-%(theme)s.png")
116        validate_file_name("brand/logo-%(theme)s.svg")
117        validate_file_name("images/icon-%(theme)s.png")
118        validate_file_name("%(theme)s/logo.png")
119        validate_file_name("brand/%(theme)s/logo.png")
120
121    def test_sanitize_theme_variable_multiple(self):
122        """Test sanitizing filename with multiple %(theme)s variables"""
123        validate_file_name("%(theme)s/logo-%(theme)s.png")
124
125    def test_sanitize_theme_variable_invalid_format(self):
126        """Test that partial or malformed theme variables are rejected"""
127        invalid_paths = [
128            "test%(theme.png",  # missing )s
129            "test%theme)s.png",  # missing (
130            "test%(themes).png",  # wrong variable name
131            "test%(THEME)s.png",  # wrong case
132            "test%()s.png",  # empty variable name
133        ]
134
135        for path in invalid_paths:
136            with self.assertRaises(ValidationError):
137                validate_file_name(path)
class TestSanitizeFilePath(django.test.testcases.TestCase):
 12class TestSanitizeFilePath(TestCase):
 13    """Test validate_file_name function"""
 14
 15    def test_sanitize_valid_filename(self):
 16        """Test sanitizing valid filename"""
 17        validate_file_name("test.png")
 18
 19    def test_sanitize_valid_path_with_directory(self):
 20        """Test sanitizing valid path with directory"""
 21        validate_file_name("images/test.png")
 22
 23    def test_sanitize_valid_path_with_nested_dirs(self):
 24        """Test sanitizing valid path with nested directories"""
 25        validate_file_name("dir1/dir2/dir3/test.png")
 26
 27    def test_sanitize_with_hyphens(self):
 28        """Test sanitizing filename with hyphens"""
 29        validate_file_name("test-file-name.png")
 30
 31    def test_sanitize_with_underscores(self):
 32        """Test sanitizing filename with underscores"""
 33        validate_file_name("test_file_name.png")
 34
 35    def test_sanitize_with_dots(self):
 36        """Test sanitizing filename with multiple dots"""
 37        validate_file_name("test.file.name.png")
 38
 39    def test_sanitize_strips_whitespace(self):
 40        """Test sanitizing filename strips whitespace"""
 41        with self.assertRaises(ValidationError):
 42            validate_file_name("  test.png  ")
 43
 44    def test_sanitize_removes_duplicate_slashes(self):
 45        """Test sanitizing path removes duplicate slashes"""
 46        with self.assertRaises(ValidationError):
 47            validate_file_name("dir1//dir2///test.png")
 48
 49    def test_sanitize_empty_path_raises(self):
 50        """Test sanitizing empty path raises ValidationError"""
 51        with self.assertRaises(ValidationError):
 52            validate_file_name("")
 53
 54    def test_sanitize_whitespace_only_raises(self):
 55        """Test sanitizing whitespace-only path raises ValidationError"""
 56        with self.assertRaises(ValidationError):
 57            validate_file_name("   ")
 58
 59    def test_sanitize_invalid_characters_raises(self):
 60        """Test sanitizing path with invalid characters raises ValidationError"""
 61        invalid_paths = [
 62            "test file.png",  # space
 63            "test@file.png",  # @
 64            "test#file.png",  # #
 65            "test$file.png",  # $
 66            "test%file.png",  # % (but %(theme)s is allowed)
 67            "test&file.png",  # &
 68            "test*file.png",  # *
 69            "test(file).png",  # parentheses (but %(theme)s is allowed)
 70            "test[file].png",  # brackets
 71            "test{file}.png",  # braces
 72        ]
 73
 74        for path in invalid_paths:
 75            with self.assertRaises(ValidationError):
 76                validate_file_name(path)
 77
 78    def test_sanitize_absolute_path_raises(self):
 79        """Test sanitizing absolute path raises ValidationError"""
 80        with self.assertRaises(ValidationError):
 81            validate_file_name("/absolute/path/test.png")
 82
 83    def test_sanitize_parent_directory_raises(self):
 84        """Test sanitizing path with parent directory reference raises ValidationError"""
 85        with self.assertRaises(ValidationError):
 86            validate_file_name("../test.png")
 87
 88    def test_sanitize_nested_parent_directory_raises(self):
 89        """Test sanitizing path with nested parent directory reference raises ValidationError"""
 90        with self.assertRaises(ValidationError):
 91            validate_file_name("dir1/../test.png")
 92
 93    def test_sanitize_starts_with_dot_raises(self):
 94        """Test sanitizing path starting with dot raises ValidationError"""
 95        with self.assertRaises(ValidationError):
 96            validate_file_name(".hidden")
 97
 98    def test_sanitize_too_long_path_raises(self):
 99        """Test sanitizing too long path raises ValidationError"""
100        long_path = "a" * (MAX_FILE_NAME_LENGTH + 1) + ".png"
101
102        with self.assertRaises(ValidationError):
103            validate_file_name(long_path)
104
105    def test_sanitize_too_long_component_raises(self):
106        """Test sanitizing path with too long component raises ValidationError"""
107        long_component = "a" * (MAX_PATH_COMPONENT_LENGTH + 1)
108        path = f"dir/{long_component}.png"
109
110        with self.assertRaises(ValidationError):
111            validate_file_name(path)
112
113    def test_sanitize_theme_variable_valid(self):
114        """Test sanitizing filename with %(theme)s variable"""
115        # These should all be valid
116        validate_file_name("logo-%(theme)s.png")
117        validate_file_name("brand/logo-%(theme)s.svg")
118        validate_file_name("images/icon-%(theme)s.png")
119        validate_file_name("%(theme)s/logo.png")
120        validate_file_name("brand/%(theme)s/logo.png")
121
122    def test_sanitize_theme_variable_multiple(self):
123        """Test sanitizing filename with multiple %(theme)s variables"""
124        validate_file_name("%(theme)s/logo-%(theme)s.png")
125
126    def test_sanitize_theme_variable_invalid_format(self):
127        """Test that partial or malformed theme variables are rejected"""
128        invalid_paths = [
129            "test%(theme.png",  # missing )s
130            "test%theme)s.png",  # missing (
131            "test%(themes).png",  # wrong variable name
132            "test%(THEME)s.png",  # wrong case
133            "test%()s.png",  # empty variable name
134        ]
135
136        for path in invalid_paths:
137            with self.assertRaises(ValidationError):
138                validate_file_name(path)

Test validate_file_name function

def test_sanitize_valid_filename(self):
15    def test_sanitize_valid_filename(self):
16        """Test sanitizing valid filename"""
17        validate_file_name("test.png")

Test sanitizing valid filename

def test_sanitize_valid_path_with_directory(self):
19    def test_sanitize_valid_path_with_directory(self):
20        """Test sanitizing valid path with directory"""
21        validate_file_name("images/test.png")

Test sanitizing valid path with directory

def test_sanitize_valid_path_with_nested_dirs(self):
23    def test_sanitize_valid_path_with_nested_dirs(self):
24        """Test sanitizing valid path with nested directories"""
25        validate_file_name("dir1/dir2/dir3/test.png")

Test sanitizing valid path with nested directories

def test_sanitize_with_hyphens(self):
27    def test_sanitize_with_hyphens(self):
28        """Test sanitizing filename with hyphens"""
29        validate_file_name("test-file-name.png")

Test sanitizing filename with hyphens

def test_sanitize_with_underscores(self):
31    def test_sanitize_with_underscores(self):
32        """Test sanitizing filename with underscores"""
33        validate_file_name("test_file_name.png")

Test sanitizing filename with underscores

def test_sanitize_with_dots(self):
35    def test_sanitize_with_dots(self):
36        """Test sanitizing filename with multiple dots"""
37        validate_file_name("test.file.name.png")

Test sanitizing filename with multiple dots

def test_sanitize_strips_whitespace(self):
39    def test_sanitize_strips_whitespace(self):
40        """Test sanitizing filename strips whitespace"""
41        with self.assertRaises(ValidationError):
42            validate_file_name("  test.png  ")

Test sanitizing filename strips whitespace

def test_sanitize_removes_duplicate_slashes(self):
44    def test_sanitize_removes_duplicate_slashes(self):
45        """Test sanitizing path removes duplicate slashes"""
46        with self.assertRaises(ValidationError):
47            validate_file_name("dir1//dir2///test.png")

Test sanitizing path removes duplicate slashes

def test_sanitize_empty_path_raises(self):
49    def test_sanitize_empty_path_raises(self):
50        """Test sanitizing empty path raises ValidationError"""
51        with self.assertRaises(ValidationError):
52            validate_file_name("")

Test sanitizing empty path raises ValidationError

def test_sanitize_whitespace_only_raises(self):
54    def test_sanitize_whitespace_only_raises(self):
55        """Test sanitizing whitespace-only path raises ValidationError"""
56        with self.assertRaises(ValidationError):
57            validate_file_name("   ")

Test sanitizing whitespace-only path raises ValidationError

def test_sanitize_invalid_characters_raises(self):
59    def test_sanitize_invalid_characters_raises(self):
60        """Test sanitizing path with invalid characters raises ValidationError"""
61        invalid_paths = [
62            "test file.png",  # space
63            "test@file.png",  # @
64            "test#file.png",  # #
65            "test$file.png",  # $
66            "test%file.png",  # % (but %(theme)s is allowed)
67            "test&file.png",  # &
68            "test*file.png",  # *
69            "test(file).png",  # parentheses (but %(theme)s is allowed)
70            "test[file].png",  # brackets
71            "test{file}.png",  # braces
72        ]
73
74        for path in invalid_paths:
75            with self.assertRaises(ValidationError):
76                validate_file_name(path)

Test sanitizing path with invalid characters raises ValidationError

def test_sanitize_absolute_path_raises(self):
78    def test_sanitize_absolute_path_raises(self):
79        """Test sanitizing absolute path raises ValidationError"""
80        with self.assertRaises(ValidationError):
81            validate_file_name("/absolute/path/test.png")

Test sanitizing absolute path raises ValidationError

def test_sanitize_parent_directory_raises(self):
83    def test_sanitize_parent_directory_raises(self):
84        """Test sanitizing path with parent directory reference raises ValidationError"""
85        with self.assertRaises(ValidationError):
86            validate_file_name("../test.png")

Test sanitizing path with parent directory reference raises ValidationError

def test_sanitize_nested_parent_directory_raises(self):
88    def test_sanitize_nested_parent_directory_raises(self):
89        """Test sanitizing path with nested parent directory reference raises ValidationError"""
90        with self.assertRaises(ValidationError):
91            validate_file_name("dir1/../test.png")

Test sanitizing path with nested parent directory reference raises ValidationError

def test_sanitize_starts_with_dot_raises(self):
93    def test_sanitize_starts_with_dot_raises(self):
94        """Test sanitizing path starting with dot raises ValidationError"""
95        with self.assertRaises(ValidationError):
96            validate_file_name(".hidden")

Test sanitizing path starting with dot raises ValidationError

def test_sanitize_too_long_path_raises(self):
 98    def test_sanitize_too_long_path_raises(self):
 99        """Test sanitizing too long path raises ValidationError"""
100        long_path = "a" * (MAX_FILE_NAME_LENGTH + 1) + ".png"
101
102        with self.assertRaises(ValidationError):
103            validate_file_name(long_path)

Test sanitizing too long path raises ValidationError

def test_sanitize_too_long_component_raises(self):
105    def test_sanitize_too_long_component_raises(self):
106        """Test sanitizing path with too long component raises ValidationError"""
107        long_component = "a" * (MAX_PATH_COMPONENT_LENGTH + 1)
108        path = f"dir/{long_component}.png"
109
110        with self.assertRaises(ValidationError):
111            validate_file_name(path)

Test sanitizing path with too long component raises ValidationError

def test_sanitize_theme_variable_valid(self):
113    def test_sanitize_theme_variable_valid(self):
114        """Test sanitizing filename with %(theme)s variable"""
115        # These should all be valid
116        validate_file_name("logo-%(theme)s.png")
117        validate_file_name("brand/logo-%(theme)s.svg")
118        validate_file_name("images/icon-%(theme)s.png")
119        validate_file_name("%(theme)s/logo.png")
120        validate_file_name("brand/%(theme)s/logo.png")

Test sanitizing filename with %(theme)s variable

def test_sanitize_theme_variable_multiple(self):
122    def test_sanitize_theme_variable_multiple(self):
123        """Test sanitizing filename with multiple %(theme)s variables"""
124        validate_file_name("%(theme)s/logo-%(theme)s.png")

Test sanitizing filename with multiple %(theme)s variables

def test_sanitize_theme_variable_invalid_format(self):
126    def test_sanitize_theme_variable_invalid_format(self):
127        """Test that partial or malformed theme variables are rejected"""
128        invalid_paths = [
129            "test%(theme.png",  # missing )s
130            "test%theme)s.png",  # missing (
131            "test%(themes).png",  # wrong variable name
132            "test%(THEME)s.png",  # wrong case
133            "test%()s.png",  # empty variable name
134        ]
135
136        for path in invalid_paths:
137            with self.assertRaises(ValidationError):
138                validate_file_name(path)

Test that partial or malformed theme variables are rejected