How to do URL masking with Django? - django

On a Django 1.9 project I need to redirect:
https://example.com/app/
to
https://examplebucket.s3.amazonaws.com/app/index.html
But I need https://examplce.com/app/ to be still visible on the browser address bar...
I know this must be possible in theory with Django because the previous team working on this project did a setup to serve the /static/ media files from an S3 bucket. And if I access those static files via https://example.com/static/app/index.html, they are served from the S3 bucket but the browser address bar still shows the original url I input.
I'm deploying an Ionic Browser project and I want the files (including the index) to be served from the S3 but the url needs to be user friendly, thats the reason.

The old (dirty) way of doing this is frame-based forwarding.
You set up an iframe on a page in /app/ which points at the real app, letting the url stay the same.
It's not considered a good practice because of security issues (can't be sure where you are typing credentials into), and bookmarking issues (url is always the same so can't bookmark inner pages).
Another alternative is to set up a proxy script that just takes the url, turns that into the equivalent aws url, downloads it and then returns it. This would break the benefits of your cloud hosting if it has multiple regions... it would always be passed through the bottleneck of your server.

Related

How to host images stored inside S3 static website, over HTTPS?

I have an S3 bucket which I'm using for storing images uploaded by users. Then I save paths to those images in my database, each path looks like so https://bucket-name.s3.eu-central-1...
I then added an image resizing feature which requires the S3 bucket to be a static website, so that redirection rules can be used.
Appearantly this static website thingy made it impossible to download those pictures using old paths with https protocol, and because my website is using https - I can't make http requests. So now all the profile pictures of the users aren't displayed at all.
I'm looking for a solution to this problem. I can change pictures' paths stored in the database if needed.
One possible solution I have in mind is using a subdomain with CloudFront, e.g. pictures.my-website.com/name-of-the-picture.png
Do you think it'll work and it's a good solution, or there is a better way?
Use CloudFront as a server with predefined domain and SSL certificates https://medium.com/#tsubasakondo_36683/serve-images-with-cloudfront-s3-8691d5c387b6

Next.js: How to make links work with exported sites when hosted on AWS Cloudfront?

I'm trying to get a prototype Next.js project up by doing a Static html export (i.e. next export) and then copying the generated output to AWS S3 and serving it via Cloudfront.
I've got the following two pages in the /pages directory:
index.tsx
Pricing.tsx
Then, following along from the routing doco I added a Link to the pricing page from the index page, like so:
<Link href="/Pricing">
<a>Pricing</a>
</Link>
This results in a link that looks like example.com/Pricing (when you hover over it and when you click the link, the page does change to the pricing page and the browser shows example.com/Pricing in the URL bar).
The problem is, that link is not real - it cannot be bookmarked or navigated to directly via the url bar.
The problem seems to be that when I do a next export, Next.js generates a .html file for each page, but the router doesn't use those .html suffixes.
So when using the site, if the user tries to bookmark example.com/Pricing; loading that bookmark later will fail because Cloudfront will return a 404 (because CF only knows about the .html file).
I then tried changing my Link to look like:
<Link href="/Pricing.html">
<a>Pricing</a>
</Link>
That causes the router to use example.com/Pricing.html and that works fine with Cloudfront - but it actually causes a 404 during local development (i.e. using next dev)!
Other workarounds I could try are renaming all the .html files and removing the extension before I upload them to S3 (and make sure they get a content-type: text/html header) - or introducing a Cloudfront lambda that does the renaming on the fly when .html resources are requested. I don't really want to do the lambda thing, but the renaming before uploading shouldn't be too difficult.
But it feels like I'm really working uphill here. Am I doing something wrong at a basic level? How is Next.js linking supposed to work with a static html export?
Next.js version: 9.5.3-canary.23
Alternate answer if you want your URLs to be "clean" and not have .html on the end.
To get Next.js default URL links working properly with S3/Cloudfront, you must configure the "add a trailing slash" option in your next.config.js:
module.exports = {
trailingSlash: true,
}
As per the documentation
export pages as index.html files and require trailing slashes, /about becomes /about/index.html and is routable via /about/. This was the default behavior prior to Next.js 9.
So now you can leave your Link definition as:
<Link href="/Pricing">
<a>Pricing</a>
</Link>
This causes Next.js to do two things:
use the url example.com/Pricing/ - note the / on the end
generate each page as index.html in it's own directory - e.g. /Pricing/index.html
Many HTML servers, in their default configuration, will serve up the index.html from inside the matching directory if they see a trailing / character in the URL.
S3 will do this also, if you have it set up to serve as a website and IFF you access the URL through the website endpoint, as opposed to the REST endpoint.
So your Cloudfront distribution origin must be configured as a Origin type = Custom Origin pointing at a domain something like example.com.s3-website.us-east-1.amazonaws.com, not as an S3 Origin.
If you have your Cloudfront/S3 mis-configured, when you hit a "trailing slash" style URL - you will probably see your browser download a file of type binary/octet-stream containing 0 bytes.
Edit: Beware pages with . characters, as per issue 16617.
Followup to Shorn's self-answer of using the as field in the next/link component. This worked for me, however it would fail if I refreshed the page I was on.
Instead, I used exportPathMap to link my pages to a page.html equivalent that would be created when running next export.
The downside of this approach is that when running next start, those .html files will not be created or accessible. They will, however, from next dev. As I am creating a purely static website, I've now just been using next dev.
While making this change I was validating by manually copying my built assets from next export into S3 and hosting in CloudFront as Shorn was doing -- I no longer do this to validate and haven't had issues so far.
If anyone knows, let me know what I else may be missing by ignoring next start as part of development. This solution has worked for me so far though.
After writing this question, I found a reasonable workaround - though I'm not sure if it's the "right" answer.
Change the Link to:
<Link href="/Pricing" as="/Pricing.html">
<a>Pricing</a>
</Link>
This seems to work in both local dev and for bookmarking the site as served by Cloudfront. Still feels kind of wonky though. I kind of like those non .html urls better too. Oh well, maybe I'll do the renaming workaround instead.

Amazon S3 Securing Static Website

I'm looking for a combination of policies to access a static website in a S3 bucket only with a certain token/sign string.
I mean, is it possibile to make the static website not readable by everyone by default but temporary accessible with something like http://mybucket.s3-website-location.amazonaws.com/myfolder/index.html?sign=XXXXX?
With this call you should also have access to all the tree in the "myfolder" folder.
I don't think its possible - think about how you would do that on a regular website, you would need to read the querystring and then do some sort of lookup/logic to determine if the token was valid, i.e. you need to do some server-side processing to carry out that logic.
Once you need to add server-side logic you are no longer have a 'static' website (even though ultimately you may be serving up static pages). S3 may not be the right solution for you in this case.
From aws: http://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html
You can host a static website on Amazon S3. On a static website, individual web pages include static content. They may also contain client-side scripts. By contrast, a dynamic website relies on server-side processing, including server-side scripts such as PHP, JSP, or ASP.NET. Amazon S3 does not support server-side scripting.
You can only do this for a single URL at a time, using a signed S3 URL with an expiration time. There is no way to create a signature that can be appended to any of a group of URLs that will make them all work with the signature, but not work without it.
Sorry.
However, this is fairly easy to do with an actual website as a front end. You'd have to code the website to redirect every request to a signed URL specific to that object. To do that, you'd need an EC2 instance that runs the code you write. But as of now, S3 doesn't have a way to do this all by itself.

Protecting static files from non logged in users in Django

I have an existing site with a number of documents being served staticly. Client wants to add login protection to the site - not a problem using django_auth. However, the files being served from apache are still downloadable?
Is there a way to restrict access?
Ideally, this would require the path to these docs not changing on the site.
Was thinking of removing the alias from the apache config and having that route to a view that has the #login_required decorator on it, and then forwarding on.
See Having Django serve downloadable files on how to set up Django to work with Apache X-Sendfile. You can wrap the X-Sendfile header sending with some authentication checks and you should be good to go.

Django: control access to "static" files

Ok, I know that serving media files through Django is a not recommended. However, I'm in a situation where I'd like to serve "static" files using fine-grained access control through Django models.
Example: I want to serve my movie library to myself over the web. I'm often travelling and I'd like to be able to view any of my movies wherever I am, provided I have internet access. So I rip my DVDs, upload them to my server and build this simple Django application coupled with some embeddable video player.
To avoid any legal repercussions, I'd like to ensure that only logged-on users with the proper permissions (i.e. myself and people living in the same household, which can, like me, access the real DVDs at their convenience), but denies it to other users (i.e. people who posted comments on my blog) and returns an HTTP 404.
Now, serving these files directly using Apache and mod_wsgi is rather troublesome because when an HTTP request for the media files (i.e. http://video.mywebsite.com/my-favorite-movie/) comes in, I need to validate against my user database that the person at the other end has the proper permissions.
Question: can I achieve this effect without serving the media files directly through a Django view? What are my options?
One thing I did think of is to write a simple script that takes a session ID and a video's slug and returns some boolean indicating if the user may (or may not) access the video file. Then, somehow request mod_wsgi to execute this script before accessing the requested URL and return an HTTP 404 if the script failed. However, I don't have a clue if this is even possible.
Edit: Posting this question clarified some of my ideas for search and I've come across mod_python's file wrapper extension. Does anyone have enough experience with that to validate that it is a viable solution?
Yes, you can hook into Django's authentication from Apache. See this how-to:
Authenticating against Django’s user database from Apache