Add howto
[catagits/Catalyst-Plugin-Authentication.git] / lib / Catalyst / Authentication / Credential / Remote.pm
index 6c6b460..5e20adc 100644 (file)
@@ -1,14 +1,13 @@
 package Catalyst::Authentication::Credential::Remote;
+use Moose;
+use namespace::autoclean;
 
-use strict;
-use warnings;
+with 'MooseX::Emulate::Class::Accessor::Fast';
 
-use base 'Class::Accessor::Fast';
+use Try::Tiny qw/ try catch /;
 
-BEGIN {
-    __PACKAGE__->mk_accessors(
-        qw/allow_re deny_re cutname_re source realm username_field/);
-}
+__PACKAGE__->mk_accessors(
+    qw/allow_re deny_re cutname_re source realm username_field/);
 
 sub new {
     my ( $class, $config, $app, $realm ) = @_;
@@ -17,21 +16,27 @@ sub new {
     bless $self, $class;
 
     # we are gonna compile regular expresions defined in config parameters
-    # and explicitly throw an exception saying what parameter was invalid 
-    if (defined($config->{allow_regexp}) && ($config->{allow_regexp} ne "")) { 
-        eval { $self->allow_re( qr/$config->{allow_regexp}/ ) };
-        Catalyst::Exception->throw( "Invalid regular expression in ".
-        "'allow_regexp' configuration parameter") if $@;
+    # and explicitly throw an exception saying what parameter was invalid
+    if (defined($config->{allow_regexp}) && ($config->{allow_regexp} ne "")) {
+        try { $self->allow_re( qr/$config->{allow_regexp}/ ) }
+        catch {
+            Catalyst::Exception->throw( "Invalid regular expression in ".
+                "'allow_regexp' configuration parameter");
+        };
     }
-    if (defined($config->{deny_regexp}) && ($config->{deny_regexp} ne "")) { 
-        eval { $self->deny_re( qr/$config->{deny_regexp}/ ) };     
-        Catalyst::Exception->throw( "Invalid regular expression in ".
-             "'deny_regexp' configuration parameter") if $@;
+    if (defined($config->{deny_regexp}) && ($config->{deny_regexp} ne "")) {
+        try { $self->deny_re( qr/$config->{deny_regexp}/ ) }
+        catch {
+            Catalyst::Exception->throw( "Invalid regular expression in ".
+                 "'deny_regexp' configuration parameter");
+        };
     }
-    if (defined($config->{cutname_regexp}) && ($config->{cutname_regexp} ne "")) { 
-        eval { $self->cutname_re( qr/$config->{cutname_regexp}/ ) };
-        Catalyst::Exception->throw( "Invalid regular expression in ".
-             "'cutname_regexp' configuration parameter") if $@;
+    if (defined($config->{cutname_regexp}) && ($config->{cutname_regexp} ne "")) {
+        try { $self->cutname_re( qr/$config->{cutname_regexp}/ ) }
+        catch {
+            Catalyst::Exception->throw( "Invalid regular expression in ".
+                "'cutname_regexp' configuration parameter");
+        };
     }
     $self->source($config->{source} || 'REMOTE_USER');
     $self->realm($realm);
@@ -58,12 +63,12 @@ sub authenticate {
             # maybe show warning that we are gonna use DEPRECATED $req->user            
             if (ref($c->req->user)) {
                 # I do not know exactly when this happens but it happens
-               Catalyst::Exception->throw( "Cannot get remote user from ".
-               "\$c->req->user as it seems to be a reference not a string" );
-           }
-           else {
-               $remuser = $c->req->user;
-           }
+            Catalyst::Exception->throw( "Cannot get remote user from ".
+        "\$c->req->user as it seems to be a reference not a string" );
+        }
+        else {
+            $remuser = $c->req->user;
+        }
         }
     }    
     elsif ($self->source =~ /^(SSL_CLIENT_.*|CERT_*|AUTH_USER)$/) {
@@ -299,4 +304,61 @@ support $c->req->remote_user.
 This module tries some workarounds when it detects an older version and should
 work as well.
 
+=head1 USING WITH A REVERSE PROXY
+
+If you are using a reverse proxy, then the WEBUSER will not be
+directly accessible by the Catalyst server.  To use remote
+authentication, you will have to modify the web server to set a header
+containing the WEBUSER.  You would then need to modify the PSGI
+configuration to map the header back to the WEBUSER variable.
+
+For example, in Apache you would add the configuration
+
+  RequestHeader unset X-Forwarded-User
+  RewriteEngine On
+  RewriteCond %{LA-U:REMOTE_USER} (.+)
+  RewriteRule . - [E=RU:%1]
+  RequestHeader set X-Forwarded-User %{RU}e
+
+You then need to create a Plack::Middleware module to map the
+header back to the WEBUSER:
+
+  package Plack::Middleware::MyRemote;
+
+  use parent qw( Plack::Middleware );
+
+  use Plack::Util;
+
+  sub call {
+      my ($self, $env) = @_;
+
+      my $user = $env->{HTTP_X_FORWARDED_USER} // "";
+
+      $env->{REMOTE_USER} = $user
+        if ($user && ($user ne '(null)'));
+
+      my $res = $self->app->($env);
+
+      return $res;
+  }
+
+  1;
+
+Finally, you need to modify F<myapp.psgi> to use the custom middleware:
+
+  use strict;
+  use warnings;
+
+  use MyApp;
+
+  use Plack::Builder;
+
+  my $app = Drain->apply_default_middlewares(Drain->psgi_app);
+
+  builder {
+     enable "Plack::Middleware::MyRemote";
+     $app;
+  };
+
+
 =cut