netglue / zf2-ssl-module
ZF2 Module that helps enforce the use of an SSL connection for HTTP requests
Requires
- php: >=5.3.3
- zendframework/zendframework: 2.*
This package is auto-updated.
Last update: 2021-09-02 12:01:58 UTC
README
The purpose of this module is to perform redirects either manually from within controllers or by specifying controllers/routes/urls that must be ssl or non-ssl within config.
Installation
Installation should be done with composer by adding to your composer.json
the following:
require {
'netglue/zf2-ssl-module': "dev-master"
}
Depending whether the module has been tagged with any release or stability information, you may also have to add to composer the "minimum-stability":"dev"
setting.
Once you've run $ php composer.phar update
, add 'NetglueSSL'
as a module name to your ZF2 applications config/application.config.php
file, copy the dist config found in vendor/netglue/zf2-ssl-module/config/module.config.php.dist
to your autoloading configuration directory and rename/modify to suit your needs.
Contributing, Feedback & Issues
This module has been made primarily for my own use as a quick and dirty solution to a common problem I face. If it's useful to you I'd love to know about it and if you have improvements to contribute, great, go forth and fork. I don't have the time to answer support requests but if you find any bugs, feel free to add them to the issue tracker
Todo
- Tests
Controller Plugins
There are 2 controller plugins: forceSSL
and forceHttp
. Providing the module is correctly configured, within any controller action, you can issue a $this->forceSSL()
to redirect to the SSL host if currently connected over standard http and the reverse for $this->forceHttp()
To stop the rest of the action running before the redirect occurs, you should wrap the calls to the controller plugins with something like this:
if($this->forceSSL()) {
return;
}
The __invoke()
methods of both forceSSL
and forceHttp
will return either a Zend\Http\Response
object if a redirect is required, or NULL
if the current request is already using the required protocol.
Configuration
The main options tells the module about the SSL and non-SSL hosts you're using. If the app is running on a server where both of these hosts are the same, both HTTP and HTTPS are on the standard ports and there's no differing prefix to uris for each host, all the options can be left unset, or null.
Supposing that these two uris are equivalent:
http://www.example.com/app-root/some-action
https://www.ssl-host.com/secure/app-root/some-action
Your configuration of the basic options would be:
'ssl_hostname' => 'www.ssl-host.com',
'http_hostname' => 'www.example.com',
'ssl_path_prefix' => '/secure',
'http_path_prefix' => NULL,
Forcing SSL/Non-SSL with Route Parameters
To force any of your configured routes to use SSL, add 'force-ssl' => 'ssl'
to the route defaults or 'force-ssl' => 'http'
to force HTTP.
Using this approach allows you to set a default for a route and override it in child routes. Rather than 'forcing' it, you can also set force-ssl to false to in a child route to stop any further evaluation taking place.
This method is first in evaluation and circumvents testing of the uri using controller, route name and uri configuration
Forcing SSL/Non-SSL with Controllers, route names and partial uris
The other options ssl_only
and http_only
are expected to take the form of the following array
'ssl_only' => array(
'controllers' => array(
'Some\Controller\Class', // As it would be when retreived from the RouteMatch object, i.e. 'Application\Controller\Index'
),
'routes' => array(
'home',
'some/other/routename',
),
'uris' => array(
'/account',
'/login',
),
);
The matching for these is really basic and you'll have to be careful not to create endless redirection loops.
Any controller name in the 'controllers'
array will be matched if in_array($controllerName, $searchArray)
evaluates to true. So, if you were to add the same controller to both ssl_only
and http_only
you'd be straight into an endless redirection loop.
The same is true of route names.
The uri array is slightly different. Each element of this array is transformed into a basic regex, so a value of /ssl-only-please
will be turned into the pattern /^\/ssl-only-please/
Only the path part of the uri is tested, so query strings, hostname, fragments etc are ignored. You should expect the example to match urls such as /ssl-only-please/foo
, /ssl-only-please?blah=blah
Deciding whether to redirect is done in the following order, controllers, routes, uris. As soon as a match is made, the response is returned and the redirect occurs so you can't force ssl for an entire controller and force std http for one of it's actions. it's just not that clever. You'd be better off using route parameters if that's waht you're after
Caveats
As previously mentioned, controller, route name and uri pattern matching is a country mile from intelligent and could be greatly improved I'm sure. Also, if you end up using any of the configuration options, including setting route params, it's probably best to avoid using the controller plugins because you might end up in infinite redirect loops with those. For example if you define a route such as 'my-route'
with forced SSL as a route param and then in the corresponding controller, issue a $this->forceHttp()
, clearly, you'll be going around in circles!