Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider setting 403 Forbidden on failed authBasic() #49

Closed
ramsey opened this issue May 15, 2012 · 9 comments
Closed

Consider setting 403 Forbidden on failed authBasic() #49

ramsey opened this issue May 15, 2012 · 9 comments

Comments

@ramsey
Copy link
Contributor

ramsey commented May 15, 2012

Consider the following code example using the authBasic() routine:

<?php
$r3 = new \Respect\Rest\Router();

$r3->get('/', function() {
    echo 'Hello';
})->authBasic('My Realm', function($user, $pass) {
    return $user === 'admin' && $pass === 'pass';
});

When I query this without providing basic auth headers, I get the correct 401 Authorization Required response that I expect:

HTTP/1.1 401 Authorization Required
Date: Tue, 15 May 2012 22:55:38 GMT
Server: Apache/2.2.20 (Ubuntu)
X-Powered-By: PHP/5.4.0-3~oneiric+4
WWW-Authenticate: Basic realm="My Realm"
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 20
Content-Type: text/html

However, if I do provide authentication headers, but the username and password are incorrect, causing the authBasic() routine to return false, then I get back a 200 OK response with no content.

HTTP/1.1 200 OK
Date: Tue, 15 May 2012 22:57:08 GMT
Server: Apache/2.2.20 (Ubuntu)
X-Powered-By: PHP/5.4.0-3~oneiric+4
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 20
Content-Type: text/html

There is no security concern here, since you are properly blocking the client from receiving the content, but the 200 OK doesn't seem appropriate. Perhaps a 403 Forbidden is more appropriate by default, or we can continue to leave it up to the application developer.

Here's an example of how I'm accomplishing this right now:

<?php
$r3 = new \Respect\Rest\Router();

$r3->get('/', function() {
    echo 'Hello';
})->authBasic('My Realm', function($user, $pass) {
    if ($user === 'admin' && $pass === 'pass') {
        return true;
    } else {
        header('HTTP/1.1 403 Forbidden');
        return false;
    }   
});
@ramsey
Copy link
Contributor Author

ramsey commented May 15, 2012

Unfortunately, I just realized my example has the negative effect of always setting 403 Forbidden in the response if you do not provide auth credentials, so the 401 Authorization Required is never set. With a bit more logic, though, you can set the 403 only if a $user and $pass are present but fail to authorize.

@alganet
Copy link
Member

alganet commented May 16, 2012

You're right! Shouldn't be hard to implement. I'll do this by the end of this week =)

@alganet
Copy link
Member

alganet commented May 17, 2012

I've reconsidered this after reading the RFC2616 again. Section 10.4.2 says (about 401):

   If the request already included Authorization credentials, then the 401
   response indicates that authorization has been refused for those
   credentials. 

Section 10.4.4 also says that (about 403):

   The server understood the request, but is refusing to fulfill it.
   Authorization will not help and the request SHOULD NOT be repeated.

I'm more towards returning 401 again on failure instead of 403. What do you guys think? @ramsey @augustohp

@mta59066
Copy link

Yes, I think 401 would be the correct return code. Here is how I did it.

public function by(Request $request, $params)
{
    $result = false;
    if (isset($_SERVER['HTTP_AUTHORIZATION']))
        $result = call_user_func_array(
            $this->callback,
            explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6))
        ));
    elseif (isset($_SERVER['PHP_AUTH_USER']))
        $result = call_user_func($this->callback, $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);

    if($result !== true) {
        header('HTTP/1.1 401');
        header("WWW-Authenticate: Basic realm=\"{$this->realm}\"");
        return $result;
    }
}

@mta59066
Copy link

Actually 401 needs to be the return code if authentication was tried and not successful. If authentication was not even tried, than perhaps should be left to the application developer like what ramsey suggested in the initial post, but maybe the expected behavior by the application developer is to end up at 403? Not sure how to implement that on AuthBasic.php.

@ramsey
Copy link
Contributor Author

ramsey commented May 24, 2012

I'm switching my original request and agreeing with everyone that the return code should be 401, rather than 403, for failed authentication. As @mta59066 has suggested, I've changed my own code to return 401 and WWW-Authentication headers.

@nickl-
Copy link
Member

nickl- commented Jun 20, 2012

Does this mean the issue is resolved and we can close it? If not does anyone care to roll a patch and make a pull request, please. If AuthBasic is in need of some TLC lets do that.

@ramsey
Copy link
Contributor Author

ramsey commented Jun 21, 2012

The issue wasn't resolved, so I quickly created a patch and issued a pull request. :-)

@nickl-
Copy link
Member

nickl- commented Jun 21, 2012

Awesome Tx! Will have a look see... you rock! =)

@nickl- nickl- closed this as completed Jun 21, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants