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 ) = @_;
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);
# 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)$/) {
Besides the common methods like HTTP Basic and Digest authentication you can
also use sophisticated ones like so called "integrated authentication" via
NTLM or Kerberos (popular in corporate intranet applications running in Windows
-Active Directory enviroment) or even the SSL authentication when users
+Active Directory environment) or even the SSL authentication when users
authenticate themself using their client SSL certificates.
The main idea of this module is based on a fact that webserver passes the name
This config item is B<OPTIONAL> - no default value.
If param B<cutname_regexp> is specified we try to cut the final usename passed to
-Catalyst application as a substring from WEBUSER. This is usefull for
+Catalyst application as a substring from WEBUSER. This is useful for
example in case of SSL authentication when WEBUSER looks like this
'CN=john, OU=Unit Name, O=Company, C=CZ' - from this format we can simply cut
pure usename by cutname_regexp set to 'CN=(.*), OU=Unit Name, O=Company, C=CZ'.
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