Released RequireSSL 0.03: code cleanup and Static::Simple support v0.03
Andy Grundman [Tue, 6 Sep 2005 02:11:47 +0000 (02:11 +0000)]
Changes
META.yml
README
lib/Catalyst/Plugin/RequireSSL.pm

diff --git a/Changes b/Changes
index 3662180..c850236 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,10 @@
 Revision history for Perl extension Catalyst::Plugin::RequireSSL
 
+0.03    2005-09-05 22:00:00
+        - Proper handling for static files in SSL mode when using
+          Static::Simple.
+        - Code cleanup per Best Practices.
+
 0.02    2005-06-23 20:40:00
         - fixed README file
 
index b7a20d3..38dcb58 100644 (file)
--- a/META.yml
+++ b/META.yml
@@ -1,8 +1,14 @@
---- #YAML:1.0
+---
 name: Catalyst-Plugin-RequireSSL
-version: 0.01
+version: 0.03
 author:
-  - Andy Grundman, C<andy@hybridized.org>
+  - 'Andy Grundman, <andy@hybridized.org>'
 abstract: Force SSL mode on select pages
 license: perl
-generated_by: Module::Build version 0.2604, without YAML.pm
+requires:
+  Catalyst: 5.23
+provides:
+  Catalyst::Plugin::RequireSSL:
+    file: lib/Catalyst/Plugin/RequireSSL.pm
+    version: 0.03
+generated_by: Module::Build version 0.2611
diff --git a/README b/README
index 5098a8b..72e8620 100644 (file)
--- a/README
+++ b/README
@@ -2,7 +2,9 @@ NAME
     Catalyst::Plugin::RequireSSL - Force SSL mode on select pages
 
 SYNOPSIS
-        use Catalyst 'RequireSSL';
+        # in MyApp.pm
+        use Catalyst;
+        MyApp->setup( qw/RequireSSL/ );
     
         MyApp->config->{require_ssl} = {
             https => 'secure.mydomain.com',
@@ -10,6 +12,7 @@ SYNOPSIS
             remain_in_ssl => 0,
         };
 
+        # in any controller methods that should be secured
         $c->require_ssl;
 
 DESCRIPTION
@@ -46,42 +49,32 @@ CONFIGURATION
         remain_in_ssl
     
     If you'd like your users to remain in SSL mode after visiting an
-    SSL-required page, you can set this option to 1. By default, users will
-    be redirected back to non-SSL mode as soon as possible.
+    SSL-required page, you can set this option to 1. By default, this option
+    is disabled and users will be redirected back to non-SSL mode as soon as
+    possible.
 
-  METHODS
-    require_ssl
-        Call require_ssl in any controller method you wish to be secured.
+METHODS
+  require_ssl
+    Call require_ssl in any controller method you wish to be secured.
 
-            $c->require_ssl;
-
-        The browser will be redirected to the same path on your SSL server.
-        POST requests are never redirected.
-
-    finalize (extended)
-        Redirect back to non-SSL mode if necessary.
-
-    setup
-        Setup default values.
+        $c->require_ssl;
 
-    _redirect_uri
-        Generate the redirection URI.
+    The browser will be redirected to the same path on your SSL server. POST
+    requests are never redirected.
 
 KNOWN ISSUES
     When viewing an SSL-required page that uses static files served from the
-    Static plugin, the static files are redirected to the non-SSL path. It
-    may be possible to work around this by checking the referer protocol,
-    but currently there is no way to determine if a file being served is
-    static content.
+    Static plugin, the static files are redirected to the non-SSL path.
 
-    For best results, always serve static files directly from your web
-    server without using the Static plugin.
+    In order to get the correct behaviour where static files are not
+    redirected, you should use the Static::Simple plugin or always serve
+    static files directly from your web server.
 
 SEE ALSO
-    Catalyst
+    Catalyst, Catalyst::Plugin::Static::Simple
 
 AUTHOR
-    Andy Grundman, "andy@hybridized.org"
+    Andy Grundman, <andy@hybridized.org>
 
 COPYRIGHT
     This program is free software, you can redistribute it and/or modify it
index 452cd3f..a03aad5 100644 (file)
@@ -4,9 +4,98 @@ use strict;
 use base qw/Class::Accessor::Fast/;
 use NEXT;
 
-our $VERSION = '0.02';
+our $VERSION = '0.03';
 
-__PACKAGE__->mk_accessors( '_require_ssl' );
+__PACKAGE__->mk_accessors('_require_ssl');
+
+sub require_ssl {
+    my $c = shift;
+
+    $c->_require_ssl(1);
+
+    if ( !$c->req->secure && $c->req->method ne "POST" ) {
+        my $redir = $c->_redirect_uri('https');
+        if ( $c->config->{require_ssl}->{disabled} ) {
+            $c->log->warn( "RequireSSL: Would have redirected to $redir" );
+        }
+        else {
+            $c->res->redirect( $redir );
+        }
+    }
+}
+
+sub finalize {
+    my $c = shift;
+    
+    # Do not redirect static files (only works with Static::Simple)
+    if ( $c->isa( "Catalyst::Plugin::Static::Simple" ) ) {
+        return $c->NEXT::finalize(@_) if $c->_static_file;
+    }
+    
+    # redirect back to non-SSL mode
+    REDIRECT:
+    {
+        # No redirect if:
+        # we're not in SSL mode
+        last REDIRECT if !$c->req->secure;
+        # it's a POST request
+        last REDIRECT if $c->req->method eq "POST";
+        # we're already required to be in SSL for this request
+        last REDIRECT if $c->_require_ssl;
+        # or the user doesn't want us to redirect
+        last REDIRECT if $c->config->{require_ssl}->{remain_in_ssl};
+        
+        $c->res->redirect( $c->_redirect_uri('http') );
+    }
+
+    return $c->NEXT::finalize(@_);
+}
+
+sub setup {
+    my $c = shift;
+
+    $c->NEXT::setup(@_);
+
+    # disable the plugin when running under certain engines which don't
+    # support SSL
+    # XXX: I didn't include Catalyst::Engine::Server here as it may be used as
+    # a backend in a proxy setup.
+    if ( $c->engine eq "Catalyst::Engine::HTTP" ) {
+        $c->config->{require_ssl}->{disabled} = 1;
+        $c->log->warn( "RequireSSL: Disabling SSL redirection while running "
+                     . "under " . $c->engine );
+    }
+}
+
+sub _redirect_uri {
+    my ( $c, $type ) = @_;
+
+    # XXX: Cat needs a $c->req->host method...
+    # until then, strip off the leading protocol from base
+    if ( !$c->config->{require_ssl}->{$type} ) {
+        my $host = $c->req->base;
+        $host =~ s/^http(s?):\/\///;
+        $c->config->{require_ssl}->{$type} = $host;
+    }
+
+    if ( $c->config->{require_ssl}->{$type} !~ /\/$/xms ) {
+        $c->config->{require_ssl}->{$type} .= '/';
+    }
+
+    my $redir
+        = $type . '://' . $c->config->{require_ssl}->{$type} . $c->req->path;
+
+    if ( scalar $c->req->param ) {
+        my @params 
+            = map { "$_=" . $c->req->params->{$_} } sort $c->req->param;
+        $redir .= "?" . join "&", @params;
+    }
+        
+    return $redir;
+}
+
+1;
+__END__
 
 =head1 NAME
 
@@ -14,7 +103,9 @@ Catalyst::Plugin::RequireSSL - Force SSL mode on select pages
 
 =head1 SYNOPSIS
 
-    use Catalyst 'RequireSSL';
+    # in MyApp.pm
+    use Catalyst;
+    MyApp->setup( qw/RequireSSL/ );
     
     MyApp->config->{require_ssl} = {
         https => 'secure.mydomain.com',
@@ -22,25 +113,27 @@ Catalyst::Plugin::RequireSSL - Force SSL mode on select pages
         remain_in_ssl => 0,
     };
 
+    # in any controller methods that should be secured
     $c->require_ssl;
 
 =head1 DESCRIPTION
 
-Use this plugin if you wish to selectively force SSL mode on some of your web pages, 
-for example a user login form or shopping cart.
+Use this plugin if you wish to selectively force SSL mode on some of your web
+pages, for example a user login form or shopping cart.
 
-Simply place $c->require_ssl calls in any controller method you wish to be secured. 
+Simply place $c->require_ssl calls in any controller method you wish to be
+secured. 
 
-This plugin will automatically disable itself if you are running under the standalone
-HTTP::Daemon Catalyst server.  A warning message will be printed to the log file whenever
-an SSL redirect would have occurred.
+This plugin will automatically disable itself if you are running under the
+standalone HTTP::Daemon Catalyst server.  A warning message will be printed to
+the log file whenever an SSL redirect would have occurred.
 
 =head1 WARNINGS
 
-If you utilize different servers or hostnames for non-SSL and SSL requests, and you rely
-on a session cookie to determine redirection (i.e for a login page), your cookie must
-be visible to both servers.  For more information, see the documentation for the Session plugin
-you are using.
+If you utilize different servers or hostnames for non-SSL and SSL requests,
+and you rely on a session cookie to determine redirection (i.e for a login
+page), your cookie must be visible to both servers.  For more information, see
+the documentation for the Session plugin you are using.
 
 =head1 CONFIGURATION
 
@@ -52,138 +145,42 @@ If your SSL domain name is different from your non-SSL domain, set this value.
 
     http => $non_ssl_host
     
-If you have set the https value above, you must also set the hostname of your non-SSL
-server.
+If you have set the https value above, you must also set the hostname of your
+non-SSL server.
 
     remain_in_ssl
     
-If you'd like your users to remain in SSL mode after visiting an SSL-required page, you can
-set this option to 1.  By default, users will be redirected back to non-SSL mode as soon as
-possible.
+If you'd like your users to remain in SSL mode after visiting an SSL-required
+page, you can set this option to 1.  By default, this option is disabled and
+users will be redirected back to non-SSL mode as soon as possible.
 
-=head2 METHODS
+=head1 METHODS
 
-=over 4
-
-=item require_ssl
+=head2 require_ssl
 
 Call require_ssl in any controller method you wish to be secured.
 
     $c->require_ssl;
 
-The browser will be redirected to the same path on your SSL server.  POST requests
-are never redirected.
-
-=cut
-
-sub require_ssl {
-    my $c = shift;
-    
-    $c->_require_ssl( 1 );
-      
-    unless ( $c->req->secure || $c->req->method eq "POST" ) {
-        if ( $c->config->{require_ssl}->{disabled} ) {
-            $c->log->warn( "RequireSSL: Would have redirected to " . $c->_redirect_uri( 'https' ) );
-        } else {
-            $c->res->redirect( $c->_redirect_uri( 'https' ) );
-        }
-    }
-}
-
-=item finalize (extended)
-
-Redirect back to non-SSL mode if necessary.
-
-=cut
-
-sub finalize {
-    my $c = shift;
-    
-    # redirect unless:
-    # we're not in SSL mode,
-    # it's a POST request,
-    # we're already required to be in SSL for this request,
-    # or the user doesn't want us to redirect
-    unless ( !$c->req->secure
-      || $c->req->method eq "POST"
-      || $c->_require_ssl
-      || $c->config->{require_ssl}->{remain_in_ssl} ) {
-          $c->res->redirect( $c->_redirect_uri( 'http' ) );
-    }
-    
-    return $c->NEXT::finalize(@_);    
-}
-
-=item setup
-
-Setup default values.
-
-=cut
-
-sub setup {
-    my $c = shift;
-    
-    $c->NEXT::setup(@_);
-    
-    # disable the plugin when running under certain engines which don't support SSL
-    # XXX: I didn't include Catalyst::Engine::Server here as it may be used as a backend
-    # in a proxy setup.
-    if ( $c->engine eq "Catalyst::Engine::HTTP" ) {
-        $c->config->{require_ssl}->{disabled} = 1;
-        $c->log->warn( "RequireSSL: Disabling SSL redirection while running under " . $c->engine );
-    }
-}
-
-=item _redirect_uri
-
-Generate the redirection URI.
-
-=cut
-
-sub _redirect_uri {
-    my ( $c, $type ) = @_;
-    
-    # XXX: Cat needs a $c->req->host method...
-    # until then, strip off the leading protocol from base
-    unless ( $c->config->{require_ssl}->{$type} ) {
-        my $host = $c->req->base;
-        $host =~ s/^http(s?):\/\///;
-        $c->config->{require_ssl}->{$type} = $host;
-    }
-    
-    $c->config->{require_ssl}->{$type} .= '/'
-        unless ( $c->config->{require_ssl}->{$type} =~ /\/$/ );
-    
-    my $redir = $type . '://' . $c->config->{require_ssl}->{$type} . $c->req->path;
-    if ( scalar keys %{ $c->req->params } ) {
-        my @params = ();
-        foreach my $k ( sort keys %{ $c->req->params } ) {
-            push @params, $k . "=" . $c->req->params->{$k};
-        }
-        $redir .= "?" . join "&", @params;
-    }
-    
-    return $redir;
-}
-
-=back
+The browser will be redirected to the same path on your SSL server.  POST
+requests are never redirected.
 
 =head1 KNOWN ISSUES
 
-When viewing an SSL-required page that uses static files served from the Static plugin, the static
-files are redirected to the non-SSL path.  It may be possible to work around this by checking the
-referer protocol, but currently there is no way to determine if a file being served is static content.
+When viewing an SSL-required page that uses static files served from the
+Static plugin, the static files are redirected to the non-SSL path.
 
-For best results, always serve static files directly from your web server without using the Static
-plugin.
+In order to get the correct behaviour where static files are not redirected,
+you should use the Static::Simple plugin or always serve static files
+directly from your web server.
 
 =head1 SEE ALSO
 
-L<Catalyst>
+L<Catalyst>, L<Catalyst::Plugin::Static::Simple>
 
 =head1 AUTHOR
 
-Andy Grundman, C<andy@hybridized.org>
+Andy Grundman, <andy@hybridized.org>
 
 =head1 COPYRIGHT
 
@@ -191,5 +188,3 @@ This program is free software, you can redistribute it and/or modify it under
 the same terms as Perl itself.
 
 =cut
-
-1;