|
9 | 9 |
|
10 | 10 | # Jane Doe has access to specific resources.
|
11 | 11 | user_jane_doe = {
|
12 |
| - 'first_name': "Jane", |
13 |
| - 'last_name': "Doe", |
14 |
| - 'username': "jane.doe", |
15 |
| - 'email': "jane.doe@stackable.tech", |
16 |
| - 'roles': [{'name': "User"}], |
17 |
| - 'password': "T8mn72D9" |
| 12 | + "first_name": "Jane", |
| 13 | + "last_name": "Doe", |
| 14 | + "username": "jane.doe", |
| 15 | + "email": "jane.doe@stackable.tech", |
| 16 | + "roles": [{"name": "User"}], |
| 17 | + "password": "T8mn72D9", |
18 | 18 | }
|
19 | 19 | # Richard Roe has no access.
|
20 | 20 | user_richard_roe = {
|
21 |
| - 'first_name': "Richard", |
22 |
| - 'last_name': "Roe", |
23 |
| - 'username': "richard.roe", |
24 |
| - 'email': "richard.roe@stackable.tech", |
25 |
| - 'roles': [{'name': "User"}], |
26 |
| - 'password': "NvfpU518" |
| 21 | + "first_name": "Richard", |
| 22 | + "last_name": "Roe", |
| 23 | + "username": "richard.roe", |
| 24 | + "email": "richard.roe@stackable.tech", |
| 25 | + "roles": [{"name": "User"}], |
| 26 | + "password": "NvfpU518", |
27 | 27 | }
|
28 | 28 |
|
| 29 | + |
29 | 30 | def create_user(user):
|
30 | 31 | requests.post(
|
31 |
| - 'http://airflow-webserver:8080/auth/fab/v1/users', |
32 |
| - auth=('airflow', 'airflow'), |
33 |
| - json=user |
| 32 | + "http://airflow-webserver:8080/auth/fab/v1/users", |
| 33 | + auth=("airflow", "airflow"), |
| 34 | + json=user, |
34 | 35 | )
|
35 | 36 |
|
| 37 | + |
36 | 38 | def check_api_authorization_for_user(
|
37 |
| - user, |
38 |
| - expected_status_code, |
39 |
| - method, |
40 |
| - endpoint, |
41 |
| - data=None, |
42 |
| - api="api/v1" |
43 |
| - ): |
44 |
| - api_url = f'http://airflow-webserver:8080/{api}' |
45 |
| - |
46 |
| - auth = (user['username'], user['password']) |
47 |
| - response = requests.request(method, f'{api_url}/{endpoint}', auth=auth, json=data) |
| 39 | + user, expected_status_code, method, endpoint, data=None, api="api/v1" |
| 40 | +): |
| 41 | + api_url = f"http://airflow-webserver:8080/{api}" |
| 42 | + |
| 43 | + auth = (user["username"], user["password"]) |
| 44 | + response = requests.request(method, f"{api_url}/{endpoint}", auth=auth, json=data) |
48 | 45 | assert response.status_code == expected_status_code
|
49 | 46 |
|
| 47 | + |
50 | 48 | def check_api_authorization(method, endpoint, data=None, api="api/v1"):
|
51 | 49 | check_api_authorization_for_user(
|
52 |
| - user_jane_doe, |
53 |
| - 200, |
54 |
| - method=method, |
55 |
| - endpoint=endpoint, |
56 |
| - data=data, |
57 |
| - api=api |
| 50 | + user_jane_doe, 200, method=method, endpoint=endpoint, data=data, api=api |
58 | 51 | )
|
59 | 52 | check_api_authorization_for_user(
|
60 |
| - user_richard_roe, |
61 |
| - 403, |
62 |
| - method=method, |
63 |
| - endpoint=endpoint, |
64 |
| - data=data, |
65 |
| - api=api |
| 53 | + user_richard_roe, 403, method=method, endpoint=endpoint, data=data, api=api |
66 | 54 | )
|
67 | 55 |
|
| 56 | + |
68 | 57 | def check_website_authorization_for_user(user, expected_status_code):
|
69 |
| - username = user['username'] |
70 |
| - password = user['password'] |
| 58 | + username = user["username"] |
| 59 | + password = user["password"] |
71 | 60 | with requests.Session() as session:
|
72 | 61 | login_response = session.post(
|
73 |
| - 'http://airflow-webserver:8080/login/', |
| 62 | + "http://airflow-webserver:8080/login/", |
74 | 63 | data=f"username={username}&password={password}",
|
75 | 64 | allow_redirects=False,
|
76 |
| - headers={'Content-Type': 'application/x-www-form-urlencoded'} |
| 65 | + headers={"Content-Type": "application/x-www-form-urlencoded"}, |
77 | 66 | )
|
78 | 67 | assert login_response.ok, f"Login for {username} failed"
|
79 | 68 | home_response = session.get(
|
80 |
| - 'http://airflow-webserver:8080/home', |
81 |
| - allow_redirects=False |
| 69 | + "http://airflow-webserver:8080/home", allow_redirects=False |
82 | 70 | )
|
83 |
| - assert home_response.status_code == expected_status_code, \ |
84 |
| - f"GET /home returned status code {home_response.status_code}, but {expected_status_code} was expected." |
| 71 | + assert ( |
| 72 | + home_response.status_code == expected_status_code |
| 73 | + ), f"GET /home returned status code {home_response.status_code}, but {expected_status_code} was expected." |
| 74 | + |
85 | 75 |
|
86 | 76 | def test_is_authorized_configuration():
|
87 | 77 | # section == null
|
88 |
| - check_api_authorization('GET', 'config') |
| 78 | + check_api_authorization("GET", "config") |
89 | 79 | # section != null
|
90 |
| - check_api_authorization('GET', 'config?section=core') |
| 80 | + check_api_authorization("GET", "config?section=core") |
| 81 | + |
91 | 82 |
|
92 |
| -def test_is_authorized_connection(): |
| 83 | +def test_is_authorized_connection(): |
93 | 84 | # conn_id == null
|
94 |
| - check_api_authorization('GET', 'connections') |
| 85 | + check_api_authorization("GET", "connections") |
95 | 86 | # conn_id != null
|
96 |
| - check_api_authorization('GET', 'connections/postgres_default') |
| 87 | + check_api_authorization("GET", "connections/postgres_default") |
| 88 | + |
97 | 89 |
|
98 | 90 | def test_is_authorized_dag():
|
99 | 91 | # access_entity == null and id == null
|
100 | 92 | # There is no API endpoint to test this case.
|
101 | 93 |
|
102 | 94 | # access_entity == null and id != null
|
103 |
| - check_api_authorization('GET', 'dags/example_trigger_target_dag') |
| 95 | + check_api_authorization("GET", "dags/example_trigger_target_dag") |
104 | 96 |
|
105 | 97 | # access_entity != null and id == null
|
106 | 98 | # Check "GET /dags/~/dagRuns" because access to "GET /dags" is always allowed
|
107 |
| - check_api_authorization('GET', 'dags/~/dagRuns') |
| 99 | + check_api_authorization("GET", "dags/~/dagRuns") |
108 | 100 |
|
109 | 101 | # access_entity != null and id != null
|
110 |
| - check_api_authorization('GET', 'dags/example_trigger_target_dag/dagRuns') |
| 102 | + check_api_authorization("GET", "dags/example_trigger_target_dag/dagRuns") |
| 103 | + |
111 | 104 |
|
112 | 105 | def test_is_authorized_dataset():
|
113 | 106 | # uri == null
|
114 |
| - check_api_authorization('GET', 'datasets') |
| 107 | + check_api_authorization("GET", "datasets") |
115 | 108 | # uri != null
|
116 |
| - check_api_authorization('GET', 'datasets/s3%3A%2F%2Fbucket%2Fmy-task') |
| 109 | + check_api_authorization("GET", "datasets/s3%3A%2F%2Fbucket%2Fmy-task") |
| 110 | + |
117 | 111 |
|
118 | 112 | def test_is_authorized_pool():
|
119 | 113 | # name == null
|
120 |
| - check_api_authorization('GET', 'pools') |
| 114 | + check_api_authorization("GET", "pools") |
121 | 115 | # name != null
|
122 |
| - check_api_authorization('GET', 'pools/default_pool') |
| 116 | + check_api_authorization("GET", "pools/default_pool") |
| 117 | + |
123 | 118 |
|
124 | 119 | def test_is_authorized_variable():
|
125 | 120 | # key != null
|
126 |
| - check_api_authorization('POST', 'variables', data={'key': 'myVar', 'value': '1'}) |
| 121 | + check_api_authorization("POST", "variables", data={"key": "myVar", "value": "1"}) |
127 | 122 | # key == null
|
128 |
| - check_api_authorization('GET', 'variables/myVar') |
| 123 | + check_api_authorization("GET", "variables/myVar") |
| 124 | + |
129 | 125 |
|
130 | 126 | def test_is_authorized_view():
|
131 | 127 | check_website_authorization_for_user(user_jane_doe, 200)
|
132 | 128 | check_website_authorization_for_user(user_richard_roe, 403)
|
133 | 129 |
|
| 130 | + |
134 | 131 | def test_is_authorized_custom_view():
|
135 | 132 | user_jane_doe_patched = user_jane_doe.copy()
|
136 |
| - user_jane_doe_patched['email'] = "jane@stackable.tech" |
| 133 | + user_jane_doe_patched["email"] = "jane@stackable.tech" |
137 | 134 | check_api_authorization_for_user(
|
138 | 135 | user_jane_doe,
|
139 | 136 | 200,
|
140 |
| - 'PATCH', |
141 |
| - 'users/jane.doe?update_mask=email', |
| 137 | + "PATCH", |
| 138 | + "users/jane.doe?update_mask=email", |
142 | 139 | data=user_jane_doe_patched,
|
143 |
| - api='/auth/fab/v1' |
| 140 | + api="/auth/fab/v1", |
144 | 141 | )
|
145 | 142 |
|
146 | 143 | user_richard_roe_patched = user_richard_roe.copy()
|
147 |
| - user_richard_roe_patched['email'] = "richard@stackable.tech" |
| 144 | + user_richard_roe_patched["email"] = "richard@stackable.tech" |
148 | 145 | check_api_authorization_for_user(
|
149 | 146 | user_richard_roe,
|
150 | 147 | 403,
|
151 |
| - 'PATCH', |
152 |
| - 'users/richard.roe?update_mask=email', |
| 148 | + "PATCH", |
| 149 | + "users/richard.roe?update_mask=email", |
153 | 150 | data=user_richard_roe_patched,
|
154 |
| - api='/auth/fab/v1' |
| 151 | + api="/auth/fab/v1", |
155 | 152 | )
|
156 | 153 |
|
| 154 | + |
157 | 155 | # Create test users
|
158 | 156 | create_user(user_jane_doe)
|
159 | 157 | create_user(user_richard_roe)
|
|
0 commit comments