1
1
Fork 0
mirror of https://code.mensbeam.com/MensBeam/Arsse.git synced 2024-12-23 09:02:41 +00:00

Second set of authentication tests

This commit is contained in:
J. King 2019-09-28 14:41:35 -04:00
parent ba17d16358
commit c0f42ac031
4 changed files with 29 additions and 14 deletions

View file

@ -39,7 +39,12 @@ class URL {
* @param string $p Password to add to the URL, if a username is specified * @param string $p Password to add to the URL, if a username is specified
*/ */
public static function normalize(string $url, string $u = null, string $p = null): string { public static function normalize(string $url, string $u = null, string $p = null): string {
extract(parse_url($url)); $parts = parse_url($url);
if (!$parts) {
// bail if there is no authority
return $url;
}
extract($parts);
$out = ""; $out = "";
if (isset($scheme)) { if (isset($scheme)) {
$out .= strtolower($scheme).":"; $out .= strtolower($scheme).":";

View file

@ -120,6 +120,9 @@ class Auth extends \JKingWeb\Arsse\REST\AbstractHandler {
*/ */
protected function matchIdentifier(string $canonical, string $me): bool { protected function matchIdentifier(string $canonical, string $me): bool {
$me = parse_url(URL::normalize($me)); $me = parse_url(URL::normalize($me));
if (!$me) {
return false;
}
$me['scheme'] = $me['scheme'] ?? ""; $me['scheme'] = $me['scheme'] ?? "";
$me['path'] = explode("/", $me['path'] ?? ""); $me['path'] = explode("/", $me['path'] ?? "");
$me['id'] = rawurldecode(array_pop($me['path']) ?? ""); $me['id'] = rawurldecode(array_pop($me['path']) ?? "");
@ -191,7 +194,7 @@ class Auth extends \JKingWeb\Arsse\REST\AbstractHandler {
return new EmptyResponse(400); return new EmptyResponse(400);
} }
try { try {
$state = $query['state'] ?? ""; $state = rawurlencode($query['state'] ?? "");
// ensure the logged-in user matches the IndieAuth identifier URL // ensure the logged-in user matches the IndieAuth identifier URL
$user = $req->getAttribute("authenticatedUser"); $user = $req->getAttribute("authenticatedUser");
if (!$this->matchIdentifier($this->buildIdentifier($req, $user), $query['me'])) { if (!$this->matchIdentifier($this->buildIdentifier($req, $user), $query['me'])) {
@ -210,7 +213,7 @@ class Auth extends \JKingWeb\Arsse\REST\AbstractHandler {
], \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); ], \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE);
// issue an authorization code and build the redirect URL // issue an authorization code and build the redirect URL
$code = Arsse::$db->tokenCreate($user, "microsub.auth", null, Date::add("PT2M"), $data); $code = Arsse::$db->tokenCreate($user, "microsub.auth", null, Date::add("PT2M"), $data);
$next = URL::queryAppend($redir, "code=$code&state=$state"); $next = URL::queryAppend($redir, "state=$state&code=$code");
return new EmptyResponse(302, ['Location' => $next]); return new EmptyResponse(302, ['Location' => $next]);
} catch (ExceptionAuth $e) { } catch (ExceptionAuth $e) {
$next = URL::queryAppend($redir, "state=$state&error=".$e->getMessage()); $next = URL::queryAppend($redir, "state=$state&error=".$e->getMessage());

View file

@ -73,6 +73,7 @@ class TestURL extends \JKingWeb\Arsse\Test\AbstractTest {
["EXAMPLE.COM/", "EXAMPLE.COM/"], ["EXAMPLE.COM/", "EXAMPLE.COM/"],
["EXAMPLE.COM", "EXAMPLE.COM"], ["EXAMPLE.COM", "EXAMPLE.COM"],
[" ", "%20"], [" ", "%20"],
["http:///%G", "http:///%G"]
]; ];
} }

View file

@ -8,6 +8,7 @@ namespace JKingWeb\Arsse\TestCase\REST\Microsub;
use JKingWeb\Arsse\Arsse; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Database; use JKingWeb\Arsse\Database;
use JKingWeb\Arsse\Misc\Date;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Zend\Diactoros\Response\JsonResponse as Response; use Zend\Diactoros\Response\JsonResponse as Response;
use Zend\Diactoros\Response\EmptyResponse; use Zend\Diactoros\Response\EmptyResponse;
@ -97,7 +98,7 @@ class TestAuth extends \JKingWeb\Arsse\Test\AbstractTest {
$act = $this->req("http://example.com/u/?f=auth", "GET", $params, [], [], "", null, $authenticatedUser); $act = $this->req("http://example.com/u/?f=auth", "GET", $params, [], [], "", null, $authenticatedUser);
$this->assertMessage($exp, $act); $this->assertMessage($exp, $act);
if ($act->getStatusCode() == 302 && !preg_match("/\berror=\w/", $act->getHeaderLine("Location") ?? "")) { if ($act->getStatusCode() == 302 && !preg_match("/\berror=\w/", $act->getHeaderLine("Location") ?? "")) {
\Phake::verify(Arsse::$db)->tokenCreate($authenticatedUser, "microsub.auth", null, null, json_encode([ \Phake::verify(Arsse::$db)->tokenCreate($authenticatedUser, "microsub.auth", null, $this->isInstanceOf(\DateTimeInterface::class), json_encode([
'me' => $params['me'], 'me' => $params['me'],
'client_id' => $params['client_id'], 'client_id' => $params['client_id'],
'redirect_uri' => $params['redirect_uri'], 'redirect_uri' => $params['redirect_uri'],
@ -110,16 +111,21 @@ class TestAuth extends \JKingWeb\Arsse\Test\AbstractTest {
public function provideLoginData() { public function provideLoginData() {
return [ return [
'Challenge' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], null, new EmptyResponse(401)], 'Challenge' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], null, new EmptyResponse(401)],
'Failed challenge' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "", new EmptyResponse(401)], 'Failed challenge' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "", new EmptyResponse(401)],
'Wrong user 1' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "jane.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])], 'Wrong user 1' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "jane.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])],
'Wrong user 2' => [['me' => "https://example.com/u/jane.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])], 'Wrong user 2' => [['me' => "https://example.com/u/jane.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])],
'Wrong domain' => [['me' => "https://example.net/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])], 'Wrong domain 1' => [['me' => "https://example.net/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])],
'Wrong port' => [['me' => "https://example.com:80/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])], 'Wrong domain 2' => [['me' => "https:///u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])],
'Wrong scheme' => [['me' => "ftp://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])], 'Wrong port' => [['me' => "https://example.com:80/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])],
'Wrong path' => [['me' => "http://example.com/user/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])], 'Wrong scheme' => [['me' => "ftp://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])],
'Bad redirect' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "//example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(400)], 'Wrong path' => [['me' => "http://example.com/user/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=access_denied"])],
'Bad response type' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "bad"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=unsupported_response_type"])], 'Bad redirect 1' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "//example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(400)],
'Bad redirect 2' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "https:///redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(400)],
'Bad response type' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "bad"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&error=unsupported_response_type"])],
'Success 1' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=ABCDEF&code=authCode"])],
'Success 2' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/redirect", 'state' => "R&R", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/redirect?state=R%26R&code=authCode"])],
'Success 3' => [['me' => "https://example.com/u/john.doe", 'client_id' => "http://example.org/", 'redirect_uri' => "http://example.org/?p=redirect", 'state' => "ABCDEF", 'response_type' => "code"], "john.doe", new EmptyResponse(302, ['Location' => "http://example.org/?p=redirect&state=ABCDEF&code=authCode"])],
]; ];
} }
} }