@auth.requires_login()
By deafult it is not redirected to url he askedI had definded auth.settings.login_next=url(default url)but by removing it also not redirecting to the url user asked.
This is in general a security hazard so it needs to be enabled:
auth = Auth(db,auto_redirect=[URL(...),URL(...)])
where URL(...) are the urls where it is safe to redirect to after
login if originally requested. trunk only.
> auto_redirect works for any redierct, even if not relative.
> So you send an email like
>
> click here
> http://...../app/path
>
> and if http://...../app/path requires login, you get redirected to
> login but not back to http://...../app/path unless '/app/path' is in
> auto_redirect.
> Internally is still uses _next.
>
> Sometimes I think the need for auto_redirect is paranoid.
What's the hazard? Presumably there's nothing to stop the user from going to the same URL after a successful login, so why not automatically?
> Sometimes I think the need for auto_redirect is paranoid.
What's the hazard? Presumably there's nothing to stop the user from going to the same URL after a successful login, so why not automatically?
-1
. adds complexity in API and code
. not a security feature
IMHO it is more dangerous than nothing
mic
2011/9/16 Jonathan Lundell <jlun...@pobox.com>:
I think so. You've got a contradictory self.user test there, though. Is the startswith test needed? Right? If we're already at that URL, why redirect?
The auth requires decorators redirect to (say) the login page, and stuff _next=URL() into vars. This is a bit of a hazard because vars can get corrupted in the outside world, and we check it somewhat (I'm not 100% convinced by the check, and it's all so not-DRY, but that's another story).
OTOH, Auth.__init__ has some auto_redirect logic that stores the next-URL in the session (good, that's more secure). But presumably that path is different from the decorator logic (otherwise we'd have two possible next-URLs, one in vars, one in the session).
So what's the Auth() logic used for? Could these logic paths be unified? Wouldn't it be better to always store the next-URL link in the session instead of exposing it in the redirect URL?
Straighten me out, please.
should it just be?
if not self.user:
if not session._auth_next:
session._auth_next = URL(args=request.args,
vars=request.get_vars)
if self.user and session._auth_next and not self.user and
session._auth_next.startswith(URL()):
next = session._auth_next
session._auth_next = None
redirect(next)
> OK. So I followed the advice and rewrote all the next logic in trunk
> (for Auth, not Crud) to use sessions.
>
> I tested with normal login, janrain and cas. It seems to work. Yet if
> you can test it too would be best.
>
> there are two weird cases (and they were weird before):
> - app A redirect to CAS provider app B. user does not have account in
> app B and needs register. app B does not redirect to app A
> - user tries to visit page in app A that requires login, after login
> the app forces a redirection to edit profile, app A does not redirect
> use to original requested page
>
> PLEAE CHECK THIS! There are subtleties.
It's certainly cleaner, anyway.
One thing I don't understand (and it's not new, just relocated):
+def is_relative(url):
+ return url and not url[0] == '/' and url[:4] != 'http'
+
I don't see how this can work, since the output of URL() typically (always?) starts with '/'. Doesn't it?
> OK. So I followed the advice and rewrote all the next logic in trunk
> (for Auth, not Crud) to use sessions.
>
> I tested with normal login, janrain and cas. It seems to work. Yet if
> you can test it too would be best.
>
> there are two weird cases (and they were weird before):
> - app A redirect to CAS provider app B. user does not have account in
> app B and needs register. app B does not redirect to app A
> - user tries to visit page in app A that requires login, after login
> the app forces a redirection to edit profile, app A does not redirect
> use to original requested page
>
> PLEAE CHECK THIS! There are subtleties.
I also don't entirely understand this:
def pop_next(self):
next = current.session._auth_next
if next and next.startswith(URL()):
next = current.session._auth_next = None
return next
The startswith test: are we simply saying that if the startswith test is met, then we're already at the destination, so don't redirect?
But shouldn't we be setting _auth_next to None in the redirection case?
It seems to me that there are two issues here. One is cleaning up the logic to make it uniform, DRY and understandable. The other is deciding where to put the next link (and doing proper validation of the URL).
I understand (I think) the basic use case for @requires_login, I think.
What's the use case for saving the return link in Auth()?
Does it make sense to try to save a next link in cases like change-password? Profile editing?
I'm fine with reverting for now, but I really think that this logic is due for a review and cleanup. Maybe starting with a spec: what are we really trying to do? And how do these dynamic _next links relate to the various next-URL links in auth.settings?
The old logic saves a next link in session in Auth(). What's that for?
Instead of the is_relative function, how about a replace_id function that checks for a relative URL and does the replace? So, the above would just be:
Sounds like this will be completely re-thought, so maybe comments on the current (trunk) code aren't necessary, but here are some observations (not sure if these are correct because I haven't tested anything, just quickly looked at the code):
- It still looks like _auth_next will be the first URL visited during the session, whether or not it requires login, but then it can't get overwritten. So won't the redirect end up going to the first URL of the session rather than the last URL right before login (we want the latter, no)?
- _auth_next is reset to None if it starts with the current URL, but don't we want it to be an exact match for the current URL (including args and vars) in order to conclude that the redirect has happened?
- I'm not sure I'm following properly, but does this involve an additional redirect -- one immediately after login, and then another when that redirect hits Auth.__init__?
- This is repeated many times:
if is_relative(next):next = self.url(next.replace('[id]', str(form.vars.id)))Instead of the is_relative function, how about a replace_id function that checks for a relative URL and does the replace? So, the above would just be:next = replace_id(next,form)
Passing _next to the authenticating app is exactly what oauth specification does for the same problem.
The callback URL must be under an agreed domain and path.
Mic
mic
2011/9/18 Massimo Di Pierro <massimo....@gmail.com>:
I would consider this minor, you are already naked when you use third
party authorization... ;-)