Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2, switch to HTTPS after authentication

I want to force user to use HTTPS instead of HTTP but only after authentication. The only option I've found is forcing HTTPS on per controller/method basis. Anonymous users should only use HTTP.

How to set force-HTTPS only for authenticated users and force NOT to use HTTPS for unauthenticated users in all controllers in my bundle?

Again - this isn't about disabling HTTPS for authorisation page.

I want to use all the same controllers for authenticated and unauthenticated users but force those logged in to use HTTPS, and those who aren't to use HTTP. Basically add requirement for HTTPS for ALL controllers when the user is authenticated.

This question is Symfony 2 specific. I want to do it using Symfony mechanisms. I know how to detect this thing, but it will break Twig links. Symfony can automatically switch to HTTPS, I just want to know how to do it on per-user role basis, not per controller basis.

like image 474
Chris Hasiński Avatar asked Nov 30 '11 13:11

Chris Hasiński


2 Answers

One would think the access controller would do this for us:

access_control:
    - { role: ROLE_USER, requires_channel: https }
    - { role: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: http }

But, no... I think this would be a very nice feature though.

In that case, we can hack something together with a request listener using kernel events:

namespace YourBundle\EventListener;

use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;

class RequestListener
{
    public function onKernelRequest(GetResponseEvent $event)
    {
        $request = $event->getRequest();

        // force ssl based on authentication
        if ($this->container->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')) {
            if (!$request->isSecure()) {
                $request->server->set('HTTPS', true);
                $request->server->set('SERVER_PORT', 443);
                $event->setResponse(new RedirectResponse($request->getUri()));
            } 
        } else {
            if ($request->isSecure()) {
                $request->server->set('HTTPS', false);
                $request->server->set('SERVER_PORT', 80);
                $event->setResponse(new RedirectResponse($request->getUri()));
            }
        }
    }
}

Define your listener in config.yml under services:

myapp.request.listener:
    class: MyApp\MyBundle\EventListener\RequestListener
    tags:
        - { name: kernel.event_listener, event: kernel.request }

See Symfony Internals for details on events and the like.

like image 73
nurikabe Avatar answered Oct 24 '22 08:10

nurikabe


In Symfony 2.0.11 I get a redirection error. To solve this I've commented out the following lines in the listener.

class RequestListener {
    public function onKernelRequest(GetResponseEvent $event) {
        $request = $event->getRequest();

        // force ssl based on authentication
        if     ($this->container->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')) {
            if (!$request->isSecure()) {
                $request->server->set('HTTPS', true);
                $request->server->set('SERVER_PORT', 443);
                // $event->setResponse(new RedirectResponse($request->getUri()));
            } 
        } else {
            if ($request->isSecure()) {
                $request->server->set('HTTPS', false);
                $request->server->set('SERVER_PORT', 80);
                // $event->setResponse(new RedirectResponse($request->getUri()));
            }
        }
    }
}
like image 25
hpmewes Avatar answered Oct 24 '22 06:10

hpmewes