Codebase list python-faraday / 7bee975
Update flask-security to 3.4.5 Sophie Brun 3 years ago
8 changed file(s) with 130 addition(s) and 42 deletion(s). Raw diff Collapse all Expand all
100100 verify_and_update_password,
101101 )
102102
103 __version__ = "3.4.2"
103 __version__ = "3.4.5"
120120 @with_appcontext
121121 @commit
122122 def roles_add(user, role):
123 """Add user to role."""
123 """Add role to user."""
124124 user, role = _datastore._prepare_role_modify_args(user, role)
125125 if user is None:
126126 raise click.UsageError("Cannot find user.")
128128 raise click.UsageError("Cannot find role.")
129129 if _datastore.add_role_to_user(user, role):
130130 click.secho(
131 'Role "{0}" added to user "{1}" ' "successfully.".format(role, user),
131 'Role "{0}" added to user "{1}" ' "successfully.".format(role.name, user),
132132 fg="green",
133133 )
134134 else:
141141 @with_appcontext
142142 @commit
143143 def roles_remove(user, role):
144 """Remove user from role."""
144 """Remove role from user."""
145145 user, role = _datastore._prepare_role_modify_args(user, role)
146146 if user is None:
147147 raise click.UsageError("Cannot find user.")
149149 raise click.UsageError("Cannot find role.")
150150 if _datastore.remove_role_from_user(user, role):
151151 click.secho(
152 'Role "{0}" removed from user "{1}" ' "successfully.".format(role, user),
152 'Role "{0}" removed from user "{1}" '
153 "successfully.".format(role.name, user),
153154 fg="green",
154155 )
155156 else:
164165 """Activate a user."""
165166 user_obj = _datastore.get_user(user)
166167 if user_obj is None:
167 raise click.UsageError("ERROR: User not found.")
168 raise click.UsageError("User not found.")
168169 if _datastore.activate_user(user_obj):
169170 click.secho('User "{0}" has been activated.'.format(user), fg="green")
170171 else:
179180 """Deactivate a user."""
180181 user_obj = _datastore.get_user(user)
181182 if user_obj is None:
182 raise click.UsageError("ERROR: User not found.")
183 raise click.UsageError("User not found.")
183184 if _datastore.deactivate_user(user_obj):
184185 click.secho('User "{0}" has been deactivated.'.format(user), fg="green")
185186 else:
186187 click.secho('User "{0}" was already deactivated.'.format(user), fg="yellow")
188
189
190 @users.command(
191 "reset_access",
192 help="Reset all authentication credentials for user."
193 " This includes session, auth token, two-factor"
194 " and unified sign in secrets. ",
195 )
196 @click.argument("user")
197 @with_appcontext
198 @commit
199 def users_reset_access(user):
200 """ Reset all authentication tokens etc."""
201 user_obj = _datastore.get_user(user)
202 if user_obj is None:
203 raise click.UsageError("User not found.")
204 _datastore.reset_user_access(user_obj)
205 click.secho(
206 'User "{user}" authentication credentials have been reset.'.format(user=user),
207 fg="green",
208 )
677677 Caller must commit to DB.
678678
679679 .. versionadded:: 3.3.0
680
681 .. deprecated:: 3.4.4
682 Use :meth:`.UserDatastore.remove_permissions_from_role`
680683 """
681684 if hasattr(self, "permissions"):
682685 current_perms = self.get_permissions()
687690 else:
688691 perms = {permissions}
689692 self.permissions = ",".join(current_perms.union(perms))
690 else:
693 else: # pragma: no cover
691694 raise NotImplementedError("Role model doesn't have permissions")
692695
693696 def remove_permissions(self, permissions):
699702 Caller must commit to DB.
700703
701704 .. versionadded:: 3.3.0
705
706 .. deprecated:: 3.4.4
707 Use :meth:`.UserDatastore.remove_permissions_from_role`
702708 """
703709 if hasattr(self, "permissions"):
704710 current_perms = self.get_permissions()
709715 else:
710716 perms = {permissions}
711717 self.permissions = ",".join(current_perms.difference(perms))
712 else:
718 else: # pragma: no cover
713719 raise NotImplementedError("Role model doesn't have permissions")
714720
715721
790796
791797 """
792798 for role in self.roles:
793 if hasattr(role, "permissions"):
794 if permission in role.get_permissions():
795 return True
799 if permission in role.get_permissions():
800 return True
796801 return False
797802
798803 def get_security_payload(self):
199199 rv = True
200200 user.roles.remove(role)
201201 self.put(user)
202 return rv
203
204 def add_permissions_to_role(self, role, permissions):
205 """Add one or more permissions to role.
206
207 :param role: The role to modify. Can be a Role object or
208 string role name
209 :param permissions: a set, list, or single string.
210 :return: True if permissions added, False if role doesn't exist.
211
212 Caller must commit to DB.
213
214 .. versionadded:: 3.4.4
215 """
216
217 rv = False
218 user, role = self._prepare_role_modify_args(None, role)
219 if role:
220 rv = True
221 role.add_permissions(permissions)
222 self.put(role)
223 return rv
224
225 def remove_permissions_from_role(self, role, permissions):
226 """Remove one or more permissions from a role.
227
228 :param role: The role to modify. Can be a Role object or
229 string role name
230 :param permissions: a set, list, or single string.
231 :return: True if permissions removed, False if role doesn't exist.
232
233 Caller must commit to DB.
234
235 .. versionadded:: 3.4.4
236 """
237
238 rv = False
239 user, role = self._prepare_role_modify_args(None, role)
240 if role:
241 rv = True
242 role.remove_permissions(permissions)
243 self.put(role)
202244 return rv
203245
204246 def toggle_active(self, user):
6262 def default_unauthn_handler(mechanisms, headers=None):
6363 """ Default callback for failures to authenticate
6464
65 If caller wants JSON - return 401
65 If caller wants JSON - return 401.
66 If caller wants BasicAuth - return 401 (the WWW-Authenticate header is set).
6667 Otherwise - assume caller is html and redirect if possible to a login view.
6768 We let Flask-Login handle this.
6869
6970 """
71 headers = headers or {}
7072 msg = get_message("UNAUTHENTICATED")[0]
7173
7274 if config_value("BACKWARDS_COMPAT_UNAUTHN"):
7375 return _get_unauthenticated_response(headers=headers)
7476 if _security._want_json(request):
75 # Ignore headers since today, the only thing in there might be WWW-Authenticate
76 # and we never want to send that in a JSON response (browsers will intercept
77 # that and pop up their own login form).
77 # Remove WWW-Authenticate from headers for JSON responses since
78 # browsers will intercept that and pop up their own login form.
79 headers.pop("WWW-Authenticate", None)
7880 payload = json_error_response(errors=msg)
79 return _security._render_json(payload, 401, None, None)
81 return _security._render_json(payload, 401, headers, None)
82
83 # Basic-Auth is often used to provide a browser based login form and then the
84 # browser will always add the BasicAuth credentials. For that to work we need to
85 # return 401 and not redirect to our login view.
86 if "WWW-Authenticate" in headers:
87 return Response(msg, 401, headers)
8088 return _security.login_manager.unauthorized()
8189
8290
211219
212220 :param realm: optional realm name
213221
222 If authentication fails, then a 401 with the 'WWW-Authenticate' header set will be
223 returned.
224
214225 Once authenticated, if so configured, CSRF protection will be tested.
215226 """
216227
268279 return 'Dashboard'
269280
270281 :param auth_methods: Specified mechanisms (token, basic, session). If not specified
271 then all current available mechanisms will be tried.
282 then all current available mechanisms (except "basic") will be tried.
272283 :kwparam within: Add 'freshness' check to authentication. Is either an int
273284 specifying # of minutes, or a callable that returns a timedelta. For timedeltas,
274285 timedelta.total_seconds() is used for the calculations:
296307 On authentication failure `.Security.unauthorized_callback` (deprecated)
297308 or :meth:`.Security.unauthn_handler` will be called.
298309
310 .. note::
311 If "basic" is specified in addition to other methods, then if authentication
312 fails, a 401 with the "WWW-Authenticate" header will be returned - rather than
313 being redirected to the login view.
314
299315 .. versionchanged:: 3.3.0
300316 If ``auth_methods`` isn't specified, then all will be tried. Authentication
301317 mechanisms will always be tried in order of ``token``, ``session``, ``basic``
303319
304320 .. versionchanged:: 3.4.0
305321 Added ``within`` and ``grace`` parameters to enforce a freshness check.
322
323 .. versionchanged:: 3.4.4
324 If ``auth_methods`` isn't specified try all mechanisms EXCEPT ``basic``.
306325
307326 """
308327
313332 }
314333 mechanisms_order = ["token", "session", "basic"]
315334 if not auth_methods:
316 auth_methods = {"basic", "session", "token"}
335 auth_methods = {"session", "token"}
317336 else:
318337 auth_methods = [am for am in auth_methods]
319338
169169 msg = user.tf_send_security_token(
170170 method=user.tf_primary_method,
171171 totp_secret=user.tf_totp_secret,
172 phone_number=user.tf_phone_number,
172 phone_number=getattr(user, "tf_phone_number", None),
173173 )
174174 if msg:
175175 # send code didn't work
343343 msg = user.us_send_security_token(
344344 method,
345345 totp_secret=totp_secrets[method],
346 phone_number=user.us_phone_number,
346 phone_number=getattr(user, "us_phone_number", None),
347347 send_magic_link=True,
348348 )
349349 code_sent = True
141141 """
142142
143143 if current_user.is_authenticated and request.method == "POST":
144 # Just redirect current_user to POST_LOGIN_VIEW (or next).
144 # Just redirect current_user to POST_LOGIN_VIEW.
145145 # While its tempting to try to logout the current user and login the
146146 # new requested user - that simply doesn't work with CSRF.
147147
148 # While this is close to anonymous_user_required - it differs in that
149 # it uses get_post_login_redirect which correctly handles 'next'.
150 # TODO: consider changing anonymous_user_required to also call
151 # get_post_login_redirect - not sure why it never has?
148 # This does NOT use get_post_login_redirect() so that it doesn't look at
149 # 'next' - which can cause infinite redirect loops
150 # (see test_common::test_authenticated_loop)
152151 if _security._want_json(request):
153152 payload = json_error_response(
154153 errors=get_message("ANONYMOUS_USER_REQUIRED")[0]
155154 )
156155 return _security._render_json(payload, 400, None, None)
157156 else:
158 return redirect(get_post_login_redirect())
157 return redirect(get_url(_security.post_login_view))
159158
160159 form_class = _security.login_form
161160
181180 login_user(form.user, remember=remember_me, authn_via=["password"])
182181 after_this_request(_commit)
183182
184 if not _security._want_json(request):
185 return redirect(get_post_login_redirect())
183 if _security._want_json(request):
184 return base_render_json(form, include_auth_token=True)
185 return redirect(get_post_login_redirect())
186186
187187 if _security._want_json(request):
188188 if current_user.is_authenticated:
189189 form.user = current_user
190 return base_render_json(form, include_auth_token=True)
190 return base_render_json(form)
191191
192192 if current_user.is_authenticated:
193 # Basically a no-op if authenticated - just perform the same
194 # post-login redirect as if user just logged in.
195 return redirect(get_post_login_redirect())
193 return redirect(get_url(_security.post_login_view))
196194 else:
197195 return _security.render_template(
198196 config_value("LOGIN_USER_TEMPLATE"), login_user_form=form, **_ctx("login")
624622 if form.validate_on_submit():
625623 after_this_request(_commit)
626624 change_user_password(current_user._get_current_object(), form.new_password.data)
627 if not _security._want_json(request):
628 do_flash(*get_message("PASSWORD_CHANGE"))
629 return redirect(
630 get_url(_security.post_change_view)
631 or get_url(_security.post_login_view)
632 )
625 if _security._want_json(request):
626 form.user = current_user
627 return base_render_json(form, include_auth_token=True)
628
629 do_flash(*get_message("PASSWORD_CHANGE"))
630 return redirect(
631 get_url(_security.post_change_view) or get_url(_security.post_login_view)
632 )
633633
634634 if _security._want_json(request):
635635 form.user = current_user
636 return base_render_json(form, include_auth_token=True)
636 return base_render_json(form)
637637
638638 return _security.render_template(
639639 config_value("CHANGE_PASSWORD_TEMPLATE"),
733733 msg = user.tf_send_security_token(
734734 method=pm,
735735 totp_secret=session["tf_totp_secret"],
736 phone_number=user.tf_phone_number,
736 phone_number=getattr(user, "tf_phone_number", None),
737737 )
738738 if msg:
739739 # send code didn't work
920920 msg = form.user.tf_send_security_token(
921921 method="email",
922922 totp_secret=form.user.tf_totp_secret,
923 phone_number=form.user.tf_phone_number,
923 phone_number=getattr(form.user, "tf_phone_number", None),
924924 )
925925 if msg:
926926 rproblem = ""