Skip to content

Instantly share code, notes, and snippets.

@tarlepp
Last active February 7, 2017 21:37
Show Gist options
  • Save tarlepp/0e2c779695b2aa96271c to your computer and use it in GitHub Desktop.
Save tarlepp/0e2c779695b2aa96271c to your computer and use it in GitHub Desktop.

Revisions

  1. tarlepp revised this gist Feb 11, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion var_dump
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@ array(1) {
    ["ajax.listener"]=>
    array(2) {
    ["class"]=>
    string(39) "App\Listener\AjaxAuthenticationListener"
    string(39) "App\Listeners\AjaxAuthenticationListener"
    ["tags"]=>
    array(1) {
    [0]=>
  2. tarlepp revised this gist Feb 11, 2016. 3 changed files with 66 additions and 0 deletions.
    37 changes: 37 additions & 0 deletions AjaxAuthenticationListener.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,37 @@
    <?php

    namespace App\Listeners;

    use Symfony\Component\HttpFoundation\JsonResponse;
    use Symfony\Component\HttpKernel\Event\GetResponseEvent;
    use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
    use Symfony\Component\Security\Core\Exception\AuthenticationException;
    use Symfony\Component\Security\Core\Exception\AccessDeniedException;
    use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;

    class AjaxAuthenticationListener
    {
    /**
    * Handles security related exceptions.
    *
    * @param GetResponseForExceptionEvent $event An GetResponseForExceptionEvent instance
    */
    public function onCoreException(GetResponseForExceptionEvent $event)
    {
    $exception = $event->getException();
    $request = $event->getRequest();

    // It never hits here

    if ($request->isXmlHttpRequest()) {

    if ($exception instanceof AuthenticationException || $exception instanceof AccessDeniedException || $exception instanceof AuthenticationCredentialsNotFoundException) {
    $responseData = array('status' => 401, 'msg' => 'User Not Authenticated');
    $response = new JsonResponse();
    $response->setData($responseData);
    $response->setStatusCode($responseData['status']);
    $event->setResponse($response);
    }
    }
    }
    }
    6 changes: 6 additions & 0 deletions app.log
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,6 @@
    [2016-02-11 21:45:44] myapp.INFO: Populated the TokenStorage with an anonymous Token. [] []
    [2016-02-11 21:45:44] myapp.INFO: > POST /backend/auth/login [] []
    [2016-02-11 21:45:44] myapp.INFO: An AuthenticationException was thrown; redirecting to authentication entry point. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\UsernameNotFoundException(code: 0): User 'admdin' not found. at /home/wunder/projects/backend-silex/src/App/Providers/UserProvider.php:66)"} []
    [2016-02-11 21:45:44] myapp.DEBUG: Calling Authentication entry point. [] []
    [2016-02-11 21:45:44] myapp.INFO: < 302 http://wunder.sytes.net:6969/backend/login [] []
    [2016-02-11 21:45:44] myapp.ERROR: Symfony\Component\HttpKernel\Exception\NotFoundHttpException: No route found for "GET /login" (uncaught exception) at /home/wunder/projects/backend-silex/vendor/symfony/http-kernel/EventListener/RouterListener.php line 176 {"exception":"[object] (Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException(code: 0): No route found for \"GET /login\" at /home/wunder/projects/backend-silex/vendor/symfony/http-kernel/EventListener/RouterListener.php:176, Symfony\\Component\\Routing\\Exception\\ResourceNotFoundException(code: 0): No routes found for \"/login\". at /home/wunder/projects/backend-silex/vendor/symfony/routing/Matcher/UrlMatcher.php:98)"} []
    23 changes: 23 additions & 0 deletions var_dump
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    var_dump($this['services']);

    array(1) {
    ["ajax.listener"]=>
    array(2) {
    ["class"]=>
    string(39) "App\Listener\AjaxAuthenticationListener"
    ["tags"]=>
    array(1) {
    [0]=>
    array(4) {
    ["name"]=>
    string(21) "kernel.event_listener"
    ["event"]=>
    string(16) "kernel.exception"
    ["method"]=>
    string(15) "onCoreException"
    ["priority"]=>
    int(1000)
    }
    }
    }
    }
  3. tarlepp created this gist Feb 11, 2016.
    256 changes: 256 additions & 0 deletions Application.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,256 @@
    <?php
    /**
    * /src/App/Application.php
    *
    * @author TLe, Tarmo Leppänen <[email protected]>
    */
    namespace App;

    // Silex application
    use App\Components\Swagger\SwaggerServiceProvider;
    use App\Listeners\AjaxAuthenticationListener;
    use App\Providers\SecurityServiceProvider as ApplicationSecurityServiceProvider;
    use Silex\Application as SilexApplication;

    // Silex specified providers
    use Silex\Provider\DoctrineServiceProvider;
    use Silex\Provider\MonologServiceProvider;
    use Silex\Provider\SecurityJWTServiceProvider;
    use Silex\Provider\SecurityServiceProvider;
    use Silex\Provider\ValidatorServiceProvider;

    // 3rd party providers
    use Dflydev\Silex\Provider\DoctrineOrm\DoctrineOrmServiceProvider;
    use JDesrosiers\Silex\Provider\CorsServiceProvider;
    use Sorien\Provider\PimpleDumpProvider;
    use M1\Vars\Provider\Silex\VarsServiceProvider;

    // Application specified providers
    use App\Providers\UserProvider;
    use App\Services\Loader;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;

    /**
    * Class Application
    *
    * Main application class that is used to run application. Class bootstraps application all providers, mount routes,
    * etc.
    *
    * @category Core
    * @package App
    * @author TLe, Tarmo Leppänen <[email protected]>
    */
    class Application extends SilexApplication
    {
    /**
    * Project root directory, determined via this file
    *
    * @var string
    */
    private $rootDir;

    /**
    * Current environment which is used to run application.
    *
    * @var string
    */
    private $env;

    /**
    * Application constructor.
    *
    * @param string $env
    */
    public function __construct($env)
    {
    // Set private vars
    $this->rootDir = __DIR__ . '/../../';
    $this->env = $env;

    // Construct Silex application
    parent::__construct();

    // Create application configuration
    $this->applicationConfig();

    // Register all necessary providers
    $this->applicationRegister();

    // Configure application firewall
    $this->applicationFirewall();

    // Load services
    $this->loadServices();

    // Attach application mount points
    $this->applicationMount();

    // Attach CORS to application
    $this->after($this['cors']);
    }

    /**
    * Getter method for 'rootDir' property.
    *
    * @return string
    */
    public function getRootDir()
    {
    return $this->rootDir;
    }

    /**
    * Getter method for 'env' property.
    *
    * @return string
    */
    public function getEnv()
    {
    return $this->env;
    }

    /**
    * Application configuration.
    *
    * @return void
    */
    private function applicationConfig()
    {
    // Register configuration provider
    $this->register(
    new VarsServiceProvider($this->rootDir . 'resources/config/' . $this->env . '/config.yml'),
    [
    'vars.options' => [
    'cache' => true,
    'cache_path' => $this->rootDir . 'var',
    'cache_expire' => $this->env === 'dev' ? 0 : 0,
    'replacements' => [
    'rootDir' => $this->rootDir,
    'env' => $this->env,
    ],
    ],
    ]
    );

    // Set application level values
    $this['debug'] = $this['vars']->get('debug');
    $this['security.jwt'] = $this['vars']->get('security.jwt');
    $this['pimpledump.output_dir'] = $this['vars']->get('pimpledump.output_dir');

    $this['services'] = $this['vars']->get('services');

    return;
    }

    /**
    * Method to register all specified providers for application.
    *
    * @return void
    */
    private function applicationRegister()
    {
    $this['dispatcher']->addListener("kernel.exception", function(GetResponseForExceptionEvent $event) {
    if (
    ($event->getException()->getCode() == '403') ||
    ($event->getException()->getCode() == '404')
    ) {
    $request = $event->getRequest();

    if ($request->isXmlHttpRequest()) {
    $event->setResponse(new Response("Access Denied", 403));
    }
    }
    });

    // Register all providers for application
    $this->register(new ValidatorServiceProvider());
    $this->register(new SecurityServiceProvider());
    $this->register(new ApplicationSecurityServiceProvider());
    $this->register(new SecurityJWTServiceProvider());
    $this->register(new PimpleDumpProvider());
    $this->register(new MonologServiceProvider(), $this['vars']->get('monolog'));
    $this->register(new DoctrineServiceProvider(), $this['vars']->get('database'));
    $this->register(new DoctrineOrmServiceProvider(), $this['vars']->get('orm'));
    $this->register(new CorsServiceProvider(), $this['vars']->get('cors'));
    $this->register(new SwaggerServiceProvider(), $this['vars']->get('swagger'));
    }

    /**
    * Method to setup application firewall.
    *
    * @see http://silex.sensiolabs.org/doc/providers/security.html
    *
    * @return array
    */
    private function applicationFirewall()
    {
    $entityManager = $this['orm.em'];
    $app = $this;

    // Set provider for application users
    $this['users'] = function() use ($app, $entityManager) {
    return new UserProvider($entityManager);
    };

    // Security Firewalls configuration
    $this['security.firewalls'] = [
    // Root route
    'root' => [
    'pattern' => '^/$',
    'anonymous' => true,
    ],
    // Login route
    'login' => [
    'pattern' => '^/auth/login$',
    'anonymous' => true,
    ],
    // Pimple dump
    'pimpleDump' => [
    'pattern' => '^/_dump$',
    'anonymous' => true,
    ],
    // CORS preflight requests
    'cors-preflight' => array(
    'pattern' => $this['cors_preflight_request_matcher'],
    ),
    // API docs are also anonymous
    'docs' => [
    'pattern' => '^/api',
    'anonymous' => true,
    ],
    // And all other routes
    'secured' => [
    'pattern' => '^.*$',
    'users' => $this['users'],
    'jwt' => [
    'use_forward' => true,
    'require_previous_session' => false,
    'stateless' => true,
    ],
    ],
    ];
    }

    /**
    * Method to attach main mount point to be handled via ControllerProvider.
    *
    * @return void
    */
    private function applicationMount()
    {
    // Register all application routes
    $this->mount('', new ControllerProvider());
    }

    /**
    * Load shared services.
    *
    * @return void
    */
    private function loadServices()
    {
    $loader = new Loader($this);
    $loader->bindServicesIntoContainer();
    }
    }