pallets-eco / flask-security

Quick and simple security for Flask applications
MIT License
1.63k stars 513 forks source link

'next' parameter fails with blueprint endpoints (e.g. "User.view") #843

Open nk9 opened 5 years ago

nk9 commented 5 years ago

The login view is a NextFormMixin subclass, so it accepts a next parameter. As I understand it, the parameter can be a URL, a path or an endpoint. If you use a simple endpoint like "index", it works as expected and redirects to the provided endpoint on login.

However, endpoints in a blueprint have a period, like "User.profile". If you pass this kind of endpoint to 'next', the login view will treat it like a path and send you to e.g. http://localhost:4000/User.profile. This happens because validate_redirect_url() returns True for the blueprint endpoint. This, in turn, means that get_post_action_redirect() will use the very first URL in its list, which is just the raw endpoint name. It doesn't get to the 3rd element of the list, which is the result of get_url(request.form.get('next')) and is the correct path.

I am not sure what the right solution to this problem is. Perhaps the declared value should be compared with a list of the application's registered endpoints either in validate_redirect_url() or just before it's called. Or perhaps declared should be added later in the list so that the resolved endpoint will be evaluated first. URLs should return None when passed to get_url(), so while this will change precedence, it shouldn't change the outcome. Paths which contain a slash should work the same. Is there a similar API which we can model the behavior on?

As a workaround, I'm using the request's path in my decorator instead of passing the endpoint.

return redirect(url_for('security.login', next=request.path))