Django Public URL Rewrite - python

I am deploying a Django application to an environment which requires a user login for everything by default, however allows you to specific URLs you want to display without a login if you start the URL with /public, for instance /public/forums (this is a security measure to have everything protected by default and explicitly define what should be publically accessible).
I decided just to prefix all the URLs I want public in urls.py with /public. This works, however I don't want /public to be shown. I added to the .htaccess:
RewriteEngine On
RewriteCond %{THE_REQUEST} /public/([^\s?]*) [NC]
RewriteRule ^ %1 [L,NE,R=302]
RewriteRule ^((?!public/).*)$ public/$1 [L,NC]
however, my server is coming back with LimitInternalRecursion.
How can I fix this to achieve a URL without public?

Your RewriteCond is being triggered by your RewriteRule. That is, you are rewriting to a URL that fires your rewrite, hence the recursion error. This is because your regular expression in RewriteCond %{THE_REQUEST} /public/([^\s?]*) [NC] is catching everything, even /public/forums/. Check out this saved example: https://regex101.com/r/dI8cH4/1. And try getting a simpler rewrite to work first (like to your landing/home page):
Options +FollowSymLinks
RewriteEngine On
RewriteRule /public/ http://example.com/

Related

Enable Website access from both www and non-www

I recently hosted my site on Cpanel, however, I am still not able to find the right solution for my problem.
I intend to make my site accessible from www.site.com too.
Currently accessing the site using the above returns the following on the browser
This site can’t be reached
www.site.com’s server IP address could not be found.
Try:
Checking the connection
Checking the proxy, firewall, and DNS configuration
ERR_NAME_NOT_RESOLVED
How can I make the site accessible using www.site.com as well? Probably using .htaccess file
Adding the following on my .htaccess file still does not work
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
</IfModule>
It's a Python app
I can see that you are getting the error "ERR_NAME_NOT_RESOLVED". This means that the DNS record for www.site.com is missing. You need to add a CNAME or A record for www.site.com to point to the IP address of your server.
You can add the records from cPanel >> Zone editor.
https://docs.cpanel.net/cpanel/domains/zone-editor/
This works only if your nameservers are the same as your hosting server. If you are using any other nameserver you will need to add the records on it.

HTTP_AUTHORIZATION header in Django

I wrote a simple check in django which requires an access token to be passed along in some requests (I'm using a decorator).
authorization = request.META.get('HTTP_AUTHORIZATION', None)
# Forbid access when no access token, or an invalid one, is provided
form = AccessTokenForm({ 'access_token': authorization })
if not form.is_valid():
raise exceptions.HttpDeniedException()
This has been working fine with django's development server, but recently I deployed using Apache and now it doesn't work anymore, as the authorisation variable is None. Has anyone faced something similiar before? The client is passing the header as Authorization; again, this is working fine in localhost, but not on the remote server.
Edit: I found this, and it seems that it should work, but it doesn't. Actually, I didn't even have an .htaccess file, and adding one doesn't seem to have taken any effect at all. Here are the contents:
RewriteEngine On
RewriteRule ^(media/.*)$ - [L]
RewriteRule ^(static/.*)$ - [L]
RewriteCond %{REQUEST_URL} !(dispatch.fcgi)
RewriteRule ^(.*)$ dispatch.fcgi/$1 [QSA,L,E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
The thing is, I'm not even sure Apache is using this at all..
It seems there's a ticket for this issue here. Just add the following to apache2.conf:
WSGIPassAuthorization on

Why does my django web app on shared hosting have its GET urls treated differently than POST urls

I have a django web app on A2hosting, where I am using .htaccess files and passenger_wsgi.py. It was working fine the last time I touched it, but then someone who had a look at it later informed me that it was broken.
I created a test situation to find the problem and here's the gist of it.
When I do a GET (to www.geo4ce.com/quiz/test_weird/), it goes to a page with a simple form that just has one input and a submit and an action that has "/quiz/test_weird/" and method="post". When I submit the form, the server expects the "quiz" part of the url to be referring to a path on the file server, can't find it and then logs an error that it can't find it. But, then it checks the test_weird part of the url against my django urls.py file, finds a different view for that and displays it.
A scenario that almost works properly is with www.geo4ce.com/quiz/test_hacked/, that has the same set up, except the form has action = "/anythinghere/quiz/test_hacked/". In this case, the "anythinghere" part of the url gets an error logged, since it doesn't exist on the file server, and then the /quiz/test_hacked/ part of the url works normally to get back to the original web page.
Anyone have any idea how I might be able to fix or debug this?
[EDIT]
I don't think it's the .htaccess file that's the cause. It looks something like this.
PassengerEnabled On
PassengerAppRoot /path/to/app/folder/
# Prevent Apache from serving .htaccess files:
<FilesMatch "^\.htaccess">
Order allow,deny
Deny from all
</FilesMatch>
deny from xxx.yyy.zzz
Apparently the issue is caused by a certain version of Passenger (with RoR). I've been told to switch to using FCGI.

making HTTP authentication optional with mod-python

I've a web application that accesses multiple controller classes based on the parameters it is passed. For some of the controllers, I want users to authenticate themselves (by simple HTTP authentication), and for some I want public access.
Is there a way to make this happen? In my .htaccess file, I now have
AddHandler mod_python .py
PythonHandler handler
PythonAuthenHandler handler
PythonDebug On
AuthType Basic
AuthName "My Realm"
AuthBasicAuthoritative Off
require valid-user
The authenhandler is called correctly, but even when I just do
def authenhandler(req):
return apache.OK
the user is asked for a password (though any password that is entered is accepted)
I tried removing the Auth* stuff (and the require directive) from the .htaccess entirely, and just did the following in the normal handler for those cases where I do want authentication (and it was not found):
request.err_headers_out.add('WWW-Authenticate', 'Basic realm="My Realm")
return apache.HTTP_UNAUTHORIZED
which is what I understand what the server should do when not receiving correct authentication. That did not work either, however.
I come from a PHP background and I know that the latter is how it's done in PHP - but PHP sometimes does extra little pieces of undocumented magic to make this stuff actually work. Is this one of those cases?
Is there any way to optionally request authentication, depending on the URL passed, from the same handler?
There are a couple ways to specify authentication scope with Apache, the one most people are used to is gt;Directorylt; based - i.e. anything in or below a directory gets authenticated against htpasswd.
There's also gt;Locationlt;, which applies directives to content that live outside the filesystem such as mod_python registered code.
This is how you can set authentication on a 'virtual' path like /status, if you have mod_status enabled.
You can do the same thing with mod_python paths
<Location /python/app1/>
Order allow,deny
Allow from all
</Location>
<Location /python/app2/>
Order allow,deny
Allow from all
AuthType basic
AuthName "Protected Intranet Area"
AuthUserFile /etc/apache2/htpasswd
Require valid-user
</Location>
I should add - it's not necessarily clear if you mean 'some users should authenticate with a username and password and other users should only have to put in a username'
or
'some applications should require authentication 100% of the time, and other applications should be freely available 100% of the time'
My first answer sorts out the last query.

How to hide "cgi-bin", ".py", etc from my URLs?

Brand new to web design, using python. Got Apache up and running, test python script working in cgi-bin directory. Get valid results when I type in the URL explicitly: ".../cgi-bin/showenv.py"
But I don't want the URL to look that way. Here at stackoverflow, for example, the URLs that display in my address bar never have the messy details showing the script that was used to run them. They're clean of cgi-bin, .py, etc. extensions. How do I do that?
EDIT: Thanks for responses, every single one helpful, lots to learn. I'm going with URL Rewriting for now; example in the docs looks extremely close to what I actually want to do. But I'm committed to python, so will have to look at WSGI down the road.
The python way of writing web applications is not cgi-bin. It is by using WSGI.
WSGI is a standard interface between web servers and Python web applications or frameworks. The PEP 0333 defines it.
There are no disadvantages in using it instead of CGI. And you'll gain a lot. Beautiful URLs is just one of the neat things you can do easily.
Also, writing a WSGI application means you can deploy on any web server that supports the WSGI interface. Apache does so by using mod_wsgi.
You can configure it in apache like that:
WSGIScriptAlias /myapp /usr/local/www/wsgi-scripts/myapp.py
Then all requests on http://myserver.domain/myapp will go to myapp.py's application callable, including http://myserver.domain/myapp/something/here.
example myapp.py:
def application(environ, start_response):
start_response('200 OK', [('Content-type', 'text/plain')])
return ['Hello World!']
I think you can do this by rewriting URL through Apache configuration. You can see the Apache documentation for rewriting here.
You have to use URL Rewriting.
It is not a noob question, it can be quite tricky :)
http://httpd.apache.org/docs/2.0/misc/rewriteguide.html
Hope you find it helpful
this is an excerpt from a .htaccess that I use to achieve such a thing, this for example redirects all requests that were not to index.php to that file, of course you then have to check the server-variables within the file you redirect to to see, what was requested.
Or you simply make a rewrite rule, where you use a RegExp like ^.*\/cgi-bin\/.*\.py$ to determine when and what to rewrite. Such a RegExp must be crafted very carefully, so that rewriting only takes place when desired.
<IfModule mod_rewrite.c>
RewriteEngine On #activate rewriting
RewriteBase / #url base for rewriting
RewriteCond %{REQUEST_FILENAME} !index.php #requested file is not index.php
RewriteCond %{REQUEST_FILENAME} !^.*\.gif$ #requested file is no .gif
RewriteCond %{REQUEST_FILENAME} !^.*\.jpg$ #requested file is no .jpg
RewriteCond %{REQUEST_FILENAME} !-d #is not a directory
RewriteRule . /index.php [L] #send it all to index.php
</IfModule>
The above Example uses RewriteConditions to determine when to rewrite ( .gif's, .jpeg's and index.php are excluded ).
Hmm, so thats a long text already. Hope it was a bit helpful, but you won't be able to avoid learning the syntax of the Apache RewriteEngine.
You'll find the ScriptAlias directive helpful. Using
ScriptAlias /urlpath /your/cgi-bin/script.py
you can access your script via http://yourserver/urlpath.
You also might want to look into mod_passenger, though the last time I used it, WSGI was kind of a "second-class citizen" within the library—it could detect WSGI scripts if it were used to serve the whole domain, but otherwise there are no directives to get it to run a WSGI app.
Just use some good web framework e.g. django and you can have such URLs
more than URLs you will have a better infrastructure, templates, db orm etc

Categories

Resources