]> git.proxmox.com Git - ceph.git/blame - ceph/qa/tasks/mgr/dashboard/test_auth.py
import ceph 16.2.7
[ceph.git] / ceph / qa / tasks / mgr / dashboard / test_auth.py
CommitLineData
11fdf7f2
TL
1# -*- coding: utf-8 -*-
2
3from __future__ import absolute_import
4
5import time
6
7import jwt
cd265ab1
TL
8from teuthology.orchestra.run import \
9 CommandFailedError # pylint: disable=import-error
11fdf7f2 10
f67539c2 11from .helper import DashboardTestCase, JLeaf, JObj
11fdf7f2
TL
12
13
14class AuthTest(DashboardTestCase):
15
16 AUTO_AUTHENTICATE = False
17
18 def setUp(self):
9f95a23c 19 super(AuthTest, self).setUp()
11fdf7f2
TL
20 self.reset_session()
21
22 def _validate_jwt_token(self, token, username, permissions):
cd265ab1 23 payload = jwt.decode(token, options={'verify_signature': False})
11fdf7f2
TL
24 self.assertIn('username', payload)
25 self.assertEqual(payload['username'], username)
26
27 for scope, perms in permissions.items():
28 self.assertIsNotNone(scope)
29 self.assertIn('read', perms)
30 self.assertIn('update', perms)
31 self.assertIn('create', perms)
32 self.assertIn('delete', perms)
33
cd265ab1
TL
34 def test_login_without_password(self):
35 with self.assertRaises(CommandFailedError):
36 self.create_user('admin2', '', ['administrator'], force_password=True)
37
11fdf7f2 38 def test_a_set_login_credentials(self):
adb31ebb 39 # test with Authorization header
11fdf7f2
TL
40 self.create_user('admin2', 'admin2', ['administrator'])
41 self._post("/api/auth", {'username': 'admin2', 'password': 'admin2'})
42 self.assertStatus(201)
43 data = self.jsonBody()
44 self._validate_jwt_token(data['token'], "admin2", data['permissions'])
45 self.delete_user('admin2')
46
adb31ebb
TL
47 # test with Cookies set
48 self.create_user('admin2', 'admin2', ['administrator'])
49 self._post("/api/auth", {'username': 'admin2', 'password': 'admin2'}, set_cookies=True)
50 self.assertStatus(201)
51 data = self.jsonBody()
52 self._validate_jwt_token(data['token'], "admin2", data['permissions'])
53 self.delete_user('admin2')
54
11fdf7f2 55 def test_login_valid(self):
adb31ebb 56 # test with Authorization header
11fdf7f2
TL
57 self._post("/api/auth", {'username': 'admin', 'password': 'admin'})
58 self.assertStatus(201)
59 data = self.jsonBody()
9f95a23c
TL
60 self.assertSchema(data, JObj(sub_elems={
61 'token': JLeaf(str),
62 'username': JLeaf(str),
63 'permissions': JObj(sub_elems={}, allow_unknown=True),
64 'sso': JLeaf(bool),
65 'pwdExpirationDate': JLeaf(int, none=True),
66 'pwdUpdateRequired': JLeaf(bool)
67 }, allow_unknown=False))
11fdf7f2
TL
68 self._validate_jwt_token(data['token'], "admin", data['permissions'])
69
adb31ebb
TL
70 # test with Cookies set
71 self._post("/api/auth", {'username': 'admin', 'password': 'admin'}, set_cookies=True)
72 self.assertStatus(201)
73 data = self.jsonBody()
74 self.assertSchema(data, JObj(sub_elems={
75 'token': JLeaf(str),
76 'username': JLeaf(str),
77 'permissions': JObj(sub_elems={}, allow_unknown=True),
78 'sso': JLeaf(bool),
79 'pwdExpirationDate': JLeaf(int, none=True),
80 'pwdUpdateRequired': JLeaf(bool)
81 }, allow_unknown=False))
82 self._validate_jwt_token(data['token'], "admin", data['permissions'])
83
11fdf7f2 84 def test_login_invalid(self):
adb31ebb 85 # test with Authorization header
11fdf7f2
TL
86 self._post("/api/auth", {'username': 'admin', 'password': 'inval'})
87 self.assertStatus(400)
88 self.assertJsonBody({
89 "component": "auth",
90 "code": "invalid_credentials",
91 "detail": "Invalid credentials"
92 })
93
adb31ebb
TL
94 def test_lockout_user(self):
95 # test with Authorization header
96 self._ceph_cmd(['dashboard', 'set-account-lockout-attempts', '3'])
97 for _ in range(3):
98 self._post("/api/auth", {'username': 'admin', 'password': 'inval'})
99 self._post("/api/auth", {'username': 'admin', 'password': 'admin'})
100 self.assertStatus(400)
101 self.assertJsonBody({
102 "component": "auth",
103 "code": "invalid_credentials",
104 "detail": "Invalid credentials"
105 })
106 self._ceph_cmd(['dashboard', 'ac-user-enable', 'admin'])
107 self._post("/api/auth", {'username': 'admin', 'password': 'admin'})
108 self.assertStatus(201)
109 data = self.jsonBody()
110 self.assertSchema(data, JObj(sub_elems={
111 'token': JLeaf(str),
112 'username': JLeaf(str),
113 'permissions': JObj(sub_elems={}, allow_unknown=True),
114 'sso': JLeaf(bool),
115 'pwdExpirationDate': JLeaf(int, none=True),
116 'pwdUpdateRequired': JLeaf(bool)
117 }, allow_unknown=False))
118 self._validate_jwt_token(data['token'], "admin", data['permissions'])
119
120 # test with Cookies set
121 self._ceph_cmd(['dashboard', 'set-account-lockout-attempts', '3'])
122 for _ in range(3):
123 self._post("/api/auth", {'username': 'admin', 'password': 'inval'}, set_cookies=True)
124 self._post("/api/auth", {'username': 'admin', 'password': 'admin'}, set_cookies=True)
125 self.assertStatus(400)
126 self.assertJsonBody({
127 "component": "auth",
128 "code": "invalid_credentials",
129 "detail": "Invalid credentials"
130 })
131 self._ceph_cmd(['dashboard', 'ac-user-enable', 'admin'])
132 self._post("/api/auth", {'username': 'admin', 'password': 'admin'}, set_cookies=True)
133 self.assertStatus(201)
134 data = self.jsonBody()
135 self.assertSchema(data, JObj(sub_elems={
136 'token': JLeaf(str),
137 'username': JLeaf(str),
138 'permissions': JObj(sub_elems={}, allow_unknown=True),
139 'sso': JLeaf(bool),
140 'pwdExpirationDate': JLeaf(int, none=True),
141 'pwdUpdateRequired': JLeaf(bool)
142 }, allow_unknown=False))
143 self._validate_jwt_token(data['token'], "admin", data['permissions'])
144
11fdf7f2 145 def test_logout(self):
adb31ebb 146 # test with Authorization header
11fdf7f2
TL
147 self._post("/api/auth", {'username': 'admin', 'password': 'admin'})
148 self.assertStatus(201)
149 data = self.jsonBody()
150 self._validate_jwt_token(data['token'], "admin", data['permissions'])
151 self.set_jwt_token(data['token'])
152 self._post("/api/auth/logout")
153 self.assertStatus(200)
154 self.assertJsonBody({
155 "redirect_url": "#/login"
156 })
a4b75251 157 self._get("/api/host", version='1.1')
11fdf7f2
TL
158 self.assertStatus(401)
159 self.set_jwt_token(None)
160
adb31ebb
TL
161 # test with Cookies set
162 self._post("/api/auth", {'username': 'admin', 'password': 'admin'}, set_cookies=True)
163 self.assertStatus(201)
164 data = self.jsonBody()
165 self._validate_jwt_token(data['token'], "admin", data['permissions'])
166 self.set_jwt_token(data['token'])
167 self._post("/api/auth/logout", set_cookies=True)
168 self.assertStatus(200)
169 self.assertJsonBody({
170 "redirect_url": "#/login"
171 })
a4b75251 172 self._get("/api/host", set_cookies=True, version='1.1')
adb31ebb
TL
173 self.assertStatus(401)
174 self.set_jwt_token(None)
175
11fdf7f2 176 def test_token_ttl(self):
adb31ebb 177 # test with Authorization header
11fdf7f2
TL
178 self._ceph_cmd(['dashboard', 'set-jwt-token-ttl', '5'])
179 self._post("/api/auth", {'username': 'admin', 'password': 'admin'})
180 self.assertStatus(201)
181 self.set_jwt_token(self.jsonBody()['token'])
a4b75251 182 self._get("/api/host", version='1.1')
11fdf7f2
TL
183 self.assertStatus(200)
184 time.sleep(6)
a4b75251 185 self._get("/api/host", version='1.1')
11fdf7f2
TL
186 self.assertStatus(401)
187 self._ceph_cmd(['dashboard', 'set-jwt-token-ttl', '28800'])
188 self.set_jwt_token(None)
189
adb31ebb
TL
190 # test with Cookies set
191 self._ceph_cmd(['dashboard', 'set-jwt-token-ttl', '5'])
192 self._post("/api/auth", {'username': 'admin', 'password': 'admin'}, set_cookies=True)
193 self.assertStatus(201)
194 self.set_jwt_token(self.jsonBody()['token'])
a4b75251 195 self._get("/api/host", set_cookies=True, version='1.1')
adb31ebb
TL
196 self.assertStatus(200)
197 time.sleep(6)
a4b75251 198 self._get("/api/host", set_cookies=True, version='1.1')
adb31ebb
TL
199 self.assertStatus(401)
200 self._ceph_cmd(['dashboard', 'set-jwt-token-ttl', '28800'])
201 self.set_jwt_token(None)
202
f67539c2 203 def test_remove_from_blocklist(self):
adb31ebb 204 # test with Authorization header
11fdf7f2
TL
205 self._ceph_cmd(['dashboard', 'set-jwt-token-ttl', '5'])
206 self._post("/api/auth", {'username': 'admin', 'password': 'admin'})
207 self.assertStatus(201)
208 self.set_jwt_token(self.jsonBody()['token'])
f67539c2 209 # the following call adds the token to the blocklist
11fdf7f2
TL
210 self._post("/api/auth/logout")
211 self.assertStatus(200)
a4b75251 212 self._get("/api/host", version='1.1')
11fdf7f2
TL
213 self.assertStatus(401)
214 time.sleep(6)
215 self._ceph_cmd(['dashboard', 'set-jwt-token-ttl', '28800'])
216 self.set_jwt_token(None)
217 self._post("/api/auth", {'username': 'admin', 'password': 'admin'})
218 self.assertStatus(201)
219 self.set_jwt_token(self.jsonBody()['token'])
f67539c2 220 # the following call removes expired tokens from the blocklist
11fdf7f2
TL
221 self._post("/api/auth/logout")
222 self.assertStatus(200)
223
adb31ebb
TL
224 # test with Cookies set
225 self._ceph_cmd(['dashboard', 'set-jwt-token-ttl', '5'])
226 self._post("/api/auth", {'username': 'admin', 'password': 'admin'}, set_cookies=True)
227 self.assertStatus(201)
228 self.set_jwt_token(self.jsonBody()['token'])
229 # the following call adds the token to the blocklist
230 self._post("/api/auth/logout", set_cookies=True)
231 self.assertStatus(200)
a4b75251 232 self._get("/api/host", set_cookies=True, version='1.1')
adb31ebb
TL
233 self.assertStatus(401)
234 time.sleep(6)
235 self._ceph_cmd(['dashboard', 'set-jwt-token-ttl', '28800'])
236 self.set_jwt_token(None)
237 self._post("/api/auth", {'username': 'admin', 'password': 'admin'}, set_cookies=True)
238 self.assertStatus(201)
239 self.set_jwt_token(self.jsonBody()['token'])
240 # the following call removes expired tokens from the blocklist
241 self._post("/api/auth/logout", set_cookies=True)
242 self.assertStatus(200)
243
11fdf7f2 244 def test_unauthorized(self):
adb31ebb 245 # test with Authorization header
a4b75251 246 self._get("/api/host", version='1.1')
11fdf7f2
TL
247 self.assertStatus(401)
248
adb31ebb 249 # test with Cookies set
a4b75251 250 self._get("/api/host", set_cookies=True, version='1.1')
adb31ebb
TL
251 self.assertStatus(401)
252
11fdf7f2 253 def test_invalidate_token_by_admin(self):
adb31ebb 254 # test with Authorization header
a4b75251 255 self._get("/api/host", version='1.1')
11fdf7f2
TL
256 self.assertStatus(401)
257 self.create_user('user', 'user', ['read-only'])
258 time.sleep(1)
259 self._post("/api/auth", {'username': 'user', 'password': 'user'})
260 self.assertStatus(201)
261 self.set_jwt_token(self.jsonBody()['token'])
a4b75251 262 self._get("/api/host", version='1.1')
11fdf7f2
TL
263 self.assertStatus(200)
264 time.sleep(1)
cd265ab1
TL
265 self._ceph_cmd_with_secret(['dashboard', 'ac-user-set-password', '--force-password',
266 'user'],
267 'user2')
11fdf7f2 268 time.sleep(1)
a4b75251 269 self._get("/api/host", version='1.1')
11fdf7f2
TL
270 self.assertStatus(401)
271 self.set_jwt_token(None)
272 self._post("/api/auth", {'username': 'user', 'password': 'user2'})
273 self.assertStatus(201)
274 self.set_jwt_token(self.jsonBody()['token'])
a4b75251 275 self._get("/api/host", version='1.1')
11fdf7f2
TL
276 self.assertStatus(200)
277 self.delete_user("user")
9f95a23c 278
adb31ebb 279 # test with Cookies set
a4b75251 280 self._get("/api/host", set_cookies=True, version='1.1')
adb31ebb
TL
281 self.assertStatus(401)
282 self.create_user('user', 'user', ['read-only'])
283 time.sleep(1)
284 self._post("/api/auth", {'username': 'user', 'password': 'user'}, set_cookies=True)
285 self.assertStatus(201)
286 self.set_jwt_token(self.jsonBody()['token'])
a4b75251 287 self._get("/api/host", set_cookies=True, version='1.1')
adb31ebb
TL
288 self.assertStatus(200)
289 time.sleep(1)
cd265ab1
TL
290 self._ceph_cmd_with_secret(['dashboard', 'ac-user-set-password', '--force-password',
291 'user'],
292 'user2')
adb31ebb 293 time.sleep(1)
a4b75251 294 self._get("/api/host", set_cookies=True, version='1.1')
adb31ebb
TL
295 self.assertStatus(401)
296 self.set_jwt_token(None)
297 self._post("/api/auth", {'username': 'user', 'password': 'user2'}, set_cookies=True)
298 self.assertStatus(201)
299 self.set_jwt_token(self.jsonBody()['token'])
a4b75251 300 self._get("/api/host", set_cookies=True, version='1.1')
adb31ebb
TL
301 self.assertStatus(200)
302 self.delete_user("user")
303
9f95a23c 304 def test_check_token(self):
adb31ebb 305 # test with Authorization header
9f95a23c
TL
306 self.login("admin", "admin")
307 self._post("/api/auth/check", {"token": self.jsonBody()["token"]})
308 self.assertStatus(200)
309 data = self.jsonBody()
310 self.assertSchema(data, JObj(sub_elems={
311 "username": JLeaf(str),
312 "permissions": JObj(sub_elems={}, allow_unknown=True),
313 "sso": JLeaf(bool),
314 "pwdUpdateRequired": JLeaf(bool)
315 }, allow_unknown=False))
316 self.logout()
317
adb31ebb
TL
318 # test with Cookies set
319 self.login("admin", "admin", set_cookies=True)
320 self._post("/api/auth/check", {"token": self.jsonBody()["token"]}, set_cookies=True)
321 self.assertStatus(200)
322 data = self.jsonBody()
323 self.assertSchema(data, JObj(sub_elems={
324 "username": JLeaf(str),
325 "permissions": JObj(sub_elems={}, allow_unknown=True),
326 "sso": JLeaf(bool),
327 "pwdUpdateRequired": JLeaf(bool)
328 }, allow_unknown=False))
329 self.logout(set_cookies=True)
330
9f95a23c 331 def test_check_wo_token(self):
adb31ebb 332 # test with Authorization header
9f95a23c
TL
333 self.login("admin", "admin")
334 self._post("/api/auth/check", {"token": ""})
335 self.assertStatus(200)
336 data = self.jsonBody()
337 self.assertSchema(data, JObj(sub_elems={
a4b75251
TL
338 "login_url": JLeaf(str),
339 "cluster_status": JLeaf(str)
9f95a23c
TL
340 }, allow_unknown=False))
341 self.logout()
adb31ebb
TL
342
343 # test with Cookies set
344 self.login("admin", "admin", set_cookies=True)
345 self._post("/api/auth/check", {"token": ""}, set_cookies=True)
346 self.assertStatus(200)
347 data = self.jsonBody()
348 self.assertSchema(data, JObj(sub_elems={
a4b75251
TL
349 "login_url": JLeaf(str),
350 "cluster_status": JLeaf(str)
adb31ebb
TL
351 }, allow_unknown=False))
352 self.logout(set_cookies=True)