One Django app instance for multiple domains - python

I try to create an Django app which will work for multiple domains with single app instance.
For example:
there are three domains: group1.com, group2.com, group3.com
each domain has restricted content available after login
user1 is associated with group1.com and group2.com
when user1 log in to group1.com and try to enter group2.com, he will be automatically log in into the group2.com
there is URL, e.g. DOMAIN_NAME/posts/ which will show all content for user which is logged in from all domains which are associated with this user (in this case, for user1 there should be all "posts" from group1.com and group2.com)
when user1 enter group3.com, he's not logged in
I used Django Site framework to associate user with domains - content restriction for user in specific domains works fine.
Additionally, I used SESSION_COOKIE_DOMAIN parameter in settings.py for "share" cookie between domains and, unfortunately, it only works for subdomains. For example, after set:
SESSION_COOKIE_DOMAIN = '.group.com'
and after I wrote simple middleware, I'm able to meet the requirements that I wrote above but only for subdomains, like 'one.group.com', 'two.group.com', 'three.group.com'.
I was looking for solution for handle that, but I haven't found an answer for newest Django 3.x framework.
Is there any way to handle that like I explained?

I think "django-hosts" package for you.
Firstly, you should give permission some domain.
ALLOWED_HOSTS = [example1.com,example2.com,example3.com]
And than, you can use django-hosts
from django_hosts import patterns, host
host_patterns = patterns('path.to',
host(r'api', 'api.urls', name='api'),
host(r'beta', 'beta.urls', name='beta'),
)
You can see more information -> https://github.com/jazzband/django-hosts

Related

Accessing cookie from another sub-domain

I have two django applications that are deployed at two different sub-domains, for example:
data.mysite.com
i.mysite.com
Both sites use the same django authentication framework and such, setting a cookie called sessionid. I can read the cookie from the current site using:
def my_view(request):
# suppose this view is within the i.mysite.com application
i_session_id = request.COOKIES['sessionid']
data_session_id = ? # how to get this?
But then how could I grab the cookies from the
If you want to have a shared authentication between your 2 subdomains then you need to set your session on .mysite.com domain. Then when you request to data.mysite.com will include this cookie, same for i.mysite.com domain. So, in settings.py:
SESSION_COOKIE_DOMAIN=".mysite.com"

Django send authenticated user to another django server with the same db

I know question sounds strange, I will explain it here.
I have two Django servers which share the same DB. One is a light front/back server and the order one takes the heavy computing part. They share the same database.
I am currently securing the web, and I have a couple of views in the light server requiring user login:
#login_required()
#permission_required('auth.can_upload', login_url='/accounts/login/')
This works nicely in the light server since the user is authenticated (request.user returns a valid user in the views).
The problem comes when I have to send the uploaded data to the other server since it is protected as I showed earlier, I do not know how to pass it the user that is already logged (user is valid since servers share the DB).
# send an upload request using requests
s = requests.Session()
r1 = s.get(upload_process_url)
csrf_token = r1.cookies['csrftoken']
a = s.post(upload_process_url, files=request.FILES,
data={'csrfmiddlewaretoken': csrf_token},
headers=dict(Referer=upload_process_url))
I cannot ask every time the user and password or save them. The thing is I want to pass the user that is already logged in a request.
The user was logged using the default django accounts/login page and authentication.
Any clues and what could I try? I think this problem cannot be as difficult as it looks to me. I just want to send an authenticated request. If I remove the decorators everything works nicely with this code
Thanks a lot
Have a look at REMOTE_USER authentication:
This document describes how to make use of external authentication sources (where the Web server sets the REMOTE_USER environment variable) in your Django applications. This type of authentication solution is typically seen on intranet sites, with single sign-on solutions such as IIS and Integrated Windows Authentication or Apache and mod_authnz_ldap, CAS, Cosign, WebAuth, mod_auth_sspi, etc.
Basically your "light" server does the authentication as it already does. When you are doing a request to your "heavy" server, you should set a Auth-User header containing the username of your user. Django will then automatically authenticates the corresponding user.
By default, Django will read an environment variable set by an authentication server. But we can make it work with a HTTP header instead:
# middlewares.py
from django.contrib.auth.middleware import RemoteUserMiddleware
class CustomHeaderMiddleware(RemoteUserMiddleware):
header = 'HTTP_AUTH_USER'
# settings.py
MIDDLEWARE = [
'...',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'my_project.middlewares.CustomHeaderMiddleware',
'...',
]
Then, you can do something like this then in your request (assuming you have your Django user at hand):
s = requests.Session()
r1 = s.get(upload_process_url)
a = s.post(
upload_process_url,
files=request.FILES,
headers={
'Auth-User': user.username,
},
)
Since you're not doing a request from a browser, you can avoid the CSRF protection by marking the called "heavy" view with #csrf_exempt decorator (as you found yourself).
Be careful though that your "heavy" server should not be accessible directly on the internet and always behind a proxy/VPN accessible only by your "light" server.

Django Allauth different login redirection for facebook and twitter python 2.7

I am trying to redirect the different pages for the Facebook and Twitter in Django 1.11.5 using the Django-Allauth.
My settings.py
I have tried something like this but it didn't work in my case:
import allauth.socialaccount.providers as ASP
if ASP == 'facebook':
LOGIN_REDIRECT_URL = '/test/'
else:
LOGIN_REDIRECT_URL = '/'
I want to know how I can redirect the url for different social media on different links?
Kindly suggested me the improvements in the code.
You could use the method described in the official documentation:
https://django-allauth.readthedocs.io/en/latest/advanced.html?highlight=LOGIN_REDIRECT_URL#custom-redirects
That does exactly what you want.
Or use a simple workaround that would be to define a route in LOGIN_REDIRECT_URL that would then forward/redirect the user to the correct page according to sign in method or social account type. Like this:
LOGIN_REDIRECT_URL = '/after-login-example/'
then:
# view for that url
def example_view(request):
account = SocialAccount.objects.get(user=request.user)
if account.provider == "Twitter":
return HttpResponseRedirect(<your twitter page>)
elif:
...
Note1: I didn't test the above example and it assumes that the user has one or another method (not both), but even if the condition is different it exemplifies the overall approach.
Note2: The first (and official) one is obviously a better solution.

Integrate python-social-auth (social-app-django) to be used with the Django admin

I want to create an app that uses the django admin, but allows logins via google (my company google account) in place of the django default ModelAdmin.
Currently, it looks like social-app-django (google) is the way to go, but after having installed and setup a project, it's not clear to me how I can allow django admin logins to use the social-app-django authentication. I've attempted to configure my project as described here http://python-social-auth.readthedocs.io/en/latest/configuration/django.html but it isn't clear how this can be integrated with the django admin.
I found this snippit (which seems out-of-date), and added it, but get a 404 when I try to goto /admin/:
Page not found (404) Request Method: GET Request
URL: http://127.0.0.1:8000/accounts/login/?next=/admin/login/%3Fnext%3D/admin/
Using the URLconf defined in telos.urls, Django tried these URL
patterns, in this order: ^login/(?P[^/]+)/$ [name='begin']
^complete/(?P[^/]+)/$ [name='complete']
^disconnect/(?P[^/]+)/$ [name='disconnect']
^disconnect/(?P[^/]+)/(?P[^/]+)/$
[name='disconnect_individual'] ^admin/ The current path,
accounts/login/, didn't match any of these.
If I remove the snippit, /admin/ will redirect to /admin/login/ and on login attempt return the ERROR text:
Please enter the correct username and password for a staff account.
Note that both fields may be case-sensitive.
In addition to the configuration, I've added the following to my settings.py:
projects/models.py (MyUser)
from django.contrib.auth.models import AbstractUser
class MyUser(AbstractUser):
pass
settings.py
# for identification of SOCIAL_AUTH_USER
# http://python-social-auth.readthedocs.io/en/latest/configuration/settings.html#user-model
SOCIAL_AUTH_USER_MODEL = 'projects.MyUser'
AUTH_USER_MODEL = 'projects.MyUser' # not sure if this is needed
Can anyone direct me on how I can setup my project to allow me to login to the django admin through social-app-django (google)?
Django Admin uses the auth contrib application, so any authentication process triggers the same mechanism than a user logging in to a non-admin section and it will be processed by python-social-auth backends if they are defined in AUTHENTICATION_BACKENDS setting.
In order to make it work you will need to:
Add a Login with Google link (linking to /login/google-oauth2) to the login form. You can override the default login form by adding a admin/login.html template or by defining a custom AdminSite
Ensure that the user is flagged as is_staff, otherwise access to the admin will be forbidden.

Django user impersonation by admin

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.

Categories

Resources