package Catalyst::Plugin::RequireSSL;

use strict;
use base qw/Class::Accessor::Fast/;
use MRO::Compat;

our $VERSION = '0.07';

__PACKAGE__->mk_accessors( qw/_require_ssl _allow_ssl _ssl_strip_output/ );

sub require_ssl {
    my $c = shift;


    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 );
            $c->detach if $c->config->{require_ssl}->{detach_on_redirect};

sub allow_ssl {
    my $c = shift;


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::method(@_) if $c->_static_file;
    # redirect back to non-SSL mode
        # 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->_allow_ssl;
        $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( '' );

    return $c->next::method(@_);

sub setup {
    my $c = shift;


    # disable the plugin when running under certain engines which don't
    # support SSL
    if ( $c->engine =~ /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 ) = @_;

    if ( !$c->config->{require_ssl}->{$type} ) {
        my $req_uri = $c->req->uri;
        $c->config->{require_ssl}->{$type} =
          join(':', $req_uri->host, $req_uri->_port);

    $c->config->{require_ssl}->{$type} =~ s/\/+$//;

    my $redir = $c->req->uri->clone;

    if ( $c->config->{require_ssl}->{no_cache} ) {        
        delete $c->config->{require_ssl}->{$type};
    return $redir;


=head1 NAME

Catalyst::Plugin::RequireSSL - Force SSL mode on select pages


    # in
    use Catalyst qw/
        require_ssl => {
            https => '',
            http => '',
            remain_in_ssl => 0,
            no_cache => 0,
            detach_on_redirect => 1,

    # in any controller methods that should be secured


B<Note:> This module is considered to be deprecated for most purposes. Consider
using L<Catalyst::ActionRole::RequireSSL> instead.

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

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.


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.


Configuration is optional.  You may define the following configuration values:

    https => $ssl_host
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'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.


If you have a wildcard certificate you will need to set this option if you are
using multiple domains on one instance of Catalyst.


By default C<< $c->require_ssl >> only calls C<< $c->response->redirect >> but
does not stop request processing (so it returns and subsequent statements are
run). This is probably not what you want. If you set this option to a true
value C<< $c->require_ssl >> will call C<< $c->detach >> when it redirects.

=head1 METHODS

=head2 require_ssl

Call require_ssl in any controller method you wish to be secured.


The browser will be redirected to the same path on your SSL server.  POST
requests are never redirected.

=head2 allow_ssl

Call allow_ssl in any controller method you wish to access both in SSL and
non-SSL mode.


The browser will not be redirected, independently of whether the request was
made to the SSL or non-SSL server.

=head2 setup

Disables this plugin if running under an engine which does not support SSL.

=head2 finalize

Performs the redirect to SSL url if required.


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.

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::ActionRole::RequireSSL>,

=head1 AUTHOR

Andy Grundman, <>


Simon Elliott <> (support for wildcards)


This program is free software, you can redistribute it and/or modify it under
the same terms as Perl itself.