I am getting my feet wet working with the Pyramid framework (great framework), and I've come to the point of user authorization. I want to take advantage of the ACL to block users who are already logged in from visiting the registration page. Obviously, I could do this other ways, but I was wondering if there was any way to do this using tools in pyramid.
I know that by adding permissions to a view, users who do not meet the criteria are shown a forbidden view. In my case, I simply want to re route users who are already members away from views that don't apply to them (registration, login, etc.).
I've tried __acl__ = [(Deny, Authenticated, 'guest')] to no avail, as it blocks the login page for all users.
Also, somewhat on another note, is there any way to dynamically change a route. I want the home page to be different for users who are logged in than it is for guests.
You'll want to investigate the principals that are being returned by your authentication policy to understand what's going on. It's easy to tell if you turn on pyramid.debug_authorization in your INI file. The authorization policy will compare the ACL found against the principals returned via pyramid.security.effective_principals(request). If these do not match up, it should be clear what is going on.
The way to implement a form-based login would be (assuming Pyramid 1.3a9+):
from pyramid.httpexceptions import HTTPSeeOther
from pyramid.security import authenticated_userid
from pyramid.view import forbidden_view_config
#forbidden_view_config()
def forbidden_view(request):
if authenticated_userid(request):
# user is already logged in, they are really forbidden
return request.context # the forbidden 403 response
url = request.route_url('login', _query={'came_from': request.path})
return HTTPSeeOther(url)
That will add the came_from parameter to the URL as request.GET['came_from'] in your login view. Of course if that isn't there you can just redirect them to the home screen after logging in.
Related
Details
I have made my custom authentication process for the users, (no, i didn't use django's dedicated authentication), I almost finished it, but still having concerns on the most important part at the time.
so these are main parts of authentication process:
User sign's into the website via steam's social authentication.
My authentication system checks if database contains user's data, if not it will create a new user object with all the information.
System will create cookie as key logged with the value of True.
After these steps, there begins a problem, website should show users data when logged cookie's value is True.
Strategies and Questions
So as example, let's take stackoverflow, as i see: when it's login cookie is activated, it show's me my profile picture, and my score.
How did it know that i was that specific user?
via cookies:
If i tracked users data via cookies, i know that it would be a very bad idea since they are super-easy to change.
via ip address:
Then there's a second way, to track them with ip address, which i don't think is a good idea:
from .models import User, IPs
from django.http import HttpResponseRedirect, HttpResponse
import steamapi
def index(request, self):
ip = request.META['HTTP_X_FORWARDED_FOR']
for search in IPs.objects.all():
if str(ip) in str(search):
break
user = ip.strip(ip) # model will contain ip address with username. e.g ( user 127.0.0.1 ), so i strip the ip
else:
username = steamapi.user.SteamUser(self.steamid) # i get steamid from different function which is not important.
username = IPs(data=username + " " + ip)
username.save()
print request.COOKIES
if request.COOKIES.get('logged'):
return HttpResponse("User %s" + "is logged in" % username)
else:
response = HttpResponse("User is not logged in")
response.set_cookie('logged', True)
return response
via sessions:
I don't exactly know Django's sessions (except cookies), would it be good if i used django's cached sessions? if so how?
Note: i am looking for the code that will fit to my steps at beginning, so code example would be excellent.
First strategy is totally bad idea, i think second is not pythonic and is not a good strategy, Third however, is one i need a help with.
General Question:
So what would best strategy be for displaying specific users data on the website? As i mentioned simillar to stackoverflow's bar, where it displays my profile picture and score.
Writing your own auth system is a nice way to learn all the details of how it works, but you must be careful to not introduce security issues. The Django auth framework has been working for 10 years or so, so it can be trusted to do the right thing.
Bruno's answer is right: you should use sessions. Sessions work by setting a cookie with a random value on the user's computer. After that, the browser sends back that random value on each request, and the Django Session framework (a middleware, IIRC) matches the random string with a Session instance (dict like object) and puts it in the request instance.
If you're using a modern Django version and for any reason want to stick to using Cookies only, you can check out the new Cookie based sessions. Internally, it signs the cookie (meaning no-one else can tamper with it, even though it's stored on the user's computer).
The canonical solution is to use sessions. FWIW note that all of your problems are already solved in Django's contrib.auth app, taking care of a whole lot of known security issues.
Is it possible redirect to another web after login with python-social-auth?
let's say:
The example above is according to the documentation and it is working well, but when I try this:
I get the following error:
http://example.com:8000/accounts/profile/ Not Found
This makes sense; I don't have this URL defined
At this point I have been already logged in, but I see an error page.
But with the same configuration, if I redirect to my own site, this works, I think this is something about settings, but I don't know which one.
EDIT:
If I remove the next GET param in the first configuration, it raise the same error.
It isn't safe to redirect to a different domain, e.g. https://www.google.com. To understand why, imagine that I send your users a link to:
http://www.yoursite.com/login?next=http://myevilsite.com
If your login page trusted the next url, then your users will be redirected to my site after they have logged in. I could use this for phishing attacks.
To prevent against this, Django checks that the next url is safe to redirect to. If it is not safe, then it will redirect to the settings.LOGIN_REDIRECT_URL, which defaults to /accounts/profile/. You can see the code here.
I had the same problem and I think there is some situations where it is interesting to redirect to another domain (ie: you have your backend under a different domain than your frontend).
After some investigation I found that you can control which domains are safe to redirect to (https://github.com/python-social-auth/social-core/blob/1d809941ab8a99af9e1bdf12bae548202c94eaa2/social_core/actions.py#L20).
Just add this to your settings.py:
SOCIAL_AUTH_ALLOWED_REDIRECT_HOSTS = ['domain1', 'domain2']
I am using RemoteUserMiddleware to authenticate with VAS.
Right now I set it up so the REMOTE_USER variable gets set only for my SSO login URL (/accounts/login/sso/), because I must allow my users to login via forms (for users not present in our SSO system). According to my debugging, the user gets authenticated correctly in VasMiddleware (which extends RemoteUserMiddleware to pre-process REMOTE_USER), but after the user gets redirected to the home page (/), authentication is lost.
How can I persist the information that user has been logged in?
Django 1.9 will have a PersistentRemoteUserMiddleware, which will work when the authentication header is only present on the login page.
If you look at the patch, it shouldn't be too hard to do something similar in Django 1.8. I would try overriding process_request so that it doesn't call self._remove_invalid_user(request) to log out your user (that might end up duplicating a lot of code), or overriding _remove_invalid_user itself.
From a very old blog post from FB:
As promised, we have changed the login procedure. This change should
improve your users experience and requires no modifications to
existing applications. Now, if a user was already using Facebook,
logging into an app happens transparently. Because of this, developers
might want to provide a way for users to logout by posting the word
"confirm" to http://www.facebook.com/logout.php. Alternatively,
developers can provide a link to switch the user via the login page’s
"skipcookie" parameter (as described in the authentication guide.
What if I don't want this to happen, but rather want the user to be redirected to FB and confirm his identity even if logged in to FB? I looked everywhere for this skipcookie directive but found nothing about it, in fact I think it has been discontinued.
For the record I'm using django in my app.
Thanks in advance for any help.
That is very old, and like you said, doesn't really apply anymore especially since everything moved from oauth over to oauth 2.
What if I don't want this to happen, but rather want the user to be redirected to FB and confirm his identity even if logged in to FB?
So here's what you do. If you want to force the user to re-login to facebook (confirming his identity and it's not some person who just walked up to an unlocked computer already logged into Facebook), call FB.logout() first, then call FB.login() to log the user in. Since you called logout() first, it will force the user to log into Facebook before authorizing your app.
If anybody is still curious as to how to implement this using Django, here's how I log the user out of facebook server-side:
next_url = 'http://your.app.url/return/from/fb/'
args = {
'next':next_url,
'access_token':access_token
}
redirect_to = "https://www.facebook.com/logout.php?" + urllib.urlencode(args)
return HttpResponseRedirect(redirect_to)
With this you can log the user out using the server side script (be it python/Django or any other language/framework, just use your language's url fetching API).
With this code the user will be redirected to the FB logout url and will then return to next_url
I have the following user flow:
1) user registers.
2) user has a 'getting_started' page where he fills out some basic info and adds a picture.
3) user activates his email and logs in
After a user has finished filling out his info on the getting started page, if he goes back to the page getting_started/, I want the user to be redirected to his home/. What would be the easiest way to accomplish this? (As a reference, similar to the LinkedIn or Facebook Sign Up flow).
The way that comes to mind for me is to set a global variable getting_started = 1 after the user fills out the getting_started page, and on the getting_started page, do --
if getting_started:
redirect to home/
else:
...(normal getting started view)...
Is it just the getting_started view/page that you want to redirect on? Don't think in terms of global variables, think in terms of database fields!
Once your user has signed up, they will be a registered user (if you are using djangos auth app) and they will have an entry in the database. Therefore you simply have to check to see if the user is registered already: if so, redirect, otherwise allow them to continue signing up.
You could simply put a check at the start of the getting_started view to see if the user has already signed up
from django.http import HttpResponseRedirect
def getting_started_view(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('home_view'))
where home_view is in your urls.py:
url("...","someapp.views.viewname", name="home_view"),
...
(or you could hard code the redirect)
If you are looking for more complex redirects (maybe numerous pages that require a redirect to the home page) you should look at writing some middleware. This will allow you to intercept every request coming in, see if it's to a certain page, and redirect.
https://docs.djangoproject.com/en/dev/topics/http/middleware/?from=olddocs