I'm working on a Django 3.2 project which is hosted using Apache 2.4 server. The user authentication in this project is handled using HTTP Basic Authentication configured using LDAP.
I have implemented a sign up feature for new users. For that I have created the necessary form, view, template and url pattern in the Django project. The urlpattern to visit the sign up form is /signup.
My goal is to make the sign up urlpattern accessible to anyone i.e. prevent the Basic Authentication from showing when the sign up urlpattern is requested by user in the browser.
JFI, the complete Apache configuration is already complete and works already.
To achieve this, I have used the "LocationMatch" directive in the Apache configuration within the VirtualHost directive:
...
<LocationMatch "^/signup$">
Require all granted
</LocationMatch>
...
With this the Basic Authentication is removed when /signup URI is requested, but the server always redirects to another url which ultimately requires authentication hence giving the basic auth pop-up.
$ curl -I https://*****.com/signup
HTTP/1.1 302 Found
...
I have tried to redirect the request explicitly to /signup whenever the is /signup. This ends up in an endless loop of redirections.
RewriteEngine on
...
RewriteRule ^/signup$ /signup [R=301,L]
I have also tried other ways by setting environment variables within Apache configuration, I have restarted Apache whenever a change was done in config, I have cleared browser cache etc., but nothing seems be working.
FYI, I can access the /signup url successfully after logging into the application which is not useful for me.
I'm afraid I cannot share the complete source (apache config, django source etc.) here as the project is not completely open source yet. But I'm sure your suggestions would surely help me in some way.
I want to fix the redirection. I have no clue what I'm missing out here.
I am not sure why this is happening, but when I specify HTTP or HTTPS as my full URL in a redirect, the part after my domain name is appended to my current domain.
For example: if I redirect to https://www.external_site.com/error/page/hi_there.html it will go to https://www.currentdomain.com/error/hi_there/html
return redirect('https://www.external_site.com/error/page/hi_there.html')
But, when I remove the https: part (but leave the //), the redirect works as expected:
return redirect('//www.external_site.com/error/page/hi_there.html')
I am using Django v 1.11.23 but also tested it on Django 2.
Django runs on Apache on mod_wsgi, and goes through an IIS reverse proxy (the reverse proxy is just a reverse proxy in this instance, no special rules or anything besides to rewrite the external domain to the internal domain.)
I found the issue.
It is related to "IIS reverse rewrite host in response headers" ARR setting. I disabled it by going to "IIS Manager -> Machine or Site (I used Machine so it applies to all sites) -> Application Request Routing Cache -> Server Proxy Settings and uncheck the "Reverse rewrite host in response headers" checkbox“
Now it is working as it should.
I have a website in Django, hosted in Heroku.
I have 2 domains, registered in different places:
mysite.com and mysite.com.br
I don't want to be penalized by Google for having 2 domains with the same website, therefor I would like to redirect everyone who enters mysite.com.br to mysite.com.
I entered in the DNS mysite.com.br(Not hosted anywhere) CNAME mysite.com(hosted in Heroku), which makes the user actually access the Heroku content, but the url keeps the .BR ....
So the Heroku support told me to do the redirection in the application. In this case, what's the best practice to redirect? I would imagine to do that in the url.py, but how can I do that if the "path" doesnt read the domain?
Thanks.
You can't do this in the URLs. I would write some middleware to check the host via request.get_host and redirect if you're not on the canonical one.
In fact it looks like someone has already written this: django-enforce-host.
Our DjangoCMS site is accessible via http and https.
Anonymous usage via http is ok. But I want to disable logins via http.
Is there a way to force the usage of https as soon as the user wants to login?
Even the login-page (with username and password fields) should not be available via http.
Background: I don't want the password to go over the wire unencrypted.
Update: The site gets hosted on an apache web server.
As I already mentioned it in the comments I strongly suggest you to NOT only serve the login page via https.
Doing so just hides the fact that for example session information and authentication data is still transfered on the other requests unencrypted via http. Your site will not be secure at all.
You're just pseudo-securing stuff so it's fancy to somebodys eye. It's just like using the password 12345.
So please serve your website over https to the user. A small guide, for nginx or apache2, on how to redirect your traffic from http to https can be found here:
Redirecting to SSL using nginx
Force redirect to SSL for all pages apart from one
As you've accepted in the comments, pushing all traffic to HTTPS is the best solution these days. If you only authenticate via SSL, you'll need to consider encryption/security in everything you write moving forward rather than it just being the default.
So in your server config, force all traffic to port 443. Assuming you're using apache you'd do this;
<VirtualHost *:80>
ServerName www.example.com
Redirect / https://www.example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName www.example.com
# ... SSL configuration goes here
</VirtualHost>
Then in your Django settings turn on secure cookies;
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
As a side note, Django has a setting to redirect HTTP traffic to HTTPS which is SECURE_SSL_REDIRECT, but if you're doing this at the apache/nginx level you don't need to worry. For some further reading on SSL/HTTPS have a look here; https://docs.djangoproject.com/en/1.11/topics/security/#ssl-https
Django request has a is_secure()
You can check it in the view and redirect if not is secure:
if not request.is_secure():
return redirect("https://www.yourdomain.com/login")
#user1 has the logic right and you should serve your site through https in order to have it safe.
But in order to answer your exact question:
As shown here: How to know using Django if server is secure (uses https) and as #Zartch mentions in his answer, you should use the is_secure() HTTPRequest method to check if your request is coming through https.
In order to use is_secure() you need to check an incoming request
to your views:
def my_login_view(request):
if request.is_secure():
Do loggin
else:
Don't login
Now you can protect your other views with the login_required decorator:
#login_required(login_url='/your/login/url')
def protected_view(request):
...
Personal suggestion: I use Django Rest Framework extensively and I would suggest it, in your case, because it has an isAuthenticatedOrReadOnly permission class which you will like:
class MyLoginView(ObtainAuthToken):
"""
Login view for token-based authentication
"""
def post(self, request, *args, **kwargs):
if request.is_secure():
super().post(request, *args, **kwargs)
else:
Probably some redirect goes here...
Then in any other view or class-based view:
class MyOtherView(generics.GenericAPIView):
authentication_classes = (TokenAuthentication,)
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
...
The above will ensure that your users can login only through https and if they are not logged in they will only see a read-only view.
Give it a try if you like.
You didn't accept an answer yet, so I thought, that the answers might not match your question well enough.
Anonymous usage via http is ok. But I want to disable logins via http.
As I understand, you have the following use case:
Some person visits your website as anonymous user, the used protocol is http.
This person opens the login form and logs in, the form is sent through https.
The logged in user continues browsing your website through https.
If the login form is routed to the secure version your user will continue browsing your website in https mode (as long as all other links are agnostic to the used protocol).
<form action="https://your.domain/path/to/login/" method="post">
If the application you're using to authenticate users is sanely written, you can configure your settings.LOGIN_URL, else you'll probably need to do it in the template form.
I recommend allowing session cookies to be sent only through https, using settings.SESSION_COOKIE_SECURE.
With this setting, the user will still be able to make http requests, but the session cookie will not be sent (and the user will be treated as an anonymous user).
Please, make sure that your login view accepts only secure post requests (or else the user may send the password through non https protocol).
This can be achieved either in the Django code (like John Moutafis suggests with his MyLoginView) or at production server level by rejecting non https post requests for the login URL.
--
Could you provide access to the repository with the code?
You may use one or a combination of:
htaccess file, take a look here
webserver level, depend of server type: Apache, Nginx, IIS ?...
django server level, take a look here, and host header validation or SSL/HTTPS
I have a project with the following components:
a single page backbone application for the web client
a django app for the api
nginx in front to direct requests to backbone and django
In my nginx conf, I direct the requests to django if the path starts with /api ,
otherwise, I serve the files directly (index.html and static files)
This setup works fine, the problem arises when django needs to redirect the url. Say, for instance, I request /api/users , as I have forgotten the trailing slash, django automatically redirects this, but instead of redirecting to /api/users/ , it redirects to /users/ as django does not know that I am hosting it on /api. How can I configure django to handle this redirect correctly?