diff --git a/app/Foundation/Providers/RouteServiceProvider.php b/app/Foundation/Providers/RouteServiceProvider.php index cca41e32..9a17c2a6 100644 --- a/app/Foundation/Providers/RouteServiceProvider.php +++ b/app/Foundation/Providers/RouteServiceProvider.php @@ -13,7 +13,13 @@ namespace CachetHQ\Cachet\Foundation\Providers; use Barryvdh\Cors\HandleCors; use CachetHQ\Cachet\Http\Middleware\Acceptable; +use CachetHQ\Cachet\Http\Middleware\Authenticate; use CachetHQ\Cachet\Http\Middleware\Timezone; +use CachetHQ\Cachet\Http\Routes\ApiSystemRoutes; +use CachetHQ\Cachet\Http\Routes\AuthRoutes; +use CachetHQ\Cachet\Http\Routes\Setup\ApiRoutes as ApiSetupRoutes; +use CachetHQ\Cachet\Http\Routes\SetupRoutes; +use CachetHQ\Cachet\Http\Routes\SignupRoutes; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Illuminate\Cookie\Middleware\EncryptCookies; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken; @@ -41,6 +47,21 @@ class RouteServiceProvider extends ServiceProvider */ protected $namespace = 'CachetHQ\Cachet\Http\Controllers'; + /** + * These are the route files that should always be available anonymously. + * + * When applying the always_authenticate feature, these routes will be skipped. + * + * @var string[] + */ + protected $whitelistedAuthRoutes = [ + AuthRoutes::class, + SetupRoutes::class, + SignupRoutes::class, + ApiSystemRoutes::class, + ApiSetupRoutes::class, + ]; + /** * Define the route model bindings, pattern filters, etc. * @@ -89,6 +110,7 @@ class RouteServiceProvider extends ServiceProvider $router->group(['namespace' => $this->namespace, 'as' => 'core::'], function (Router $router) { $path = app_path('Http/Routes'); + $applyAlwaysAuthenticate = $this->app['config']->get('setting.always_authenticate', false); $AllFileIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path)); $PhpFileIterator = new \RegexIterator($AllFileIterator, '/^.+\.php$/i', \RecursiveRegexIterator::GET_MATCH); @@ -100,9 +122,9 @@ class RouteServiceProvider extends ServiceProvider $routes = $this->app->make("CachetHQ\\Cachet\\Http\\Routes${class}"); if ($routes::$browser) { - $this->mapForBrowser($router, $routes); + $this->mapForBrowser($router, $routes, $applyAlwaysAuthenticate); } else { - $this->mapOtherwise($router, $routes); + $this->mapOtherwise($router, $routes, $applyAlwaysAuthenticate); } } }); @@ -113,10 +135,11 @@ class RouteServiceProvider extends ServiceProvider * * @param \Illuminate\Routing\Router $router * @param object $routes + * @param bool $applyAlwaysAuthenticate * * @return void */ - protected function mapForBrowser(Router $router, $routes) + protected function mapForBrowser(Router $router, $routes, $applyAlwaysAuthenticate) { $middleware = [ EncryptCookies::class, @@ -127,6 +150,10 @@ class RouteServiceProvider extends ServiceProvider SubstituteBindings::class, ]; + if ($applyAlwaysAuthenticate && !$this->isWhiteListedAuthRoute($routes)) { + $middleware[] = Authenticate::class; + } + $router->group(['middleware' => $middleware], function (Router $router) use ($routes) { $routes->map($router); }); @@ -137,10 +164,11 @@ class RouteServiceProvider extends ServiceProvider * * @param \Illuminate\Routing\Router $router * @param object $routes + * @param bool $applyAlwaysAuthenticate * * @return void */ - protected function mapOtherwise(Router $router, $routes) + protected function mapOtherwise(Router $router, $routes, $applyAlwaysAuthenticate) { $middleware = [ HandleCors::class, @@ -149,8 +177,31 @@ class RouteServiceProvider extends ServiceProvider Timezone::class, ]; + if ($applyAlwaysAuthenticate && !$this->isWhiteListedAuthRoute($routes)) { + $middleware[] = 'auth.api:true'; + } + $router->group(['middleware' => $middleware], function (Router $router) use ($routes) { $routes->map($router); }); } + + /** + * Validates if the route object is an instance of the whitelisted routes. + * A small workaround since we cant use multiple classes in a `instanceof` comparison. + * + * @param object $routes + * + * @return bool + */ + private function isWhiteListedAuthRoute($routes) + { + foreach ($this->whitelistedAuthRoutes as $whitelistedRoute) { + if (is_a($routes, $whitelistedRoute)) { + return true; + } + } + + return false; + } } diff --git a/app/Http/Controllers/Dashboard/SettingsController.php b/app/Http/Controllers/Dashboard/SettingsController.php index 5417f59d..65829c93 100644 --- a/app/Http/Controllers/Dashboard/SettingsController.php +++ b/app/Http/Controllers/Dashboard/SettingsController.php @@ -20,6 +20,7 @@ use Exception; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Log\Writer; use Illuminate\Routing\Controller; +use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Lang; @@ -384,6 +385,10 @@ class SettingsController extends Controller Lang::setLocale(Binput::get('app_locale')); } + if (Binput::has('always_authenticate')) { + Artisan::call('route:clear'); + } + return Redirect::back()->withSuccess(trans('dashboard.settings.edit.success')); } diff --git a/app/Http/Routes/ApiRoutes.php b/app/Http/Routes/ApiRoutes.php index 3408123a..d18e4064 100644 --- a/app/Http/Routes/ApiRoutes.php +++ b/app/Http/Routes/ApiRoutes.php @@ -41,10 +41,6 @@ class ApiRoutes 'prefix' => 'api/v1', ], function (Registrar $router) { $router->group(['middleware' => ['auth.api']], function (Registrar $router) { - $router->get('ping', 'GeneralController@ping'); - $router->get('version', 'GeneralController@version'); - $router->get('status', 'GeneralController@status'); - $router->get('components', 'ComponentController@index'); $router->get('components/groups', 'ComponentGroupController@index'); $router->get('components/groups/{component_group}', 'ComponentGroupController@show'); diff --git a/app/Http/Routes/ApiSystemRoutes.php b/app/Http/Routes/ApiSystemRoutes.php new file mode 100644 index 00000000..80899f71 --- /dev/null +++ b/app/Http/Routes/ApiSystemRoutes.php @@ -0,0 +1,50 @@ + + */ +class ApiSystemRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = false; + + /** + * Define the api routes for the system status, ping and version. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'namespace' => 'Api', + 'prefix' => 'api/v1', + ], function (Registrar $router) { + $router->group(['middleware' => ['auth.api']], function (Registrar $router) { + $router->get('ping', 'GeneralController@ping'); + $router->get('version', 'GeneralController@version'); + $router->get('status', 'GeneralController@status'); + }); + }); + } +} diff --git a/config/setting.php b/config/setting.php index 4f58d404..c9615c35 100644 --- a/config/setting.php +++ b/config/setting.php @@ -111,4 +111,16 @@ return [ */ 'only_disrupted_days' => false, + + /* + |-------------------------------------------------------------------------- + | Always authenticate + |-------------------------------------------------------------------------- + | + | Whether to lock down Cachet and only allow viewing pages + | when authenticated. + | + */ + + 'always_authenticate' => false, ]; diff --git a/resources/lang/en/forms.php b/resources/lang/en/forms.php index 6425fa34..f5a11877 100644 --- a/resources/lang/en/forms.php +++ b/resources/lang/en/forms.php @@ -177,8 +177,10 @@ return [ 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ - 'allowed-domains' => 'Allowed domains', - 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', ], 'stylesheet' => [ 'custom-css' => 'Custom Stylesheet', diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 7c17920f..a5f709bf 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -36,11 +36,13 @@