Released RequireSSL 0.04: bug fixes, full test suite v0.04
Andy Grundman [Wed, 14 Sep 2005 18:48:06 +0000 (18:48 +0000)]
Changes
MANIFEST
MANIFEST.SKIP [new file with mode: 0644]
META.yml
lib/Catalyst/Plugin/RequireSSL.pm
t/04ssl.t [new file with mode: 0644]
t/05ssl_host.t [new file with mode: 0644]
t/06remain_in_ssl.t [new file with mode: 0644]
t/lib/TestApp.pm [new file with mode: 0644]
t/lib/TestApp/C/SSL.pm [new file with mode: 0644]

diff --git a/Changes b/Changes
index c850236..2f7cb21 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,11 @@
 Revision history for Perl extension Catalyst::Plugin::RequireSSL
 
+0.04    2005-09-14 13:30:00
+        - Fixed bug in redirect code that ignored duplicate key names.
+        - Strip all output content when doing a redirect from HTTP -> HTTPS
+          to avoid sending secure data over HTTP.
+        - Added test suite.
+
 0.03    2005-09-05 22:00:00
         - Proper handling for static files in SSL mode when using
           Static::Simple.
index 731a9a7..146acc4 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -8,3 +8,8 @@ README
 t/01use.t
 t/02pod.t
 t/03podcoverage.t
+t/04ssl.t
+t/05ssl_host.t
+t/06remain_in_ssl.t
+t/lib/TestApp.pm
+t/lib/TestApp/C/SSL.pm
diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP
new file mode 100644 (file)
index 0000000..2ffcc10
--- /dev/null
@@ -0,0 +1,25 @@
+# Avoid version control files.
+\bRCS\b
+\bCVS\b
+,v$
+\B\.svn\b
+
+# Avoid Makemaker generated and utility files.
+\bMakefile$
+\bblib
+\bMakeMaker-\d
+\bpm_to_blib$
+\bblibdirs$
+^MANIFEST\.SKIP$
+
+# Avoid Module::Build generated and utility files.
+\bBuild$
+\b_build
+
+# Avoid temp and backup files.
+~$
+\.tmp$
+\.old$
+\.bak$
+\#$
+\b\.#
index 38dcb58..f54c07b 100644 (file)
--- a/META.yml
+++ b/META.yml
@@ -1,6 +1,6 @@
 ---
 name: Catalyst-Plugin-RequireSSL
-version: 0.03
+version: 0.04
 author:
   - 'Andy Grundman, <andy@hybridized.org>'
 abstract: Force SSL mode on select pages
@@ -10,5 +10,5 @@ requires:
 provides:
   Catalyst::Plugin::RequireSSL:
     file: lib/Catalyst/Plugin/RequireSSL.pm
-    version: 0.03
+    version: 0.04
 generated_by: Module::Build version 0.2611
index a03aad5..f5457db 100644 (file)
@@ -4,9 +4,9 @@ use strict;
 use base qw/Class::Accessor::Fast/;
 use NEXT;
 
-our $VERSION = '0.03';
+our $VERSION = '0.04';
 
-__PACKAGE__->mk_accessors('_require_ssl');
+__PACKAGE__->mk_accessors( qw/_require_ssl _ssl_strip_output/ );
 
 sub require_ssl {
     my $c = shift;
@@ -19,6 +19,7 @@ sub require_ssl {
             $c->log->warn( "RequireSSL: Would have redirected to $redir" );
         }
         else {
+            $c->_ssl_strip_output(1);
             $c->res->redirect( $redir );
         }
     }
@@ -48,6 +49,11 @@ sub finalize {
         $c->res->redirect( $c->_redirect_uri('http') );
     }
 
+    # do not allow any output to be displayed on the insecure page
+    if ( $c->_ssl_strip_output ) {
+        $c->res->body( undef );
+    }
+
     return $c->NEXT::finalize(@_);
 }
 
@@ -84,12 +90,20 @@ sub _redirect_uri {
 
     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;
-    }
+        my @params;
+        foreach my $arg ( sort keys %{ $c->req->params } ) {
+            if ( ref $c->req->params->{$arg} ) {
+                my $list = $c->req->params->{$arg};
+                push @params, map { "$arg=" . $_  } sort @{$list};
+            }
+            else {
+                push @params, "$arg=" . $c->req->params->{$arg};
+            }
+        }
+        $redir .= '?' . join( '&', @params );
+    }        
         
     return $redir;
 }
diff --git a/t/04ssl.t b/t/04ssl.t
new file mode 100644 (file)
index 0000000..18fc7d1
--- /dev/null
+++ b/t/04ssl.t
@@ -0,0 +1,49 @@
+#!perl\r
+\r
+use strict;\r
+use warnings;\r
+\r
+use FindBin;\r
+use lib "$FindBin::Bin/lib";\r
+\r
+use Test::More tests => 15;\r
+use Catalyst::Test 'TestApp';\r
+use HTTP::Request::Common;\r
+\r
+# test an SSL redirect\r
+ok( my $res = request('http://localhost/ssl/secured'), 'request ok' );\r
+is( $res->code, 302, 'redirect code ok' );\r
+is( $res->header('location'), 'https://localhost/ssl/secured', 'redirect uri ok' );\r
+isnt( $res->content, 'Secured', 'no content displayed on secure page, ok' );\r
+\r
+# test redirection params\r
+ok( $res = request('http://localhost/ssl/secured?a=2&a=1&b=3&c=4'), 'request ok' );\r
+is( $res->header('location'), 'https://localhost/ssl/secured?a=1&a=2&b=3&c=4', 'redirect with params ok' );\r
+\r
+# test that it doesn't redirect on POST\r
+my $request = POST( 'http://localhost/ssl/secured', \r
+    'Content'      => '',\r
+    'Content-Type' => 'application/x-www-form-urlencoded'\r
+);\r
+ok( $res = request($request), 'request ok' );\r
+is( $res->code, 200, 'POST ok' );\r
+\r
+# test that it doesn't redirect if already in SSL mode\r
+SKIP:\r
+{\r
+    skip "These tests require a patch to Catalyst", 7;\r
+    # patch is to Catalyst::Engine::HTTP::Base in 5.3x\r
+    #             Catalyst::Engine::Test in 5.5\r
+    ok( $res = request('https://localhost/ssl/secured'), 'request ok' );\r
+    is( $res->code, 200, 'SSL request, ok' );\r
+    \r
+    # test redirect back to http mode\r
+    ok( $res = request('https://localhost/ssl/unsecured'), 'request ok' );\r
+    is( $res->code, 302, 'redirect back to http ok' );\r
+    is( $res->header('location'), 'http://localhost/ssl/unsecured', 'redirect uri ok' );\r
+    \r
+    # test redirection params\r
+    ok( $res = request('https://localhost/ssl/unsecured?a=2&a=1&b=3&c=4'), 'request ok' );\r
+    is( $res->header('location'), 'http://localhost/ssl/unsecured?a=1&a=2&b=3&c=4', 'redirect with params ok' );\r
+}\r
+\r
diff --git a/t/05ssl_host.t b/t/05ssl_host.t
new file mode 100644 (file)
index 0000000..56235f9
--- /dev/null
@@ -0,0 +1,32 @@
+#!perl
+
+use strict;
+use warnings;
+
+use FindBin;
+use lib "$FindBin::Bin/lib";
+
+use Test::More tests => 6;
+use Catalyst::Test 'TestApp';
+
+TestApp->config->{require_ssl} = {
+    https => 'secure.mydomain.com',
+    http => 'www.mydomain.com',
+};
+
+# test an SSL redirect
+ok( my $res = request('http://localhost/ssl/secured'), 'request ok' );
+is( $res->code, 302, 'redirect code ok' );
+is( $res->header('location'), 'https://secure.mydomain.com/ssl/secured', 'other domain redirect uri ok' );
+isnt( $res->content, 'Secured', 'no content displayed on secure page, ok' );
+
+# test redirect back to HTTP
+SKIP:
+{
+    skip "These tests require a patch to Catalyst", 2;
+    # patch is to Catalyst::Engine::HTTP::Base in 5.3x
+    #             Catalyst::Engine::Test in 5.5
+    ok( $res = request('https://secure.mydomain.com/ssl/unsecured'), 'request ok' );
+    is( $res->header('location'), 'http://www.mydomain.com/ssl/unsecured', 'other domain redirect uri ok' );
+}
+
diff --git a/t/06remain_in_ssl.t b/t/06remain_in_ssl.t
new file mode 100644 (file)
index 0000000..956385a
--- /dev/null
@@ -0,0 +1,31 @@
+#!perl
+
+use strict;
+use warnings;
+
+use FindBin;
+use lib "$FindBin::Bin/lib";
+
+use Test::More tests => 6;
+use Catalyst::Test 'TestApp';
+
+TestApp->config->{require_ssl} = {
+    remain_in_ssl => 1,
+};
+
+# test an SSL redirect
+ok( my $res = request('http://localhost/ssl/secured'), 'request ok' );
+is( $res->code, 302, 'redirect code ok' );
+is( $res->header('location'), 'https://localhost/ssl/secured', 'redirect uri ok' );
+isnt( $res->content, 'Secured', 'no content displayed on secure page, ok' );
+
+# test redirect back to HTTP, should not redirect
+SKIP:
+{
+    skip "These tests require a patch to Catalyst", 2;
+    # patch is to Catalyst::Engine::HTTP::Base in 5.3x
+    #             Catalyst::Engine::Test in 5.5
+    ok( $res = request('https://localhost/ssl/unsecured'), 'request ok' );
+    is( $res->code, 200, 'remain in SSL ok' );
+}
+
diff --git a/t/lib/TestApp.pm b/t/lib/TestApp.pm
new file mode 100644 (file)
index 0000000..9ef2899
--- /dev/null
@@ -0,0 +1,20 @@
+package TestApp;\r
+\r
+use strict;\r
+use Catalyst;\r
+use Data::Dumper;\r
+\r
+our $VERSION = '0.01';\r
+\r
+TestApp->config(\r
+    name => 'TestApp',\r
+);\r
+\r
+TestApp->setup( qw/RequireSSL/ );\r
+\r
+sub default : Private {\r
+    my ( $self, $c ) = @_;\r
+    \r
+}\r
+\r
+1;\r
diff --git a/t/lib/TestApp/C/SSL.pm b/t/lib/TestApp/C/SSL.pm
new file mode 100644 (file)
index 0000000..6faeddf
--- /dev/null
@@ -0,0 +1,20 @@
+package TestApp::C::SSL;
+
+use strict;
+use base 'Catalyst::Base';
+
+sub secured : Local {
+    my ( $self, $c ) = @_;
+    
+    $c->require_ssl;
+    
+    $c->res->output( 'Secured' );
+}
+
+sub unsecured : Local {
+    my ( $self, $c ) = @_;
+    
+    $c->res->output( 'Unsecured' );
+}
+
+1;