Apache-AuthCAS

 view release on metacpan or  search on metacpan

lib/Apache/AuthCAS.pm  view on Meta::CPAN

my $PROD_CAS_PORT="443";
# CAS login URI
my $DEFAULT_CAS_LOGIN_URI="/cas/login";
my $CAS_LOGIN_URI=$DEFAULT_CAS_LOGIN_URI;
# CAS logout URI
my $DEFAULT_CAS_LOGOUT_URI="/cas/logout";
my $CAS_LOGOUT_URI=$DEFAULT_CAS_LOGOUT_URI;
# CAS proxy URI
my $DEFAULT_CAS_PROXY_URI="/cas/proxy";
my $CAS_PROXY_URI=$DEFAULT_CAS_PROXY_URI;
# CAS proxy validate URI
my $DEFAULT_CAS_PROXY_VALIDATE_URI="/cas/proxyValidate";
my $CAS_PROXY_VALIDATE_URI=$DEFAULT_CAS_PROXY_VALIDATE_URI;
# CAS service validate URI
my $DEFAULT_CAS_SERVICE_VALIDATE_URI="/cas/serviceValidate";
my $CAS_SERVICE_VALIDATE_URI=$DEFAULT_CAS_SERVICE_VALIDATE_URI;
# parameter used to pass in PGTIOU
my $PGT_IOU_PARAM = "pgtIou";
# parameter used to pass in PGT
my $PGT_ID_PARAM = "pgtId";
# number of proxy tickets to give the underlying application
my $DEFAULT_NUM_PROXY_TICKETS = 1;
my $NUM_PROXY_TICKETS = $DEFAULT_NUM_PROXY_TICKETS;
# the name of the cookie that will be used for sessions
my $DEFAULT_SESSION_COOKIE_NAME = "APACHECAS";
my $SESSION_COOKIE_NAME = $DEFAULT_SESSION_COOKIE_NAME;
# the domain the session cookies will be sent for
my $DEFAULT_SESSION_COOKIE_DOMAIN = "";
my $SESSION_COOKIE_DOMAIN = "";
# the max time before a session expires (in seconds)
my $DEFAULT_SESSION_TIMEOUT = 1800;
my $SESSION_TIMEOUT = $DEFAULT_SESSION_TIMEOUT;
# the name of the DBI database driver
my $DB_DRIVER = "";
my $DEVEL_DB_DRIVER = "Pg";
my $PROD_DB_DRIVER = "Pg";
# the host name of the database server
my $DB_HOST = "";
my $DEVEL_DB_HOST = "devel.localhost";
my $PROD_DB_HOST = "localhost";
# the port number of the database server
my $DB_PORT = "";
my $DEVEL_DB_PORT = "5432";
my $PROD_DB_PORT = "5432";
# the name of the database for sessions/pgtiou mapping
my $DB_NAME = "";
my $DEVEL_DB_NAME = "apache_cas";
my $PROD_DB_NAME = "apache_cas";
# the name of the session table
my $DB_SESSION_TABLE = "";
my $DEVEL_DB_SESSION_TABLE = "cas_sessions";
my $PROD_DB_SESSION_TABLE = "cas_sessions";
# the name of the pgtiou to pgt mapping table
my $DB_PGTIOU_TABLE = "";
my $DEVEL_DB_PGTIOU_TABLE = "cas_pgtiou_to_pgt";
my $PROD_DB_PGTIOU_TABLE = "cas_pgtiou_to_pgt";
# the user to connnect to the database with
my $DB_USER = "";
my $DEVEL_DB_USER = "develuser";
my $PROD_DB_USER = "produser";
# the password to connect to the databse with
my $DB_PASS = "";
my $DEVEL_DB_PASS = "develpass";
my $PROD_DB_PASS = "prodpass";
# whether or not we want redirect magic to remove service ticket from URL
my $DEFAULT_REMOVE_TICKET = "0";
my $REMOVE_TICKET = $DEFAULT_REMOVE_TICKET;
# are we running with production config, or other?
my $PRODUCTION = "0";
# session cleanup threshold (1 in N requests, session cleanup will occur for
# each Apache thread or process - i.e. for 10 processes, it may take as many as
# 100 requests before session cleanup is performed for a threshold of 10)
my $SESSION_CLEANUP_THRESHOLD = "10";
# when set to true, this module will attempt to make the underlying authz
# mechanism believe that "Basic" authentication has occurred
my $PRETEND_BASIC_AUTH = "0";
# this will turn on initialization that will only occur once for each apache
# process, meaning that changes will require a restart.  This has the benefit
# of speed for high-load sites, but will typically not be what you want.  The
# config of the first resource protected by AuthCAS will persist for the apache
# process that served up the request
my $STATIC_INITIALIZATION = "0";

if (!defined($INITIALIZED)) {
	# default to not initialized
	$INITIALIZED = 0;
}
if (!defined($SESSION_CLEANUP_COUNTER)) {
	# default to 0
	$SESSION_CLEANUP_COUNTER = 0;
}

my $tmp;

sub initialize($$) {
	my $self = shift;
	my $r = shift;

	# get all of our settings from the server config

	# logging
	if ($tmp = $r->dir_config("CASLogLevel")) {
		$LOG_LEVEL = $tmp;
	} else {
		# default
		$LOG_LEVEL = $DEFAULT_LOG_LEVEL;
	}
	
	Apache->warn("$$: CAS: initialize()") unless ($LOG_LEVEL < $LOG_INFO);

	# determine if we are running in production
	if ($tmp = $r->dir_config("CASProduction")) {
		if (defined($tmp) and ($tmp ne "") and 
			(($tmp eq "1") or ($tmp =~ /true/i))) 
		{
			$PRODUCTION = 1;
		}
		Apache->warn("$$: CAS: initialize(): setting CASProduction to $PRODUCTION") unless ($LOG_LEVEL < $LOG_INFO);
	} else {
		# default
		$PRODUCTION = 0;

lib/Apache/AuthCAS.pm  view on Meta::CPAN

		Apache->warn("$$: CAS: initialize(): setting database host to $DB_HOST") unless ($LOG_LEVEL < $LOG_INFO);
	
	}
	if ($tmp = $r->dir_config("CASDatabasePort")) {
		$DB_PORT = $tmp;
		Apache->warn("$$: CAS: initialize(): setting database port to $DB_PORT") unless ($LOG_LEVEL < $LOG_INFO);
	} elsif ($PRODUCTION) {
		$DB_PORT = $PROD_DB_PORT;
		Apache->warn("$$: CAS: initialize(): setting database port to $DB_PORT") unless ($LOG_LEVEL < $LOG_INFO);
	} else {
		# default
		$DB_PORT = $DEVEL_DB_PORT;
		Apache->warn("$$: CAS: initialize(): setting database port to $DB_PORT") unless ($LOG_LEVEL < $LOG_INFO);
	}
	if ($tmp = $r->dir_config("CASDatabaseName")) {
		$DB_NAME = $tmp;
		Apache->warn("$$: CAS: initialize(): setting database name to $DB_NAME") unless ($LOG_LEVEL < $LOG_INFO);
	} elsif ($PRODUCTION) {
		$DB_NAME = $PROD_DB_NAME;
		Apache->warn("$$: CAS: initialize(): setting database name to $DB_NAME") unless ($LOG_LEVEL < $LOG_INFO);
	} else {
		# default
		$DB_NAME = $DEVEL_DB_NAME;
		Apache->warn("$$: CAS: initialize(): setting database name to $DB_NAME") unless ($LOG_LEVEL < $LOG_INFO);
	}
	if ($tmp = $r->dir_config("CASDatabaseSessionTable")) {
		$DB_SESSION_TABLE = $tmp;
		Apache->warn("$$: CAS: initialize(): setting session table to $DB_SESSION_TABLE") unless ($LOG_LEVEL < $LOG_INFO);
	} elsif ($PRODUCTION) {
		$DB_SESSION_TABLE = $PROD_DB_SESSION_TABLE;
		Apache->warn("$$: CAS: initialize(): setting session table to $DB_SESSION_TABLE") unless ($LOG_LEVEL < $LOG_INFO);
	} else {
		# default
		$DB_SESSION_TABLE = $DEVEL_DB_SESSION_TABLE;
		Apache->warn("$$: CAS: initialize(): setting session table to $DB_SESSION_TABLE") unless ($LOG_LEVEL < $LOG_INFO);
	}
	if ($tmp = $r->dir_config("CASDatabasePGTIOUTable")) {
		$DB_PGTIOU_TABLE = $tmp;
		Apache->warn("$$: CAS: initialize(): setting pgtiou table to $DB_PGTIOU_TABLE") unless ($LOG_LEVEL < $LOG_INFO);
	} elsif ($PRODUCTION) {
		$DB_PGTIOU_TABLE = $PROD_DB_PGTIOU_TABLE;
		Apache->warn("$$: CAS: initialize(): setting pgtiou table to $DB_PGTIOU_TABLE") unless ($LOG_LEVEL < $LOG_INFO);
	} else {
		# default
		$DB_PGTIOU_TABLE = $DEVEL_DB_PGTIOU_TABLE;
		Apache->warn("$$: CAS: initialize(): setting pgtiou table to $DB_PGTIOU_TABLE") unless ($LOG_LEVEL < $LOG_INFO);
	}
	if ($tmp = $r->dir_config("CASDatabaseUser")) {
		$DB_USER = $tmp;
		Apache->warn("$$: CAS: initialize(): setting database user to $DB_USER") unless ($LOG_LEVEL < $LOG_INFO);
	} elsif ($PRODUCTION) {
		$DB_USER = $PROD_DB_USER;
		Apache->warn("$$: CAS: initialize(): setting database user to $DB_USER") unless ($LOG_LEVEL < $LOG_INFO);
	} else {
		# default
		$DB_USER = $DEVEL_DB_USER;
		Apache->warn("$$: CAS: initialize(): setting database user to $DB_USER") unless ($LOG_LEVEL < $LOG_INFO);
	}
	if ($tmp = $r->dir_config("CASDatabasePass")) {
		$DB_PASS = $tmp;
		Apache->warn("$$: CAS: initialize(): setting database password to $DB_PASS") unless ($LOG_LEVEL < $LOG_INFO);
	} elsif ($PRODUCTION) {
		$DB_PASS = $PROD_DB_PASS;
		Apache->warn("$$: CAS: initialize(): setting database password to $DB_PASS") unless ($LOG_LEVEL < $LOG_INFO);
	} else {
		# default
		$DB_PASS = $DEVEL_DB_PASS;
		Apache->warn("$$: CAS: initialize(): setting database password to $DB_PASS") unless ($LOG_LEVEL < $LOG_INFO);
	}

	if (!$DB_HOST or !$DB_PORT or !$DB_NAME or !$DB_USER or !$DB_PASS) {
		Apache->warn("$$: CAS: initialize(): database not properly configured.  Please specify: 'CASDatabaseHost', 'CASDatabasePort', 'CASDatabaseName', 'CASDatabaseUser', 'CASDatabasePassword'");
	}

	if ($tmp = $r->dir_config("CASRemoveTicket")) {
		$REMOVE_TICKET = $tmp;
		Apache->warn("$$: CAS: initialize(): setting CASRemoveTicket to $REMOVE_TICKET") unless ($LOG_LEVEL < $LOG_INFO);
	} else {
		# default
		$REMOVE_TICKET = $DEFAULT_REMOVE_TICKET;
	}

	# specify that we have been successfully initialized
	$INITIALIZED = 1;
}

# used for underlying services that need proxy tickets (PTs)
sub authenticate($$) {
	my $self = shift;
	my $r = shift;
	my $tmp;

	# Only authenticate the first internal request
	return (MP2 ? Apache::OK : Apache::Constants::OK) unless $r->is_initial_req;

	# get our configuration, unless we already have and we are running static
	unless ($STATIC_INITIALIZATION and $INITIALIZED) {
		$self->initialize($r);
	}

	# perform any cleanup that is needed
	$self->cleanup($r);
	
	Apache->warn("$$: CAS: authenticate()") unless ($LOG_LEVEL < $LOG_DEBUG);

	# see if any of our other handlers have specified that they have already
	# sufficiently checked the authenticating user
	my $authenticated = $r->subprocess_env->{'AUTHENTICATED'} || "";
	Apache->warn("$$: CAS: authenticated='$authenticated'") unless ($LOG_LEVEL < $LOG_DEBUG);

	if ($authenticated eq "true") {
		return (MP2 ? Apache::OK : Apache::Constants::OK);
	}

	# Parse the query string to get the ticket, plus any GET variables
	# to rebuild our service string (which is needed for CAS to send the
	# client back to the originating service).

	# grab the uri that was requested
	my $uri = $r->parsed_uri;
	my $path = $uri->path();
	my $unparsed = $uri->unparse();
	my $query = $uri->query || "";
	if ($query) {
		$path .= "?$query";
	} elsif ($unparsed =~ /\?$/) {
		$path .= "?";
	}

lib/Apache/AuthCAS.pm  view on Meta::CPAN

		Apache->warn("$$: CAS: this_url(): 2: setting port to '$local_port2'") unless ($LOG_LEVEL < $LOG_DEBUG);
		$port = $local_port2;
	} elsif ($local_port3 ne "") {
		Apache->warn("$$: CAS: this_url(): 3: setting port to '$local_port3'") unless ($LOG_LEVEL < $LOG_DEBUG);
		$port = $local_port3;
	}

	my $scheme = $uri->scheme;
	if (($scheme eq "http") && ($local_port eq "80")) {
		return "$scheme://$local_hostname$path";
	} elsif (($scheme eq "https") && ($local_port eq "443")) {
		return "$scheme://$local_hostname$path";
	}
	return "$scheme://$local_hostname:$local_port$path";
}

sub this_url_encoded ($$) {
	# get our request and log object
	my ($self, $r) = @_;

	Apache->warn("$$: CAS: this_url_encoded()") unless ($LOG_LEVEL < $LOG_DEBUG);

	my $url = $self->this_url($r);

	return $self->urlEncode($url);
}

1;
__END__

=head1 NAME

Apache::AuthCAS - A configurable Apache authentication module that enables you
to protect content on an Apache server using an existing Yale CAS
authentication server.

=head1 SYNOPSIS

C<perl -MCPAN -e 'install Apache::AuthCAS'>

=head1 DESCRIPTION

=head2 General

This module should be loaded in the mod_perl startup script or equivalent.

Add the following lines to an Apache configuration file or .htaccess file:

    AuthType Apache::AuthCAS
    AuthName "CAS"
    PerlAuthenHandler Apache::AuthCAS->authenticate
    require valid-user

    *note* - this simple config assumes that custom settings are configured
             into the module itself.  If not, they will need to be specified
             with PerlSetVar params (see below for examples).

You can configure this module by placing the devel/production settings in the
module itself.  This is particular handy if you would like to make
authentication with this module available via .htaccess to users whom you would
rather not share the database username/password with.

Any options that are not set in the Apache configuration will default to the
values preconfigured in the Apache::AuthCAS module.  Either explicitly override
those options that do not match your environment or set them in the module
itself.

The I<Apache::AuthCAS> module allows a user to protect their non-Java content
on an Apache server with the Yale CAS authentication server.

=head2 Requirements

Perl modules:
    Net::SSLeay
    MIME::Base64
    DBI
    DBD::<module name> (i.e. DBD::Pg)

=head2 Proxiable Credentials

This module can be optionally configured to use proxy credentials.  This is
enabled by setting the I<CASService> and I<CASProxyService> configuration
parameters.

=head2 Examples

Example configuration without proxiable credentials, which assumes that the
module itself has been configured with devel and production variables set:

    AuthType Apache::AuthCAS
    AuthName "CAS"
    PerlAuthenHandler Apache::AuthCAS->authenticate
    PerlSetVar CASProduction "1"
    require valid-user

Example configuration without proxiable credentials, which has not been
modified:

    AuthType Apache::AuthCAS
    AuthName "CAS"
    PerlAuthenHandler Apache::AuthCAS->authenticate
    PerlSetVar CASHost "auth.somedomain.com"
    PerlSetVar CASPort "443"
    PerlSetVar CASErrorURL "https://somedomain.com/cas/error/"
    PerlSetVar CASDatabaseName "cas"
    PerlSetVar CASDatabaseHost "db.somedomain.com"
    PerlSetVar CASDatabasePort "5432"
    PerlSetVar CASDatabaseDriver "Pg"
    PerlSetVar CASDatabaseUser "dbuser"
    PerlSetVar CASDatabasePass "dbpass"
    PerlSetVar CASSessionCookieName "APACHECAS"
    PerlSetVar CASSessionTimeout "1800"
    PerlSetVar CASLogLevel "0"
    PerlSetVar CASRemoveTicket "false"

    require valid-user

Example configuration with proxiable credentials, which assumes that the module
itself has been configured with devel and production variables set:

    AuthType Apache::AuthCAS

lib/Apache/AuthCAS.pm  view on Meta::CPAN

    PerlAuthenHandler Apache::AuthCAS->authenticate
    PerlSetVar CASService "https://somedomain.com/email/"
    PerlSetVar CASProxyService "mail.somedomain.com"
    PerlSetVar CASNumProxyTickets "1"
    PerlSetVar CASHost "auth.somedomain.com"
    PerlSetVar CASPort "443"
    PerlSetVar CASErrorURL "https://somedomain.com/cas/error/"
    PerlSetVar CASDatabaseName "cas"
    PerlSetVar CASDatabaseHost "db.somedomain.com"
    PerlSetVar CASDatabasePort "5432"
    PerlSetVar CASDatabaseDriver "Pg"
    PerlSetVar CASDatabaseUser "dbuser"
    PerlSetVar CASDatabasePass "dbpass"
    PerlSetVar CASSessionCookieName "APACHECAS"
    PerlSetVar CASSessionTimeout "1800"
    PerlSetVar CASLogLevel "0"
    PerlSetVar CASRemoveTicket "false"

    require valid-user

=head2 Configuration Options

These are Apache configuration option examples for Apache::AuthCAS

    # the host name of the CAS server
    PerlSetVar CASHost "auth.somedomain.com"

    # the port number for the CAS server
    PerlSetVar CASPort "443"

    # are we running with production config or dev config
    PerlSetVar CASProduction "1"

    # the URL a client is redirected to after logging in
    PerlSetVar CASService "https://somedomain.com/email/"

    # the service proxy tickets will be granted for
    PerlSetVar CASProxyService "mail.somedomain.com"

    # number of proxy tickets to give the underlying application
    PerlSetVar CASNumProxyTickets "2"

    # the URL the client is redirected to when an error occurs
    PerlSetVar CASErrorURL "https://somedomain.com/error/"

    # the name of the DBI database driver
    PerlSetVar CASDatabaseDriver "Pg"

    # the host name of the database server
    PerlSetVar CASDatabaseHost "db.somedomain.com"

    # the port number of the database server
    PerlSetVar CASDatabasePort "5433"

    # the name of the database for sessions/pgtiou mapping
    PerlSetVar CASDatabaseName "cas"

    # the user to connnect to the database with
    PerlSetVar CASDatabaseUser "dbuser"

    # the password to connect to the databse with
    PerlSetVar CASDatabasePass "dbpass"

    # the name of the session table
    PerlSetVar CASDatabaseSessionTable "cas_sessions"

    # the name of the pgtiou to pgt mapping table
    PerlSetVar CASDatabasePGTIOUTable "cas_pgtiou_to_pgt"

    # the level of logging
    PerlSetVar CASLogLevel "4"

    # whether we should perform a redirect, stripping the service ticket
    # once we have already created a session for the client
    PerlSetVar CASRemoveTicket "true"

    # the name of the cookie that will be used for sessions
    PerlSetVar CASSessionCookieName "APACHECAS"
    
    # the max time before a session expires (in seconds)
    PerlSetVar CASSessionTimeout "1800"

    # not currently able to override through Apache configuration:
    #   CAS login URI
    #   CAS logout URI
    #   CAS proxy URI
    #   CAS proxy validate URI
    #   CAS service validate URI
    #   parameter used to pass in PGTIOU
    #   parameter used to pass in PGT
    #   session cleanup threshold
    #   basic authentication emulation

=head1 NOTES

Any options that are not set in the Apache configuration will default to the
values preconfigured in the Apache::AuthCAS module.  Either explicitly override
those options that do not match your environment or set them in the module
itself.

=head1 COMPATIBILITY

This module should work in both mod_perl 1 and 2.  For Apache 2/mod_perl 2, the
Apache::compat may need to be loaded in your mod_perl startup script.  This can
be done by adding:

    use Apache::compat;

into the script included by the PerlRequire directive in your Apache
configuration.  For instance, if your Apache configuration includes the line:

    PerlRequire /usr/local/sbin/modperl_startup.pl

then the "use" line mentioned above should be added to this file.  Consult the
mod_perl documentation for more information regarding mod_perl startup scripts.

=head1 SEE ALSO

=head2 Official Yale CAS Website

http://www.yale.edu/tp/auth/



( run in 1.162 second using v1.01-cache-2.11-cpan-39bf76dae61 )