Redirect with HTTP 403 - php

I'm using Slim PHP and want to redirect the user to /login if they are not logged in but try to access a page that requires a user to be logged in. When searching for how to build my middleware, I find variations of this code all over the place
class Auth{
public function requireLogin(Request $request, Response $response, $next){
if( !isLoggedIn() ) return $response->withRedirect('/login', 403);
return $next($request, $response);
}
}
for example in this SO answer and this Slim discourse answer.
The problem is that I can't get the combination of redirecting and HTTP 403 to work. From what I can tell, normal HTTP redirects are restricted to the HTTP codes 3xx. Indeed, the above code works fine when used with for example 302.
Am I missing something, or are all the answers that combine withRedirect and 403 "incorrect" (as in not causing an actual redirect of the users browser)?

If your application is an HTML website that's accessed using a web browser, then the browser will only redirect if the status code is a 3xx one.
If your application is an API that's accessed using an HTTP client then you have more leeway. For an API, you'd use a 403 or 401 status code to indicate that the request cannot be fulfilled without authorisation. You may also include a Location header to tell the client where to go to get authorisation, but of course it's up to the client if they follow up on that link.

Related

Slim3 redirect GET request as POST request

Just started learning Slim3. Have been spending some time figuring out how to perform redirects with overriding original request type with no success.
I want the /origin route to perform the redirect to /dest route.
/origin route receives GET request performs validation and after success redirects with POST request to /dest uri route. Here is the screenshot. I think I am doing something dumb here:
$app->get('/origin', function($req,$res,$args)
{
$req= $req->withHeader('X-Http-Method-Override','POST');
return $res->withRedirect('/dest');
});
$app->post('/dest', function($req,$res,$args)
{
echo "this is destination page";
});
As noted in the comment, this is not possible as the request made by the browser is not in your control.
When you call ->withRedirect() you are sending a status code of 302 and a Location header to the HTTP client (web browser usually).
The web browser sees the 302 status code and then issues a new request to the URL in the Location header. The server has no control over this request and every web browser makes a GET request.
Now, if you want to redirect a POST request to another URL and keep the same POST method, then you can use the 307 status code with a Location header and the browser should do the right thing. Note that this code does not let you change a GET into a POST - it just keeps the same method as the original request for the followup redirection request.

Redirect POST Requests with Slim 3

I have an API gate in PHP with Slim 3 Framework (server1) and a web services server (server2) to access/edit the datas.
I handle user authentication and define my authenticated routes in server1. The dialog between server1 and server2 works with tokens.
I want to use my server1 to forward GET/POST requests to my server2. What is the best way to do that ?
With Slim on my server1, I can use the withRedirect method but I can't make it work with POST requests :
$app->post('/api/resource', function ($request, $response, $args) {
return $response->withRedirect("http://server2/api/resource?additionla_parameter=value");
});
Maybe should I use an app like Guzzle or a proxy ?
I personally would go the Guzzle route, meaning to just create a client on the server-side to communicate with server2, but there actually is a HTTP 307 response code for such purposes. It states that a client should not change the method (in your case the POST) during a redirect. Here is a nice little wrap-up: https://softwareengineering.stackexchange.com/questions/99894/why-doesnt-http-have-post-redirect/99966#99966
I just peeked at the slim source and the method accepts a second parameter for the status code which defaults to 302 when not set. See https://github.com/slimphp/Slim/blob/3.x/Slim/Http/Response.php#L289. So just try this:
$response->withRedirect("http://postplease", 307);
That might work

Change HTTP request authorisation header with PHP or HTML

The quick question is: is there ane way to change http authorisation header with html / php / javascript?
The goal
I'd like to make an auth service used for user login as well as providing with whole site protection. I want user to be restricted from viewing any file except login page unless authorised. For php I can of course check at the beginning for example session token availability, and redirect if missing, but I can't do it directly for for example jpg images. I thought of creating htaccess file that will verify if user is logged.
The solution
1.
Using Apache I've created .htaccess file, that verifies, if HTTP authorisation is set. If not it redirects any request to login page. With that solution one can not open any file (no matter if it is php script or for example jpg image) except of the login page:
RewriteCond %{HTTP:Authorization} ^$
RewriteCond %{REQUEST_URI} !^/login.php
RewriteRule .* /login.php [L,R]
2.
The login page should display form and when login and password are correct set the http request auth header with proper token.
Unfortunately I can't find a way to create manually http request auth header. The only way I found was to use basic auth:
$auth = new Auth();
if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SESSION)) {
$auth->logout();
}
if (!empty($_SERVER['PHP_AUTH_USER']) && empty($_SESSION)) {
$login = $_SERVER['PHP_AUTH_USER'];
$haslo = (!empty($_SERVER['PHP_AUTH_PW']) ? Auth::hashPassword($_SERVER['PHP_AUTH_PW']) : null);
$auth->login($login, $haslo);
}
$auth->getLoginForm();
Where getLoginForm() displays Basic Auth standard form
public function getLoginForm()
{
header(self::HEADER_ERROR_ASK_CLIENT_DATA);
header(self::HEADER_RESPONSE_401);
exit;
}
This solution works, but http request auth header holds the original login data all the time, which is what I want to avoid. I want to inject there "Bearer + token" string, which will help in securing whole system.
What I've tried
I can easily do that with external frontend. For example with windows desktop app I can send one request with basic auth header and the next with bearer header.
The same I can do with JQuery and AJAX - I can retrieve token using url with basic auth, and then use token with custom header for next requests.
I can also make different requests with PHP CURL.
But I can't find a way to force regular browser to login with Basic auth header and after success keep new, custom bearer header for next requests.
There is no standard mechanism to get a User Agent (browser) to provide an Authorization: Bearer header by itself.
What you can do:
make sure all your requests are done via XHR (Ajax), and send the header there. But this will not allow "regular" file loads (new pages, images, scripts, CSS...).
what most people do: send a cookie with your authentication token, and check for that cookie. The browser will automatically send the cookie.
As an aside, note that your .htaccess only checks that there is an Authorization header present, not its value, so it's quite useless. You want to channel all reads via a script that will actually verify the header or cookie before delivering the file.

PHP: How to detect a website redirect that returns a '404' status code?

I am writing a small php script that can distinguish two between different kinds of responses from a third-party website.
For the human visitor, recognizing the difference is fairly easy: Response #1 is a bare-bones 404 error page, whereas response #2 redirects to the main page.
For my script, this turns out to be somewhat more difficult. Both types return a '404' status code, file_get_contents() returns empty for both and the "redirect" doesn't really register as a redirect (like I said, there's a '404' status code, not a '30X'). Get_headers() shows no distinction, either (no "Location:" or anything of that sort).
Any way I can get this done?
There are many ways to do a redirect:
the HTTP response codes for redirect (usually 301 and 302) accompanied by the Location: header that contains the URL
HTTP/1.1 302 Found
Location: http://www.example.org
the HTTP header Refresh:; it contains a number of seconds to wait and the new URL:
Refresh: 0; url=http://www.example.org
the HTML meta element that emulates the Refresh HTTP header:
<meta http-equiv="Refresh" content="0; url=http://www.example.org">
Javascript:
<script>document.location = 'http://www.example.org';</script>
Note that there are countless possibilities to redirect using Javascript. What is common to all of them is the usage of the location property of document or window. location is an object of type Location that can be assigned directly using a string or can be changed using its href property or its methods assign() and replace().
If the requests to your URLs does not return any content, the both return status code 404 and no Location: header then check for the presence of the Refresh: header in the response.
You better use curl to make the requests instead of file_get_contents(). curl provides a better control of the headers sent and received.
I would suggest You to make a cURL request to desired site and see what kind of response it is.
As described in PHP manual,
curl_getinfo ($handle, CURLINFO_HTTP_CODE);
will give You an associative array, in it You will find the http_code key, which will hold Your status code.
If redirect case will give You non-30X status code, You can try to fetch redirect url by this:
curl_getinfo ($handle, CURLINFO_REDIRECT_URL);

Test For Password Protected Folder

How do I use PHP to check whether a folder is password protected or not? I am using a PHP script that check for return codes 401 and 403 but when it runs into a folder that is password protected it recognizes that its a 403 but does not allow the popup box for username and password to display? How do I detect that the folder is password protected so I can tell my script to ignore it?
Actually 403 means forbidden. A password-protected resource would normally return 401 Unauthorized.
You already have the information you need: The HTTP response code (403 or whatever) is how you know that the resource (folder, file) is inaccessible.
You say you already have a script to check if the header code is 401 and 403 and yet you want to know how you can check if a page sends a 403 header?
Perhaps you mean talking about the Authentication header.
Assuming the server uses standard HTTP Authentication, the page is password protected if following conditions are met,
The response status code is 401.
www-authenticate header is present in response.
Zhihong

Categories