1 package Catalyst::Authentication::Credential::Remote;
6 use base 'Class::Accessor::Fast';
9 __PACKAGE__->mk_accessors(qw/allow_re deny_re cutname_re source realm/);
13 my ( $class, $config, $app, $realm ) = @_;
18 # we are gonna compile regular expresions defined in config parameters
19 # and explicitly throw an exception saying what parameter was invalid
20 if (defined($config->{allow_regexp}) && ($config->{allow_regexp} ne "")) {
21 eval { $self->allow_re( qr/$config->{allow_regexp}/ ) };
22 Catalyst::Exception->throw( "Invalid regular expression in ".
23 "'allow_regexp' configuration parameter") if $@;
25 if (defined($config->{deny_regexp}) && ($config->{deny_regexp} ne "")) {
26 eval { $self->deny_re( qr/$config->{deny_regexp}/ ) };
27 Catalyst::Exception->throw( "Invalid regular expression in ".
28 "'deny_regexp' configuration parameter") if $@;
30 if (defined($config->{cutname_regexp}) && ($config->{cutname_regexp} ne "")) {
31 eval { $self->cutname_re( qr/$config->{cutname_regexp}/ ) };
32 Catalyst::Exception->throw( "Invalid regular expression in ".
33 "'cutname_regexp' configuration parameter") if $@;
35 $self->source($config->{source} || 'REMOTE_USER');
41 my ( $self, $c, $realm, $authinfo ) = @_;
44 if ($self->source eq "REMOTE_USER") {
46 if (defined($c->engine->env)) {
47 # BEWARE: $c->engine->env was broken prior 5.80005
48 $remuser = $c->engine->env->{REMOTE_USER};
50 elsif ($c->req->can('remote_user')) {
51 # $c->req->remote_users was introduced in 5.80005; if not evailable we are
52 # gonna use $c->req->user that is deprecated but more or less works as well
53 $remuser = $c->req->remote_user;
55 elsif ($c->req->can('user')) {
56 # maybe show warning that we are gonna use DEPRECATED $req->user
57 if (ref($c->req->user)) {
58 # I do not know exactly when this happens but it happens
59 Catalyst::Exception->throw( "Cannot get remote user from ".
60 "\$c->req->user as it seems to be a reference not a string" );
63 $remuser = $c->req->user;
67 elsif ($self->source =~ /^(SSL_CLIENT_.*|CERT_*|AUTH_USER)$/) {
68 # if you are using 'exotic' webserver or if the user is
69 # authenticated e.g via SSL certificate his name could be avaliable
70 # in different variables
71 # BEWARE: $c->engine->env was broken prior 5.80005
72 my $nam=$self->source;
73 if ($c->engine->can('env')) {
74 $remuser = $c->engine->env->{$nam};
77 # this happens on Catalyst 5.80004 and before (when using FastCGI)
78 Catalyst::Exception->throw( "Cannot handle parameter 'source=$nam'".
79 " as runnig Catalyst engine has broken \$c->engine->env" );
83 Catalyst::Exception->throw( "Invalid value of 'source' parameter");
85 return unless defined($remuser);
86 return if ($remuser eq "");
88 # $authinfo hash can contain item username (it is optional) - if it is so
89 # this username has to be equal to remote_user
90 my $authuser = $authinfo->{username};
91 return if (defined($authuser) && ($authuser ne $remuser));
93 # handle deny / allow checks
94 return if (defined($self->deny_re) && ($remuser =~ $self->deny_re));
95 return if (defined($self->allow_re) && ($remuser !~ $self->allow_re));
97 # if param cutname_regexp is specified we try to cut the final usename as a
98 # substring from remote_user
100 if (defined($self->cutname_re)) {
101 if (($remuser =~ $self->cutname_re) && ($1 ne "")) {
106 $authinfo->{id} = $authinfo->{username} = $usr;
107 $authinfo->{remote_user} = $remuser; # just to keep the original value
108 my $user_obj = $realm->find_user( $authinfo, $c );
109 return ref($user_obj) ? $user_obj : undef;
120 Catalyst::Authentication::Credential::Remote - Let the webserver (e.g. Apache)
121 authenticate Catalyst application users
128 'Plugin::Authentication' => {
129 default_realm => 'remoterealm',
134 allow_regexp => '^(user.*|admin|guest)$',
135 deny_regexp => 'test',
139 # if you want to have some additional user attributes
140 # like user roles, user full name etc. you can specify
141 # here the store where you keep this data
149 # in your Controller/Root.pm you can implement "auto-login" in this way
150 sub begin : Private {
151 my ( $self, $c ) = @_;
152 unless ($c->user_exists) {
153 # authenticate() for this module does not need any user info
154 # as the username is taken from $c->req->remote_user and
155 # password is not needed
156 unless ($c->authenticate( {} )) {
157 # return 403 forbidden or kick out the user in other way
162 # or you can implement in any controller an ordinary login action like this
164 my ( $self, $c ) = @_;
165 $c->authenticate( {} );
170 This module allows you to authenticate the users of your Catalyst application
171 on underlaying webserver. The complete list of authentication method available
172 via this module depends just on what your webserver (e.g. Apache, IIS, Lighttpd)
175 Besides the common methods like HTTP Basic and Digest authentication you can
176 also use sophisticated ones like so called "integrated authentication" via
177 NTLM or Kerberos (popular in corporate intranet applications running in Windows
178 Active Directory enviroment) or even the SSL authentication when users
179 authenticate themself using their client SSL certificates.
181 The main idea of this module is based on a fact that webserver passes the name
182 of authenticated user into Catalyst application as REMOTE_USER variable (or in
183 case of SSL client authentication in other variables like SSL_CLIENT_S_DN on
184 Apache + mod_ssl) - from this point referenced as WEBUSER.
185 This module simply takes this value - perfoms some optional checks (see
186 below) - and if everything is OK the WEBUSER is declared as authenticated on
187 Catalyst level. In fact this module does not perform any check for password or
188 other credential; it simply believes the webserver that user was properly
195 This config item is B<REQUIRED>.
197 B<class> is part of the core L<Catalyst::Plugin::Authentication> module, it
198 contains the class name of the store to be used.
200 The classname used for Credential. This is part of L<Catalyst::Plugin::Authentication>
201 and is the method by which Catalyst::Authentication::Credential::Remote is
202 loaded as the credential validator. For this module to be used, this must be set
207 This config item is B<OPTIONAL> - default is REMOTE_USER.
209 B<source> contains a name of a variable passed from webserver that contains the
212 Supported values: REMOTE_USER, SSL_CLIENT_*, CERT_*, AUTH_USER
214 B<BEWARE:> Support for using different variables than REMOTE_USER does not work
215 properly with Catalyst 5.8004 and before (if you want details see source code).
217 Note1: Apache + mod_ssl uses SSL_CLIENT_S_DN, SSL_CLIENT_S_DN_* etc. (has to be
218 enabled by 'SSLOption +StdEnvVars') or you can also let Apache make a copy of
219 this value into REMOTE_USER (Apache option 'SSLUserName SSL_CLIENT_S_DN').
221 Note2: Microsoft IIS uses CERT_SUBJECT, CERT_SERIALNUMBER etc. for storing info
222 about client authenticated via SSL certificate. AUTH_USER on IIS seems to have
223 the same value as REMOTE_USER (but there might be some differences I am not
228 This config item is B<OPTIONAL> - no default value.
230 B<deny_regexp> contains a regular expression used for check against WEBUSER
235 This config item is B<OPTIONAL> - no default value.
237 B<deny_regexp> contains a regular expression used for check against WEBUSER.
239 Allow/deny checking of WEBUSER values goes in this way:
241 1) If B<deny_regexp> is defined and WEBUSER matches deny_regexp then
242 authentication FAILS otherwise continues with next step. If deny_regexp is not
243 defined or is an empty string we skip this step.
245 2) If B<allow_regexp> is defined and WEBUSER matches allow_regexp then
246 authentication PASSES otherwise FAILS. If allow_regexp is not
247 defined or is an empty string we skip this step.
249 The order deny-allow is fixed.
251 =head2 cutname_regexp
253 This config item is B<OPTIONAL> - no default value.
255 If param B<cutname_regexp> is specified we try to cut the final usename passed to
256 Catalyst application as a substring from WEBUSER. This is usefull for
257 example in case of SSL authentication when WEBUSER looks like this
258 'CN=john, OU=Unit Name, O=Company, C=CZ' - from this format we can simply cut
259 pure usename by cutname_regexp set to 'CN=(.*), OU=Unit Name, O=Company, C=CZ'.
261 Substring is always taken as '$1' regexp substring. If WEBUSER does not
262 match cutname_regexp at all or if '$1' regexp substring is empty we pass the
263 original WEBUSER value (without cutting) to Catalyst application.
267 =head2 new ( $config, $app, $realm )
269 Instantiate a new Catalyst::Authentication::Credential::Remote object using the
270 configuration hash provided in $config. In case of invalid value of any
271 configuration parameter (e.g. invalid regular expression) throws an exception.
275 =head2 authenticate ( $realm, $authinfo )
277 Takes the username form WEBUSER set by webserver, performs additional
278 checks using optional allow_regexp/deny_regexp configuration params, optionaly
279 takes substring from WEBUSER and the sets the resulting value as
286 It is B<strongly recommended> to use this module with Catalyst 5.80005 and above
287 as previous versions have some bugs related to $c->engine->env and do not
288 support $c->req->remote_user.
290 This module tries some workarounds when it detects an older version and should