cookie-session based access restriction in apache - apache

My project use htaccess files to restrict access to the server resources. The access is granted with an HTTP authentication.
I want to leave HTTP authentication and use a php-session-like login authentication to check access.
What I want to do could be simply done in a script like:
<?php
session_start()
if ( !isset($_SESSION['user']) ) {
header('location : /login.php');
exit;
}
//...also we could use url rewriting to redirect all urls pointing to static resource through
// a script that will deliver its content or redirect to the login form depending on
// identification status
Using php for dynamic pages is not a problem, but how to I grand access to Static resource using a session id passed with cookies in apache ?
I've seen questions related to cookie based redirection in apache, but none of them treat about identifying a user based on a sessionId passed by cookie.

For HTML content, keep your "static" content in PHP scripts whose only "dynamic" feature is that they contain a common header included for checking login/session.
For images, css, javascript, documents, anything else, this more extensive discussion will be of help.

Related

Only allow access to files in directory from the website they are a part of

I know there are a lot of similar questions out there, and I've trawled them all, but I can't seem to get any of the solutions to work.
I have a folder on the root of my website containing uploaded files that can be viewed and downloaded from the site when a user is logged in. They are here: https://example.com/uploads (for example). I need the site to continue to be able to access them to display them (some are images) and provide links for download (pdfs etc) so the user can download them, but I want to avoid anyone who get's hold of the url of a particular file being able to download them directly, like this: https://example.com/uploads/2020/02/myfile.pdf. OR these urls getting into search engines (or if they do, the server prevents them from being accessed directly.
I've tried adding an .htaccess file in the uploads directory with the following content:
Order Deny,Allow
Deny from all
Allow from 127.0.0.1
And I've tried
Order Allow,Deny
Deny from all
Allow from 127.0.0.1
...as I read that might allow HTTPS calls from the site itself as well as local urls.
But it forbids the site and a direct url request, which is no good.
Is there a way to do this?
The user interface that provides the ‘official’ access to the files has user authentication, yes, but the files still exist in a directory than won’t stop anyone getting to them if they know the url.
You need to protect the files using the same authentication system that you are using to protect access to the user interface. The only way you could protect these resources by IP address (the client IP address) - as you are currently attempting in .htaccess - is if the client's IP is fixed and known in advance (but if this was the case then you wouldn't need another form of authentication to begin with).
So, this will primarily be an exercise in whatever scripting language/CMS is being used to authenticate the "user interface".
What you can use .htaccess for is to rewrite requests for these files to your server-side script that handles the authentication and then serves the file to the client once authenticated.
For example:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^uploads/. /serve-protected-file.php [L]
Any request for /uploads/<something> (eg. /uploads/2020/02/myfile.pdf), that maps to a valid file is routed to your script: /serve-protected-file.php.
/serve-protected-file.php would then need to do something like the following:
// 1. Parse the file being requested from REQUEST_URI
// 2. Is the requested file "protected"?
// (Serving both protected and public files from the same directory?)
// 3. If not protected then serve/stream the resource to the client. END
// 4. If protected then authenticate the user...
// 5. If user authenticated then serve/stream the resource to the client. END
// 6. Resource is protected and user not authenticated...
// Serve a 403 Forbidden. END
(Ideally, the location of these "protected" resources would be entirely outside of the document root - so they are "private" by default - and the URL the user uses to access these resources is entirely virtual - then you probably wouldn't need any additional coding in .htaccess and everything would be implemented by your front-controller - but that all depends on how your site is implemented and the way in which URLs are routed.)

How to differentiate between users using Basic Authentication

Problem
I have a website that uses Basic Authentication and has multiple different logins. I'd like a way to tell, using javascript, the username of the person currently logged in.
I checked the cookies and the basic Authentication credentials are not stored there.
Stack
I'm using Apache configured with a .htaccess and .htpasswd file so using the backend to tell the frontend which user is logged in is not an option.
Goal
The problem I'm trying to solve is really simple, I want my website to display the username of the person currently logged in.
Not without a tiny bit of PHP. Javascript executes on the client and as you have already discovered, the username is not sent from the server so you will need something at the server end to send that userid.
Here is how:
As your page is generated at the server, it uses a small piece of PHP to add the username into your JavaScript and that's how JavaScript has it at the client to do with it what it needs.
Note, the userid wont change until the page is requested again by a different user, so it's not something that needs to be dynamic at the client side mid session.
PHP generates the page at server end when user logs in it includes it in the JavaScript code on the page. Where you want that name in your JavaScript you put it there using <?php echo $_SERVER['REMOTE_USER']; ?>. File extension will need to be .php for your file on the server that has your html and JavaScript code.

Can Cloudflare cache HTML for anonymous users but not logged in users?

We have a website with anonymous user content generally static (updated once every hour), and content for logged in users different for every user, updated frequently.
Is it possible to configure cloudflare so that HTML is cached for anonymous users but not logged in users, given the same URL for both?
Are there any cache headers we can set that are relevant?
i have been struggling with the same scenario, and as far as i seen there's no way,
In cloudflare you can set up Page Rules but those will only look at the URL itself.
So the only solution i see would be having diferent URL's (some extra parameter or maybe a subdomain) for each kind of users, then you'll easily set up the rules to manually force the cache expiration time
I am not sure if this would work, but the only way I can think of doing this as a possibility is via HTTP/HTTPS as you can use this in the CloudFlare Page Rules.
So if you set the WordPress FORCE_SSL_ADMIN constant to true, and then were to redirect all the logged in user URL requests to the HTTPS schema of the page, this might do the trick and thus make it possible to bypass the CloudFlare cache?
This is not possible unless you are on the Enterprise plan level.
https://www.cloudflare.com/plans/
A solution from here
Add a private cache control to the page header:
//recommended by cloudflare for logged in users
if ( is_user_logged_in() ) {
header(‘Cache-Control: private, max-age=3600’);
}
Yes. Cloudflare says it will respect meta tags requesting no cache, therefore simply add those tags to the header section of the page for logged in users.
Example (using smarty)
{if $loggedin}
<meta http-equiv="cache-control" content="no-cache" />
{/if}
(using PHP)
if($loggedin)
{
echo "<meta http-equiv=\"cache-control\" content=\"no-cache\" />";
}

How to properly cache my Symfony2 APIs?

I'm making classic stateless RESTfull APIs on Symfony2: users/apps gets an authentication token on the authenticate API and give it to all others APIs to be logged and post data / access protected/private/personal data on others APIs.
I've got now three concerns regarding this workflow and caching:
How to use HTTP cache for my 'static' APIs (that always deliver the same content, regardless the logged user and its token) assuming that different tokens would be passed in the url by different users for the same API, so that the url would never be the same? How to use HTTP shared cache then?
I've got APIs for the same url that produce a different output, regarding the logged user rights (I've basically 4 different rights levels). Question is: is it a good pattern? It is not better to have 4 different urls, one for each right, that I could cache? If not, how to implement a proper cache on that?
Is shared HTTP Cache working on HTTPS? If not, which type of caching should I implement, and how?
Thanks for your answers and lights on that.
I have had a similar issue (with all 3 scenarios) and have used the following strategy successfully with Symfony's built-in reverse-proxy cache:
If using Apache, update .htaccess to add an environment variable for your application to the http cache off of (NOTE: environment automatically adds REDIRECT_ to the environment variable):
# Add `REDIRECT_CACHE` if API subdomain
RewriteCond %{HTTP_HOST} ^api\.
RewriteRule .* - [E=CACHE:1]
# Add `REDIRECT_CACHE` if API subfolder
RewriteRule ^api(.*)$ - [E=CACHE:1]
Add this to app.php after instantiating AppKernel:
// If environment instructs us to use cache, enable it
if (getenv('CACHE') || getenv('REDIRECT_CACHE')) {
require_once __DIR__.'/../app/AppCache.php';
$kernel = new AppCache($kernel);
}
For your "static" APIs, all you have to do is take your response object and modify it:
$response->setPublic();
$response->setSharedMaxAge(6 * 60 * 60);
Because you have a session, user or security token, Symfony effectively defaults to $response->setPrivate().
Regarding your second point, REST conventions (as well as reverse-proxy recommendations), GET & HEAD requests aren't meant to change between requests. Because of this, if content changes based on the logged in user, you should set the response to private & prevent caching at all for the reverse-proxy cache.
If caching is required for speed, it should be handled internally & not by the reverse-proxy.
Because we didn't want to introduce URLs based on each user role, we simply cached the response by role internally (using Redis) & returned it directly rather than letting the cache (mis)handle it.
As for your third point, because HTTP & HTTPS traffic are hitting the same cache & the responses are having public/private & cache-control settings explicitly set, the AppCache is serving the same response both secure & insecure traffic.
I hope this helps as much as it has for me!

Authenticate sites with different domain names using the Facebook API

We have a CMS that supports multiple sites, one of our features allows our users (The site admin) to connect to the site facebook account to allow status updates, create events and upload pictures to FB from with in the CMS.
The authentication needs to occur once since each site may have multiple site admins that do not have access to the site FB user name and password. We use iframe and authenticate using $facebook->require_login() which redirects the user to the FB login and authentication pages.
All this works just fine but when the user hits "Allow" the authentication will break as it will only redirect to whatever is in the "Post-Authorize Redirect URL" field making the app obsolete for any other domain except the one in the "Post-Authorize Redirect URL"
I know other API's authentication methods like in Vimeo and YouTube will allow you to specify a NEXT parameter which is the equivalent of the "Post-Authorize Redirect URL" and it can be set at run time.
How can I make this work for multiple domain names?
Any hints on this issue will be of great help
If the call back page is in your domain, that page could acts as a proxy, all you have to do is pass the parameters needed by the proxy page to redirect the user to the proper location. For example I used the URL of the domain I want to redirect and an ID needed for me to know which user I am dealing with.
My code end up looking something like this:
Authorize link:
$authorizeURL = "http://www.facebook.com/authorize.php?api_key=" . $facebookApiKey . "&v=1.0&ext_perm=status_update&domainName=$domainName&path=/path/to/my/next/page.php";
and the "proxy" code would like something like this:
$path = $_GET['path'];
$query = $_GET['query'];
$domainName = $_GET['domainName'];
//if you happen to have a query, get the values like this:
parse_str($query, $queryValues);
$id = $queryValues['id'];
// construct the url where your user came from or where you want them to be redirected.
$url = "http://$domainName/$path?$query";
header("Location: " . $url);
exit;
This is not the whole code, but it will give you an idea on how to do it.
make a separated domain used only for FB authentication.