Skip to content

Commit e681868

Browse files
authored
Merge pull request #97 from arenaxr/fs-pass-renew
filestore rework password renewal and docs
2 parents d899982 + 4d39df8 commit e681868

File tree

3 files changed

+151
-39
lines changed

3 files changed

+151
-39
lines changed

users/filestore.py

+138-20
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,36 @@
1111

1212

1313
def get_user_scope(user: User):
14+
""" Helper method to construct single user filebrowser scope.
15+
Args:
16+
user (User): The User model this action is for.
17+
18+
Returns:
19+
path (string): The single user scope path relative to root filebrowser path.
20+
"""
1421
return f"./users/{user.username}"
1522

1623

1724
def get_admin_login():
25+
""" Helper method to construct admin filebrowser login json string.
26+
27+
Returns:
28+
admin_login (string): The admin login json string.
29+
"""
1830
admin_login = {"username": os.environ["STORE_ADMIN_USERNAME"],
1931
"password": os.environ["STORE_ADMIN_PASSWORD"]}
2032
return admin_login
2133

2234

2335
def get_user_login(user: User):
36+
""" Helper method to construct user.username's filebrowser login json string.
37+
38+
Args:
39+
user (User): The User model this action is for.
40+
41+
Returns:
42+
user_login (string): The user login json string.
43+
"""
2444
if user.username == os.environ["STORE_ADMIN_USERNAME"]:
2545
password = os.environ["STORE_ADMIN_PASSWORD"]
2646
else:
@@ -31,44 +51,72 @@ def get_user_login(user: User):
3151

3252

3353
def use_filestore_auth(user: User):
54+
""" Helper method of to login to user.username's filebrowser account.
55+
56+
Args:
57+
user (User): The User model this action is for.
58+
59+
Returns:
60+
fs_user_token (string): Updated filebrowser api jwt for user.username.
61+
http_status (integer): HTTP status code from filebrowser api login.
62+
"""
3463
if not user.is_authenticated:
3564
return None
3665
verify, host = get_rest_host()
3766
user_login = get_user_login(user)
3867
user_token, status = get_filestore_token(user_login, host, verify)
3968
if not user_token:
40-
return None
41-
return user_token
69+
return None, status
70+
return user_token, status
4271

4372

4473
def get_filestore_token(user_login, host, verify):
74+
""" Uses the filebrowser api to login the user.username's filebrowser account and return their auth jwt.
75+
76+
Args:
77+
user_login (string): The user login json string.
78+
host (string): The django runtime hostname.
79+
verify (bool): True to verify the hostname tls certificate.
80+
81+
Returns:
82+
fs_user_token (string): Updated filebrowser api jwt for user.username.
83+
http_status (integer): HTTP status code from filebrowser api login.
84+
"""
4585
try:
4686
r_userlogin = requests.get(f"https://{host}/storemng/api/login",
4787
data=json.dumps(user_login), verify=verify, timeout=FS_API_TIMEOUT)
4888
r_userlogin.raise_for_status()
4989
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as err:
50-
print("{0}: ".format(err))
90+
print(err)
5191
return None, r_userlogin.status_code
5292
return r_userlogin.text, r_userlogin.status_code
5393

5494

5595
def add_filestore_auth(user: User):
96+
""" Uses the filebrowser api to add the user.username's filebrowser account and return their auth jwt.
97+
98+
Args:
99+
user (User): The User model this action is for.
100+
101+
Returns:
102+
fs_user_token (string): Updated filebrowser api jwt for user.username.
103+
"""
56104
if not user.is_authenticated:
57105
return None
58106
verify, host = get_rest_host()
59107
# get auth for setting new user
60108
admin_login = get_admin_login()
61109
admin_token, status = get_filestore_token(admin_login, host, verify)
62110
if not admin_token:
63-
return False
111+
return None
64112
# get user defaults from global settings
65113
try:
66114
r_gset = requests.get(f"https://{host}/storemng/api/settings",
67115
headers={"X-Auth": admin_token}, verify=verify, timeout=FS_API_TIMEOUT)
68116
r_gset.raise_for_status()
69117
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as err:
70-
print("{0}: ".format(err))
71-
return False
118+
print(err)
119+
return None
72120
settings = r_gset.json()
73121
# set new user options
74122
fs_user = {
@@ -89,35 +137,43 @@ def add_filestore_auth(user: User):
89137
data=json.dumps(fs_user), headers={"X-Auth": admin_token}, verify=verify, timeout=FS_API_TIMEOUT)
90138
r_useradd.raise_for_status()
91139
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as err:
92-
print("{0}: ".format(err))
140+
print(err)
93141
return None
94142

95143
if user.is_staff: # admin and staff get root scope
96144
set_filestore_scope(user)
97145

98-
fs_user_token = use_filestore_auth(user)
146+
fs_user_token, status = use_filestore_auth(user)
99147
return fs_user_token
100148

101149

102150
def set_filestore_scope(user: User):
151+
""" Uses the filebrowser api to reset the user.username's filebrowser account scope and return their auth jwt.
152+
153+
Args:
154+
user (User): The User model this action is for.
155+
156+
Returns:
157+
fs_user_token (string): Updated filebrowser api jwt for user.username.
158+
"""
103159
verify, host = get_rest_host()
104160
# get auth for setting new user
105161
admin_login = get_admin_login()
106162
admin_token, status = get_filestore_token(admin_login, host, verify)
107163
if not admin_token:
108-
return False
164+
return None
109165
# find user
110-
fs_user_token = use_filestore_auth(user)
166+
fs_user_token, status = use_filestore_auth(user)
111167
if not fs_user_token:
112-
return False
168+
return None
113169
payload = jwt.decode(fs_user_token, options={"verify_signature": False})
114170
try:
115171
r_user = requests.get(f"https://{host}/storemng/api/users/{payload['user']['id']}",
116172
headers={"X-Auth": admin_token}, verify=verify, timeout=FS_API_TIMEOUT)
117173
r_user.raise_for_status()
118174
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as err:
119-
print("{0}: ".format(err))
120-
return False
175+
print(err)
176+
return None
121177
edit_user = r_user.json()
122178
if user.is_staff: # admin and staff get root scope
123179
scope = "."
@@ -135,13 +191,75 @@ def set_filestore_scope(user: User):
135191
data=json.dumps(fs_user), headers={"X-Auth": admin_token}, verify=verify, timeout=FS_API_TIMEOUT)
136192
r_useradd.raise_for_status()
137193
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as err:
138-
print("{0}: ".format(err))
139-
return False
194+
print(err)
195+
return None
196+
197+
fs_user_token, status = use_filestore_auth(user)
198+
return fs_user_token
140199

141-
return True
200+
201+
def set_filestore_pass(user: User):
202+
""" Uses the filebrowser api to reset the user.username's filebrowser account password and return their auth jwt.
203+
204+
Args:
205+
user (User): The User model this action is for.
206+
207+
Returns:
208+
fs_user_token (string): Updated filebrowser api jwt for user.username.
209+
"""
210+
if not user.is_authenticated:
211+
return None
212+
if user.username == os.environ["STORE_ADMIN_USERNAME"]:
213+
return None # root admin not allowed pass renew
214+
verify, host = get_rest_host()
215+
# get auth for removing user
216+
admin_login = get_admin_login()
217+
admin_token, status = get_filestore_token(admin_login, host, verify)
218+
if not admin_token:
219+
return None
220+
# find user without valid pass, loop through all
221+
edit_user = {}
222+
try:
223+
r_users = requests.get(f"https://{host}/storemng/api/users",
224+
headers={"X-Auth": admin_token}, verify=verify, timeout=FS_API_TIMEOUT)
225+
r_users.raise_for_status()
226+
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as err:
227+
print(err)
228+
return False
229+
print(r_users.text)
230+
for r_user in json.loads(r_users.text):
231+
if r_user["username"] == user.username:
232+
edit_user = r_user
233+
break
234+
print(edit_user)
235+
# return False
236+
edit_user["password"] = user.password
237+
fs_user = {
238+
"what": "user",
239+
"which": ["all"],
240+
"data": edit_user,
241+
}
242+
try:
243+
r_useradd = requests.put(f"https://{host}/storemng/api/users/{edit_user['id']}",
244+
data=json.dumps(fs_user), headers={"X-Auth": admin_token}, verify=verify, timeout=FS_API_TIMEOUT)
245+
r_useradd.raise_for_status()
246+
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as err:
247+
print(err)
248+
return None
249+
250+
fs_user_token, status = use_filestore_auth(user)
251+
return fs_user_token
142252

143253

144254
def delete_filestore_user(user: User):
255+
""" Uses the filebrowser api to delete the user.username's filebrowser account and files.
256+
257+
Args:
258+
user (User): The User model this action is for.
259+
260+
Returns:
261+
bool: True when user.username's filebrowser account and files are both removed.
262+
"""
145263
if not user.is_authenticated:
146264
return False
147265
if user.username == os.environ["STORE_ADMIN_USERNAME"]:
@@ -153,7 +271,7 @@ def delete_filestore_user(user: User):
153271
if not admin_token:
154272
return False
155273
# find user
156-
fs_user_token = use_filestore_auth(user)
274+
fs_user_token, status = use_filestore_auth(user)
157275
if not fs_user_token:
158276
return False
159277
payload = jwt.decode(fs_user_token, options={"verify_signature": False})
@@ -162,7 +280,7 @@ def delete_filestore_user(user: User):
162280
headers={"X-Auth": admin_token}, verify=verify, timeout=FS_API_TIMEOUT)
163281
r_user.raise_for_status()
164282
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as err:
165-
print("{0}: ".format(err))
283+
print(err)
166284
return False
167285
del_user = r_user.json()
168286
# remove user scope files
@@ -172,15 +290,15 @@ def delete_filestore_user(user: User):
172290
headers={"X-Auth": fs_user_token}, verify=verify, timeout=FS_API_TIMEOUT)
173291
r_filesdel.raise_for_status()
174292
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as err:
175-
print("{0}: ".format(err))
293+
print(err)
176294
return False
177295
# delete user from filestore db
178296
try:
179297
r_userdel = requests.delete(f"https://{host}/storemng/api/users/{del_user['id']}",
180298
headers={"X-Auth": fs_user_token}, verify=verify, timeout=FS_API_TIMEOUT)
181299
r_userdel.raise_for_status()
182300
except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as err:
183-
print("{0}: ".format(err))
301+
print(err)
184302
return False
185303

186304
return True

users/persistence.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import json
22

3-
import jwt
43
import requests
54
from requests.exceptions import HTTPError
65

@@ -54,7 +53,7 @@ def _urlopen(url, token, method, verify):
5453
)
5554
return response.text
5655
except (requests.exceptions.ConnectionError, HTTPError) as err:
57-
print("{0}: ".format(err) + url)
56+
print(f"{err}: {url}")
5857
except ValueError as err:
59-
print(f"{response.text} {0}: ".format(err) + url)
58+
print(f"{response.text} {err}: {url}")
6059
return None

users/views.py

+11-16
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
from rest_framework.schemas import AutoSchema
2626

2727
from .filestore import (add_filestore_auth, delete_filestore_user,
28-
set_filestore_scope, use_filestore_auth)
28+
set_filestore_pass, set_filestore_scope,
29+
use_filestore_auth)
2930
from .forms import (DeviceForm, SceneForm, SocialSignupForm, UpdateDeviceForm,
3031
UpdateSceneForm, UpdateStaffForm)
3132
from .models import Device, Scene
@@ -335,7 +336,7 @@ def profile_update_staff(request):
335336
print(f"Setting Filebrowser user {staff_username}, staff={is_staff}")
336337
if not set_filestore_scope(user):
337338
messages.error(
338-
request, f"Unable to update user's filestore status.")
339+
request, "Unable to update user's filestore status.")
339340
return redirect("user_profile")
340341

341342
return redirect("user_profile")
@@ -369,9 +370,7 @@ def my_scenes(request):
369370
try:
370371
user = get_user_from_id_token(gid_token)
371372
except (ValueError, SocialAccount.DoesNotExist) as err:
372-
return JsonResponse(
373-
{"error": "{0}".format(err)}, status=status.HTTP_403_FORBIDDEN
374-
)
373+
return JsonResponse({"error": err}, status=status.HTTP_403_FORBIDDEN)
375374

376375
serializer = SceneNameSerializer(get_my_scenes(user), many=True)
377376
return JsonResponse(serializer.data, safe=False)
@@ -493,7 +492,7 @@ def user_profile(request):
493492
# delete filestore files/account
494493
if not delete_filestore_user(request.user):
495494
messages.error(
496-
request, f"Unable to delete account/files from the filestore.")
495+
request, "Unable to delete account/files from the filestore.")
497496
return redirect("user_profile")
498497

499498
# Be careful of foreign keys, in that case this is suggested:
@@ -572,9 +571,7 @@ def user_state(request):
572571
try:
573572
user = get_user_from_id_token(gid_token)
574573
except (ValueError, SocialAccount.DoesNotExist) as err:
575-
return JsonResponse(
576-
{"error": "{0}".format(err)}, status=status.HTTP_403_FORBIDDEN
577-
)
574+
return JsonResponse({"error": err}, status=status.HTTP_403_FORBIDDEN)
578575

579576
if user.is_authenticated:
580577
if user.username.startswith("admin"):
@@ -612,14 +609,14 @@ def storelogin(request):
612609
try:
613610
user = get_user_from_id_token(gid_token)
614611
except (ValueError, SocialAccount.DoesNotExist) as err:
615-
return JsonResponse(
616-
{"error": "{0}".format(err)}, status=status.HTTP_403_FORBIDDEN
617-
)
612+
return JsonResponse({"error": err}, status=status.HTTP_403_FORBIDDEN)
618613

619614
fs_user_token = None
620615
if user.is_authenticated:
621616
# try user auth
622-
fs_user_token = use_filestore_auth(user)
617+
fs_user_token, status = use_filestore_auth(user)
618+
if status == 403: # if django allauth pass updated by oauth, update pass
619+
fs_user_token = set_filestore_pass(user)
623620
if not fs_user_token:
624621
# otherwise user needs to be added
625622
fs_user_token = add_filestore_auth(user)
@@ -746,9 +743,7 @@ def arena_token(request):
746743
try:
747744
user = get_user_from_id_token(gid_token)
748745
except (ValueError, SocialAccount.DoesNotExist) as err:
749-
return JsonResponse(
750-
{"error": "{0}".format(err)}, status=status.HTTP_403_FORBIDDEN
751-
)
746+
return JsonResponse({"error": err}, status=status.HTTP_403_FORBIDDEN)
752747

753748
if user.is_authenticated:
754749
username = user.username

0 commit comments

Comments
 (0)