Implemented detach_on_redirect config option.
[catagits/Catalyst-Plugin-RequireSSL.git] / lib / Catalyst / Plugin / RequireSSL.pm
CommitLineData
1763fe29 1package Catalyst::Plugin::RequireSSL;
2
3use strict;
4use base qw/Class::Accessor::Fast/;
5use NEXT;
6
ffd9355f 7our $VERSION = '0.07';
1763fe29 8
c4744895 9__PACKAGE__->mk_accessors( qw/_require_ssl _allow_ssl _ssl_strip_output/ );
eeefd598 10
11sub require_ssl {
12 my $c = shift;
13
14 $c->_require_ssl(1);
15
16 if ( !$c->req->secure && $c->req->method ne "POST" ) {
17 my $redir = $c->_redirect_uri('https');
18 if ( $c->config->{require_ssl}->{disabled} ) {
19 $c->log->warn( "RequireSSL: Would have redirected to $redir" );
20 }
21 else {
4585dfb1 22 $c->_ssl_strip_output(1);
eeefd598 23 $c->res->redirect( $redir );
794abe2a 24 $c->detach if $c->config->{require_ssl}->{detach_on_redirect};
eeefd598 25 }
26 }
27}
28
c4744895 29sub allow_ssl {
30 my $c = shift;
31
32 $c->_allow_ssl(1);
33}
34
eeefd598 35sub finalize {
36 my $c = shift;
37
38 # Do not redirect static files (only works with Static::Simple)
39 if ( $c->isa( "Catalyst::Plugin::Static::Simple" ) ) {
40 return $c->NEXT::finalize(@_) if $c->_static_file;
41 }
42
43 # redirect back to non-SSL mode
44 REDIRECT:
45 {
46 # No redirect if:
47 # we're not in SSL mode
48 last REDIRECT if !$c->req->secure;
49 # it's a POST request
50 last REDIRECT if $c->req->method eq "POST";
51 # we're already required to be in SSL for this request
52 last REDIRECT if $c->_require_ssl;
53 # or the user doesn't want us to redirect
c4744895 54 last REDIRECT if $c->config->{require_ssl}->{remain_in_ssl} || $c->_allow_ssl;
eeefd598 55
56 $c->res->redirect( $c->_redirect_uri('http') );
57 }
58
4585dfb1 59 # do not allow any output to be displayed on the insecure page
60 if ( $c->_ssl_strip_output ) {
cc4f2717 61 $c->res->body( '' );
4585dfb1 62 }
63
eeefd598 64 return $c->NEXT::finalize(@_);
65}
66
67sub setup {
68 my $c = shift;
69
70 $c->NEXT::setup(@_);
71
72 # disable the plugin when running under certain engines which don't
73 # support SSL
cae2ad7f 74 if ( $c->engine =~ /Catalyst::Engine::HTTP/ ) {
eeefd598 75 $c->config->{require_ssl}->{disabled} = 1;
76 $c->log->warn( "RequireSSL: Disabling SSL redirection while running "
77 . "under " . $c->engine );
78 }
79}
80
81sub _redirect_uri {
82 my ( $c, $type ) = @_;
83
84 # XXX: Cat needs a $c->req->host method...
85 # until then, strip off the leading protocol from base
86 if ( !$c->config->{require_ssl}->{$type} ) {
87 my $host = $c->req->base;
88 $host =~ s/^http(s?):\/\///;
89 $c->config->{require_ssl}->{$type} = $host;
90 }
91
92 if ( $c->config->{require_ssl}->{$type} !~ /\/$/xms ) {
93 $c->config->{require_ssl}->{$type} .= '/';
94 }
95
96 my $redir
97 = $type . '://' . $c->config->{require_ssl}->{$type} . $c->req->path;
4585dfb1 98
eeefd598 99 if ( scalar $c->req->param ) {
4585dfb1 100 my @params;
101 foreach my $arg ( sort keys %{ $c->req->params } ) {
102 if ( ref $c->req->params->{$arg} ) {
103 my $list = $c->req->params->{$arg};
104 push @params, map { "$arg=" . $_ } sort @{$list};
105 }
106 else {
107 push @params, "$arg=" . $c->req->params->{$arg};
108 }
109 }
110 $redir .= '?' . join( '&', @params );
51ef6cb3 111 }
112
b0b7bb46 113 if ( $c->config->{require_ssl}->{no_cache} ) {
ffd9355f 114 delete $c->config->{require_ssl}->{$type};
115 }
116
eeefd598 117 return $redir;
118}
119
1201;
121__END__
1763fe29 122
123=head1 NAME
124
125Catalyst::Plugin::RequireSSL - Force SSL mode on select pages
126
127=head1 SYNOPSIS
128
eeefd598 129 # in MyApp.pm
130 use Catalyst;
131 MyApp->setup( qw/RequireSSL/ );
1763fe29 132
133 MyApp->config->{require_ssl} = {
134 https => 'secure.mydomain.com',
135 http => 'www.mydomain.com',
136 remain_in_ssl => 0,
ffd9355f 137 no_cache => 0,
794abe2a 138 detach_on_redirect => 1,
1763fe29 139 };
140
eeefd598 141 # in any controller methods that should be secured
1763fe29 142 $c->require_ssl;
143
144=head1 DESCRIPTION
145
eeefd598 146Use this plugin if you wish to selectively force SSL mode on some of your web
147pages, for example a user login form or shopping cart.
1763fe29 148
eeefd598 149Simply place $c->require_ssl calls in any controller method you wish to be
150secured.
1763fe29 151
eeefd598 152This plugin will automatically disable itself if you are running under the
153standalone HTTP::Daemon Catalyst server. A warning message will be printed to
154the log file whenever an SSL redirect would have occurred.
1763fe29 155
156=head1 WARNINGS
157
eeefd598 158If you utilize different servers or hostnames for non-SSL and SSL requests,
159and you rely on a session cookie to determine redirection (i.e for a login
160page), your cookie must be visible to both servers. For more information, see
161the documentation for the Session plugin you are using.
1763fe29 162
163=head1 CONFIGURATION
164
165Configuration is optional. You may define the following configuration values:
166
167 https => $ssl_host
168
169If your SSL domain name is different from your non-SSL domain, set this value.
170
171 http => $non_ssl_host
172
eeefd598 173If you have set the https value above, you must also set the hostname of your
174non-SSL server.
1763fe29 175
176 remain_in_ssl
177
eeefd598 178If you'd like your users to remain in SSL mode after visiting an SSL-required
179page, you can set this option to 1. By default, this option is disabled and
180users will be redirected back to non-SSL mode as soon as possible.
1763fe29 181
ffd9355f 182 no_cache
11f9b043 183
184If you have a wildcard certificate you will need to set this option if you are
51ef6cb3 185using multiple domains on one instance of Catalyst.
11f9b043 186
794abe2a 187 detach_on_redirect
188
189By default C<< $c->require_ssl >> only calls C<< $c->response->redirect >> but
190does not stop request processing (so it returns and subsequent statements are
191run). This is probably not what you want. If you set this option to a true
192value C<< $c->require_ssl >> will call C<< $c->detach >> when it redirects.
193
eeefd598 194=head1 METHODS
1763fe29 195
eeefd598 196=head2 require_ssl
1763fe29 197
198Call require_ssl in any controller method you wish to be secured.
199
200 $c->require_ssl;
201
eeefd598 202The browser will be redirected to the same path on your SSL server. POST
203requests are never redirected.
1763fe29 204
c4744895 205=head2 allow_ssl
206
207Call allow_ssl in any controller method you wish to access both in SSL and
208non-SSL mode.
209
210 $c->allow_ssl;
211
212The browser will not be redirected, independently of whether the request was
213made to the SSL or non-SSL server.
214
ffd9355f 215=head2 setup
216
217Disables this plugin if running under an engine which does not support SSL.
218
219=head2 finalize
220
221Performs the redirect to SSL url if required.
222
1763fe29 223=head1 KNOWN ISSUES
224
eeefd598 225When viewing an SSL-required page that uses static files served from the
226Static plugin, the static files are redirected to the non-SSL path.
1763fe29 227
eeefd598 228In order to get the correct behaviour where static files are not redirected,
229you should use the Static::Simple plugin or always serve static files
230directly from your web server.
1763fe29 231
232=head1 SEE ALSO
233
eeefd598 234L<Catalyst>, L<Catalyst::Plugin::Static::Simple>
1763fe29 235
236=head1 AUTHOR
237
eeefd598 238Andy Grundman, <andy@hybridized.org>
1763fe29 239
11f9b043 240=head1 CONTRIBUTORS
241
242Simon Elliott <simon@browsing.co.uk> (support for wildcards)
243
1763fe29 244=head1 COPYRIGHT
245
246This program is free software, you can redistribute it and/or modify it under
247the same terms as Perl itself.
248
249=cut