zou 0.20.81__py3-none-any.whl → 0.20.83__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,7 +29,7 @@ from zou.app.services import (
29
29
  persons_service,
30
30
  auth_service,
31
31
  events_service,
32
- templates_service
32
+ templates_service,
33
33
  )
34
34
 
35
35
  from zou.app.utils.flask import is_from_browser
@@ -58,20 +58,15 @@ from zou.app.services.exception import (
58
58
 
59
59
 
60
60
  class AuthenticatedResource(Resource):
61
- """
62
- Returns information if the user is authenticated else it returns a 401
63
- response.
64
- It can be used by third party tools, especially browser frontend, to know
65
- if current user is still logged in.
66
- """
67
61
 
68
62
  @jwt_required()
69
63
  def get(self):
70
64
  """
71
- Returns information if the user is authenticated else it returns a 401
72
- response.
65
+ Check authentication status
73
66
  ---
74
- description: It can be used by third party tools, especially browser frontend, to know if current user is still logged in.
67
+ description: Returns information if the user is authenticated.
68
+ It can be used by third party tools, especially browser frontend,
69
+ to know if current user is still logged in.
75
70
  tags:
76
71
  - Authentication
77
72
  responses:
@@ -92,25 +87,19 @@ class AuthenticatedResource(Resource):
92
87
 
93
88
 
94
89
  class LogoutResource(Resource):
95
- """
96
- Log user out by revoking his auth tokens. Once log out, current user
97
- cannot access to API anymore.
98
- """
99
90
 
100
91
  @jwt_required()
101
92
  @permissions.require_person
102
93
  def get(self):
103
94
  """
104
- Log user out by revoking his auth tokens.
95
+ Logout user
105
96
  ---
106
- description: Once logged out, current user cannot access the API anymore.
97
+ description: Log user out by revoking auth tokens. Once logged out, current user cannot access the API anymore.
107
98
  tags:
108
99
  - Authentication
109
100
  responses:
110
101
  200:
111
102
  description: Logout successful
112
- 500:
113
- description: Access token not found
114
103
  """
115
104
  try:
116
105
  auth_service.logout(get_jwt()["jti"])
@@ -131,49 +120,61 @@ class LogoutResource(Resource):
131
120
 
132
121
 
133
122
  class LoginResource(Resource, ArgsMixin):
134
- """
135
- Log in user by creating and registering auth tokens. Login is based
136
- on email and password. If no user match given email and a destkop ID,
137
- it looks in matching the desktop ID with the one stored in database. It is
138
- useful for clients that run on desktop tools and that don't know user
139
- email.
140
- """
141
123
 
142
124
  def post(self):
143
125
  """
144
- Log in user by creating and registering auth tokens.
126
+ Login user
145
127
  ---
146
- description: Login is based on email and password.
147
- If no user match given email and a destkop ID, it looks in matching the desktop ID with the one stored in database.
148
- It is useful for clients that run on desktop tools and that don't know user email.
128
+ description: Log in user by creating and registering auth tokens.
129
+ Login is based on email and password. If no user matches given email
130
+ It fallbacks to a desktop ID. It is useful for desktop tools that
131
+ don't know user email.
132
+ It is also possible to login with TOTP, Email OTP, FIDO and recovery
133
+ code.
149
134
  tags:
150
135
  - Authentication
151
- parameters:
152
- - in: formData
153
- name: email
154
- required: True
155
- type: string
156
- format: email
157
- example: admin@example.com
158
- - in: formData
159
- name: password
160
- required: True
161
- type: string
162
- format: password
163
- example: mysecretpassword
164
- - in: formData
165
- name: otp
166
- required: False
167
- type: string
168
- format: password
169
- example: 123456
136
+ requestBody:
137
+ required: true
138
+ content:
139
+ application/json:
140
+ schema:
141
+ type: object
142
+ properties:
143
+ email:
144
+ type: string
145
+ format: email
146
+ example: admin@example.com
147
+ description: User email address
148
+ password:
149
+ type: string
150
+ format: password
151
+ example: mysecretpassword
152
+ description: User password
153
+ required: true
154
+ totp:
155
+ type: string
156
+ example: 123456
157
+ description: TOTP verification code for two-factor authentication
158
+ required: false
159
+ email_otp:
160
+ type: string
161
+ example: 123456
162
+ description: Email OTP verification code for two-factor authentication
163
+ fido_authentication_response:
164
+ type: object
165
+ description: FIDO authentication response for WebAuth
166
+ recovery_code:
167
+ type: string
168
+ example: ABCD-EFGH-IJKL-MNOP
169
+ description: Recovery code for two-factor authentication
170
+ required:
171
+ - email
172
+ - password
170
173
  responses:
171
174
  200:
172
175
  description: Login successful
173
176
  400:
174
177
  description: Login failed
175
- 500:
176
- description: Database not reachable
177
178
  """
178
179
  (
179
180
  email,
@@ -372,9 +373,10 @@ class RefreshTokenResource(Resource):
372
373
  @permissions.require_person
373
374
  def get(self):
374
375
  """
375
- Tokens are considered as outdated every two weeks.
376
+ Refresh access token
376
377
  ---
377
- description: This route allows to make their lifetime long before they get outdated.
378
+ description: Tokens are considered outdated every two weeks.
379
+ This route allows to extend their lifetime before they get outdated.
378
380
  tags:
379
381
  - Authentication
380
382
  responses:
@@ -403,35 +405,43 @@ class RegistrationResource(Resource, ArgsMixin):
403
405
 
404
406
  def post(self):
405
407
  """
406
- Allow a user to register himself to the service.
408
+ Register new user
407
409
  ---
410
+ description: Allow a user to register himself to the service.
408
411
  tags:
409
412
  - Authentication
410
- parameters:
411
- - in: formData
412
- name: email
413
- required: True
414
- type: string
415
- format: email
416
- example: admin@example.com
417
- - in: formData
418
- name: password
419
- required: True
420
- type: string
421
- format: password
422
- - in: formData
423
- name: password_2
424
- required: True
425
- type: string
426
- format: password
427
- - in: formData
428
- name: first_name
429
- required: True
430
- type: string
431
- - in: formData
432
- name: last_name
433
- required: True
434
- type: string
413
+ requestBody:
414
+ required: true
415
+ content:
416
+ application/json:
417
+ schema:
418
+ type: object
419
+ properties:
420
+ email:
421
+ type: string
422
+ format: email
423
+ example: admin@example.com
424
+ description: User email address
425
+ password:
426
+ type: string
427
+ format: password
428
+ description: User password
429
+ password_2:
430
+ type: string
431
+ format: password
432
+ description: Password confirmation
433
+ first_name:
434
+ type: string
435
+ description: User first name
436
+ last_name:
437
+ type: string
438
+ description: User last name
439
+ required:
440
+ - email
441
+ - password
442
+ - password_2
443
+ - first_name
444
+ - last_name
435
445
  responses:
436
446
  201:
437
447
  description: Registration successful
@@ -508,42 +518,41 @@ class RegistrationResource(Resource, ArgsMixin):
508
518
 
509
519
 
510
520
  class ChangePasswordResource(Resource, ArgsMixin):
511
- """
512
- Allow the user to change his password. Prior to modify the password,
513
- it requires to give the current password (to make sure the user changing
514
- the password is not someone who stealed the session).
515
- The new password requires a confirmation to ensure that the user didn't
516
- make mistake by typing his new password.
517
- """
518
521
 
519
522
  @jwt_required()
520
523
  @permissions.require_person
521
524
  def post(self):
522
525
  """
523
- Allow the user to change his password.
526
+ Change user password
524
527
  ---
525
- description: Prior to modifying the password, it requires to give the current password
526
- (to make sure the user changing the password is not someone who stealed the session).
527
- The new password requires a confirmation to ensure that the user didn't
528
- make a mistake by typing his new password.
528
+ description: Allow the user to change his password. Requires current
529
+ password for verification and password confirmation to ensure
530
+ accuracy.
529
531
  tags:
530
532
  - Authentication
531
- parameters:
532
- - in: formData
533
- name: old_password
534
- required: True
535
- type: string
536
- format: password
537
- - in: formData
538
- name: password
539
- required: True
540
- type: string
541
- format: password
542
- - in: formData
543
- name: password_2
544
- required: True
545
- type: string
546
- format: password
533
+ requestBody:
534
+ required: true
535
+ content:
536
+ application/json:
537
+ schema:
538
+ type: object
539
+ properties:
540
+ old_password:
541
+ type: string
542
+ format: password
543
+ description: Current password
544
+ password:
545
+ type: string
546
+ format: password
547
+ description: New password
548
+ password_2:
549
+ type: string
550
+ format: password
551
+ description: New password confirmation
552
+ required:
553
+ - old_password
554
+ - password
555
+ - password_2
547
556
  responses:
548
557
  200:
549
558
  description: Password changed
@@ -625,42 +634,45 @@ Your IP when you have changed your password is: {person_IP}.
625
634
 
626
635
 
627
636
  class ResetPasswordResource(Resource, ArgsMixin):
628
- """
629
- Resource to allow a user to change his password when he forgets it.
630
- It uses a classic scheme: a token is sent by email to the user. Then
631
- he can change his password.
632
- """
633
637
 
634
638
  def put(self):
635
639
  """
636
- Resource to allow a user to change his password when he forgets it.
640
+ Reset password with token
637
641
  ---
638
- description: "It uses a classic scheme: a token is sent by email to the user.
639
- Then he can change his password."
642
+ description: Allow a user to change his password when he forgets it.
643
+ It uses a token sent by email to the user to verify it is the user
644
+ who requested the password reset.
640
645
  tags:
641
646
  - Authentication
642
- parameters:
643
- - in: formData
644
- name: email
645
- required: True
646
- type: string
647
- format: email
648
- example: admin@example.com
649
- - in: formData
650
- name: token
651
- required: True
652
- type: string
653
- format: JWT token
654
- - in: formData
655
- name: password
656
- required: True
657
- type: string
658
- format: password
659
- - in: formData
660
- name: password2
661
- required: True
662
- type: string
663
- format: password
647
+ requestBody:
648
+ required: true
649
+ content:
650
+ application/json:
651
+ schema:
652
+ type: object
653
+ properties:
654
+ email:
655
+ type: string
656
+ format: email
657
+ example: admin@example.com
658
+ description: User email address
659
+ token:
660
+ type: string
661
+ format: JWT token
662
+ description: Password reset token
663
+ password:
664
+ type: string
665
+ format: password
666
+ description: New password
667
+ password2:
668
+ type: string
669
+ format: password
670
+ description: New password confirmation
671
+ required:
672
+ - email
673
+ - token
674
+ - password
675
+ - password2
664
676
  responses:
665
677
  200:
666
678
  description: Password reset
@@ -712,19 +724,26 @@ class ResetPasswordResource(Resource, ArgsMixin):
712
724
 
713
725
  def post(self):
714
726
  """
715
- Resource to allow a user to change his password when he forgets it.
727
+ Request password reset
716
728
  ---
717
- description: "It uses a classic scheme: a token is sent by email to the user.
718
- Then he can change his password."
729
+ description: Send a password reset token by email to the user.
730
+ It uses a classic scheme where a token is sent by email.
719
731
  tags:
720
732
  - Authentication
721
- parameters:
722
- - in: formData
723
- name: email
724
- required: True
725
- type: string
726
- format: email
727
- example: admin@example.com
733
+ requestBody:
734
+ required: true
735
+ content:
736
+ application/json:
737
+ schema:
738
+ type: object
739
+ properties:
740
+ email:
741
+ type: string
742
+ format: email
743
+ example: admin@example.com
744
+ description: User email address
745
+ required:
746
+ - email
728
747
  responses:
729
748
  200:
730
749
  description: Reset token sent
@@ -767,8 +786,12 @@ class ResetPasswordResource(Resource, ArgsMixin):
767
786
  html = f"""<p>Hello {user["first_name"]},</p>
768
787
 
769
788
  <p>
770
- You have requested for a password reset. You can follow this link to change your
771
- password: <a href="{reset_url}">{reset_url}</a>
789
+ You have requested for a password reset. Click on the following button
790
+ to change your password:
791
+ </p>
792
+
793
+ <p class="cta">
794
+ <a class="button" href="{reset_url}">Change your password</a>
772
795
  </p>
773
796
 
774
797
  <p>
@@ -785,26 +808,22 @@ The IP of the person who requested this is: {person_IP}.
785
808
 
786
809
 
787
810
  class TOTPResource(Resource, ArgsMixin):
788
- """
789
- Resource to allow a user to enable/disable TOTP.
790
- """
791
811
 
792
812
  @jwt_required()
793
813
  @permissions.require_person
794
814
  def put(self):
795
815
  """
796
- Resource to allow a user to pre-enable TOTP.
816
+ Pre-enable TOTP
797
817
  ---
798
- description: ""
818
+ description: Prepare TOTP (Time-based One-Time Password) for enabling.
819
+ It returns provisioning URI and secret for authenticator app setup.
799
820
  tags:
800
821
  - Authentication
801
822
  responses:
802
823
  200:
803
- description: TOTP enabled
824
+ description: TOTP pre-enabled
804
825
  400:
805
- description: Invalid password
806
- Wrong or expired token
807
- Inactive user
826
+ description: TOTP already enabled
808
827
  """
809
828
  try:
810
829
  totp_provisionning_uri, totp_secret = auth_service.pre_enable_totp(
@@ -824,18 +843,29 @@ class TOTPResource(Resource, ArgsMixin):
824
843
  @permissions.require_person
825
844
  def post(self):
826
845
  """
827
- Resource to allow a user to enable TOTP.
846
+ Enable TOTP
828
847
  ---
829
- description: ""
848
+ description: Enable TOTP (Time-based One-Time Password) authentication.
849
+ It requires verification code from authenticator app.
830
850
  tags:
831
851
  - Authentication
852
+ requestBody:
853
+ required: true
854
+ content:
855
+ application/json:
856
+ schema:
857
+ type: object
858
+ properties:
859
+ totp:
860
+ type: string
861
+ description: TOTP verification code from authenticator app
862
+ required:
863
+ - totp
832
864
  responses:
833
865
  200:
834
866
  description: TOTP enabled
835
867
  400:
836
- description: Invalid password
837
- Wrong or expired token
838
- Inactive user
868
+ description: TOTP already enabled or verification failed
839
869
  """
840
870
  args = self.get_args([("totp", "", True)])
841
871
 
@@ -863,16 +893,36 @@ class TOTPResource(Resource, ArgsMixin):
863
893
  @permissions.require_person
864
894
  def delete(self):
865
895
  """
866
- Resource to allow a user to disable TOTP.
896
+ Disable TOTP
867
897
  ---
868
- description: ""
898
+ description: Disable TOTP (Time-based One-Time Password) authentication.
899
+ It requires two-factor authentication verification.
869
900
  tags:
870
901
  - Authentication
902
+ requestBody:
903
+ required: true
904
+ content:
905
+ application/json:
906
+ schema:
907
+ type: object
908
+ properties:
909
+ totp:
910
+ type: string
911
+ description: TOTP verification code
912
+ email_otp:
913
+ type: string
914
+ description: Email OTP verification code
915
+ fido_authentication_response:
916
+ type: object
917
+ description: FIDO authentication response
918
+ recovery_code:
919
+ type: string
920
+ description: Recovery code for two-factor authentication
871
921
  responses:
872
922
  200:
873
923
  description: TOTP disabled
874
924
  400:
875
- description: TOTP not enabled
925
+ description: TOTP not enabled or verification failed
876
926
  """
877
927
  args = self.get_args(
878
928
  [
@@ -916,25 +966,27 @@ class TOTPResource(Resource, ArgsMixin):
916
966
 
917
967
 
918
968
  class EmailOTPResource(Resource, ArgsMixin):
919
- """
920
- Resource to allow a user to enable/disable OTP by email or to send an OTP
921
- by email.
922
- """
923
969
 
924
970
  def get(self):
925
971
  """
926
- Resource to send an OTP by email to user.
972
+ Send email OTP
927
973
  ---
928
- description: ""
974
+ description: Send a one-time password by email to the user for
975
+ authentication.
929
976
  tags:
930
977
  - Authentication
978
+ parameters:
979
+ - in: query
980
+ name: email
981
+ required: True
982
+ type: string
983
+ format: email
984
+ description: User email address
931
985
  responses:
932
986
  200:
933
987
  description: OTP by email sent
934
988
  400:
935
- description: Invalid password
936
- Wrong or expired token
937
- Inactive user
989
+ description: OTP by email not enabled
938
990
  """
939
991
  args = self.get_args(
940
992
  [
@@ -969,18 +1021,17 @@ class EmailOTPResource(Resource, ArgsMixin):
969
1021
  @permissions.require_person
970
1022
  def put(self):
971
1023
  """
972
- Resource to allow a user to pre-enable OTP by email.
1024
+ Pre-enable email OTP
973
1025
  ---
974
- description: ""
1026
+ description: Prepare email OTP (One-Time Password) for enabling.
1027
+ It sets up email-based two-factor authentication.
975
1028
  tags:
976
1029
  - Authentication
977
1030
  responses:
978
1031
  200:
979
- description: OTP by email enabled
1032
+ description: Email OTP pre-enabled
980
1033
  400:
981
- description: Invalid password
982
- Wrong or expired token
983
- Inactive user
1034
+ description: Email OTP already enabled
984
1035
  """
985
1036
  try:
986
1037
  auth_service.pre_enable_email_otp(
@@ -997,18 +1048,29 @@ class EmailOTPResource(Resource, ArgsMixin):
997
1048
  @permissions.require_person
998
1049
  def post(self):
999
1050
  """
1000
- Resource to allow a user to enable OTP by email.
1051
+ Enable email OTP
1001
1052
  ---
1002
- description: ""
1053
+ description: Enable email OTP (One-Time Password) authentication.
1054
+ It requires verification code sent to email.
1003
1055
  tags:
1004
1056
  - Authentication
1057
+ requestBody:
1058
+ required: true
1059
+ content:
1060
+ application/json:
1061
+ schema:
1062
+ type: object
1063
+ properties:
1064
+ email_otp:
1065
+ type: string
1066
+ description: Email OTP verification code
1067
+ required:
1068
+ - email_otp
1005
1069
  responses:
1006
1070
  200:
1007
- description: OTP by email enabled
1071
+ description: Email OTP enabled
1008
1072
  400:
1009
- description: Invalid password
1010
- Wrong or expired token
1011
- Inactive user
1073
+ description: Email OTP already enabled or verification failed
1012
1074
  """
1013
1075
  args = self.get_args([("email_otp", "", True)])
1014
1076
 
@@ -1037,19 +1099,36 @@ class EmailOTPResource(Resource, ArgsMixin):
1037
1099
  @permissions.require_person
1038
1100
  def delete(self):
1039
1101
  """
1040
- Resource to allow a user to disable OTP by email.
1102
+ Disable email OTP
1041
1103
  ---
1042
- description: ""
1104
+ description: Disable email OTP (One-Time Password) authentication.
1105
+ It requires two-factor authentication verification.
1043
1106
  tags:
1044
1107
  - Authentication
1108
+ requestBody:
1109
+ required: true
1110
+ content:
1111
+ application/json:
1112
+ schema:
1113
+ type: object
1114
+ properties:
1115
+ totp:
1116
+ type: string
1117
+ description: TOTP verification code
1118
+ email_otp:
1119
+ type: string
1120
+ description: Email OTP verification code
1121
+ fido_authentication_response:
1122
+ type: object
1123
+ description: FIDO authentication response
1124
+ recovery_code:
1125
+ type: string
1126
+ description: Recovery code for two-factor authentication
1045
1127
  responses:
1046
1128
  200:
1047
- description: OTP by email disabled.
1129
+ description: Email OTP disabled
1048
1130
  400:
1049
- description: Invalid password.
1050
- Wrong or expired token.
1051
- Inactive user.
1052
- Wrong 2FA.
1131
+ description: Email OTP not enabled or verification failed
1053
1132
  """
1054
1133
  args = self.get_args(
1055
1134
  [
@@ -1100,16 +1179,24 @@ class FIDOResource(Resource, ArgsMixin):
1100
1179
 
1101
1180
  def get(self):
1102
1181
  """
1103
- Resource to get a challenge for a FIDO device.
1182
+ Get FIDO challenge
1104
1183
  ---
1105
- description: ""
1184
+ description: Get a challenge for FIDO device authentication.
1185
+ It is used for WebAuthn authentication flow.
1106
1186
  tags:
1107
1187
  - Authentication
1188
+ parameters:
1189
+ - in: query
1190
+ name: email
1191
+ required: True
1192
+ type: string
1193
+ format: email
1194
+ description: User email address
1108
1195
  responses:
1109
1196
  200:
1110
- description: Challenge for FIDO device.
1197
+ description: FIDO challenge generated
1111
1198
  400:
1112
- description: Wrong parameter.
1199
+ description: FIDO not enabled
1113
1200
  """
1114
1201
  args = self.get_args(
1115
1202
  [
@@ -1143,18 +1230,17 @@ class FIDOResource(Resource, ArgsMixin):
1143
1230
  @permissions.require_person
1144
1231
  def put(self):
1145
1232
  """
1146
- Resource to allow a user to pre-register a FIDO device.
1233
+ Pre-register FIDO device
1147
1234
  ---
1148
- description: ""
1235
+ description: Prepare FIDO device for registration.
1236
+ It returns registration options for WebAuthn.
1149
1237
  tags:
1150
1238
  - Authentication
1151
1239
  responses:
1152
1240
  200:
1153
- description: FIDO device pre-registered.
1241
+ description: FIDO device pre-registered data
1154
1242
  400:
1155
- description: Invalid password
1156
- Wrong or expired token
1157
- Inactive user
1243
+ description: Invalid request
1158
1244
  """
1159
1245
  return auth_service.pre_register_fido(
1160
1246
  persons_service.get_current_user()["id"]
@@ -1164,18 +1250,33 @@ class FIDOResource(Resource, ArgsMixin):
1164
1250
  @jwt_required()
1165
1251
  def post(self):
1166
1252
  """
1167
- Resource to allow a user to register a FIDO device.
1253
+ Register FIDO device
1168
1254
  ---
1169
- description: ""
1255
+ description: Register a FIDO device for WebAuthn authentication.
1256
+ It requires registration response from the device.
1170
1257
  tags:
1171
1258
  - Authentication
1259
+ requestBody:
1260
+ required: true
1261
+ content:
1262
+ application/json:
1263
+ schema:
1264
+ type: object
1265
+ properties:
1266
+ registration_response:
1267
+ type: object
1268
+ description: FIDO device registration response
1269
+ device_name:
1270
+ type: string
1271
+ description: Name for the FIDO device
1272
+ required:
1273
+ - registration_response
1274
+ - device_name
1172
1275
  responses:
1173
1276
  200:
1174
- description: FIDO device registered.
1277
+ description: FIDO device registered
1175
1278
  400:
1176
- description: Invalid password
1177
- Wrong or expired token
1178
- Inactive user
1279
+ description: Registration failed or no preregistration
1179
1280
  """
1180
1281
  try:
1181
1282
  args = self.get_args(
@@ -1209,19 +1310,41 @@ class FIDOResource(Resource, ArgsMixin):
1209
1310
  @permissions.require_person
1210
1311
  def delete(self):
1211
1312
  """
1212
- Resource to allow a user to unregister a FIDO device.
1313
+ Unregister FIDO device
1213
1314
  ---
1214
- description: ""
1315
+ description: Unregister a FIDO device from WebAuthn authentication.
1316
+ It requires two-factor authentication verification.
1215
1317
  tags:
1216
1318
  - Authentication
1319
+ requestBody:
1320
+ required: true
1321
+ content:
1322
+ application/json:
1323
+ schema:
1324
+ type: object
1325
+ properties:
1326
+ totp:
1327
+ type: string
1328
+ description: TOTP verification code
1329
+ email_otp:
1330
+ type: string
1331
+ description: Email OTP verification code
1332
+ fido_authentication_response:
1333
+ type: object
1334
+ description: FIDO authentication response
1335
+ recovery_code:
1336
+ type: string
1337
+ description: Recovery code for two-factor authentication
1338
+ device_name:
1339
+ type: string
1340
+ description: Name of the FIDO device to unregister
1341
+ required:
1342
+ - device_name
1217
1343
  responses:
1218
1344
  200:
1219
- description: FIDO device unregistered.
1345
+ description: FIDO device unregistered
1220
1346
  400:
1221
- description: Invalid password
1222
- Wrong or expired token
1223
- Inactive user
1224
- Wrong 2FA
1347
+ description: FIDO not enabled or verification failed
1225
1348
  """
1226
1349
  args = self.get_args(
1227
1350
  [
@@ -1266,26 +1389,41 @@ class FIDOResource(Resource, ArgsMixin):
1266
1389
 
1267
1390
 
1268
1391
  class RecoveryCodesResource(Resource, ArgsMixin):
1269
- """
1270
- Resource to allow a user to generate new recovery codes.
1271
- """
1272
1392
 
1273
1393
  @jwt_required()
1274
1394
  @permissions.require_person
1275
1395
  def put(self):
1276
1396
  """
1277
- Resource to allow a user to generate new recovery codes.
1397
+ Generate recovery codes
1278
1398
  ---
1279
- description: ""
1399
+ description: Generate new recovery codes for two-factor authentication.
1400
+ It requires two-factor authentication verification.
1280
1401
  tags:
1281
1402
  - Authentication
1403
+ requestBody:
1404
+ required: true
1405
+ content:
1406
+ application/json:
1407
+ schema:
1408
+ type: object
1409
+ properties:
1410
+ totp:
1411
+ type: string
1412
+ description: TOTP verification code
1413
+ email_otp:
1414
+ type: string
1415
+ description: Email OTP verification code
1416
+ fido_authentication_response:
1417
+ type: object
1418
+ description: FIDO authentication response
1419
+ recovery_code:
1420
+ type: string
1421
+ description: Recovery code for two-factor authentication
1282
1422
  responses:
1283
1423
  200:
1284
- description: new recovery codes.
1424
+ description: New recovery codes generated
1285
1425
  400:
1286
- description: Invalid password
1287
- Wrong or expired token
1288
- Inactive user
1426
+ description: No two-factor authentication enabled or verification failed
1289
1427
  """
1290
1428
  args = self.get_args(
1291
1429
  [
@@ -1334,22 +1472,20 @@ class RecoveryCodesResource(Resource, ArgsMixin):
1334
1472
 
1335
1473
 
1336
1474
  class SAMLSSOResource(Resource, ArgsMixin):
1337
- """
1338
- Resource to allow a user to login with SAML SSO.
1339
- """
1340
-
1341
1475
  def post(self):
1342
1476
  """
1343
- Resource to allow a user to login with SAML SSO.
1477
+ SAML SSO login
1344
1478
  ---
1345
- description: ""
1479
+ description: Handle SAML SSO login response. Processes authentication
1480
+ response from SAML identity provider and creates a new user if they
1481
+ don't exist.
1346
1482
  tags:
1347
1483
  - Authentication
1348
1484
  responses:
1349
1485
  302:
1350
- description: Login successful, redirect to the home page.
1486
+ description: Login successful, redirect to home page
1351
1487
  400:
1352
- description: Wrong parameter
1488
+ description: SAML not enabled or wrong parameter
1353
1489
  """
1354
1490
  if not config.SAML_ENABLED:
1355
1491
  return {"error": "SAML is not enabled."}, 400
@@ -1425,22 +1561,20 @@ class SAMLSSOResource(Resource, ArgsMixin):
1425
1561
 
1426
1562
 
1427
1563
  class SAMLLoginResource(Resource, ArgsMixin):
1428
- """
1429
- Resource to allow a user to login with SAML SSO.
1430
- """
1431
1564
 
1432
1565
  def get(self):
1433
1566
  """
1434
- Resource to allow a user to login with SAML SSO.
1567
+ SAML SSO login redirect
1435
1568
  ---
1436
- description: ""
1569
+ description: Initiate SAML SSO login by redirecting to SAML identity
1570
+ provider.
1437
1571
  tags:
1438
1572
  - Authentication
1439
1573
  responses:
1440
1574
  302:
1441
- description: Redirect to the SAML IDP.
1575
+ description: Redirect to SAML identity provider
1442
1576
  400:
1443
- description: Wrong parameter.
1577
+ description: SAML not enabled or wrong parameter
1444
1578
  """
1445
1579
  if not config.SAML_ENABLED:
1446
1580
  return {"error": "SAML is not enabled."}, 400