Merge pull request #738 from cachethq/errors

Respond with the correct responses on error
This commit is contained in:
Graham Campbell 2015-06-18 20:08:18 +01:00
commit 26857597f0
24 changed files with 72 additions and 348 deletions

View File

@ -45,5 +45,6 @@ class Kernel extends HttpKernel
'app.isSetup' => 'CachetHQ\Cachet\Http\Middleware\AppIsSetup',
'app.hasSetting' => 'CachetHQ\Cachet\Http\Middleware\HasSetting',
'app.subscribers' => 'CachetHQ\Cachet\Http\Middleware\SubscribersConfigured',
'accept' => 'CachetHQ\Cachet\Http\Middleware\Acceptable',
];
}

View File

@ -0,0 +1,36 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Cachet HQ <support@cachethq.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use Closure;
use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
class Acceptable
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $type
*
* @return mixed
*/
public function handle($request, Closure $next, $type)
{
if (!$request->accepts($type)) {
throw new NotAcceptableHttpException();
}
return $next($request);
}
}

View File

@ -13,7 +13,7 @@ namespace CachetHQ\Cachet\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Support\Facades\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
class Admin
{
@ -45,9 +45,7 @@ class Admin
public function handle($request, Closure $next)
{
if (!$this->auth->check() || ($this->auth->check() && !$this->auth->user()->isAdmin)) {
return Response::view('errors.401', [
'pageTitle' => trans('errors.unauthorized.title'),
], 401);
throw new HttpException(401);
}
return $next($request);

View File

@ -15,6 +15,7 @@ use CachetHQ\Cachet\Models\User;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
class ApiAuthenticate
{
@ -48,34 +49,19 @@ class ApiAuthenticate
if ($this->auth->guest()) {
if ($apiToken = $request->header('X-Cachet-Token')) {
try {
$user = User::findByApiToken($apiToken);
$this->auth->onceUsingId($user->id);
$this->auth->onceUsingId(User::findByApiToken($apiToken)->id);
} catch (ModelNotFoundException $e) {
return $this->handleError();
throw new HttpException(401);
}
} elseif ($user = $request->getUser()) {
} elseif ($request->getUser()) {
if ($this->auth->onceBasic() !== null) {
return $this->handleError();
throw new HttpException(401);
}
} else {
return $this->handleError();
throw new HttpException(401);
}
}
return $next($request);
}
/**
* Common method for returning an unauthorized error.
*
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function handleError()
{
return response()->json([
'message' => 'You are not authorized to view this content.',
'status_code' => 401,
], 401);
}
}

View File

@ -13,6 +13,7 @@ namespace CachetHQ\Cachet\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Symfony\Component\HttpKernel\Exception\HttpException;
class Authenticate
{
@ -44,11 +45,7 @@ class Authenticate
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('auth/login');
}
throw new HttpException(401);
}
return $next($request);

View File

@ -23,8 +23,9 @@ class ApiRoutes
public function map(Registrar $router)
{
$router->group([
'namespace' => 'Api',
'prefix' => 'api/v1',
'namespace' => 'Api',
'prefix' => 'api/v1',
'middleware' => 'accept:application/json',
], function ($router) {
// General
$router->get('ping', 'GeneralController@ping');

View File

@ -1,25 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Cachet HQ <support@cachethq.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
'not-found' => [
'code' => '404',
'title' => 'Die Seite konnte nicht gefunden werden!',
'message' => 'Entschuldigung, aber die Seite konnte nicht gefunden werden. Überprüfen Sie die URL und versuchen Sie es erneut.',
'link' => 'Zurück zur Startseite',
],
'unauthorized' => [
'code' => '401',
'title' => 'Unauthorized',
'message' => 'Sorry, you need admin privileges to see this page.',
'link' => 'Return to homepage',
],
];

View File

@ -1,25 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Cachet HQ <support@cachethq.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
'not-found' => [
'code' => 'crwdns208:0crwdne208:0',
'title' => 'crwdns367:0crwdne367:0',
'message' => 'crwdns368:0crwdne368:0',
'link' => 'crwdns369:0crwdne369:0',
],
'unauthorized' => [
'code' => 'crwdns370:0crwdne370:0',
'title' => 'crwdns371:0crwdne371:0',
'message' => 'crwdns372:0crwdne372:0',
'link' => 'crwdns373:0crwdne373:0',
],
];

View File

@ -1,25 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Cachet HQ <support@cachethq.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
'not-found' => [
'code' => '404',
'title' => 'That page went missing!',
'message' => 'Sorry, but the page you are looking for has not been found. Check the URL for errors and try again.',
'link' => 'Return to homepage',
],
'unauthorized' => [
'code' => '401',
'title' => 'Unauthorized',
'message' => 'Sorry, you need admin privileges to see this page.',
'link' => 'Return to homepage',
],
];

View File

@ -1,25 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Cachet HQ <support@cachethq.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
'not-found' => [
'code' => '404',
'title' => '¡Esta página se perdió!',
'message' => 'Lo sentimos, no se ha encontrado la página que estás buscando. Comprueba que la dirección URL no contenga errores y vuelve a intentarlo.',
'link' => 'Regresar a la página de inicio',
],
'unauthorized' => [
'code' => '401',
'title' => 'No autorizado',
'message' => 'Lo sentimos, necesitas privilegios de administrador para ver esta página.',
'link' => 'Regresar a la página de inicio',
],
];

View File

@ -1,25 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Cachet HQ <support@cachethq.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
'not-found' => [
'code' => '404',
'title' => 'Cette page est manquante !',
'message' => 'Désolé, mais la page que vous recherchez est introuvable. Vérifier l\'URL et essayez à nouveau.',
'link' => 'Retour à l\'accueil',
],
'unauthorized' => [
'code' => '401',
'title' => 'Unauthorized',
'message' => 'Sorry, you need admin privileges to see this page.',
'link' => 'Return to homepage',
],
];

View File

@ -1,25 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Cachet HQ <support@cachethq.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
'not-found' => [
'code' => '404',
'title' => 'Halaman ini hilang!',
'message' => 'Maaf, halaman yang diinginkan tidak ditemukan. Periksa apakah ada kesalahan URL lalu coba lagi.',
'link' => 'Kembali ke depan',
],
'unauthorized' => [
'code' => '401',
'title' => 'Tidak dibolehkan',
'message' => 'Maaf, anda perlu kewenangan admin untuk melihat halaman ini.',
'link' => 'Kembali ke depan',
],
];

View File

@ -1,25 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Cachet HQ <support@cachethq.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
'not-found' => [
'code' => '404',
'title' => 'Die pagina is vermist geraakt!',
'message' => 'Sorry, maar de pagina die je zoekt is niet gevonden. Controleer de URL op fouten en probeer het nogmaals.',
'link' => 'Terug naar homepagina',
],
'unauthorized' => [
'code' => '401',
'title' => 'Ongeautoriseerd',
'message' => 'Sorry, maar je moet beheerdersrechten hebben om deze pagina te bekijken.',
'link' => 'Terug naar homepagina',
],
];

View File

@ -1,25 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Cachet HQ <support@cachethq.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
'not-found' => [
'code' => '404',
'title' => 'That page went missing!',
'message' => 'Sorry, but the page you are looking for has not been found. Check the URL for errors and try again.',
'link' => 'Return to homepage',
],
'unauthorized' => [
'code' => '401',
'title' => 'Unauthorized',
'message' => 'Sorry, you need admin privileges to see this page.',
'link' => 'Return to homepage',
],
];

View File

@ -1,25 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Cachet HQ <support@cachethq.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
'not-found' => [
'code' => '404',
'title' => 'Essa página desapareceu!',
'message' => 'Desculpe, mas a página que você está procurando não foi encontrada. Verifique a URL por erros e tente novamente.',
'link' => 'Voltar para a página inicial',
],
'unauthorized' => [
'code' => '401',
'title' => 'Não autorizado',
'message' => 'Desculpe, que você precisa de privilégios de administrador para ver esta página.',
'link' => 'Voltar para a página inicial',
],
];

View File

@ -1,25 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Cachet HQ <support@cachethq.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
'not-found' => [
'code' => '404',
'title' => '这个页面失踪了!',
'message' => '抱歉,但我们无法找到您要访问的的页面。请检查你的 URL然后重试。',
'link' => '返回主页',
],
'unauthorized' => [
'code' => '401',
'title' => '未授权',
'message' => '很抱歉,您需要管理员权限才能看到此页面。',
'link' => '返回主页',
],
];

View File

@ -1,25 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Cachet HQ <support@cachethq.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
'not-found' => [
'code' => '404',
'title' => '找不到頁面',
'message' => '抱歉,你所請求的頁面並不存在。請檢查你的 URL 是否正確並再試一次。',
'link' => '返回主頁',
],
'unauthorized' => [
'code' => '401',
'title' => '未經授權',
'message' => '抱歉,你需要管理員權限方可瀏覽本頁面。',
'link' => '返回主頁',
],
];

View File

@ -1,19 +0,0 @@
@extends('layout.error')
@section('content')
<div class="middle-box text-center">
<div>
<img class="logo" height="65" src="{{ url('img/cachet-logo.svg') }}" alt="Cachet">
</div>
<h1>{{ trans('errors.unauthorized.code') }}</h1>
<h3>{{ trans('errors.unauthorized.title') }}</h3>
<div class="error-desc">
<p>{{ trans('errors.unauthorized.message') }}</p>
<br>
<p>
<a href="/" class="btn btn-default btn-lg">{{ trans('errors.unauthorized.link') }}</a>
</p>
</div>
</div>
@stop

View File

@ -1,19 +0,0 @@
@extends('layout.error')
@section('content')
<div class="middle-box text-center">
<div>
<img class="logo" height="65" src="{{ url('img/cachet-logo.svg') }}" alt="Cachet">
</div>
<h1>{{ trans('errors.not-found.code') }}</h1>
<h3>{{ trans('errors.not-found.title') }}</h3>
<div class="error-desc">
<p>{{ trans('errors.not-found.message') }}</p>
<br>
<p>
<a href="/" class="btn btn-default btn-lg">{{ trans('errors.not-found.link') }}</a>
</p>
</div>
</div>
@stop

View File

@ -38,8 +38,8 @@ class ComponentTest extends AbstractTestCase
public function testPostComponentUnauthorized()
{
$this->post('/api/v1/components');
$this->assertResponseStatus(401);
$this->seeJson(['message' => 'You are not authorized to view this content.', 'status_code' => 401]);
}
public function testPostComponentNoData()

View File

@ -20,5 +20,26 @@ class GeneralTest extends AbstractTestCase
$this->get('/api/v1/ping');
$this->seeJson(['data' => 'Pong!']);
$this->assertResponseOk();
$this->seeHeader('Content-Type', 'application/json');
}
public function testErrorPage()
{
$this->get('/api/v1/not-found');
$this->assertResponseStatus(404);
$this->seeHeader('Content-Type', 'application/json');
$this->seeJson(['errors' => [[
'status' => 404,
'title' => 'Not Found',
'detail' => 'The requested resource could not be found but may be available again in the future.',
]]]);
}
public function testNotAcceptableContentType()
{
$this->get('/api/v1/ping', ['HTTP_Accept' => 'text/html']);
$this->assertResponseStatus(406);
}
}

View File

@ -39,7 +39,6 @@ class IncidentTest extends AbstractTestCase
{
$this->post('/api/v1/incidents');
$this->assertResponseStatus(401);
$this->seeJson(['message' => 'You are not authorized to view this content.', 'status_code' => 401]);
}
public function testPostIncidentNoData()

View File

@ -40,7 +40,6 @@ class MetricPointTest extends AbstractTestCase
$this->post("/api/v1/metrics/{$metric->id}/points");
$this->assertResponseStatus(401);
$this->seeJson(['message' => 'You are not authorized to view this content.', 'status_code' => 401]);
}
public function testPostMetricPoint()

View File

@ -39,7 +39,6 @@ class MetricTest extends AbstractTestCase
{
$this->post('/api/v1/metrics');
$this->assertResponseStatus(401);
$this->seeJson(['message' => 'You are not authorized to view this content.', 'status_code' => 401]);
}
public function testPostMetricNoData()