Fixed the README to actually contain the correct docs
[catagits/Catalyst-Plugin-RequireSSL.git] / lib / Catalyst / Plugin / RequireSSL.pm
1 package Catalyst::Plugin::RequireSSL;
2
3 use strict;
4 use base qw/Class::Accessor::Fast/;
5 use NEXT;
6
7 our $VERSION = '0.02';
8
9 __PACKAGE__->mk_accessors( '_require_ssl' );
10
11 =head1 NAME
12
13 Catalyst::Plugin::RequireSSL - Force SSL mode on select pages
14
15 =head1 SYNOPSIS
16
17     use Catalyst 'RequireSSL';
18     
19     MyApp->config->{require_ssl} = {
20         https => 'secure.mydomain.com',
21         http => 'www.mydomain.com',
22         remain_in_ssl => 0,
23     };
24
25     $c->require_ssl;
26
27 =head1 DESCRIPTION
28
29 Use this plugin if you wish to selectively force SSL mode on some of your web pages, 
30 for example a user login form or shopping cart.
31
32 Simply place $c->require_ssl calls in any controller method you wish to be secured. 
33
34 This plugin will automatically disable itself if you are running under the standalone
35 HTTP::Daemon Catalyst server.  A warning message will be printed to the log file whenever
36 an SSL redirect would have occurred.
37
38 =head1 WARNINGS
39
40 If you utilize different servers or hostnames for non-SSL and SSL requests, and you rely
41 on a session cookie to determine redirection (i.e for a login page), your cookie must
42 be visible to both servers.  For more information, see the documentation for the Session plugin
43 you are using.
44
45 =head1 CONFIGURATION
46
47 Configuration is optional.  You may define the following configuration values:
48
49     https => $ssl_host
50     
51 If your SSL domain name is different from your non-SSL domain, set this value.
52
53     http => $non_ssl_host
54     
55 If you have set the https value above, you must also set the hostname of your non-SSL
56 server.
57
58     remain_in_ssl
59     
60 If you'd like your users to remain in SSL mode after visiting an SSL-required page, you can
61 set this option to 1.  By default, users will be redirected back to non-SSL mode as soon as
62 possible.
63
64 =head2 METHODS
65
66 =over 4
67
68 =item require_ssl
69
70 Call require_ssl in any controller method you wish to be secured.
71
72     $c->require_ssl;
73
74 The browser will be redirected to the same path on your SSL server.  POST requests
75 are never redirected.
76
77 =cut
78
79 sub require_ssl {
80     my $c = shift;
81     
82     $c->_require_ssl( 1 );
83       
84     unless ( $c->req->secure || $c->req->method eq "POST" ) {
85         if ( $c->config->{require_ssl}->{disabled} ) {
86             $c->log->warn( "RequireSSL: Would have redirected to " . $c->_redirect_uri( 'https' ) );
87         } else {
88             $c->res->redirect( $c->_redirect_uri( 'https' ) );
89         }
90     }
91 }
92
93 =item finalize (extended)
94
95 Redirect back to non-SSL mode if necessary.
96
97 =cut
98
99 sub finalize {
100     my $c = shift;
101     
102     # redirect unless:
103     # we're not in SSL mode,
104     # it's a POST request,
105     # we're already required to be in SSL for this request,
106     # or the user doesn't want us to redirect
107     unless ( !$c->req->secure
108       || $c->req->method eq "POST"
109       || $c->_require_ssl
110       || $c->config->{require_ssl}->{remain_in_ssl} ) {
111           $c->res->redirect( $c->_redirect_uri( 'http' ) );
112     }
113     
114     return $c->NEXT::finalize(@_);    
115 }
116
117 =item setup
118
119 Setup default values.
120
121 =cut
122
123 sub setup {
124     my $c = shift;
125     
126     $c->NEXT::setup(@_);
127     
128     # disable the plugin when running under certain engines which don't support SSL
129     # XXX: I didn't include Catalyst::Engine::Server here as it may be used as a backend
130     # in a proxy setup.
131     if ( $c->engine eq "Catalyst::Engine::HTTP" ) {
132         $c->config->{require_ssl}->{disabled} = 1;
133         $c->log->warn( "RequireSSL: Disabling SSL redirection while running under " . $c->engine );
134     }
135 }
136
137 =item _redirect_uri
138
139 Generate the redirection URI.
140
141 =cut
142
143 sub _redirect_uri {
144     my ( $c, $type ) = @_;
145     
146     # XXX: Cat needs a $c->req->host method...
147     # until then, strip off the leading protocol from base
148     unless ( $c->config->{require_ssl}->{$type} ) {
149         my $host = $c->req->base;
150         $host =~ s/^http(s?):\/\///;
151         $c->config->{require_ssl}->{$type} = $host;
152     }
153     
154     $c->config->{require_ssl}->{$type} .= '/'
155         unless ( $c->config->{require_ssl}->{$type} =~ /\/$/ );
156     
157     my $redir = $type . '://' . $c->config->{require_ssl}->{$type} . $c->req->path;
158     if ( scalar keys %{ $c->req->params } ) {
159         my @params = ();
160         foreach my $k ( sort keys %{ $c->req->params } ) {
161             push @params, $k . "=" . $c->req->params->{$k};
162         }
163         $redir .= "?" . join "&", @params;
164     }
165     
166     return $redir;
167 }
168
169 =back
170
171 =head1 KNOWN ISSUES
172
173 When viewing an SSL-required page that uses static files served from the Static plugin, the static
174 files are redirected to the non-SSL path.  It may be possible to work around this by checking the
175 referer protocol, but currently there is no way to determine if a file being served is static content.
176
177 For best results, always serve static files directly from your web server without using the Static
178 plugin.
179
180 =head1 SEE ALSO
181
182 L<Catalyst>
183
184 =head1 AUTHOR
185
186 Andy Grundman, C<andy@hybridized.org>
187
188 =head1 COPYRIGHT
189
190 This program is free software, you can redistribute it and/or modify it under
191 the same terms as Perl itself.
192
193 =cut
194
195 1;