File Coverage

blib/lib/CGI/Application/Plugin/RequireSSL.pm
Criterion Covered Total %
statement 53 56 94.6
branch 14 18 77.7
condition 6 12 50.0
subroutine 13 13 100.0
pod 2 3 66.6
total 88 102 86.2


line stmt bran cond sub pod time code
1             package CGI::Application::Plugin::RequireSSL;
2 3     3   67646 use warnings;
  3         9  
  3         117  
3 3     3   18 use strict;
  3         7  
  3         103  
4 3     3   19420 use Carp;
  3         11  
  3         274  
5 3     3   19 use base 'Exporter';
  3         6  
  3         251  
6 3     3   18576 use Attribute::Handlers;
  3         22716  
  3         23  
7             our @EXPORT = qw/config_requiressl mode_redirect/;
8             our %SSL_RUN_MODES;
9 3     3   4689 use Data::Dumper;
  3         61090  
  3         814  
10              
11             =head1 NAME
12              
13             CGI::Application::Plugin::RequireSSL - Force SSL in specified pages or modules
14              
15             =head1 VERSION
16              
17             Version 0.04
18              
19             =cut
20              
21             our $VERSION = '0.04';
22              
23             =head1 SYNOPSIS
24              
25             use CGI::Application::Plugin::RequireSSL;
26              
27             sub login_form :RequireSSL {
28             my $self = shift;
29             # etc
30             }
31            
32             =head1 DESCRIPTION
33              
34             CGI::Application::Plugin::RequireSSL allows individual run modes or
35             whole modules to be protected by SSL. If a standard HTTP request is
36             received, you can specify whether an error is raised or if the request
37             should be redirected to the HTTPS equivalent URL.
38              
39             =head1 EXPORT
40              
41             Exported methods:
42             config_requiressl, mode_redirect
43              
44              
45             =head1 USAGE
46              
47             =head2 run mode-level protection
48              
49             run mode protection is specified by the RequireSSL attribute after the
50             method name:
51              
52             sub process_login :RequireSSL {
53             my $self = shift;
54             }
55              
56             =head2 Module-level protection
57              
58             You can protect a complete module by setting the 'require_ssl'
59             parameter in your instance script:
60              
61             use MyApp;
62             my $webapp = MyApp->new(
63             PARAMS => {require_ssl => 1}
64             );
65             $webapp->run();
66            
67             =head2 Redirecting to a protected URL.
68              
69             By default, an error is raised if a request is made to a protected
70             run mode or module using HTTP. However, you can specify that the request
71             is redirected to the HTTPS url by setting the rewrite_to_ssl parameter
72             as long as the requested method is not POST:
73              
74             my $webapp = MyApp->new(
75             PARAMS => {rewrite_to_ssl => 1}
76             );
77            
78             =head2 Turning off checks.
79              
80             If you need to turn off checks, simply set the ignore_check parameter
81             when configuring the plugin (see L below).
82              
83              
84             =head2 Reverting to HTTP
85              
86             Once a successful request is made to a protected run mode or module, subsequent
87             requests to a non-protected run mode or module will revert to using HTTP.
88             To prevent this from happening, set the parameter keep_in_ssl in the
89             configuration
90             (see L below)
91              
92             =cut
93              
94             sub import {
95 4     4   753 my $caller = scalar(caller);
96 4         44 $caller->add_callback(init => \&_add_runmodes);
97 4         90 $caller->add_callback(prerun => \&_check_ssl);
98 4         499 goto &Exporter::import;
99             }
100              
101             sub CGI::Application::RequireSSL : ATTR(CODE, BEGIN, CHECK) {
102 8     8 0 226346 my ($package, $symbol, $referent, $attr, $data, $phase) = @_;
103 8 100       582 if ($phase eq 'CHECK') {
104 4         10 $SSL_RUN_MODES{*{$symbol}{NAME}}++;
  4         21  
105             }
106 3     3   37 }
  3         9  
  3         28  
107              
108             =head1 METHODS
109              
110             =head2 config_requiressl
111              
112             Optionally configure the plugin in your cgiapp_init method
113              
114             $self->config_requiressl(
115             keep_in_ssl => 0,
116             ignore_check => 0,
117             )
118            
119             Valid parameters are:
120              
121             =over 4
122              
123             =item * keep_in_ssl - if set, all subsequent requests following one to a
124             protected run mode or module will be via HTTPS.
125              
126             =item * ignore_check - ignore SSL schecking. This is useful if your
127             application is deployed in an environment that doesn't support SSL.
128              
129             =back
130              
131             =cut
132              
133             sub config_requiressl {
134 1     1 1 40 my ($self, %args) = @_;
135              
136 1         2 foreach my $param (qw/ keep_in_ssl ignore_check/) {
137 2 100       23 $self->{__PACKAGE__ . $param} = $args{$param} if $args{$param};
138             }
139             }
140              
141             =head2 mode_redirect
142              
143             This is a run mode that will be automatically called if the request should
144             be redirected to the equivalent HTTP or HTTPS URL. You should not call it
145             directly.
146              
147             =cut
148              
149             sub mode_redirect {
150 2     2 1 200 my $self = shift;
151 2         9 my $new_mode = $self->{__PACKAGE__ . 'new_mode'};
152 2 50       12 croak "Cannot redirect from POST" if $self->query->request_method eq 'POST';
153 2         345 my $new_url = $self->query->url(-base => 1);
154             # Can't rely on -query option in case the query has been played with
155             # prior to the redirect being invoked. Use the REQUEST_URI instead
156 2 50       9157 $new_url .= $ENV{REQUEST_URI} if $ENV{REQUEST_URI};
157 2 50       14 if ($new_mode eq 'https') {
158 2         10 $new_url =~ s/^http:/https:/;
159             } else {
160 0         0 $new_url =~ s/^https:/http:/;
161             }
162 2         22 $self->header_type('redirect');
163 2         57 $self->header_add(-uri => $new_url);
164              
165 2         108 return ' ';
166             }
167              
168             sub _add_runmodes {
169 6     6   21429 my $self = shift;
170 6         51 $self->run_modes([qw/config_requiressl mode_redirect/]);
171             }
172              
173             sub _check_ssl {
174 6     6   5001 my $self = shift;
175 6         39 my $rm = $self->get_current_runmode;
176              
177 6 100       55 unless ($self->{__PACKAGE__ . 'ignore_check'}) {
178              
179             # Process protection is either the module or the requested run mode
180             # is protected
181 5 100 100     29 if (($self->param('require_ssl') || $SSL_RUN_MODES{$rm})
      66        
182             && !$self->query->https)
183             {
184 4 100       895 if ($self->param('rewrite_to_ssl')) {
185 2         34 $self->{__PACKAGE__ . 'new_mode'} = 'https';
186 2         24 return $self->prerun_mode('mode_redirect');
187             } else {
188 2         447 croak "https request required";
189             }
190             }
191              
192             # If a request is made using SSL, but we don't need it to be, then
193             # redirect to the non-SSL page
194 1 50 0     28 if (
      33        
195             $self->query->https
196             && !(
197             $self->{__PACKAGE__ . 'keep_in_ssl'}
198             || $self->param('require_ssl')
199             || $SSL_RUN_MODES{$rm}
200             )
201             )
202             {
203 0           $self->{__PACKAGE__ . 'new_mode'} = 'http';
204 0           return $self->prerun_mode('mode_redirect');
205             }
206             }
207             }
208              
209             =head1 AUTHOR
210              
211             Dan Horne, C<< >>
212              
213             =head1 BUGS
214              
215             Please report any bugs or feature requests to
216             C, or through the web interface at
217             L.
218             I will be notified, and then you'll automatically be notified of progress on
219             your bug as I make changes.
220              
221             =head1 CAVEAT
222              
223             This module been tested under the FastCGI persistent environment, but not under
224             mod_perl. The author would apprecaute feedback from anyone who is able to
225             test with that environment.
226              
227             =head1 SUPPORT
228              
229             You can find documentation for this module with the perldoc command.
230              
231             perldoc CGI::Application::Plugin::RequireSSL
232              
233             You can also look for information at:
234              
235             =over 4
236              
237             =item * AnnoCPAN: Annotated CPAN documentation
238              
239             L
240              
241             =item * CPAN Ratings
242              
243             L
244              
245             =item * RT: CPAN's request tracker
246              
247             L
248              
249             =item * Search CPAN
250              
251             L
252              
253             =back
254              
255             =head1 ACKNOWLEDGEMENTS
256              
257             =over 4
258              
259             =item * Users of the CGI::Application wiki (http://www.cgi-app.org) who requested
260             this module.
261              
262             =item * Andy Grundman - I stole the idea of the keep_in_ssl parameter from his
263             L module
264              
265             =back
266              
267             =head1 COPYRIGHT & LICENSE
268              
269             Copyright 2007 Dan Horne, all rights reserved.
270              
271             This program is free software; you can redistribute it and/or modify it
272             under the same terms as Perl itself.
273              
274             =cut
275              
276             1; # End of CGI::Application::Plugin::RequireSSL