Okay so, ordinary Django allows you to simply:
if request.user.is_authenticated:
I want to be able to do the same in Pyrebase. Have the views sort of already know which user has logged in based on the current session without having to sign the user in in all views.
I have tried:
def sign_in(request):
user = firebase.auth().sign_in_with_email_and_password('email', 'password')
user_token = firebase.auth().refresh(user['refreshToken']
request.session['session_id'] = user_token
I noticed this creates a session ID for me. But I don't know how to associate it with the current user and I know it has something to do with the refresh token.
If I don't check authentication, anyone can visit any page of my site without signing in.
Related
I'm having an issue when trying to get the information of the user that is logged in in Django. My Login service looks like this:
username = request.data['username']
password = request.data['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
It's currently working properly at least when using Django Rest Framework
(It even appears at the top right the user that is logged in).
I'm trying to bring the profile of the user that is logged in so I developed a profile service which tries to get the user logged in which is working perfectly when using Django Rest Framework.
The issue comes when I try to call the same endpoint from a JS client. I think it might be an issue with setting something in the header after the Django login is executed. Currently, I am not doing anything in my JS client but to call to the login endpoint which is returning properly. Should I set a cookie or something in the header of each request so Django knows which user am I? If so, how should it be that ?
Thanks in advance
Should I set a cookie or something in the header of each request so Django knows which user am I? If so, how should it be that ?
You definitively need the session cookie to be passed.
By default, it'll be sessionid
My Django application uses the Rest Framework JWT for authentication. It works great and very elegant.
However, I have a use-case which I am struggling to build. I have already coded up a working solution for the "Forgot Password" workflow. I allow an un-authenticated user to reset their password if-and-only-if they click on a secret link that I send to their email address. However, I would like to modify this solution such that after the password-reset workflow is successfully completed, the user is automatically logged in without having to retype their username and (new) password. I would like to do this to make the user's experience as frictionless as possible.
The problem is I do not know how to make this work without having the user re-type their password (or storing it in clear-text in the DB which is obviously very bad). Below is the current way I get the JWT token. You can see that in line #12, I need the user's clear password. I don't have it. I only have the encrypted password stored in my_user.password.
How can I use the encrypted password in my_user.password instead of the clear password to obtain the JWT? If I cannot use it, then how is this workflow achieved using the Rest Framework JWT?
from rest_framework_jwt.views import ObtainJSONWebToken
from rest_framework status
from django.contrib.auth.models import User
my_user = User.objects.get(pk=1)
ojwt = ObtainJSONWebToken()
if "_mutable" in dir(request.DATA):
mutable = request.DATA._mutable
request.DATA._mutable = True
request.DATA['username'] = my_user.username
request.DATA['password'] = "<my_user's clear password>"
if "_mutable" in dir(request.DATA):
request.DATA._mutable = mutable
token_response = ojwt.post(request)
if status.is_success(token_response.status_code):
# Tell the user login succeeded!!
else:
# Tell the user login failed.
# But hopefully, this shouldn't happen
When working with Django REST Framework JWT, it is typically expected that the user is generating the token on their own. Because you are generating the token on behalf of the user, you can't use any of the standard views to make it work.
You are going to need to generate the token on your own, similar to how DRF JWT does it in the views. This means using something like the following for your view code
from rest_framework_jwt.settings import api_settings
from datetime import datetime
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
my_user = User.objects.get(pk=1) # replace with your existing logic
payload = jwt_payload_handler(my_user)
# Include original issued at time for a brand new token,
# to allow token refresh
if api_settings.JWT_ALLOW_REFRESH:
payload['orig_iat'] = timegm(
datetime.utcnow().utctimetuple()
)
return {
'token': jwt_encode_handler(payload)
}
This should allow you to manually generate the token within the view, without having to know the user's password.
I have several function that need to have a 'redirect' filter. The redirect filter goes something like this --
1) if a user is not logged in and has no session data, redirect to login page.
2) if a user is logged in and has already filled out the page, redirect to user home.
3) if a user is logged in and has not already filled out the page, stay on the page.
4) if a user is not logged in and has session data, stay on the page
I've started to convert the functions into a class-based approach to make it more efficient and less code (previously my view functions were pretty massive). This is my first stab at trying make something class-based, and this is what I have so far --
def redirect_filter(request):
if request.user.is_authenticated():
user = User.objects.get(email=request.user.username)
if user.get_profile().getting_started_boolean:
return redirect('/home/') ## redirect to home if a logged-in user with profile filled out
else:
pass ## otherwise, stay on the current page
else
username = request.session.get('username')
if not username: ## if not logged in, no session info, redirect to user login
return redirect('/account/login')
else:
pass ## otherwise, stay on the current page
def getting_started_info(request, positions=[]):
location = request.session.get('location')
redirect_filter(request)
if request.method == 'POST':
form = GettingStartedForm(request.POST)
...(run the function)...
else:
form = GettingStartedForm() # inital = {'location': location}
return render_to_response('registration/getting_started_info1.html', {'form':form, 'positions': positions,}, context_instance=RequestContext(request))
Obviously, this view is not fully working yet. How would I convert this into something that's functional?
Also, I have three variables that will need to be reused in several of the getting_started functions:
user = User.objects.get(email=request.user.username)
profile = UserProfile.objects.get(user=user)
location = profile.location
Where would I put these variable definitions so I can reuse them in all the functions, and how would I call them?
Thank you.
Django actually already includes a login_required decorator that makes handling user authentication trivial. Just include the following at the top of your view.py page:
from django.contrib.auth.decorators import login_required
and then add
#login_required
before any views that require a login. It even handles redirecting the user to the appropriate page once they log in.
More info here:
https://docs.djangoproject.com/en/dev/topics/auth/#the-login-required-decorator
This should greatly simplify your views, and may result in not having to write a separate class, since all that's left is a simple re-direct.
As for the variables, each request already contains a request.user object with information on the user. You can do a search in the docs for Request and response objects to learn more.
You can use that user object to get the profile variable by extending the user module. Set AUTH_PROFILE_MODULE = 'myapp.UserProfile' in your Settings, which will allow you to access a users profile as follows:
user.get_profile().location.
More about that here:
http://www.b-list.org/weblog/2006/jun/06/django-tips-extending-user-model/
Using django, I am authenticating the user through Google. I get the initial request tokens & redirect the user to google for auth. After which google redirects the user back to my website (using the redirect_url I provide).
At this point the request.user.id is None so is request.user.username why is this happening? I need the user ID to enter the access_tokens (that google sends me) into the DB.
Under what conditions can request.user object in Django be empty?
UPDATE1: When I get redirected back from Google with the url pattern as http://mywebsite.com/lserv?s=goog control comes back to my django views function, but django gives me the request.user object user as Anonymous user with no username or id. why?
UPDATE2:
all this is running on python manage.py runserver for now...
UPDATE3: Anybody faced anythn similar to this? basically, out of no reason the user in request clears out automatically & I get assigned as Anonymous user. All this happens between url requests from the user (from browser). Why?
Django's auth mechanism has nothing to do with Google's or any other auth service. If you want to integrate third party auth service with your Django site, you should do it youself.
If you're using oauth2 library, it's README has a section named "Logging into Django w/ Twitter" may help you.
If you are using oauth api from google. To get the user you have to do something like this
from google.appengine.api import oauth
# ...
try:
# Get the db.User that represents the user on whose behalf the
# consumer is making this request.
user = oauth.get_current_user()
except oauth.OAuthRequestError, e:
# The request was not a valid OAuth request.
# ...
I have a Django app. When logged in as an admin user, I want to be able to pass a secret parameter in the URL and have the whole site behave as if I were another user.
Let's say I have the URL /my-profile/ which shows the currently logged in user's profile. I want to be able to do something like /my-profile/?__user_id=123 and have the underlying view believe that I am actually the user with ID 123 (thus render that user's profile).
Why do I want that?
Simply because it's much easier to reproduce certain bugs that only appear in a single user's account.
My questions:
What would be the easiest way to implement something like this?
Is there any security concern I should have in mind when doing this? Note that I (obviously) only want to have this feature for admin users, and our admin users have full access to the source code, database, etc. anyway, so it's not really a "backdoor"; it just makes it easier to access a user's account.
I don't have enough reputation to edit or reply yet (I think), but I found that although ionaut's solution worked in simple cases, a more robust solution for me was to use a session variable. That way, even AJAX requests are served correctly without modifying the request URL to include a GET impersonation parameter.
class ImpersonateMiddleware(object):
def process_request(self, request):
if request.user.is_superuser and "__impersonate" in request.GET:
request.session['impersonate_id'] = int(request.GET["__impersonate"])
elif "__unimpersonate" in request.GET:
del request.session['impersonate_id']
if request.user.is_superuser and 'impersonate_id' in request.session:
request.user = User.objects.get(id=request.session['impersonate_id'])
Usage:
log in: http://localhost/?__impersonate=[USERID]
log out (back to admin): http://localhost/?__unimpersonate=True
It looks like quite a few other people have had this problem and have written re-usable apps to do this and at least some are listed on the django packages page for user switching. The most active at time of writing appear to be:
django-hijack puts a "hijack" button in the user list in the admin, along with a bit at the top of page for while you've hijacked an account.
impostor means you can login with username "me as other" and your own password
django-impersonate sets up URLs to start impersonating a user, stop, search etc
I solved this with a simple middleware. It also handles redirects (that is, the GET parameter is preserved during a redirect). Here it is:
class ImpersonateMiddleware(object):
def process_request(self, request):
if request.user.is_superuser and "__impersonate" in request.GET:
request.user = models.User.objects.get(id=int(request.GET["__impersonate"]))
def process_response(self, request, response):
if request.user.is_superuser and "__impersonate" in request.GET:
if isinstance(response, http.HttpResponseRedirect):
location = response["Location"]
if "?" in location:
location += "&"
else:
location += "?"
location += "__impersonate=%s" % request.GET["__impersonate"]
response["Location"] = location
return response
#Charles Offenbacher's answer is great for impersonating users who are not being authenticated via tokens. However, it will not work with clients side apps that use token authentication. To get user impersonation to work with apps using tokens, one has to directly set the HTTP_AUTHORIZATION header in the Impersonate Middleware. My answer basically plagiarizes Charles's answer and adds lines for manually setting said header.
class ImpersonateMiddleware(object):
def process_request(self, request):
if request.user.is_superuser and "__impersonate" in request.GET:
request.session['impersonate_id'] = int(request.GET["__impersonate"])
elif "__unimpersonate" in request.GET:
del request.session['impersonate_id']
if request.user.is_superuser and 'impersonate_id' in request.session:
request.user = User.objects.get(id=request.session['impersonate_id'])
# retrieve user's token
token = Token.objects.get(user=request.user)
# manually set authorization header to user's token as it will be set to that of the admin's (assuming the admin has one, of course)
request.META['HTTP_AUTHORIZATION'] = 'Token {0}'.format(token.key)
i don't see how that is a security hole any more than using su - someuser as root on a a unix machine. root or an django-admin with root/admin access to the database can fake anything if he/she wants to. the risk is only in the django-admin account being cracked at which point the cracker could hide tracks by becoming another user and then faking actions as the user.
yes, it may be called a backdoor, but as ibz says, admins have access to the database anyways. being able to make changes to the database in that light is also a backdoor.
Set up so you have two different host names to the same server. If you are doing it locally, you can connect with 127.0.0.1, or localhost, for example. Your browser will see this as three different sites, and you can be logged in with different users. The same works for your site.
So in addition to www.mysite.com you can set up test.mysite.com, and log in with the user there. I often set up sites (with Plone) so I have both www.mysite.com and admin.mysite.com, and only allow access to the admin pages from there, meaning I can log in to the normal site with the username that has the problems.