pax_global_header00006660000000000000000000000064125565727070014532gustar00rootroot0000000000000052 comment=b506389c9802094f5d88a723ac8d81e971b2d4a4 mod_auth_tkt-2.3.99b1/000077500000000000000000000000001255657270700145435ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/.bzrignore000066400000000000000000000003161255657270700165450ustar00rootroot00000000000000{arch} .arch-ids apache_test_config.pm extra.conf extra.conf.in httpd.conf mod_auth_tkt.3 Makedefs mod_auth_tkt.la mod_auth_tkt.lo mod_auth_tkt.slo .libs t/htdocs/index.html t/logs/* *.loT sha2.lo sha2.slo mod_auth_tkt-2.3.99b1/.gitignore000066400000000000000000000001271255657270700165330ustar00rootroot00000000000000.*.sw? Makedefs Makefile.old *.a *.la *.lo *.o *.slo *.so doc/mod_auth_tkt.3 src/.libs mod_auth_tkt-2.3.99b1/CREDITS000066400000000000000000000136431255657270700155720ustar00rootroot00000000000000 Peter Karman , Ivo De Decker (the debian maintainer), and Deitmar Berg all supplied patches to update mod_auth_tkt to work with apache 2.4. The 2.4 updates are based on their work. Bearnard Hibbins provided a cookie parsing fix for when badly behaved proxy/cache servers strip whitespace from headers. Scott Shambarger added the TKTAuthGuestEmpty directive, allowing guest access to set REMOTE_USER to "", which allows some http-auth systems to fallback to another authenticator. He also updated TKTAuthQuerySeparator to be a string (allowing better inheritance, and fixed some minor compile/build issues. David McNett contributed example code for a back-end login written in Tcl (for use with Apache Rivet). Available in contrib/tcl. Christian Folini and an anonymous Swiss bank sponsored the changes to include SHA256/SHA512 support, and to integrate and test Michael Peters' TKTAuthSecretOld functionality. Version 2.0.99b1. Michael Peters provided a patch to support a TKTAuthSecretOld fallback secret, to facilitate refreshing secrets without losing existing sessions. Version 2.0.99b1. Brian Kuschak provided patches to convert relative redirect URLs to absolute ones using current schema/hostinfo settings. Sascha Hanssen provided a ticket generator for Ruby on Rails, included in the contrib directory. Version 2.0.0rc3. Peter Karman , Jose Luis Martinez , and Ton Voon provided patches to Apache::AuthTkt to allow it to parse and validate existing tickets. Version 2.0.0rc3. Charlie Brady provided patches to honour the X-Forwarded-Host header in cookie domains and back references, if set (for use behind a proxy). Version 2.0.0rc2. Joost Cassee provide a patch to port mod_auth_tkt to Apache 2.2 and provided help testing and debugging under that environment. Version 2.0.0rc2. Philip Garrett provided patches to implement the TKTAuthGuestFallback functionlity, allowing validated users to fallback to guests on ticket timeout. Version 2.0.0rc2. Michael Peters provided a patch to add an additional TKTAuthTimeoutPostURL directive to allow timeouts on POSTs to be handled differently (since redirects back aren't sensible). Suggested by Perrin Hawkins. Version 2.0.0rc1. Jay Kline provided a patch to add an apachever argument to configure (allowing mod_auth_tkt to be built with only an apache development environment available), and provided patches to build a debian package. Version 2.0.0b8. Larry Lansing provided a patch to separate out secure cookie functionality from TKTAuthRequireSSL flag to new TKTAuthCookieSecure flag. Version 2.0.0b7. Viljo Viitanen provided patches to fix some URI and HTML escaping problems in the sample cgi scripts. Version 2.0.0b7. Christian Ramseyer pointed out a couple of build problems on Solaris and contributed fixes. Version 2.0.0b7. Ian Bicking provided patches for the excellent TKTAuthGuestLogin functionality, for additional debug output with the DEBUG_VERBOSE flag, and contributed a more complete python AuthTicket class. He also identified a bug with non-base64 quoted ticket values not being parsed correctly. Versions 2.0.0b5 and 2.0.0b6. Viljo Viitanen pointed out that using wildcard cookie domains by default allowed hostile servers on a shared domain to steal and reuse tickets. So the default is now to default to the server name only - wildcard domains can easily be used, but must be done explicitly. Version 2.0.0b4. Ian Bicking patched configure to work with a less capable getopt on FreeBSD, and provided patches to correct some non-ISO-C89 c-isms that were causing problems for his gcc. Version 2.0.0b3. Christian Klinger contributed python code to generate tickets, included in contrib/auth_ticket.pyc. Version 2.0.0b2. Luc Germain and Marc-Andre Gaudreau at Universite de Sherbrooke contributed code to generate tickets from php, included in contrib/auth_ticket.inc.php. Version 2.0.0b2. Andreas Leimbacher submitted patches to fix some bogus logging calls, to add secure cookie support to TktUtil.pm, and contributed a configure script to improve the build process. Version 2.0.0b2. Nick Cleaton identified a significant vulnerability in the calculation of the ticket md5 checksum, potentially allowing an attacker to change or manipulate their username, tokens, and/or user data, and suggested a change to the md5 checksum calculation to fix the problem. Version 2.0.0a1. Joe Laffey did a thorough security review of the code and found buffer overflow vulnerabilities in both mod_auth_tkt itself and tkt_cookie, and submitted patches to fix them. Version 1.3.11. Matti Lattu provided patches to implement the TKTAuthRequireSSL directive, to require ssl and use secure ticket cookies. Version 1.3.11. Jason Burns contributed code allowing tickets to be passed via the url instead of via cookie, and suggested the initial framework about how allowing multi-domain configurations might be able to work under mod_auth_tkt. Version 1.3.9. Christian Folini submitted some great patches enabling multiple TKTAuthToken directives allowing alternative tokens; adding the strsep() function for use on Solaris; adding the scheme (http/https etc) when generating back URLs; and suggested having user tokens made available to other handlers (which lead to the REMOTE_USER_TOKENS env variable). Version 1.3.9. # vim:tw=75 mod_auth_tkt-2.3.99b1/EXCLUDE000066400000000000000000000002661255657270700155630ustar00rootroot00000000000000EXCLUDE NOSYMLINKS TODO {arch} ,,* *.swp .libs mod_auth_tkt.o mod_auth_tkt.so mod_auth_tkt.la mod_auth_tkt.lo mod_auth_tkt.slo t/conf/* t/logs/* t/modules/* t/.configure t/.testlong mod_auth_tkt-2.3.99b1/INSTALL000066400000000000000000000071371255657270700156040ustar00rootroot00000000000000Installation ============ Requires: an apache with DSO support, either 1.3.x, 2.0.x, or 2.2.x. $ ./configure --apxs=/path/to/apxs $ make $ make test # (can take a while due to timeout tests) # make install (Or install from the RPMs for RHEL/CentOS 4/5). Basic Configuration ------------------- 1. Copy conf/02_auth_tkt.conf to an apache conf include directory like /etc/httpd/conf.d (or include explicitly from your httpd.conf), and edit, UPDATING THE SHARED SECRET BEFORE YOU USE. 2. If you want to use the standard mod_auth_tkt CGI scripts, copy the conf/auth_tkt_cgi.conf config to your apache conf include directory as well (e.g. /etc/httpd/conf.d), and edit. You must uncomment one of the three /var/www/auth sections there, depending on whether you want to use mod_perl 2, mod_perl 1, or vanilla CGI. The mod_perl 2 version is recommended if you have it. 3. Set up your login pages. If you want to use the supplied CGI scripts, copy the files in the 'cgi' directory somewhere useful e.g. cp -rp cgi /var/www/auth CGI scripts are available in /usr/share/doc/mod_auth_tkt-/cgi when using the RPM, to copy somewhere manually, or you can install the mod_auth_tkt-cgi package: # Installs to /var/www/auth by default rpm -Uvh mod_auth_tkt-cgi # Install somewhere else rpm -Uvh --prefix=/var/www/cgi-bin mod_auth_tkt-cgi The scripts requires perl and the CGI perl module. You will need to edit the /var/www/auth/AuthTktConfig.pm config file to define a username/password authentication function against your repository of choice (the example one uses a standard apache htpasswd file). You can also tweak a few other customisable settings there. You should also confirm you've uncommented one of the cgi sections in the 02_auth_tkt.conf config you installed in (1). 3. If you're using mod_auth_tkt on the open internet (rather than on a private network) you should probably set 'TKTAuthIgnoreIP on', at least initially. This avoids a whole class of weird problems that aren't necessarily obvious (ISP transparent proxies, for instance). If you have a very constrained set of users you may be able turn it off later after you've got everything working. Advanced Configuration Options ------------------------------ 1. Multi-domain logins: although cookies are domain-specific, mod_auth_tkt now supports multi-domain logins and logouts by passing the authentication ticket via the URL to a new domain. To setup multi-domain logins, one of your domains should be designated the primary domain, and your login and logout scripts should be configured as normal for that domain - test your primary domain is working as desired. Then, if you are using the supplied CGI scripts, you should use 'autologin' mode for the secondary domains, which basically just looks for an existing ticket (on the primary domain) and passes it via a URL parameter back to your secondary domain. Autologin mode is configured by creating a symbolic link to 'login.cgi' called 'autologin.cgi' and using the autologin.cgi version in your TKTAuthLoginURL. Something like the following should then work for all your domains: AuthType None require valid-user TKTAuthCookieName auth_tkt TKTAuthLoginURL https://www.mydomain.com/auth/autologin.cgi TKTAuthTimeoutMin 60 (Note that no TKTAuthDomain is set, because this fragment is being used for multiple domains. TKTAuthDomain defaults to the parent domain when undefined - .mydomain.com in this case - which is usually what you want.) mod_auth_tkt-2.3.99b1/LICENSE000066400000000000000000000065211255657270700155540ustar00rootroot00000000000000/* ==================================================================== * Portions Copyright (c) 2001-2006 Open Fusion Pty Ltd (Australia). * All rights reserved. * Portions Copyright (c) 2000 Liquid Digital Information Systems, Inc. * All rights reserved. * * Portions of this software were written for Open Fusion Pty. Ltd. * by Gavin Carr and are hereby contributed to the Apache Software * Foundation for distribution under the Apache license, as follows. * * Portions of this software were written for Liquid Digital Information * Systems, Inc. by Raimondas Kiveris and are hereby contributed to the * Apache Software Foundation for distribution under the Apache license, * as follows. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * 4. The names "Apache Server" and "Apache Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Group and was originally based * on public domain software written at the National Center for * Supercomputing Applications, University of Illinois, Urbana-Champaign. * For more information on the Apache Group and the Apache HTTP server * project, please see . * */ mod_auth_tkt-2.3.99b1/Makefile000066400000000000000000000004141255657270700162020ustar00rootroot00000000000000TARGETS = all install clean TESTS = test $(TARGETS): Makedefs cd src && $(MAKE) $@ cd doc && $(MAKE) $@ Makedefs: ./configure realclean: cd src && make clean cd t && make realclean test -f Makedefs && rm -f Makedefs $(TESTS): cd t && $(MAKE) $@ # vim:noet mod_auth_tkt-2.3.99b1/NOSYMLINKS000066400000000000000000000000001255657270700161620ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/README.md000066400000000000000000000214321255657270700160240ustar00rootroot00000000000000Introduction ------------ See the INSTALL file for installation instructions. *NOTE: this version of mod_auth_tkt (2.0.x) works with Apache 1.3.x, 2.0.x, and 2.2.x. The older mod_auth_tkt 1.3.x is now deprecated, and all users are encouraged to upgrade.* mod_auth_tkt is a lightweight cookie-based authentication module for Apache, written in C. It implements a single-signon framework that works across multiple apache instances and multiple machines. The actual authentication is done by a user-supplied CGI or script in whatever language you like (examples are provided in Perl), meaning you can authenticate against any kind of user repository you can access (password files, ldap, databases, etc.) mod_auth_tkt supports inactivity timeouts (including the ability to control how aggressively the ticket is refreshed), the ability to include arbitrary user data within the cookie, configurable cookie names and domains, and token-based access to subsections of a site. mod_auth_tkt works by checking incoming Apache requests for a (user- defined) cookie containing a valid authentication ticket. The ticket is checked by generating an MD5 checksum for the username and any (optional) user data from the ticket together with the requesting IP address and a shared secret available to the server. If the generated MD5 checksum matches the ticket's checksum, the ticket is valid and the request is authorised. Requests without a valid ticket are redirected to a configurable URL which is expected to validate the user and generate a ticket for them. This package includes a Perl module for generating the cookies; implementations for other environments should be relatively straightforward. Pros and Cons ------------- The mod_auth_tkt scheme has several advantages and only one significant disadvantage: Advantages - 1. Usable on any apache webserver: because it's written in C using only the Apache C API, mod_auth_tkt should be usable on the simplest stripped down Apache server - no mod_perl, mod_php, or servlets required. mod_auth_tkt's only requirement is that the Apache supports DSO (Dynamic Shared Objects). 2. Single-signon across Apaches and machines, including mixed environments: mod_auth_tkt enables a user to login once and then be seamlessly authorised across multiple Apaches or machines. Mixed environments work fine too - lightweight static HTML Apache with heavier mod_perl/mod_php/servlet enabled Apache, or a mixed Unix/Windows environment. Only requirements are a shared secret across all the servers. 3. Pluggable authentication and authorisation: mod_auth_tkt hands off the authentication and authorisation problem to the URL of your choice. This means that you can use whatever technology (CGI, Perl, PHP, ASP, Java etc.) and whatever repositories (passwd files, LDAP, NIS, RDBMS, radius, or any combination thereof) you like - as long as the authorising page or script generates a valid ticket for a valid user everything should work just fine. 4. Drop-in replacement for Basic Authentication: mod_auth_tkt sets the Basic Authentication REMOTE_USER environment variable on authorised requests, so that existing scripts that work with Basic Authentication should work unchanged in a mod_auth_tkt environment. 5. No server-side storage requirements: because cookies are basically a client-side storage technology, there are no storage requirements on the server side - no session database is required (although you're free to use one if it already exists). 6. Supports cross-domain authentication (as of version 1.3.8): although cookies are domain specific, the newest version of mod_auth_tkt allows initial tickets to be passed via URLs, allowing single-signon across completely unrelated domains (www.foo.com and www.bar.com). Disadvantages - 1. Requires cookies: browsers without cookie support will never have a valid ticket and will therefore never be authorised by mod_auth_tkt. There are no current plans to support non-cookie-based authentication. Protocol Details ---------------- 1. Login procedure (by user script/CGI) 1.1 User logs in by supplying user credentials to server-side login module. Login module is implemented e.g., as CGI or servlet. 1.2 Login module has access to a login database that has following information: user credentials and additional information such as user class/groups etc. 1.3 If login module finds that user credentials supplied matches the ones in database, an authentication cookie is constructed. 1.4 Contents of authentication cookie: user ID, client IP address, timestamp, optional token list, optional user data, plus an MD5 checksum to ensure the integrity of the cookie. The MD5 checksum is generated from following information: - shared secret - user ID - client IP address - timestamp - token list, if supplied - user data, if supplied 1.5 The basic format of the ticket / authentication cookie value is as follows: ticket := ['\0' ] ['\0' ] tokens := ! [ , ... ] user-data := ! 2. Request authentication by mod_auth_tkt 2.1 If no authentication cookie is present in a request, request is redirected to a configurable login URL. 2.2 If authentication cookie is present and timeout checking is enabled, timestamp in the cookie is compared with the current time on the server. If the cookie has expired, request is redirected to a configurable timeout URL. 2.3 If authentication cookie is present and not expired, MD5 checksum is generated as described in 1.4. The MD5 checksum in cookie is compared with the one generated. If they match the user is successfully authenticated. 2.4 If a TKTAuthToken is also required for this url/area, mod_auth_tkt will then check the first field of the user_data (which has been checked via the MD5 checksum in the previous step) for a comma- separated list of tokens for this user. If the required token is not found in this list, the request is redirected to a configurable unauthorised URL. 2.4 Upon successful authentication authentication mod_auth_tkt sets environment variables for user ID and user data. User data is also placed in query string. 2.5 If authentication fails, request is redirected as in 2.1. 2.6 Upon redirection in 2.1, 2.2 or 2.4 mod_auth_tkt attempts to pass the requested URL as a 'back' link so that after checking user credentials login module can bounce the request back again. If the TktAuthBackCookieName parameter is set, mod_auth_tkt will set a cookie with that name to hold this link; otherwise it will pass it as a GET parameter to the authenticating URL (back=). Cookie Format ------------- The TKTAuthCookieName cookie is constructed using following algorithm: ('+' is concatenation operation) cookie := digest + hextimestamp + user_id + '!' + user_data or if using tokens: cookie := digest + hextimestamp + user_id + '!' + token_list + '!' + user_data digest := MD5(digest0 + key) digest0 := MD5(iptstamp + key + user_id + '\0' + token_list + '\0' + user_data) iptstamp is a 8 bytes long byte array, bytes 0-3 are filled with client's IP address as a binary number in network byte order, bytes 4-7 are filled with timestamp as a binary number in network byte order. hextimestamp is 8 character long hexadecimal number expressing timestamp used in iptstamp. token_list is an optional comma-separated list of access tokens for this user. This list is checked if TKTAuthToken is set for a particular area. user_data is optional Credits and Disclaimer ---------------------- This is the Open Fusion version of the mod_auth_tkt Apache module. mod_auth_tkt was originally written by Raimondas Kiveris for Liquid Digital Information Systems, Inc. (see http://www.ldis.com/tkt_auth/), and further developed by Nelio Alves Pereira Filho (see http://www.ime.usp.br/~nelio/software/apache/). This version is the work of Gavin Carr of Open Fusion Pty. Ltd. (Australia), and the contributors cited in the CREDITS file in the distribution. The definitive site for this version is http://www.openfusion.com.au/labs. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. mod_auth_tkt-2.3.99b1/README.upgrading_to_2.0.x000066400000000000000000000015061255657270700207330ustar00rootroot00000000000000Upgrading from mod_auth_tkt version 1.3.x to version 2.0.x ========================================================== In general, upgrading should be a non-issue - just recompile and reinstall mod_auth_tkt on each of your apache instances, both apache 1.3.x and apache 2.0.x. The only gotcha is that the ticket format has changed (due to a vulnerability in the previous format), so tickets produced using the old TktUtil.pm or tkt_cookie will not work with mod_auth_tkt 2.0.x - use the new Apache::AuthTkt perl module instead (or see the contrib directory for possible alternatives). Also, the C tkt_cookie executable for generating cookies has been removed from this version due to additional vulnerabilities and the maintenance overhead. If you used that, you'll have to use the Perl cgi scripts instead, or roll your own solution. mod_auth_tkt-2.3.99b1/VERSION000066400000000000000000000000111255657270700156030ustar00rootroot000000000000002.3.99b1 mod_auth_tkt-2.3.99b1/cgi/000077500000000000000000000000001255657270700153055ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/cgi/Apache/000077500000000000000000000000001255657270700164665ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/cgi/Apache/AuthTkt.pm000066400000000000000000000405751255657270700204230ustar00rootroot00000000000000# # Module to generate authentication tickets for mod_auth_tkt apache module. # package Apache::AuthTkt; use 5.005; use Carp; use MIME::Base64; use strict; use vars qw($VERSION $AUTOLOAD); $VERSION = 2.1; my $me = 'Apache::AuthTkt'; my $PREFIX = 'TKTAuth'; my %DEFAULTS = ( digest_type => 'MD5', cookie_name => 'auth_tkt', back_arg_name => 'back', timeout => 2 * 60 * 60, timeout_min => 2 * 60, timeout_refresh => 0.5, guest_login => 0, guest_user => 'guest', ignore_ip => 0, require_ssl => 0, cookie_secure => 0, ); my %BOOLEAN = map { $_ => 1 } qw( TKTAuthGuestLogin TKTAuthIgnoreIP TKTAuthRequireSSL TKTAuthCookieSecure ); # Default TKTAuthDomain to host part of HTTP_HOST, or SERVER_NAME ($DEFAULTS{TKTAuthDomain}) = split /:/, $ENV{HTTP_HOST} || ''; $DEFAULTS{TKTAuthDomain} ||= $ENV{SERVER_NAME}; my %ATTR = map { $_ => 1 } qw( conf secret secret_old digest_type cookie_name back_cookie_name back_arg_name domain cookie_expires login_url timeout_url post_timeout_url unauth_url timeout timeout_min timeout_refresh token debug guest_login guest_user ignore_ip require_ssl cookie_secure ); #my %TICKET_ARGS = map { $_ => 1 } # digest_type => [ module, function ] my %DIGEST_TYPE = ( MD5 => [ 'Digest::MD5', 'md5_hex' ], SHA256 => [ 'Digest::SHA', 'sha256_hex' ], SHA512 => [ 'Digest::SHA', 'sha512_hex' ], ); # Helper routine to convert time units into seconds my %units = ( s => 1, m => 60, h => 3600, d => 86400, w => 7 * 86400, M => 30 * 86400, y => 365 * 86400, ); sub convert_time_seconds { my $self = shift; local $_ = shift; return $1 if m/^\s*(\d+)\s*$/; my $sec = 0; while (m/\G(\d+)([shdwmMy])\b\s*/gc) { my $amt = $1; my $unit = $2 || 's'; $sec += $amt * $units{$unit}; # print STDERR "$amt : $unit : $sec\n"; } return $sec; } # Parse (simplistically) the given apache config file for TKTAuth directives sub parse_conf { my $self = shift; my ($conf) = @_; my %seen = (); open CF, "<$conf" or die "[$me] open of config file '$conf' failed: $!"; # Take settings from first instance of each TKTAuth directive found local $/ = "\n"; while () { if (m/^\s*(${PREFIX}\w+)\s+(.*)/) { $seen{$1} = $2 unless exists $seen{$1}; } } close CF; die "[$me] TKTAuthSecret directive not found in config file '$conf'" unless $seen{TKTAuthSecret}; # Set directives as $self attributes my %merge = ( %seen ); for my $directive (keys %merge) { local $_ = $directive; s/^TKTAuth(\w)/\L$1/; s/([a-z])([A-Z]+)/\L$1_$2/g; $merge{$directive} =~ s/^"([^"]+)"$/$1/ if $merge{$directive}; if ($BOOLEAN{$directive}) { $merge{$directive} = 0 if $merge{$directive} =~ m/^(off|no|false)$/i; $merge{$directive} = 1 if $merge{$directive} =~ m/^(on|yes|true)$/i; } elsif (defined $merge{$directive}) { $merge{$directive} =~ s/^\s+//; $merge{$directive} =~ s/\s+$//; } if ($directive eq 'TKTAuthCookieExpires' || $directive eq 'TKTAuthTimeout') { $self->{$_} = $self->convert_time_seconds($merge{$directive}); } # Don't allow TKTAuthDebug to turn on debugging here elsif ($directive ne 'TKTAuthDebug') { $self->{$_} = $merge{$directive}; } } } # Process constructor args sub init { my $self = shift; my %arg = @_; # Check for invalid args for (keys %arg) { croak "[$me] invalid argument to constructor: $_" unless exists $ATTR{$_}; } # Parse config file if set if ($arg{conf}) { $self->parse_conf($arg{conf}); } # Store/override from given args $self->{$_} = $arg{$_} foreach keys %arg; croak "[$me] bad constructor - 'secret' or 'conf' argument required" unless $self->{conf} || $self->{secret}; croak "[$me] invalid digest_type '" . $self->{digest_type} . "'" unless $DIGEST_TYPE{ $self->{digest_type } }; $self; } # Constructor sub new { my $class = shift; my $self = { %DEFAULTS }; bless $self, $class; $self->init(@_); } # Setup autoload accessors/mutators sub AUTOLOAD { my $self = shift; my $attr = $AUTOLOAD; $attr =~ s/.*:://; die qq(Can't locate object method "$attr" via package "$self") unless $ATTR{$attr}; @_ and $self->{$attr} = $_[0]; return $self->{$attr}; } sub DESTROY {} sub errstr { my $self = shift; $@[0] and $self->{errstr} = join ' ', @_; $self->{errstr}; } # Return a mod_auth_tkt ticket containing the given user details sub ticket { my $self = shift; my %DEFAULTS = ( base64 => 1, data => '', tokens => '', ); my %arg = ( %DEFAULTS, %$self, @_ ); $arg{uid} = $self->guest_user unless exists $arg{uid}; $arg{ip_addr} = $arg{ignore_ip} ? '0.0.0.0' : $ENV{REMOTE_ADDR} unless exists $arg{ip_addr}; # 0 or undef ip_addr treated as 0.0.0.0 $arg{ip_addr} ||= '0.0.0.0'; # Data cleanups if ($arg{tokens}) { $arg{tokens} =~ s/\s+,/,/g; $arg{tokens} =~ s/,\s+/,/g; } # Data checks if ($arg{ip_addr} !~ m/^([12]?[0-9]?[0-9]\.){3}[12]?[0-9]?[0-9]$/) { $self->errstr("invalid ip_addr '$arg{ip_addr}'"); return undef; } if ($arg{tokens} =~ m/[!\s]/) { $self->errstr("invalid chars in tokens '$arg{tokens}'"); return undef; } # Calculate the hash for the ticket my $ts = $arg{ts} || time; my $digest = $self->_get_digest($ts, $arg{ip_addr}, $arg{uid}, $arg{tokens}, $arg{data}, $arg{debug}); # Construct the ticket itself my $ticket = sprintf "%s%08x%s!", $digest, $ts, $arg{uid}; $ticket .= $arg{tokens} . '!' if $arg{tokens}; $ticket .= $arg{data}; return $arg{base64} ? encode_base64($ticket, '') : $ticket; } sub _get_digest_function { my $self = shift; die "Invalid digest_type '" . $self->digest_type . "'\n" unless $DIGEST_TYPE{ $self->digest_type }; my ($module, $func) = @{ $DIGEST_TYPE{ $self->digest_type } }; eval "require $module"; return eval "\\&${module}::$func"; } sub _get_digest { my ($self, $ts, $ip_addr, $uid, $tokens, $data, $debug) = @_; my @ip = split /\./, $ip_addr; my @ts = ( (($ts & 0xff000000) >> 24), (($ts & 0xff0000) >> 16), (($ts & 0xff00) >> 8), (($ts & 0xff)) ); my $ipts = pack("C8", @ip, @ts); my $raw = $ipts . $self->secret . $uid . "\0" . $tokens . "\0" . $data; my $digest_function = $self->_get_digest_function; my $digest0 = $digest_function->($raw); my $digest = $digest_function->($digest0 . $self->secret); if ($debug) { print STDERR "ts: $ts\nip_addr: $ip_addr\nuid: $uid\ntokens: $tokens\ndata: $data\n"; print STDERR "secret: " . $self->secret . "\n"; print STDERR "raw: '$raw'\n"; my $len = length($raw); print STDERR "digest0: $digest0 (input length $len)\n"; print STDERR "digest: $digest\n"; } return $digest; } # Return a cookie containing a mod_auth_tkt ticket sub cookie { my $self = shift; my %DEFAULTS = ( cookie_name => 'auth_tkt', cookie_path => '/', ); my %arg = ( %DEFAULTS, %$self, @_ ); $arg{cookie_domain} ||= $self->domain; # Get ticket, forcing base64 for cookies my $ticket = $self->ticket(@_, base64 => 1) or return; my $cookie_fmt = "%s=%s%s%s%s"; my $path_elt = "; path=$arg{cookie_path}"; my $domain_elt = $arg{cookie_domain} ? "; domain=$arg{cookie_domain}" : ''; my $secure_elt = $arg{cookie_secure} ? "; secure" : ''; return sprintf $cookie_fmt, $arg{cookie_name}, $ticket, $domain_elt, $path_elt, $secure_elt; } # Returns a hashref representing the original ticket components # Returns undef if there were any errors sub validate_ticket { my $self = shift; my $ticket = shift || croak "No ticket passed to validate_ticket"; my %arg = ( %$self, @_ ); $arg{ip_addr} = $arg{ignore_ip} ? '0.0.0.0' : $ENV{REMOTE_ADDR} unless exists $arg{ip_addr}; # 0 or undef ip_addr treated as 0.0.0.0 $arg{ip_addr} ||= '0.0.0.0'; # Parse ticket my $info = $self->parse_ticket($ticket); # Validate digest my $expected_digest = $self->_get_digest( $info->{ts}, $arg{ip_addr}, $info->{uid}, $info->{tokens}, $info->{data}); return $info if $expected_digest eq $info->{digest}; return undef; } sub parse_ticket { my $self = shift; my $ticket = shift or croak "No ticket passed to parse_ticket"; my $parts = {}; # Strip possible quotes $ticket =~ s,^"|"$,,g; return if length($ticket) < 40; # Assume $ticket is not URL-escaped but may be base64-escaped my $raw = $ticket =~ m/!/ ? $ticket : decode_base64($ticket); # If $raw still doesn't have ! then it is bogus return if $raw !~ m/!/; # Deconstruct my ($digest,$ts,$uid,$extra) = ($raw =~ m/^(.{32})(.{8})(.+?)!(.*)$/); $parts->{digest} = $digest; $parts->{ts} = hex($ts); $parts->{uid} = $uid; $parts->{tokens} = ''; $parts->{data} = ''; # Tokens and data if present if (defined $extra) { if ($extra =~ m/!/) { ($parts->{tokens},$parts->{data}) = split m/!/, $extra, 2; } else { $parts->{data} = $extra; } } return $parts; } # Alias for compatibility with Jose/Ton's original patch *valid_ticket = \&validate_ticket; 1; __END__ =head1 NAME Apache::AuthTkt - module to generate authentication tickets for mod_auth_tkt apache module. =head1 SYNOPSIS # Constructor - either (preferred): $at = Apache::AuthTkt->new( conf => '/etc/httpd/conf.d/auth_tkt.conf', ); # OR: $at = Apache::AuthTkt->new( secret => '818f9c9d-91ed-4b74-9f48-ff99cfe00a0e', digest_type => 'MD5', ); # Generate ticket $ticket = $at->ticket(uid => $username, ip_addr => $ip_addr); # Or generate cookie containing ticket $cookie = $at->cookie( uid => $username, cookie_name => 'auth_tkt', cookie_domain => 'www.openfusion.com.au', ); # Access the shared secret $secret = $at->secret(); # If using the 'conf' constructor above, all other TKTAuth attributes # are also available e.g.: print $at->cookie_name(), $at->ignore_ip(), $at->request_ssl(); # Report error string print $at->errstr; =head1 INTRODUCTION Apache::AuthTkt is a module for generating and validating authentication tickets used with the 'mod_auth_tkt' apache module. Tickets are typically generated by a login web page of some kind when a user has been authenticated. The ticket contains a username/uid for the authenticated user, and often also the IP address they authenticated from, a set of authorisation tokens, and any other user data required. The ticket also includes an MD5 hash of all the included user data plus a shared secret, so that tickets can be validated by mod_auth_tkt without requiring access to the user repository. See http://www.openfusion.com.au/labs/mod_auth_tkt for mod_auth_tkt itself. =head1 DESCRIPTION =head2 CONSTRUCTOR An Apache::AuthTkt object is created via a standard constructor with named arguments. The preferred form is to point the constructor to the apache config file containing the mod_auth_tkt TKTAuthSecret directive, from which Apache::AuthTkt will parse the shared secret it needs, as well as any additional TKTAuth* directives it finds: $at = Apache::Tkt->new( conf => '/etc/httpd/conf/auth_tkt.conf', ); Alternatively, you can pass the mod_auth_tkt shared secret (the TKTAuthSecret value) and the digest_type to use (default is 'MD5') explicitly to the constructor: $at = Apache::AuthTkt->new( secret => '818f9c9d-91ed-4b74-9f48-ff99cfe00a0e', digest_type => 'SHA256', ); =head2 ACCESSORS If the 'conf' form of the constructor is used, Apache::AuthTkt parses all additional TKTAuth* directives it finds there and stores them in additional internal attributes. Those values are available via accessors named after the relevant TKTAuth directive (with the 'TKTAuth' prefix dropped and converted to lowercase underscore format) i.e. $at->secret() $at->secret_old() $at->digest_type() $at->cookie_name() $at->back_cookie_name() $at->back_arg_name() $at->domain() $at->cookie_expires() $at->login_url() $at->timeout_url() $at->unauth_url() $at->timeout() $at->timeout_refresh() $at->token () $at->guest_login() $at->ignore_ip() $at->require_ssl() =head2 TICKET GENERATION Tickets are generated using the ticket() method with named parameters: # Generate ticket $ticket = $at->ticket(uid => $username); Ticket returns undef on error, with error information available via the errstr() method: $ticket = $at->ticket or die $at->errstr; ticket() accepts the following arguments, all optional: =over 4 =item uid uid, username, or other user identifier for this ticket. There is no requirement that this be unique per-user. Default: 'guest'. =item ip_addr IP address associated with this ticket. Default: if $at->ignore_ip is true, then '0.0.0.0', otherwise $ENV{REMOTE_ADDR}; =item tokens A comma-separated list of tokens associated with this user. Typically only used if you are using the mod_auth_tkt TKTAuthToken directive. Default: none. =item data Arbitrary user data to be stored for this ticket. This data is included in the MD5 hash check. Default: none. =item base64 Flag used to indicate whether to base64-encode the ticket. Default: 1. =item ts Explicitly set the timestamp to use for this ticket. Only for testing! =back As an alternative to ticket(), the cookie() method can be used to return the generated ticket in cookie format. cookie() returns undef on error, with error information available via the errstr() method: $cookie = $at->cookie or die $at->errstr; cookie() supports all the same arguments as ticket(), plus the following: =over 4 =item cookie_name Cookie name. Should match the TKTAuthCookieName directive, if you're using it. Default: $at->cookie_name, or 'auth_tkt'. =item cookie_domain Cookie domain. Should match the TKTAuthDomain directive, if you're using it. Default: $at->domain. =item cookie_path Cookie path. Default: '/'. =item cookie_secure Flag whether to set the 'secure' cookie flag, so that the cookie is returned only in HTTPS contexts. Default: $at->require_ssl, or 0. =back =head2 TICKET PARSING AND VALIDATION You may parse and validate existing tickets with the validate_ticket() method. It takes as its first parameter the ticket to be validated, and then an optional list of named parameter overrides (e.g. ip_addr => 'x.x.x.x'). If the ticket is valid, validate_ticket returns a hashref with the following key/value pairs: =over 4 =item digest =item ts =item uid =item tokens =item data =back validate_ticket() will return undef if any errors with the ticket value are encountered. The validate_ticket() method algorithm is analogous to the function with the same name in the mod_auth_tkt C module. There is also a parse_ticket() method available that parses the ticket without running it through the validation phase, and returns the same data as validate_ticket(). This is only safe to use where you are certain that the ticket has been validated elsewhere. In general it's considerably safer to just use validate_ticket. =head2 DIGEST TYPES As of version 2.1.0, mod_auth_tkt supports multiple digest types. The following digest_types are currently supported: =over 4 =item MD5 The current default, for backwards compatibility. Requires the Digest::MD5 perl module. =item SHA256 Requires the Digest::SHA perl module. =back These can be set either via your config (the TKTAuthDigestType directive) or by passing a 'digest_type' parameter to the AuthTkt constructor. =head1 AUTHOR Gavin Carr Contributors: Peter Karman Ton Voon Jose Luis Martinez =head1 COPYRIGHT Copyright 2001-2009 Gavin Carr and contributors. This program is free software. You may copy or redistribute it under the same terms as perl itself. =cut # vim:sw=4 mod_auth_tkt-2.3.99b1/cgi/AuthTktConfig.pm000066400000000000000000000027461255657270700203660ustar00rootroot00000000000000# # Config settings for mod_auth_tkt CGI scripts # # Customise as required # package AuthTktConfig; use strict; # CSS stylesheet to use (optional) our $STYLESHEET = 'tkt.css'; # Page title (optional) our $TITLE = ''; # Fixed back location, overriding any set via back cookie or back arg our $FIXED_BACK_LOCATION = ''; # Default back location, if none set via back cookie or back arg our $DEFAULT_BACK_LOCATION = ''; # Boolean flag, whether to fallback to HTTP_REFERER for back location our $BACK_REFERER = 1; # For autologin, mode to fallback to if autologin fails ('login' or 'guest') our $AUTOLOGIN_FALLBACK_MODE = 'login'; # Additional cookies to clear on logout e.g. PHPSESSID our @NUKE_COOKIES = qw(); # Debug flag our $DEBUG = 0; # Username/password validation for login mode # (modify or point $validate_sub somewhere appropriate). # The validation routine should return a true value (e.g. 1) if the # given username/password combination is valid, and a false value # (e.g. 0) otherwise. # This version uses Apache::Htpasswd and a standard htpasswd file. sub validate { my ($username, $password) = @_; require Apache::Htpasswd; my $ht = Apache::Htpasswd->new({ passwdFile => '/etc/httpd/conf/htpasswd', ReadOnly => 1 }); return $ht->htCheckPassword($username, $password); } our $validate_sub = \&validate; # For guest mode (if used), setup guest username # Could use a counter or a random suffix etc. sub guest_user { return 'guest' } our $guest_sub = \&guest_user; 1; mod_auth_tkt-2.3.99b1/cgi/login.cgi000077500000000000000000000233461255657270700171140ustar00rootroot00000000000000#!/usr/bin/perl -w # # mod_auth_tkt sample login script - runs as a vanilla CGI, under # mod_perl 1 via Apache::Registry, and under mod_perl2 via # ModPerl::Registry. # # This script can run in a few different modes, depending on how it is # named. Copy the script to a cgi-bin area, and create appropriately # named symlinks to access the different behaviours. # Modes: # - login mode (default): request a username and password and test via # $AuthTktConfig::validate_sub - if successful, issue an auth ticket # and redirect to the back location # - autologin mode ('autologin.cgi'): [typically used to allow tickets # across multiple domains] if no valid auth ticket exists, redirect # to the login (or guest) version; otherwise automatically redirect # to the back location passing the current auth ticket as a GET # argument. mod_auth_tkt (>= 1.3.8) will turn this new ticket into # an auth cookie for the new domain if none already exists. # - guest mode ('guest.cgi'): [DEPRECATED - use TktAuthGuestLogin instead] # automatically issues an auth ticket a special username (as defined in # $AuthTktConfig::guest_sub, default 'guest'), and redirect to the back # location # use File::Basename; use lib dirname($ENV{SCRIPT_FILENAME}); use Apache::AuthTkt 0.03; use AuthTktConfig; use CGI qw(:standard); use CGI::Cookie; use URI::Escape; use URI; use strict; # ------------------------------------------------------------------------ # Configuration settings in AuthTktConfig.pm # ------------------------------------------------------------------------ # Main code begins my $at = Apache::AuthTkt->new(conf => $ENV{MOD_AUTH_TKT_CONF}); my $q = CGI->new; my ($server_name, $server_port) = split /:/, $ENV{HTTP_HOST} if $ENV{HTTP_HOST}; $server_name ||= $ENV{SERVER_NAME} if $ENV{SERVER_NAME}; $server_port ||= $ENV{SERVER_PORT} if $ENV{SERVER_PORT}; my $AUTH_DOMAIN = $at->domain || $server_name; my @auth_domain = $AUTH_DOMAIN ? ( -domain => $AUTH_DOMAIN ) : (); my $ticket = $q->cookie($at->cookie_name); my $probe = $q->cookie('auth_probe'); my $back_cookie = $q->cookie($at->back_cookie_name) if $at->back_cookie_name; my $have_cookies = $ticket || $probe || $back_cookie || ''; my $back = ''; $back = $AuthTktConfig::FIXED_BACK_LOCATION if $AuthTktConfig::FIXED_BACK_LOCATION; $back ||= $back_cookie; $back ||= $q->param($at->back_arg_name) if $at->back_arg_name; $back ||= $AuthTktConfig::DEFAULT_BACK_LOCATION if $AuthTktConfig::DEFAULT_BACK_LOCATION; $back ||= $ENV{HTTP_REFERER} if $ENV{HTTP_REFERER} && $AuthTktConfig::BACK_REFERER; if ($back && $back =~ m!^/!) { my $hostname = $server_name; my $port = $server_port; $hostname .= ':' . $port if $port && $port != 80 && $port != 443; $back = sprintf "http%s://%s%s", ($port == 443 ? 's' : ''), $hostname, $back; } elsif ($back && $back !~ m/^http/i) { $back = 'http://' . $back; } $back = uri_unescape($back) if $back && $back =~ m/^https?%3A%2F%2F/; my $back_esc = uri_escape($back) if $back; my $back_html = escapeHTML($back) if $back; my ($fatal, @errors); my ($mode, $location, $suffix) = fileparse($ENV{SCRIPT_NAME}, '\.cgi', '\.pl'); $mode = 'login' unless $mode eq 'guest' || $mode eq 'autologin'; my $self_redirect = $q->param('redirect') || 0; my $username = lc($q->param('username')); my $password = $q->param('password'); my $timeout = $q->param('timeout'); my $unauth = $q->param('unauth'); my $ip_addr = $at->ignore_ip ? '' : $ENV{REMOTE_ADDR}; my $redirected = 0; # ------------------------------------------------------------------------ # Set the auth cookie and redirect to $back my $set_cookie_redirect = sub { my ($tkt, $back) = @_; my @expires = $at->cookie_expires ? ( -expires => sprintf("+%ss", $at->cookie_expires) ) : (); my $cookie = CGI::Cookie->new( -name => $at->cookie_name, -value => $tkt, -path => '/', -secure => $at->require_ssl, @expires, @auth_domain, ); # If no $back, just set the auth cookie and hope for the best if (! $back) { print $q->header( -cookie => $cookie ); print $q->start_html, $q->p(Login successful), $q->end_html; return 0; } # Set (local) cookie, and redirect to $back print $q->header( -cookie => $cookie ); return 0 if $AuthTktConfig::DEBUG; my $b = URI->new($back); # If $back domain doesn't match $AUTH_DOMAIN, pass ticket via back GET param my $domain = $AUTH_DOMAIN || $server_name; if ($b->host !~ m/\b$domain$/i) { $back .= $b->query ? '&' : '?'; $back .= $at->cookie_name . '=' . $tkt; } # For some reason, using a Location: header doesn't seem to then see the # cookie, but a meta refresh one does - weird print $q->start_html( -head => meta({ -http_equiv => 'refresh', -content => "0;URL=$back" }), ), $q->end_html; return 1; }; # ------------------------------------------------------------------------ # Actual processing # If no cookies found, first check whether cookies are supported if (! $have_cookies) { # If this is a self redirect warn the user about cookie support if ($self_redirect) { $fatal = "Your browser does not appear to support cookies or has cookie support disabled.
\nThis site requires cookies - please turn cookie support on or try again using a different browser."; } # If no cookies and not a redirect, redirect to self to test cookies else { my $extra = ''; $extra .= 'timeout=1' if $timeout; $extra .= 'unauth=1' if $unauth; $extra = "&$extra" if $extra; print $q->header( -cookie => CGI::Cookie->new(-name => 'auth_probe', -value => 1, @auth_domain), ); # For some reason, a Location: redirect doesn't seem to then see the cookie, # but a meta refresh one does - go figure print $q->start_html( -head => meta({ -http_equiv => 'refresh', -content => ("0;URL=" . sprintf("%s%s%s?redirect=%s&%s=%s%s", $location, $mode, $suffix, $self_redirect + 1, $at->back_arg_name, $back_esc || '', $extra)) })); $redirected = 1; } } elsif ($mode eq 'autologin') { # If we have a ticket, redirect to $back, including ticket as GET param if ($ticket && $back && ! $timeout) { my $b = URI->new($back); $back .= $b->query ? '&' : '?'; $back .= $at->cookie_name . '=' . $ticket; print $q->redirect($back); $redirected = 1; } # Can't autologin - change mode to either guest or login else { $mode = $AuthTktConfig::AUTOLOGIN_FALLBACK_MODE; } } unless ($fatal || $redirected) { if (! $at) { $fatal = "AuthTkt error: " . $at->errstr; } elsif ($mode eq 'login') { if ($username) { my ($valid, $tokens) = $AuthTktConfig::validate_sub->($username, $password); if ($valid) { # my $user_data = join(':', encrypt($password), time(), ($ip_addr ? $ip_addr : '')); my $user_data = join(':', time(), ($ip_addr ? $ip_addr : '')); # Optional my $tkt = $at->ticket(uid => $username, data => $user_data, ip_addr => $ip_addr, tokens => $tokens, debug => $AuthTktConfig::DEBUG); if (! @errors) { $redirected = $set_cookie_redirect->($tkt, $back); $fatal = "Login successful."; } } else { push @errors, "Invalid username or password."; } } } elsif ($mode eq 'guest') { # Generate a guest ticket and redirect to $back my $tkt = $at->ticket(uid => $AuthTktConfig::guest_sub->(), ip_addr => $ip_addr); if (! @errors) { $redirected = $set_cookie_redirect->($tkt, $back); $fatal = "No back link found."; } } } my @style = (); @style = ( '-style' => { src => $AuthTktConfig::STYLESHEET } ) if $AuthTktConfig::STYLESHEET; my $title = $AuthTktConfig::TITLE || "\u$mode Page"; unless ($redirected) { # If here, either some kind of error or a login page if ($fatal) { print $q->header, $q->start_html( -title => $title, @style, ); } else { push @errors, qq(Your session has timed out.) if $timeout; push @errors, qq(You are not authorised to access this area.) if $unauth; print $q->header, $q->start_html( -title => $title, -onLoad => "getFocus()", @style, -script => qq( function getFocus() { document.forms[0].elements[0].focus(); document.forms[0].elements[0].select(); })); } print <

$title

Authorized Use Only

EOD if ($AuthTktConfig::DEBUG) { my $cookie_name = $at->cookie_name; my $back_cookie_name = $at->back_cookie_name || ''; my $back_arg_name = $at->back_arg_name || ''; my $cookie_expires = $at->cookie_expires || 0; print < server_name: $server_name server_port: $server_port domain: $AUTH_DOMAIN mode: $mode suffix: $suffix cookie_name: $cookie_name cookie_expires: $cookie_expires back_cookie_name: $back_cookie_name back_arg_name: $back_arg_name back: $back back_esc: $back_esc back_html: $back_html have_cookies: $have_cookies ip_addr: $ip_addr EOD if ($Apache::AuthTkt::VERSION >= 2.1) { printf "digest_type: %s\n", $at->digest_type; } print "\n"; } if ($fatal) { print qq(

$fatal

\n); } else { print qq(

\n), join(qq(
\n), @errors), "

\n" if @errors; print <
Username:
Password:
EOD print qq(\n) if $back_html; print qq(\n); } print qq(

Previous Page

\n) if $back_html; print < EOD } # vim:sw=2:sm:cin mod_auth_tkt-2.3.99b1/cgi/logout.cgi000077500000000000000000000067001255657270700173100ustar00rootroot00000000000000#!/usr/bin/perl -w # # mod_auth_tkt sample logout script # # Note that this needs script needs to be available locally on all domains # if using multiple domains (unlike login.cgi, which only needs to exist # on one domain). # use File::Basename; use lib dirname($ENV{SCRIPT_FILENAME}); use Apache::AuthTkt 0.03; use AuthTktConfig; use CGI qw(:standard); use URI::Escape; use URI; use strict; # ------------------------------------------------------------------------ # Configuration settings in AuthTktConfig.pm # ------------------------------------------------------------------------ # Main code begins my $at = Apache::AuthTkt->new(conf => $ENV{MOD_AUTH_TKT_CONF}); my $q = CGI->new; my ($server_name, $server_port) = split /:/, $ENV{HTTP_HOST}; $server_name ||= $ENV{SERVER_NAME}; $server_port ||= $ENV{SERVER_PORT}; my $AUTH_DOMAIN = $at->domain || $server_name; my $back = ''; $back = $AuthTktConfig::FIXED_BACK_LOCATION if $AuthTktConfig::FIXED_BACK_LOCATION; $back ||= $q->cookie($at->back_cookie_name) if $at->back_cookie_name; $back ||= $q->param($at->back_arg_name) if $at->back_arg_name; $back = $AuthTktConfig::DEFAULT_BACK_LOCATION if $AuthTktConfig::DEFAULT_BACK_LOCATION; $back ||= $ENV{HTTP_REFERER} if $ENV{HTTP_REFERER} && $AuthTktConfig::BACK_REFERER; my $back_html = ''; if ($back) { if ($back =~ m!^/!) { my $hostname = $server_name; my $port = $server_port; $hostname .= ':' . $port if $port && $port != 80 && $port != 443; $back = sprintf "http%s://%s%s", ($port == 443 ? 's' : ''), $hostname, $back; } elsif ($back !~ m/^http/i) { $back = 'http://' . $back; } $back = uri_unescape($back) if $back =~ m/^https?%3A%2F%2F/; $back_html = escapeHTML($back); } # Logout by resetting the auth cookie my @cookies = cookie(-name => $at->cookie_name, -value => '', -expires => '-1h', ($AUTH_DOMAIN ? (-domain => $AUTH_DOMAIN) : ())); push @cookies, map { cookie(-name => $_, -value => '', -expires => '-1h') } @AuthTktConfig::NUKE_COOKIES; my $redirected = 0; if ($back) { my $b = URI->new($back); # If $back domain doesn't match $AUTH_DOMAIN, add ticket reset to back if ($b->host !~ m/\b$AUTH_DOMAIN$/i) { $back .= $b->query ? '&' : '?'; $back .= $at->cookie_name . '='; } if ($AuthTktConfig::DEBUG) { print $q->header(-cookie => \@cookies); } else { # Set (local) cookie, and redirect to $back print $q->header( -cookie => \@cookies, # -location => $back, ); # For some reason, a Location: redirect doesn't seem to then see the cookie, # but a meta refresh one does - weird print $q->start_html( -head => meta({ -http_equiv => 'refresh', -content => "0;URL=$back" })); $redirected = 1; } } # If no $back, just set the auth cookie and hope for the best else { print $q->header(-cookie => \@cookies); } my @style = (); @style = ( '-style' => { src => $AuthTktConfig::STYLESHEET } ) if $AuthTktConfig::STYLESHEET; my $title = $AuthTktConfig::TITLE || "Logout Page"; unless ($redirected) { # If here, either some kind of error or no back ref found print $q->start_html( -title => $title, @style, ); print <

$title

EOD if ($AuthTktConfig::DEBUG) { print < back: $back back_html: $back_html EOD } print <You are now logged out.

EOD print qq(

Previous Page

\n) if $back_html; print < EOD } # vim:sw=2:sm:cin mod_auth_tkt-2.3.99b1/cgi/tkt.css000066400000000000000000000007421255657270700166240ustar00rootroot00000000000000/* mod_auth_tkt example css */ BODY { font-family: arial, helvetica, sans-serif; font-size: small; } P, TH, TD { font-family: arial, helvetica, sans-serif; font-size: small; } H1, H2, H3, H4, H5, H6 { color: #006; } H1 { font-size: x-large; } H2 { font-size: large; } H3 { font-size: medium; } .warning { color: #c00; font-size: medium; font-weight: bold; } TABLE { background-color: #eee; color: #666; border: 1px solid #ccc; padding: 20px; } mod_auth_tkt-2.3.99b1/conf/000077500000000000000000000000001255657270700154705ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/conf/02_auth_tkt.conf000066400000000000000000000017261255657270700204710ustar00rootroot00000000000000# # Brief sample auth_tkt.conf. # It is called 02_auth_tkt.conf by default to ensure it is loaded early # - if you're just going an 'Include conf.d/*.conf' (it should be loaded # before directories and virtual hosts you want to protect). If you're # using with mod_perl, though, mod_perl should be loaded before this # (call your mod_perl config 01_perl.conf, for example). # # See 'man mod_auth_tkt' for details on the individual directives. # Directives other than TKTAuthSecret usually go in Directory and # Location sections. # # LoadModule LoadModule auth_tkt_module modules/mod_auth_tkt.so # Shared secret - only uncomment here if you are *NOT* using the CGI # scripts on this host. If you are, uncomment the one in auth_tkt_cgi.conf # instead. And remember to CHANGE this if you uncomment it. #TKTAuthSecret "Managed by an admin is unable to read instructions :-)" # Digest type to use - default is MD5, alternatives are SHA256 or SHA512 #TKTAuthDigestType MD5 mod_auth_tkt-2.3.99b1/conf/auth_tkt_cgi.conf000066400000000000000000000051161255657270700210070ustar00rootroot00000000000000# # Sample auth_tkt_cgi.conf, for use with the default mod_auth_tkt cgi scripts. # # You need to uncomment the TKTAuthSecret directive, and CHANGE the string (!), # change the CHANGEME strings in the URLs appropriately, and uncomment ONE of # the /var/www/auth sections below. # # Shared secret - make sure the TKTAuthSecret is 02_auth_tkt.conf is # commented out if you uncomment this one. And do CHANGE this, of course. ;-) #TKTAuthSecret "Managed by an admin is unable to read instructions :-)" # Digest type to use - default is MD5, alternatives are SHA256 or SHA512 #TKTAuthDigestType MD5 # Query separator for generated URLs. Defaults to semi-colon (';') #TKTAuthQuerySeparator & # Used by sample CGI scripts to locate this config file SetEnv MOD_AUTH_TKT_CONF "/etc/httpd/conf.d/auth_tkt_cgi.conf" # Fake protected directory - used by sample CGI scripts to derive your # settings (set this up to mirror your real mod_auth_tkt settings) AuthType None require valid-user TKTAuthLoginURL https://www.CHANGEME.com/auth/login.cgi # If an internet server, you probably want the following on (at least initially) TKTAuthIgnoreIP on # If you just want *optional* authentication, so that casual users and robots # can still access some content, uncomment the following # TKTAuthGuestLogin on # To use the sample CGI scripts with a tarball installation, copy them from the # cgi subdirectory to somewhere appropriate e.g. # # cp -rp cgi /var/www/auth # # For an RPM system, just install the mod_auth_tkt-cgi RPM. # Sample CGI scripts, mod_perl 2.x version (recommended if you have mod_perl) #Alias /auth /var/www/auth # # Order deny,allow # Allow from all # # SetHandler perl-script # PerlResponseHandler ModPerl::Registry # PerlOptions +ParseHeaders # Options +ExecCGI # # # Deny from all # # # Sample CGI scripts, vanilla CGI version (if you don't have mod_perl) # Alias /auth /var/www/auth # # Order deny,allow # Allow from all # # Options +ExecCGI # # # Deny from all # # # Sample CGI scripts, mod_perl 1.x version (old) #Alias /auth /var/www/auth # # Order deny,allow # Allow from all # # SetHandler perl-script # PerlHandler Apache::Registry # Options +ExecCGI # # # Deny from all # # mod_auth_tkt-2.3.99b1/configure000077500000000000000000000056731255657270700164650ustar00rootroot00000000000000#!/bin/sh # # Simple configure script # # Defaults APXS=/usr/sbin/apxs test -x $APXS || APXS=/usr/bin/apxs test -x $APXS || unset APXS ME=`basename $0` DIR=`dirname $0` if [ $DIR = '.' ]; then DIR=`pwd` fi usage() { echo "usage: $ME [--apxs=/path/to/apxs] [--apachever=<1|2|2.2>] [--debug]" } die() { echo $* exit 2 } # Retrograde option handling to allow for primitive getopts ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` case $ac_option in --apxs=*) APXS=$ac_optarg ;; --apxs) ac_prev=APXS ;; --apachever=*) VERSION=$ac_optarg ;; --debug) # DEBUG="-g" DEBUG="-g -O0 -Wall -ansi -pedantic -Wno-implicit-function-declaration -Wno-long-long" ;; --debug-verbose) echo "--debug-verbose is no longer supported - use a 'TKTAuthDebug 2' directive in your config instead" DEBUG="-g" ;; -h | --help) usage; exit 0 ;; *) usage; exit 1 ;; esac done # Sanity checks test "$ac_prev" = "APXS" && die "Error: option '--apxs' requires an argument" test -n "$APXS" || die "Error: cannot locate apxs (use --apxs=/path/to/apxs)" test -x $APXS || die "Error: missing apxs '$APXS' (use --apxs=/path/to/apxs)" # Get Apache version if [ -z "$VERSION" ]; then HTTPD=`$APXS -q SBINDIR`/`$APXS -q TARGET` test -x $HTTPD || die "Error: cannot determine apache version (use --apachever=<1|2|2.2|2.4>)" VERSION=`$HTTPD -v | head -1 | sed -e 's/.*Apache\///' -e 's/^\([0-9]\.[0-9]\+\).*/\1/'` fi # Standardise test $VERSION = '2.0' && VERSION=2 test $VERSION = '20' && VERSION=2 test $VERSION = '22' && VERSION=2.2 test $VERSION = '24' && VERSION=2.4 if [ $VERSION != '1' -a $VERSION != '2' -a $VERSION != '2.2' -a $VERSION != '2.4' ]; then die "Error: apache version '$VERSION' not supported" fi # Generate Makedefs DIV="#-------------------------------------------------------------------------" WARNING="# Generated by $ME, do not edit!" test -f Makedefs && rm -f Makedefs test -f Makedefs && die "Error deleting Makedefs" echo $DIV >> Makedefs echo $WARNING >> Makedefs echo >> Makedefs echo "VERSION = $VERSION" >> Makedefs echo "APXS = $APXS" >> Makedefs test -n "$DEBUG" && echo "CFLAGS += $DEBUG" >> Makedefs if [ "$VERSION" = "1" ]; then echo "CFLAGS += -DAPACHE13" >> Makedefs echo "TARGET = mod_auth_tkt.so" >> Makedefs else echo "TARGET = mod_auth_tkt.la" >> Makedefs fi echo "BASEDIR = $DIR" >> Makedefs if [ "$MANPATH" != "" ]; then echo "MANPATH = $MANPATH" >> Makedefs else if [ -d /usr/share/man ]; then echo "MANPATH = /usr/share/man" >> Makedefs else echo "MANPATH = /usr/man" >> Makedefs fi fi MAT_VERSION=`cat VERSION` echo "MAT_VERSION = $MAT_VERSION" >> Makedefs echo >> Makedefs echo $WARNING >> Makedefs echo $DIV >> Makedefs # Finish with a 'make clean' make -s clean mod_auth_tkt-2.3.99b1/contrib/000077500000000000000000000000001255657270700162035ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/contrib/README.md000066400000000000000000000004261255657270700174640ustar00rootroot00000000000000This directory contains ticket generation code in PHP and Python contributed by members of the community. Please see the code for author and license details. In addition, the following libraries are available elsewhere on the Net: - ruby: http://www.meso.net/auth_tkt_rails mod_auth_tkt-2.3.99b1/contrib/auth_ticket.inc.php000066400000000000000000000151451255657270700217760ustar00rootroot00000000000000The program encountered an unexpected error.

Error code: $code

"; exit( ); } //--------------------------------------------------------------- // $result = getTKTHash( $ip, $user, $tokens, $data, $key, // [, $base64 [, $ts]] ); //--------------------------------------------------------------- // // Returns a string that contains the signed cookie. // // The cookie includes the ip address of the user, the user UID, the // tokens, the user data and a time stamp. The cookie can be // optionnally base64 encoded. The data is also crypted with the // encode() function. // //--------------------------------------------------------------- function getTKTHash( $ip, $user, $tokens, $data, $key, $base64 = false, $ts = "" ) { // set the timestamp to now // unless a time is specified if( $ts == "" ) { $ts = time(); } $ipts = pack( "NN", ip2long($ip), $ts ); // make the cookie signature $digest0 = md5( $ipts . $key . $user . "\0" . $tokens . "\0" . $data ); $digest = md5( $digest0 . $key ); if( $tokens ){ $tkt = sprintf( "%s%08x%s!%s!%s", $digest, $ts, encode( $user, $ts, 0 ), encode( $tokens, $ts, 4 ), encode( $data, $ts, 8 ) ); } else { $tkt = sprintf( "%s%08x%s!%s", $digest, $ts, encode( $user, $ts, 0 ), encode( $data, $ts, 8 ) ); } if( $base64 ) { return( base64_encode( $tkt ) ); } else { return( $tkt ); } } //--------------------------------------------------------------- // $result = encode( $data, $timestamp, $offset ); //--------------------------------------------------------------- // // Returns a "crypted" version of the data. The length of the data is // unchanged. // // The encryption is deactivated (the function simply returns the // string unencrypted) if the configuration variable $ENCRYPT_COOKIE // is not set to TRUE. // // The function implements a encryption algorithm that substitutes // each character for another one using a key to compute the shift // value. The key is generated from a hash of the timestamp of the // cookie and the secret key. This key is used from the offset // specified. This algorithm is reversed in the mod_auth_tkt apache // module before using the data. This may not be strictly // cryptographically secure, but should provide sufficient protection // for the personnal data included in the cookie. // //--------------------------------------------------------------- function encode( $data, $timestamp, $offset ) { $CHARS_TO_ENCODE = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.:"; $LENGTH = strlen( $CHARS_TO_ENCODE ); $md5key = md5( $timestamp . getSecretKey() ); $encoded = ""; global $ENCRYPT_COOKIE; // check if encryption is activated if( ! $ENCRYPT_COOKIE ) { return $data; } // encode the data one caracter at a time for( $i = 0; $i < strlen($data); $i++ ) { $pos = strpos( $CHARS_TO_ENCODE, $data{$i} ); if( $pos === FALSE ) { // skip characters that are not in list to encode $encoded .= $data{$i}; } else { $newPos = ($pos + (hexdec( $md5key{($offset + $i)%strlen($md5key)} )*7)) % $LENGTH; $encoded .= $CHARS_TO_ENCODE{$newPos}; // print $data{$i} . " -> $newPos " . $CHARS_TO_ENCODE{$newPos} . "
"; } } // print "
md5key = $md5key
data = $data
encoded = $encoded"; return $encoded; } //--------------------------------------------------------------- // $result = file_get_contents( $filename, $use_include_path = 0 ); //--------------------------------------------------------------- // // Returns the content of the file in a string, or false if there is // an error. // // This function exists in PHP >= 4.3.0 only // //--------------------------------------------------------------- if( !function_exists( 'file_get_contents' ) ) { function file_get_contents( $filename, $use_include_path = 0 ) { $data = ''; $file = @fopen( $filename, "rb", $use_include_path ); if( $file ) { while( !feof( $file ) ) { $data .= fread( $file, 1024 ); } fclose($file); } else { /* There was a problem opening the file. */ return FALSE; } return $data; } } ?> mod_auth_tkt-2.3.99b1/contrib/auth_ticket.py000066400000000000000000000101411255657270700210560ustar00rootroot00000000000000########################################################################## # # Copyright (c) 2005 Imaginary Landscape LLC and Contributors. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ########################################################################## import time as time_mod import md5 import cgi import Cookie class AuthTicket(object): """ This class represents an authentication token. You must pass in the shared secret, the userid, and the IP address. Optionally you can include tokens (a list of strings, representing role names), 'user_data', which is arbitrary data available for your own use in later scripts. Lastly, you can override the cookie name and timestamp. Once you provide all the arguments, use .cookie_value() to generate the appropriate authentication ticket. .cookie() generates a Cookie object, the str() of which is the complete cookie header to be sent. CGI usage:: token = auth_ticket.AuthTicket('sharedsecret', 'username', os.environ['REMOTE_ADDR'], tokens=['admin']) print 'Status: 200 OK' print 'Content-type: text/html' print token.cookie() print ... redirect HTML ... Webware usage:: token = auth_ticket.AuthTicket('sharedsecret', 'username', self.request().environ()['REMOTE_ADDR'], tokens=['admin']) self.response().setCookie('auth_tkt', token.cookie_value()) Be careful not to do an HTTP redirect after login; use meta refresh or Javascript -- some browsers have bugs where cookies aren't saved when set on a redirect. """ def __init__(self, secret, userid, ip, tokens=(), user_data='', time=None, cookie_name='auth_tkt', secure=False): self.secret = secret self.userid = userid self.ip = ip self.tokens = ','.join(tokens) self.user_data = user_data if time is None: self.time = time_mod.time() else: self.time = time self.cookie_name = cookie_name self.secure = secure def ipts(self): ip_chars = ''.join(map(chr, map(int, self.ip.split('.')))) t = int(self.time) ts = ((t & 0xff000000) >> 24, (t & 0xff0000) >> 16, (t & 0xff00) >> 8, t & 0xff) ts_chars = ''.join(map(chr, ts)) return ip_chars + ts_chars def digest0(self): return md5.new( self.ipts() + self.secret + self.userid + '\0' + self.tokens + '\0' + self.user_data).hexdigest() def digest(self): return md5.new(self.digest0() + self.secret).hexdigest() def cookie_value(self): v = '%s%08x%s!' % (self.digest(), int(self.time), self.userid) if self.tokens: v += self.tokens + '!' v += self.user_data return v def cookie(self): c = Cookie.SimpleCookie() c[self.cookie_name] = self.cookie_value().encode('base64').strip() c[self.cookie_name]['path'] = '/' if self.secure: c[self.cookie_name]['secure'] = 'true' return c mod_auth_tkt-2.3.99b1/contrib/auth_tkt.rb000066400000000000000000000071711255657270700203610ustar00rootroot00000000000000######################################################################## # # File: auth_tkt.rb # By: Sascha Hanssen, MESO Web Scapes (hanssen@meso.net, www.meso.net) # Date: 2008-01-23 # ######################################################################## # ######################################################################## # # This file defines functions to generate cookie tickets compatible # with the "mod_auth_tkt" apache module. # # Save this file to your RailsApplication/lib folder # Include functionallity with "include AuthTkt" into your controller # ######################################################################## module AuthTkt # set path to auth_tkt config file, where TKTAuthSecret is set SECRET_KEY_FILE = "/path/to/file.conf"; # set root domain to be able to single sign on (SSO) # (access all subdomains with one valid ticket) DOMAIN = ".yourdomain.com" # sets the auth_tkt cookie, returns the signed cookie string def set_auth_tkt_cookie(user, domain = nil, token_list = nil, user_data = nil, base64 = false) # get signed cookie string tkt_hash = get_tkt_hash(user, token_list, user_data, base64) cookie_data = { :value => tkt_hash } # set domain for cookie, if wanted cookie_data[:domain] = domain if domain # store data into cookie cookies[:auth_tkt] = cookie_data # return signed cookie return tkt_hash end # destroys the auth_tkt, to log an user out def destroy_auth_tkt_cookie # reset ticket value of cookie, to log out even if deleting cookie fails cookies[:auth_tkt] = { :value => '', :expire => Time.at(0), :domain => DOMAIN } cookies.delete :auth_tkt end # returns a string that contains the signed cookie content # data encryption is not implemented yet, ssl communication is # highly recommended, when tokens or user data will be used def get_tkt_hash(user, token_list = nil, user_data = nil, base64 = false) # ensure payload is not nil token_list ||= '' user_data ||= '' # set timestamp and binary string for timestamp and ip packed together timestamp = Time.now.to_i ip_timestamp = [ip2long(request.remote_ip), timestamp].pack("NN") # creating the cookie signature digest0 = Digest::MD5.hexdigest(ip_timestamp + get_secret_key + user + "\0" + token_list + "\0" + user_data) digest = Digest::MD5.hexdigest(digest0 + get_secret_key) # concatenating signature, timestamp and payload cookie = digest + timestamp.to_hex + user if token_list cookie += '!' + token_list end cookie += '!' + user_data # base64 encode cookie, if needed if base64 require 'base64' cookie = Base64.b64encode(cookie).gsub("\n", '').strip end return cookie end # returns the shared secret string used to sign the cookie # read from the scret key file, returns empty string on errors def get_secret_key secret_key = '' return '' unless File.file? SECRET_KEY_FILE open(SECRET_KEY_FILE) do |file| file.each do |line| if line.include? 'TKTAuthSecret' secret_key = line.gsub('TKTAuthSecret', '').strip.gsub("\"", '') break end end end secret_key end # function adapted according to php: generates an IPv4 Internet network address # from its Internet standard format (dotted string) representation. def ip2long(ip) long = 0 ip.split( /\./ ).reverse.each_with_index do |x, i| long += x.to_i << ( i * 8 ) end long end end # this class definition may be moved to application.rb # but works fine here, too class Integer def to_hex self.to_s(16) end end mod_auth_tkt-2.3.99b1/contrib/auth_tkt.rb.README000066400000000000000000000061711255657270700213140ustar00rootroot00000000000000To generate auth_tkt cookies or just the ticket string you can use this auth_tkt rails library. Configuration ------------- Copy auth_tkt.rb to the lib directory of your rails application. Edit it and set the following values: 1. Set the path to the secret key file (configuration file, usually 02_auth_tkt.conf) for the constant SECRET_KEY_FILE. 2. If you want to use the ticket across multiple subdomains you have to set a string for your top-level-domain for the constant DOMAIN (i.e. ".yourdomain.com"). Usage ----- To use the library, include it into your controller using "include AuthTkt". Creating the cookie string: User the function get_tkt_hash(user, token_list, user_data, base64) to get a signed cookie string. Parameters: The user should be the username. The token_list may be a group name or any token you want to use, leave it blank or set it to nil, if you don't want to use any. The user_data may be a any data you want to use, leave it blank or set it to nil, if you don't want to use any. The base64 value is a boolean, that activates base64 encoding for the ticket string, default is false. Keep in mind this is no encryption and does not protect your data from being red. Data encryption to protect your data is not implemented for this library yet. You should use SSL to prevent anybody from reading your data. Setting a cookie: Use the function set_auth_tkt_cookie(user, domain, token_list, user_data, base64) to set a cookie directly. Use the parameters as described in the section above. The parameter domain will be the value for the domain used in the cookie. It can be accessed from auth_tkt.rb via AuthTkt::DOMAIN or set to nil, if none should be use. Using acts_as_authenticated with auth_tkt ----------------------------------------- The common plugin acts_as_authenticated adds an out of the box login system to a rails application. The plugin acl_system2 adds role support to the acts_as_authenticated login system. To use the auth_tkt login with the rails plugins acts_as_authenticated and acl_system2 to get a auth_tkt ticket saved with each login you have to proceed the following steps: Install and setup the plugins acts_as_authenticated and acl_system2. Edit the file account_controller.rb: 1. add the line include AuthTkt at top of the class definition 2. add the following two lines role_titles = (self.current_user.roles.collect { |x| x.title }).join(',') set_auth_tkt_cookie(self.current_user.login, AuthTkt::DOMAIN, role_titles, nil, true) behind the row if logged_in? into the definition of the login function 3. add the following block if params[:back] and not params[:back].empty? redirect_to params[:back] return end above the line redirect_back_or_default(:controller => '/account', :action => 'index') into the definition of the login function 4. add the line destroy_auth_tkt_cookie after the line cookies.delete :auth_token into the definition of the logout function mod_auth_tkt-2.3.99b1/contrib/t/000077500000000000000000000000001255657270700164465ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/contrib/t/01_auth_ticket_py.t000066400000000000000000000024441255657270700221530ustar00rootroot00000000000000#!/usr/bin/perl # # Test auth_ticket.py against Apache::AuthTicket # use strict; use warnings FATAL => 'all'; use Test::More tests => 2; use File::Basename; BEGIN { use lib dirname($0) . "/../cgi"; } use Apache::AuthTicket; my $secret = 'cb3e1d39-98eb-4161-8bbd-f4e706999b0e'; my $ts = 1108811260; my $username = 'foobar'; my $ip = '192.168.1.1'; my ($at, $ticket1, $ticket2, $cookie1, $cookie2); # Get Apache::AuthTicket versions $at = Apache::AuthTicket->new(secret => $secret); $ticket1 = $at->ticket(uid => $username, ip_addr => $ip, ts => $ts, base64 => 0); $cookie1 = $at->cookie(uid => $username, ip_addr => $ip, ts => $ts); $cookie1 =~ s/^.*auth_tkt="?//; # Normalise " $cookie1 =~ s/"?;.*//; # Normalise " # Get auth_ticket.py versions $ticket2 = qx(python -c "import auth_ticket; atp = auth_ticket.AuthTicket('$secret', '$username', '$ip', time=$ts); print atp.cookie_value()"); chomp $ticket2; $cookie2 = qx(python -c "import auth_ticket; atp = auth_ticket.AuthTicket('$secret', '$username', '$ip', time=$ts); print atp.cookie()"); chomp $cookie2; $cookie2 =~ s/^.*auth_tkt="?//; # Normalise " $cookie2 =~ s/"?;.*//; # Normalise " # Test is($ticket1, $ticket2, 'ticket test 1'); is($cookie1, $cookie2, 'cookie test 1'); # vim:sw=2:et:sm:smartindent mod_auth_tkt-2.3.99b1/contrib/t/Makefile000066400000000000000000000001001255657270700200750ustar00rootroot00000000000000 test: perl -w *.t clean: rm -f auth_ticket.pyc # vim:noet mod_auth_tkt-2.3.99b1/contrib/t/auth_ticket.py000077700000000000000000000000001255657270700244102../auth_ticket.pyustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/contrib/tcl/000077500000000000000000000000001255657270700167655ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/contrib/tcl/auth_tkt.rvt000066400000000000000000000030501255657270700213430ustar00rootroot00000000000000 mod_auth_tkt-2.3.99b1/contrib/tcl/auth_tkt.tcl000066400000000000000000000040711255657270700213160ustar00rootroot00000000000000# # auth_tkt.tcl # # Author: David McNett - http://macnugget.org/ # Date: 29-May-2012 # # See http://www.openfusion.com.au/labs/mod_auth_tkt/ for more detail # package require sha256 namespace eval ::auth_tkt { proc logerr {buf} { puts stderr "ERROR (auth_tkt): $buf" } proc get_secret_key {filename} { set retbuf "" if {![file exists $filename]} { logerr "Unable to locate secret key file $filename" } else { if {[catch {set fh [open $filename r]} err]} { logerr "Unable to read secret key file $err" } else { while {1} { set line [gets $fh] if {[regexp -nocase {^\s*TKTAuthSecret\s+"?(.*?)"?} $line _ retbuf] || [eof $fh]} { close $fh break } } return $retbuf } } } proc get_tkt_to_array {arrvar args} { # # required arguments: # -ip Either the user's IP or 0.0.0.0 # -user User ID # -key Shared Private Key # # optional arguments: # -tokenlist Tcl list of tokens # -data User data # if {[catch {array set opts $args} err]} { logerr "Invalid get_tkt_hash arguments" return } foreach required_field {-ip -user -key} { if {![info exists opts($required_field)]} { logerr "get_tkt_hash required argument missing: $required_field" return } } upvar 1 $arrvar outarray foreach optional_field {-tokenlist -data} { if {![info exists opts($optional_field)]} { set opts($optional_field) "" } } if {[info exists opts(-timestamp)] && [ctype digit $opts(-timestamp)]} { set timestamp $opts(-timestamp) } else { set timestamp [clock seconds] } set hextimestamp [format "%8.8X" $timestamp] set iptstamp [binary format II 0 $timestamp] set outarray(payload0) "${iptstamp}$opts(-key)$opts(-user)\0[join $opts(-tokenlist) ","]\0$opts(-data)" set outarray(digest0) [::sha2::sha256 $outarray(payload0)] set outarray(digest) [::sha2::sha256 "$outarray(digest0)$opts(-key)"] set outarray(cookie) "$outarray(digest)${hextimestamp}$opts(-user)![join $opts(-tokenlist) ","]!$opts(-data)" } } package provide auth_tkt 1.0 mod_auth_tkt-2.3.99b1/doc/000077500000000000000000000000001255657270700153105ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/doc/Makefile000066400000000000000000000006201255657270700167460ustar00rootroot00000000000000SECTION=3 POD=mod_auth_tkt.pod MANPAGE=mod_auth_tkt.$(SECTION) include ../Makedefs all: $(MANPAGE) $(MANPAGE): $(POD) pod2man --section=$(SECTION) --release=$(MAT_VERSION) $(POD) $@ install: $(MANPAGE) mkdir -p $(DESTDIR)$(MANPATH)/man$(SECTION) cp $(MANPAGE) $(DESTDIR)$(MANPATH)/man$(SECTION) chmod 644 $(DESTDIR)$(MANPATH)/man$(SECTION)/$(MANPAGE) clean: -rm -f $(MANPAGE) # vim:noet mod_auth_tkt-2.3.99b1/doc/mod_auth_tkt.pod000066400000000000000000000324731255657270700205070ustar00rootroot00000000000000=head1 NAME mod_auth_tkt - apache ticket authentication module =head1 DESCRIPTION mod_auth_tkt is a lightweight cookie-based authentication module, written in C, for apache versions 1.3.x, 2.0.x, and 2.2.x It implements a single-signon framework that works across multiple apache instances, different apache versions, and multiple machines. mod_auth_tkt itself is completely repository-agnostic, as the actual authentication is done by a user-supplied CGI or script in your language of choice (examples are provided in Perl, with contrib libraries for use with python and PHP). This allows authentication against virtually any kind of user repository you can imagine (password files, ldap directories, databases, etc.) mod_auth_tkt supports inactivity timeouts (including the ability to control how aggressively the ticket is refreshed), the ability to include arbitrary user data within the cookie, configurable cookie names and domains, token-based access to subsections of a site, and optional 'guest' access for unauthenticated users. =head1 CONFIGURATION mod_auth_tkt is configured in your apache configuration files using the following set of directives (all mod_auth_tkt directives begin with 'TKTAuth'): =head2 Server Directives mod_auth_tkt supports two apache server-level directives, one required - TKTAuthDigest, the shared secret used for digest hashing - and one optional - TKTAuthDigestType, the type of digest to use in ticket hashes. Both may be global or specific to a virtual host. =over 4 =item TKTAuthSecret String - the secret used for digest hashing. This should be kept secret and changed periodically. e.g. TKTAuthSecret "w b@5b15#664038f.f9d8U19b7e25 664eY9ad2%4393e,a2ef" =item TKTAuthDigestType [ MD5 | SHA256 | SHA512 ] String, one of MD5 | SHA256 | SHA512. The digest/hash type to use in tickets. The default is MD5, which is faster, but has now been shown to be vulnerable to collision attacks. Such attacks are not directly applicable to mod_auth_tkt, which primarily relies on the security of the shared secret rather than the strength of the hashing scheme. More paranoid users will probably prefer to use one of the SHA digest types, however. The default is likely to change in a future version, so setting the digest type explicitly is encouraged. Note that using one of the SHA digest types with the perl CGI scripts requires a version of Apache::AuthTkt >= 2.1. =back =head2 Directory Directives All directory-level directives are optional, except that either TKTAuthLoginURL or TKTAuthGuestLogin (or both) must be set to cause mod_auth_tkt to be invoked for a particular directory. As usual, directory-level directives may be set in Directory or Location sections, or in .htaccess files. =over 4 =item AuthType None / require mod_auth_tkt requires the following standard apache authentication directives to trigger authentication: AuthType None require valid-user # or require user1, user2, etc. =item TKTAuthLoginURL Standard URL to which unauthenticated users are redirected. This is a required directive unless you are using guest mode via 'TKTAuthGuestLogin on'. e.g. TKTAuthLoginURL https://www.example.com/auth/login.cgi =item TKTAuthTimeoutURL URL to which users are redirected in the event their ticket times out. Default: TKTAuthLoginURL. e.g. TKTAuthTimeoutURL https://www.example.com/auth/login.cgi?timeout=1 =item TKTAuthPostTimeoutURL URL to which users are redirected in the event their ticket times out during a POST operation. This case is distinguished to allow you to handle such cases specially - you probably don't want to redirect back to the referrer after login, for instance. Default: TKTAuthTImeoutURL. e.g. TKTAuthPostTimeoutURL https://www.example.com/auth/login.cgi?posttimeout=1 =item TKTAuthUnauthURL URL to which users are redirected in the event that they are not authorised for a particular area e.g. incorrect tokens. TKTAuthUnauthURL https://www.example.com/auth/login.cgi?unauth=1 =item TKTAuthGuestLogin Flag to turn on 'guest' mode, which means that any user without a valid ticket is authenticated anyway as the TKTAuthGuestUser user. This is useful for allowing public access for guests and robots, while allowing more personalised or privileged access for users who login. Default: off. e.g. TKTAuthGuestLogin on =item TKTAuthGuestCookie Flag to indicate whether or not to issue a ticket cookie for guest users. Issuing a cookie is primarily useful where you are using UUID-ed guest users where you want them to keep the initial guest username you issue them for tracking purposes. e.g. TKTAuthGuestCookie on Default is 'off', unless you use a TKTAuthGuestUser with a UUID (see next), in which case it's 'on'. Setting explicitly is recommended, however. =item TKTAuthGuestUser Username to be used for the guest user (in the ticket uid, REMOTE_USER environment variable, etc). On apache 2.0.x and 2.2.x (but not on apache 1.3.x), the TKTAuthGuestUser may also contain a special sprintf-like pattern '%U', which is expanded to 36-character UUID, allowing individualised guest usernames. The %U may also include an integer <= 36 to limit the number of characters used in the UUID e.g. %12U, %20U etc. Default: 'guest'. Examples: TKTAuthGuestUser visitor TKTAuthGuestUser guest-%12U =item TKTAuthGuestFallback Flag to indicate that a timed out user ticket should automatically fallback to 'guest' status, and issue a new guest ticket, instead of redirecting to the TKTAuthTimeoutURL. Only makes sense with TKTAuthGuestLogin on, of course. Default: off. =item TKTAuthGuestEmpty Flag to indicate that the guest username should be an empty string. Useful for allowing applications to fallback to native authentication when REMOTE_USER is empty (NOTE: REMOTE_USER must exist to satisfy Require valid-user, but will be empty). Only makes sense with TKTAuthGuestLogin on, of course. Default: off. =item TKTAuthTimeout The ticket timeout period, in seconds. After this period, the ticket is considered stale, and the user is redirected to the TKTAuthTimeoutURL (if set, else to the TKTAuthLoginURL). Note that the ticket can be automatically refreshed, however, using the next setting. The following units can also be specified on the timeout (with no spaces between timeout and unit): y/years, M/months, w/weeks, d/days, h/hours, m/minutes, and s/seconds. This timeout is protected by the ticket hashing, so cannot be trivially modified, unlike the TKTAuthCookieExpires setting below. Setting TKTAuthTimeout to 0 means never timeout, but this is strongly discouraged, as it allows for trivial replay attacks. Set it to a week or two if you really don't want timeouts. Default: 2h. Examples: TKTAuthTimeout 86400 TKTAuthTimeout 1w TKTAuthTimeout 1w 4d 3h =item TKTAuthTimeoutRefresh A number between 0 and 1 indicating whether and how to refresh ticket timestamps. 0 means never refresh (hard timeouts). 1 means refresh tickets every time. .33 (for example) means refresh if less than .33 of the timeout period remains. This is a politeness setting for those paranoid types who have their browsers set to confirm all cookies - refreshing every time quickly becomes VERY tedious. Default: 0.5. e.g. TKTAuthTimeoutRefresh 0.66 =item TKTAuthCookieName The name used for the ticket cookie. Default: 'auth_tkt'. =item TKTAuthDomain The domain to use in ticket cookies, which defines the hosts for which the browser will submit this cookie. Default: the apache ServerName (either global or for a specific virtual host). =item TKTAuthCookieExpires B This directive is not currently supported on apache 1.3.x! The period until the cookie expires, used to set the 'expires' field on the ticket cookie, in seconds. This is useful if you want cookies to persist across browser sessions (and your login script must support it too, of course). The following units can also be specified on the expiry period (with no spaces between period and unit): y/years, M/months, w/weeks, d/days, h/hours, m/minutes, and s/seconds. Note that his is a B setting and is not protected by the ticket hashing, so you should always set a TKTAuthTimeout in addition to using an expiry. Cookie expiries are refreshed with tickets if TKTAuthTimeoutRefresh is set. Default: none (not used). e.g. TKTAuthCookieExpires 86400 TKTAuthCookieExpires 1w TKTAuthCookieExpires 1w 3d 4h =item TKTAuthBackArgName The name used for the back GET parameter. If this is set, mod_auth_tkt will add a GET parameter to all redirect URLs containing a URI-escaped version of the current requested page e.g. if the requested page is http://www.example.com/index.html and TKTAuthBackArgName is set to 'back', mod_auth_tkt will add a parameter like: back=http%3A%2F%2Fwww.example.com%2Findex.html to the TKTAuthLoginURL it redirects to, allowing your login script to redirect back to the requested page upon successful login. To omit altogether, set to the string B i.e. TKTAuthBackArgName None Default: 'back'. =item TKTAuthBackCookieName The cookie name to use for the back cookie. If this is set, mod_auth_tkt will set a back cookie containing a URI-escaped version of current requested page when redirecting (see TKTAuthBackArgName above), instead of using a GET parameter. Default: none (not used). =item TKTAuthToken String indicating a required token for the given location, implementing a simple form of token-based access control. If the user's ticket does not contain one or more of the required tokens in the ticket token list then mod_auth_tkt will redirect to the TKTAuthUnauthURL location (or TKTAuthLoginURL if not set). Your login script is expected to set the appropriate token list up at login time, of course. Note that this directive can be repeated, and the semantics are that B of the required tokens is sufficient for access i.e. the tokens are ORed. Default: none (not used). e.g. TKTAuthToken finance TKTAuthToken admin =item TKTAuthIgnoreIP Flag indicating that mod_auth_tkt should ignore the client IP address in authenticating tickets (your login script must support this as well, setting the client IP address to 0.0.0.0). This is often required out on the open internet, especially if you are using an HTTPS login page (as you should) and are dealing with more than a handful of users (the typical problem being transparent HTTP proxies at ISPs). Default: 'off' i.e. ticket is only valid from the originating IP address. e.g. TKTAuthIgnoreIP on =item TKTAuthRequireSSL Flag used to indicate that tickets should be refused except in SSL/HTTPS protected contexts (redirects to TKTAuthLoginURL if not, which presumably would be using HTTPS). Default: 'off' (B require SSL). e.g. TKTAuthRequireSSL on See also TKTAuthCookieSecure below. =item TKTAuthCookieSecure Flag used to set the 'secure' flag on all ticket cookies issued, indicating to the browser that they should only be sent in SSL/HTTPS protected contexts. Default: 'off' (B set 'secure' flag). e.g. TKTAuthCookieSecure on TKTAuthRequireSSL and TKTAuthCookieSecure are normally used together. One case where it makes sense to use them separately is where you are proxying through a separate SSL-equipped reverse proxy, where you would want to use TKTAuthCookieSecure by itself (since the proxied request will never be via SSL). =item TKTAuthDebug Turn on mod_auth_tkt debug output messages in your error log, with verbosity increasing with higher integer values. Current range: 1-3. Note that you will also require apache 'LogLevel debug' set to see these messages. =back =head1 EXAMPLES Minimal config using logins: AuthType None require valid-user TKTAuthLoginURL https://www.example.com/auth/login.cgi Minimal config using guest logins (users can still login explicitly, of course): AuthType None require valid-user TKTAuthGuestLogin on Example internet configuration: AuthType None require valid-user TKTAuthLoginURL https://www.example.com/auth/login.cgi TKTAuthTimeoutURL https://www.example.com/auth/login.cgi?timeout=1 TKTAuthPostTimeoutURL https://www.example.com/auth/login.cgi?timeout=1&post=1 TKTAuthIgnoreIP on TKTAuthTimeout 2h TKTAuthCookieExpires 2h Example intranet configuration: AuthType None require valid-user TKTAuthGuestLogin on TKTAuthLoginURL https://www.example.com/auth/login.cgi TKTAuthTimeoutURL https://www.example.com/auth/login.cgi?timeout=1 TKTAuthPostTimeoutURL https://www.example.com/auth/login.cgi?timeout=1&post=1 TKTAuthTimeout 4h TKTAuthCookieExpires 4h =head1 SUPPORT Support is available on the mod_auth_tkt mailing list, courtesy of sourceforge: =over 4 =item List modauthtkt-users@lists.sourceforge.net =item List Page and Signup https://lists.sourceforge.net/lists/listinfo/modauthtkt-users =item List Archive http://sourceforge.net/mailarchive/forum.php?forum=modauthtkt-users =back =head1 BUGS Ticket payload should include IP address, to make debugging IP address problems easier. =head1 AUTHOR Gavin Carr =head1 LICENCE mod_auth_tkt is licensed under the terms of the Apache Licence. mod_auth_tkt-2.3.99b1/mod_auth_tkt.spec000066400000000000000000000153561255657270700201130ustar00rootroot00000000000000 # Use "--define='apache 1'" to build a 'mod_auth_tkt1' package for apache1 %define httpd httpd %define name mod_auth_tkt %{?apache:%define httpd apache} %{?apache:%define name mod_auth_tkt1} %define perl_vendorlib %(eval "`perl -V:installvendorlib`"; echo $installvendorlib) Summary: Lightweight ticket-based authentication module for Apache. Name: %{name} Version: 2.3.99b1 Release: 1%{?org_tag}%{?dist} License: Apache Group: Applications/System Source: http://www.openfusion.com.au/labs/dist/mod_auth_tkt-%{version}.tar.gz URL: http://www.openfusion.com.au/labs/mod_auth_tkt/ Buildroot: %_tmppath/%{name}-%{version} Requires: %{httpd} BuildRequires: %{httpd}-devel %description mod_auth_tkt provides lightweight, repository-agnostic, ticket-based authentication for Apache. It implements a single-signon framework that works across multiple apache instances and multiple machines. The actual authentication requires a user-supplied CGI or script of some kind - see the mod_auth_tkt-cgi package for perl cgi versions. %package cgi Release: 1%{?org_tag}%{?dist} Summary: CGI scripts for mod_auth_tkt apache authentication modules. Group: Applications/System Requires: %{name} = %{version} %description cgi Perl CGI scripts for use with mod_auth_tkt. %prep %setup -n mod_auth_tkt-%{version} %build test %{httpd} == apache && APXS='--apxs=/usr/sbin/apxs1' test %{debug} == 1 && DEBUG='--debug' MOD_PERL=`rpm -q mod_perl | grep '^mod_perl' || /bin/true` if [ -n "$MOD_PERL" -a %{test} == 1 ]; then ./configure --test $DEBUG make make test else ./configure $APXS $DEBUG make fi %install test "$RPM_BUILD_ROOT" != "/" && rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT%{_libdir}/%{httpd}/modules mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/%{httpd}/conf.d #mkdir -p $RPM_BUILD_ROOT/usr/share/doc/%{name}-%{version}/cgi mkdir -p $RPM_BUILD_ROOT/usr/share/doc/%{name}-%{version}/contrib mkdir -p $RPM_BUILD_ROOT/var/www/auth #mkdir -p $RPM_BUILD_ROOT/%{perl_vendorlib}/Apache if [ %{httpd} == apache ]; then /usr/sbin/apxs1 -i -n "auth_tkt" -S LIBEXECDIR=$RPM_BUILD_ROOT%{_libdir}/%{httpd}/modules src/mod_auth_tkt.so else /usr/sbin/apxs -i -n "auth_tkt" -S LIBEXECDIR=$RPM_BUILD_ROOT%{_libdir}/%{httpd}/modules src/mod_auth_tkt.la fi install -m 644 conf/02_auth_tkt.conf $RPM_BUILD_ROOT%{_sysconfdir}/%{httpd}/conf.d/ install -m 644 conf/auth_tkt_cgi.conf $RPM_BUILD_ROOT%{_sysconfdir}/%{httpd}/conf.d/ #cp cgi/Apache/* $RPM_BUILD_ROOT/%{perl_vendorlib}/Apache #cp -pr cgi/* $RPM_BUILD_ROOT/usr/share/doc/%{name}-%{version}/cgi #rm -rf $RPM_BUILD_ROOT/usr/share/doc/%{name}-%{version}/cgi/Apache cp -pr cgi/* $RPM_BUILD_ROOT/var/www/auth rm -rf $RPM_BUILD_ROOT/var/www/auth/Apache cp -pr contrib/* $RPM_BUILD_ROOT/usr/share/doc/%{name}-%{version}/contrib rm -rf $RPM_BUILD_ROOT/usr/share/doc/%{name}-%{version}/contrib/t cp -pr README* INSTALL LICENSE ChangeLog CREDITS $RPM_BUILD_ROOT/usr/share/doc/%{name}-%{version} cd doc make DESTDIR=$RPM_BUILD_ROOT install %clean test "$RPM_BUILD_ROOT" != "/" && rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %{_libdir}/%{httpd} #%{perl_vendorlib}/Apache/AuthTkt.pm %doc /usr/share/doc/%{name}-%{version} %attr(0640,root,apache) %config(noreplace) %{_sysconfdir}/%{httpd}/conf.d/02_auth_tkt.conf /usr/share/man/*/* %files cgi %defattr(-,root,root) %attr(0640,root,apache) %config(noreplace) %{_sysconfdir}/%{httpd}/conf.d/auth_tkt_cgi.conf %config(noreplace)/var/www/auth/AuthTktConfig.pm %config(noreplace)/var/www/auth/tkt.css /var/www/auth/*.cgi %changelog * Fri Jul 31 2015 Gavin Carr 2.3.99b1-1 - Update to version 2.3.99b1, 2.4 release beta1. * Fri Jul 10 2009 Gavin Carr 2.1.0 - Bump version number to 2.1.0 for final 2.1 release. * Sat Mar 28 2009 Gavin Carr 2.0.99b2 - Bump version number to 2.0.99b2, second beta release of 2.1 branch. - Fix bug with partial-cookie-names incorrectly matching. * Thu Mar 05 2009 Gavin Carr 2.0.99b1 - Bump version number to 2.0.99b1, first beta release of 2.1 branch. - Add support for SHA256 digests. - Add TKTAuthSecretOld support. * Fri Feb 27 2009 Gavin Carr 2.0.0-1 - Bump to final version 2.0.0. * Fri Feb 27 2009 Gavin Carr 2.0.0-1 - Bump to final version 2.0.0. * Tue Mar 04 2008 Gavin Carr 2.0.0rc4-1 - Bump to version 2.0.0rc4. * Tue Mar 04 2008 Gavin Carr 2.0.0rc3-1 - Set explicit servername in t/TESTS to fix general test failures. - Add explicit Apache 2.2 support. - Add separate mod_auth_tkt-cgi package containing /var/www/auth CGI scripts. - Factor out cgi config settings into AuthTktConfig.pm. - Bump to version 2.0.0rc3. * Wed Nov 28 2006 Gavin Carr 2.0.0rc2 - Bump to version 2.0.0rc2. * Wed Nov 01 2006 Charlie Brady 2.0.0rc1-2 - Move Apache::AuthTkt into perl's vendorarch directory. * Mon Apr 10 2006 Gavin Carr 2.0.0rc1 - Add mod_auth_tkt man page. - Add TKTAuthDebug support, instead of compile-time debug flag. - Add TKTAuthPostTimeoutURL support (Michael Peters). * Mon Oct 24 2005 Gavin Carr 2.0.0b7 - Deprecate TKTAuthTimeoutMin, replacing with TKTAuthTimeout, using units like TKTAuthCookieExpires. - Split out TKTAuthCookieSecure functionality from TKTAuthRequireSSL (Larry Lansing). - Add TKTAuthCookieExpires directive for guest cookies and refreshes. - Add TKTAuthGuestUser %U format support for UUIDs with Apache 2. - Add TKTAuthGuestUser support for setting guest user explicitly. - Fix URI and HTML escaping issues with cgi scripts (Viljo Viitanen). - Update CGI scripts to get local settings via Apache::AuthTkt parse_conf values. - Update Apache::AuthTkt to new version (0.03) with parse_conf support. - Add server config merge support to allow global secrets with vhosts. * Mon Aug 01 2005 Gavin Carr 2.0.0b6 - Update specfile to support basic building against apache 1. - Fixed bug with non-base64 quoted ticket values not being parsed correctly. * Tue Jun 14 2005 Gavin Carr 2.0.0b5 - Change back url formation to use Host header, not server name/port. - Get cookie_match to skip empty cookies it finds (e.g. logout misconfigs). - Add Ian Bicking's AuthTicket python class in contrib. - Add TKTAuthGuestLogin support based on patch from Ian Bicking. - Add DEBUG_VERBOSE support based on patch from Ian Bicking. - Fixed bug with test harness not generating local module correctly. * Mon May 30 2005 Gavin Carr 2.0.0b4 - Change build to include 'make test' only if mod_perl is available. * Sat Apr 30 2005 Gavin Carr 2.0.0b3 * Thu Feb 21 2005 Gavin Carr 2.0.0b2 - Initial release. mod_auth_tkt-2.3.99b1/src/000077500000000000000000000000001255657270700153325ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/src/Makefile000066400000000000000000000004531255657270700167740ustar00rootroot00000000000000 include ../Makedefs MAT = mod_auth_tkt all: $(TARGET) $(TARGET): mod_auth_tkt.c ap_compat.h sha2.c sha2.h $(APXS) -c -Wc,"-fno-strict-aliasing -Wall -ansi $(CFLAGS)" $(MAT).c sha2.c install: $(TARGET) $(APXS) -i $(TARGET) clean: -rm -f *.o *.lo *.slo $(MAT).so $(MAT).la -rm -rf .libs mod_auth_tkt-2.3.99b1/src/ap22_compat.h000066400000000000000000000003651255657270700176160ustar00rootroot00000000000000/* Compatibility mappings from apache 2.0 api calls to apache 2.2 */ #ifndef AP22_COMPAT_H #define AP22_COMPAT_H #define ap_http_method ap_http_scheme #define apr_uri_default_port_for_scheme apr_uri_port_of_scheme #endif /* AP22_COMPAT_H */ mod_auth_tkt-2.3.99b1/src/ap_compat.h000066400000000000000000000172201255657270700174500ustar00rootroot00000000000000/* Compatibility mappings from apache 2.0 api calls back to apache 1.3.x */ /* Derived from apr_compat.h and apu_compat.h */ #ifndef AP_COMPAT_H #define AP_COMPAT_H #define APR_INLINE ap_inline #define AP_MODULE_DECLARE_DATA MODULE_VAR_EXPORT #define APR_OFFSETOF XtOffsetOf #define APR_EGENERAL 0 #define APR_INADDR_NONE INADDR_NONE /* Omit Apache2 status from ap_log_rerror, adding APLOG_NOERRNO instead */ #define ap_log_error(mark, level, status, ...) ap_log_error(mark, level | APLOG_NOERRNO, __VA_ARGS__) #define ap_log_rerror(mark, level, status, ...) ap_log_rerror(mark, level | APLOG_NOERRNO, __VA_ARGS__) #define apr_uri_default_port_for_scheme ap_default_port_for_scheme #define apr_pool_t pool #define apr_md5_ctx_t ap_md5_ctx_t #define apr_md5_encode ap_MD5Encode #define apr_md5_final ap_MD5Final #define apr_md5_init ap_MD5Init #define apr_md5_update ap_MD5Update #define apr_array_append ap_append_arrays #define apr_array_cat ap_array_cat #define apr_array_header_t array_header #define apr_array_pstrcat ap_array_pstrcat #define apr_pool_free_blocks_num_bytes ap_bytes_in_free_blocks #define apr_pool_num_bytes ap_bytes_in_pool #define apr_check_file_time ap_check_file_time #define apr_filetype_e ap_filetype_e #define apr_pool_cleanup_for_exec ap_cleanup_for_exec #define apr_pool_clear ap_clear_pool #define apr_table_clear ap_clear_table #define apr_array_copy ap_copy_array #define apr_array_copy_hdr ap_copy_array_hdr #define apr_table_copy ap_copy_table #define apr_cpystrn ap_cpystrn #define apr_day_snames ap_day_snames #define apr_pool_destroy ap_destroy_pool #define apr_time_exp_t ap_exploded_time_t #define apr_fnmatch ap_fnmatch #define apr_getopt ap_getopt #define apr_inet_addr ap_inet_addr #define apr_pool_alloc_init ap_init_alloc #define apr_is_empty_table ap_is_empty_table #define apr_fnmatch_test ap_is_fnmatch #define apr_pool_cleanup_kill ap_kill_cleanup #define apr_array_make ap_make_array #define apr_pool_sub_make ap_make_sub_pool #define apr_table_make ap_make_table #define apr_month_snames ap_month_snames #define apr_pool_note_subprocess ap_note_subprocess #define apr_pool_cleanup_null ap_null_cleanup #define apr_filepath_merge ap_os_canonical_filename /* #define apr_filepath_merge ap_os_case_canonical_filename */ #define apr_dso_load ap_os_dso_load #define apr_dso_unload ap_os_dso_unload #define apr_dso_sym ap_os_dso_sym #define apr_dso_error ap_os_dso_error /** @deprecated @see apr_filepath_merge * @warning apr_filepath_merge rejects invalid filenames */ /* #define ap_os_is_filename_valid apr_filepath_merge */ #define apr_proc_kill ap_os_kill /* #define ap_os_systemcase_canonical_filename apr_filepath_merge */ #define apr_table_overlap ap_overlap_tables #define apr_table_overlay ap_overlay_tables #define apr_palloc ap_palloc #define apr_pcalloc ap_pcalloc #define apr_pool_join ap_pool_join #define apr_psprintf ap_psprintf #define apr_pstrcat ap_pstrcat #define apr_pstrdup ap_pstrdup #define apr_pstrndup ap_pstrndup #define apr_array_push ap_push_array #define apr_pvsprintf ap_pvsprintf #define apr_pool_cleanup_register ap_register_cleanup #define apr_proc_other_child_register ap_register_other_child #define apr_pool_cleanup_run ap_run_cleanup #define apr_signal ap_signal #define apr_snprintf ap_snprintf #define apr_table_add ap_table_add #define apr_table_addn ap_table_addn #define apr_table_do ap_table_do #define apr_table_elts ap_table_elts #define apr_table_get ap_table_get #define apr_table_merge ap_table_merge #define apr_table_mergen ap_table_mergen #define apr_table_set ap_table_set #define apr_table_setn ap_table_setn #define apr_table_unset ap_table_unset #define apr_proc_other_child_unregister ap_unregister_other_child #define apr_password_validate ap_validate_password #define apr_vformatter ap_vformatter #define apr_vsnprintf ap_vsnprintf #define apr_wait_t ap_wait_t #define apr_isalnum ap_isalnum #define apr_isalpha ap_isalpha #define apr_iscntrl ap_iscntrl #define apr_isdigit ap_isdigit #define apr_isgraph ap_isgraph #define apr_islower ap_islower #define apr_isascii ap_isascii #define apr_isprint ap_isprint #define apr_ispunct ap_ispunct #define apr_isspace ap_isspace #define apr_isupper ap_isupper #define apr_isxdigit ap_isxdigit #define apr_tolower ap_tolower #define apr_toupper ap_toupper #define APR_USEC_PER_SEC AP_USEC_PER_SEC #define APR_RFC822_DATE_LEN AP_RFC822_DATE_LEN #define APR_OVERLAP_TABLES_MERGE AP_OVERLAP_TABLES_MERGE #define APR_OVERLAP_TABLES_SET AP_OVERLAP_TABLES_SET #define apr_base64_decode ap_base64decode #define apr_base64_decode_binary ap_base64decode_binary #define apr_base64_decode_len ap_base64decode_len #define apr_base64_encode ap_base64encode #define apr_base64_encode_binary ap_base64encode_binary #define apr_base64_encode_len ap_base64encode_len #define apr_hook_deregister_all ap_hook_deregister_all #define apr_hook_sort_register ap_hook_sort_register #define apr_hook_debug_show ap_show_hook /* -------------------------------------------------------------------- * the following symbols were moved from httpd-2.0/.../util_date.[ch] */ #define apr_date_parse_http ap_parseHTTPdate #define apr_date_checkmask ap_checkmask /* -------------------------------------------------------------------- * the following symbols were moved from httpd-2.0/.../util_xml.[ch] */ #define ap_text apr_text #define ap_text_header apr_text_header #define ap_text_append apr_text_append #define AP_XML_NS_DAV_ID APR_XML_NS_DAV_ID #define AP_XML_NS_NONE APR_XML_NS_NONE #define AP_XML_NS_ERROR_BASE APR_XML_NS_ERROR_BASE #define AP_XML_NS_IS_ERROR(e) APR_XML_NS_IS_ERROR(e) #define AP_XML_ELEM_IS_EMPTY(e) APR_XML_ELEM_IS_EMPTY(e) #define ap_xml_attr apr_xml_attr #define ap_xml_elem apr_xml_elem #define ap_xml_doc apr_xml_doc #define ap_xml_to_text apr_xml_to_text #define AP_XML_X2T_FULL APR_XML_X2T_FULL #define AP_XML_X2T_INNER APR_XML_X2T_INNER #define AP_XML_X2T_LANG_INNER APR_XML_X2T_LANG_INNER #define AP_XML_X2T_FULL_NS_LANG APR_XML_X2T_FULL_NS_LANG #define ap_xml_empty_elem apr_xml_empty_elem #define ap_xml_quote_string apr_xml_quote_string #define ap_xml_quote_elem apr_xml_quote_elem #define ap_xml_insert_uri apr_xml_insert_uri #define AP_XML_GET_URI_ITEM(a,i) APR_XML_GET_URI_ITEM(a,i) /* From Apache2 httpd.h */ # define ap_strchr(s, c) strchr(s, c) /* From Apache2 http_config.h */ # define AP_INIT_NO_ARGS(directive, func, mconfig, where, help) \ { directive, func, mconfig, where, RAW_ARGS, help } # define AP_INIT_RAW_ARGS(directive, func, mconfig, where, help) \ { directive, func, mconfig, where, RAW_ARGS, help } # define AP_INIT_TAKE1(directive, func, mconfig, where, help) \ { directive, func, mconfig, where, TAKE1, help } # define AP_INIT_ITERATE(directive, func, mconfig, where, help) \ { directive, func, mconfig, where, ITERATE, help } # define AP_INIT_TAKE2(directive, func, mconfig, where, help) \ { directive, func, mconfig, where, TAKE2, help } # define AP_INIT_TAKE12(directive, func, mconfig, where, help) \ { directive, func, mconfig, where, TAKE12, help } # define AP_INIT_ITERATE2(directive, func, mconfig, where, help) \ { directive, func, mconfig, where, ITERATE2, help } # define AP_INIT_TAKE13(directive, func, mconfig, where, help) \ { directive, func, mconfig, where, TAKE13, help } # define AP_INIT_TAKE23(directive, func, mconfig, where, help) \ { directive, func, mconfig, where, TAKE23, help } # define AP_INIT_TAKE123(directive, func, mconfig, where, help) \ { directive, func, mconfig, where, TAKE123, help } # define AP_INIT_TAKE3(directive, func, mconfig, where, help) \ { directive, func, mconfig, where, TAKE3, help } # define AP_INIT_FLAG(directive, func, mconfig, where, help) \ { directive, func, mconfig, where, FLAG, help } #endif /* AP_COMPAT_H */ mod_auth_tkt-2.3.99b1/src/mod_auth_tkt.c000066400000000000000000001553041255657270700201700ustar00rootroot00000000000000 #include #include #include "httpd.h" #include "http_config.h" #include "http_log.h" #include "http_core.h" #include "http_request.h" #include "http_protocol.h" #include "util_md5.h" #include "sha2.h" #ifdef APACHE13 #include "ap_compat.h" #else #define UUID_SUBS 2 #include "apr_lib.h" #include "apr_strings.h" #include "apr_uuid.h" #include "apr_base64.h" #if AP_MODULE_MAGIC_AT_LEAST(20030213,1) #include "ap22_compat.h" #include "ap_regex.h" #else #include "pcreposix.h" #endif #endif #define AUTH_COOKIE_NAME "auth_tkt" #define BACK_ARG_NAME "back" #define DEFAULT_DIGEST_TYPE "MD5" #define MD5_DIGEST_SZ 32 #define TSTAMP_SZ 8 #define SEPARATOR '!' #define SEPARATOR_HEX "%21" #define REMOTE_USER_ENV "REMOTE_USER" #define REMOTE_USER_DATA_ENV "REMOTE_USER_DATA" #define REMOTE_USER_TOKENS_ENV "REMOTE_USER_TOKENS" #define DEFAULT_TIMEOUT_SEC 7200 #define DEFAULT_GUEST_USER "guest" #define QUERY_SEPARATOR ';' #define FORCE_REFRESH 1 #define CHECK_REFRESH 0 #define TKT_AUTH_VERSION "2.3.99b1" /* ----------------------------------------------------------------------- */ /* Per-directory configuration */ typedef struct { char *directory; char *login_url; char *timeout_url; char *post_timeout_url; char *unauth_url; char *auth_domain; int cookie_expires; char *auth_cookie_name; char *back_cookie_name; char *back_arg_name; apr_array_header_t *auth_token; int ignore_ip; int require_ssl; int secure_cookie; int timeout_sec; double timeout_refresh; int guest_login; int guest_cookie; char *guest_user; int guest_fallback; int guest_empty; int debug; const char *query_separator; } auth_tkt_dir_conf; /* Per-server configuration */ typedef struct { const char *secret; const char *old_secret; const char *digest_type; int digest_sz; char *docroot; } auth_tkt_serv_conf; typedef struct auth_tkt_struct { char *uid; char *tokens; char *user_data; unsigned int timestamp; } auth_tkt; typedef struct { request_rec *r; char *cookie; char *cookie_name; } cookie_res; /* ----------------------------------------------------------------------- */ /* Initializer */ #ifdef APACHE13 void auth_tkt_version(server_rec *s, pool *p) { ap_add_version_component("mod_auth_tkt/" TKT_AUTH_VERSION); ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, s, "mod_auth_tkt: version %s", TKT_AUTH_VERSION); } #else static int auth_tkt_version(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { ap_add_version_component(p, "mod_auth_tkt/" TKT_AUTH_VERSION); ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, s, "mod_auth_tkt: version %s", TKT_AUTH_VERSION); return DECLINED; } #endif /* Create per-dir config structures */ static void * create_auth_tkt_config(apr_pool_t *p, char* path) { auth_tkt_dir_conf *conf = apr_palloc(p, sizeof(*conf)); conf->directory = path; conf->login_url = NULL; conf->timeout_url = NULL; conf->post_timeout_url = NULL; conf->unauth_url = NULL; conf->auth_domain = NULL; conf->cookie_expires = -1; conf->auth_token = apr_array_make(p, 0, sizeof (char *)); conf->auth_cookie_name = AUTH_COOKIE_NAME; conf->back_cookie_name = NULL; conf->back_arg_name = BACK_ARG_NAME; conf->ignore_ip = -1; conf->require_ssl = -1; conf->secure_cookie = -1; conf->timeout_sec = -1; conf->timeout_refresh = .5; conf->guest_login = -1; conf->guest_cookie = -1; conf->guest_user = NULL; conf->guest_fallback = -1; conf->guest_empty = -1; conf->debug = -1; conf->query_separator = NULL; return conf; } /* Merge per-dir config structures */ static void * merge_auth_tkt_config(apr_pool_t *p, void* parent_dirv, void* subdirv) { auth_tkt_dir_conf *parent = (auth_tkt_dir_conf *) parent_dirv; auth_tkt_dir_conf *subdir = (auth_tkt_dir_conf *) subdirv; auth_tkt_dir_conf *conf = apr_palloc(p, sizeof(*conf)); conf->directory = (subdir->directory) ? subdir->directory : parent->directory; conf->login_url = (subdir->login_url) ? subdir->login_url : parent->login_url; conf->timeout_url = (subdir->timeout_url) ? subdir->timeout_url : parent->timeout_url; conf->post_timeout_url = (subdir->post_timeout_url) ? subdir->post_timeout_url : parent->post_timeout_url; conf->unauth_url = (subdir->unauth_url) ? subdir->unauth_url : parent->unauth_url; conf->auth_domain = (subdir->auth_domain) ? subdir->auth_domain : parent->auth_domain; conf->cookie_expires = (subdir->cookie_expires >= 0) ? subdir->cookie_expires : parent->cookie_expires; conf->auth_token = (subdir->auth_token->nelts > 0) ? subdir->auth_token : parent->auth_token; conf->auth_cookie_name = (subdir->auth_cookie_name) ? subdir->auth_cookie_name : parent->auth_cookie_name; conf->back_cookie_name = (subdir->back_cookie_name) ? subdir->back_cookie_name : parent->back_cookie_name; conf->back_arg_name = (subdir->back_arg_name) ? subdir->back_arg_name : parent->back_arg_name; conf->ignore_ip = (subdir->ignore_ip >= 0) ? subdir->ignore_ip : parent->ignore_ip; conf->require_ssl = (subdir->require_ssl >= 0) ? subdir->require_ssl : parent->require_ssl; conf->secure_cookie = (subdir->secure_cookie >= 0) ? subdir->secure_cookie : parent->secure_cookie; conf->timeout_sec = (subdir->timeout_sec >= 0) ? subdir->timeout_sec : parent->timeout_sec; conf->timeout_refresh = (subdir->timeout_refresh >= 0) ? subdir->timeout_refresh : parent->timeout_refresh; conf->guest_login = (subdir->guest_login >= 0) ? subdir->guest_login : parent->guest_login; conf->guest_cookie = (subdir->guest_cookie >= 0) ? subdir->guest_cookie : parent->guest_cookie; conf->guest_user = (subdir->guest_user) ? subdir->guest_user : parent->guest_user; conf->guest_fallback = (subdir->guest_fallback >= 0) ? subdir->guest_fallback : parent->guest_fallback; conf->guest_empty = (subdir->guest_empty >= 0) ? subdir->guest_empty : parent->guest_empty; conf->debug = (subdir->debug >= 0) ? subdir->debug : parent->debug; conf->query_separator = (subdir->query_separator) ? subdir->query_separator : parent->query_separator; return conf; } /* Create per-server config structures */ static void * create_auth_tkt_serv_config(apr_pool_t *p, server_rec* s) { auth_tkt_serv_conf *sconf = apr_palloc(p, sizeof(*sconf)); sconf->secret = NULL; sconf->old_secret = NULL; sconf->digest_type = NULL; sconf->digest_sz = 0; return sconf; } /* Merge per-server config structures */ static void * merge_auth_tkt_serv_config(apr_pool_t *p, void* parent_dirv, void* subdirv) { auth_tkt_serv_conf *parent = (auth_tkt_serv_conf *) parent_dirv; auth_tkt_serv_conf *subdir = (auth_tkt_serv_conf *) subdirv; auth_tkt_serv_conf *sconf = apr_palloc(p, sizeof(*sconf)); sconf->secret = (subdir->secret) ? subdir->secret : parent->secret; sconf->old_secret = (subdir->old_secret) ? subdir->old_secret : parent->old_secret; sconf->digest_type = (subdir->digest_type) ? subdir->digest_type : parent->digest_type; sconf->digest_sz = (subdir->digest_sz) ? subdir->digest_sz : parent->digest_sz; return sconf; } /* ----------------------------------------------------------------------- */ /* Command-specific functions */ module AP_MODULE_DECLARE_DATA auth_tkt_module; /* Loosely based on mod_expires */ static const char * convert_to_seconds (cmd_parms *cmd, const char *param, int *seconds) { int num, multiplier; char unit; if (apr_isdigit(param[0])) { num = atoi(param); } else { return "Bad time string - numeric expected."; } if (*seconds < 0) *seconds = 0; multiplier = 1; unit = param[strlen(param)-1]; if (apr_isalpha(unit)) { if (unit == 's') multiplier = 1; else if (unit == 'm') multiplier = 60; else if (unit == 'h') multiplier = 60 * 60; else if (unit == 'd') multiplier = 24 * 60 * 60; else if (unit == 'w') multiplier = 7 * 24 * 60 * 60; else if (unit == 'M') multiplier = 30 * 24 * 60 * 60; else if (unit == 'y') multiplier = 365 * 24 * 60 * 60; else return apr_psprintf(cmd->pool, "Bad time string - unrecognised unit '%c'", unit); } *seconds += num * multiplier; return NULL; } static const char * set_auth_tkt_token (cmd_parms *cmd, void *cfg, const char *param) { char **new; auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *) cfg; new = (char **) apr_array_push(conf->auth_token); *new = apr_pstrdup(cmd->pool, param); return NULL; } static const char * set_auth_tkt_timeout (cmd_parms *cmd, void *cfg, const char *param) { auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *)cfg; int seconds = conf->timeout_sec; const char *error; /* Easy case - looks like all digits */ if (apr_isdigit(param[0]) && apr_isdigit(param[strlen(param) - 1])) { seconds = atoi(param); } /* Harder case - convert units to seconds */ else { error = convert_to_seconds(cmd, param, &seconds); if (error) return(error); } if (seconds < 0) return ("Timeout must be positive"); if (seconds == INT_MAX) return ("Integer overflow or invalid number"); conf->timeout_sec = seconds; return NULL; } static const char * set_auth_tkt_timeout_min (cmd_parms *cmd, void *cfg, const char *param) { auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *)cfg; int minutes = atoi(param); if (minutes < 0) return ("Timeout must be positive"); if (minutes == INT_MAX) return ("Integer overflow or invalid number"); conf->timeout_sec = minutes * 60; return NULL; } static const char * set_auth_tkt_timeout_refresh (cmd_parms *cmd, void *cfg, const char *param) { auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *)cfg; double refresh = atof(param); if (refresh < 0 || refresh > 1) return "Refresh flag must be between 0 and 1"; conf->timeout_refresh = refresh; return NULL; } static const char * setup_secret (cmd_parms *cmd, void *cfg, const char *param) { auth_tkt_serv_conf *sconf = ap_get_module_config(cmd->server->module_config, &auth_tkt_module); sconf->secret = param; return NULL; } static const char * setup_old_secret (cmd_parms *cmd, void *cfg, const char *param) { auth_tkt_serv_conf *sconf = ap_get_module_config(cmd->server->module_config, &auth_tkt_module); sconf->old_secret = param; return NULL; } static const char * setup_query_separator (cmd_parms *cmd, void *cfg, const char *param) { if (strcmp(param, ";") != 0 && strcmp(param, "&") != 0) return "QuerySeparator must be either ';' or '&'."; auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *)cfg; conf->query_separator = param; return NULL; } void setup_digest_sz (auth_tkt_serv_conf *sconf) { if (strcmp(sconf->digest_type, "MD5") == 0) { sconf->digest_sz = MD5_DIGEST_SZ; } else if (strcmp(sconf->digest_type, "SHA256") == 0) { sconf->digest_sz = SHA256_BLOCK_LENGTH; } else if (strcmp(sconf->digest_type, "SHA512") == 0) { sconf->digest_sz = SHA512_BLOCK_LENGTH; } } static const char * setup_digest_type (cmd_parms *cmd, void *cfg, const char *param) { auth_tkt_serv_conf *sconf = ap_get_module_config(cmd->server->module_config, &auth_tkt_module); if (strcmp(param, "MD5") != 0 && strcmp(param, "SHA256") != 0 && strcmp(param, "SHA512") != 0) return "Digest type must be one of: MD5 | SHA256 | SHA512."; sconf->digest_type = param; setup_digest_sz(sconf); return NULL; } static const char * set_cookie_expires (cmd_parms *cmd, void *cfg, const char *param) { auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *)cfg; int seconds = conf->cookie_expires; const char *error; /* Easy case - looks like all digits */ if (apr_isdigit(param[0]) && apr_isdigit(param[strlen(param) - 1])) { seconds = atoi(param); } /* Harder case - convert units to seconds */ else { error = convert_to_seconds(cmd, param, &seconds); if (error) return(error); } if (seconds < 0) return ("Expires must be positive"); if (seconds == INT_MAX) return ("Integer overflow or invalid number"); conf->cookie_expires = seconds; return NULL; } static const char * set_auth_tkt_debug (cmd_parms *cmd, void *cfg, const char *param) { auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *)cfg; int debug = atoi(param); if (debug < 0) return ("Debug level must be positive"); if (debug == INT_MAX) return ("Integer overflow or invalid number"); conf->debug = debug; return NULL; } /* Command table */ static const command_rec auth_tkt_cmds[] = { AP_INIT_TAKE1("TKTAuthLoginURL", ap_set_string_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, login_url), OR_AUTHCFG, "URL to redirect to if authentication fails"), AP_INIT_TAKE1("TKTAuthTimeoutURL", ap_set_string_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, timeout_url), OR_AUTHCFG, "URL to redirect to if cookie times-out"), AP_INIT_TAKE1("TKTAuthPostTimeoutURL", ap_set_string_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, post_timeout_url), OR_AUTHCFG, "URL to redirect to if cookie times-out doing a POST"), AP_INIT_TAKE1("TKTAuthUnauthURL", ap_set_string_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, unauth_url), OR_AUTHCFG, "URL to redirect to if valid user without required token"), AP_INIT_TAKE1("TKTAuthCookieName", ap_set_string_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, auth_cookie_name), OR_AUTHCFG, "name to use for ticket cookie"), AP_INIT_TAKE1("TKTAuthDomain", ap_set_string_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, auth_domain), OR_AUTHCFG, "domain to use in cookies"), #ifndef APACHE13 /* TKTAuthCookieExpires is not supported under Apache 1.3 */ AP_INIT_ITERATE("TKTAuthCookieExpires", set_cookie_expires, (void *)APR_OFFSETOF(auth_tkt_dir_conf, cookie_expires), OR_AUTHCFG, "cookie expiry period, in seconds or units [smhdwMy]"), #endif AP_INIT_TAKE1("TKTAuthBackCookieName", ap_set_string_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, back_cookie_name), OR_AUTHCFG, "name to use for back cookie (default: none)"), AP_INIT_TAKE1("TKTAuthBackArgName", ap_set_string_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, back_arg_name), OR_AUTHCFG, "name to use for back url argument ('None' to not use)"), AP_INIT_FLAG("TKTAuthIgnoreIP", ap_set_flag_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, ignore_ip), OR_AUTHCFG, "whether to ignore remote IP address in ticket"), AP_INIT_FLAG("TKTAuthRequireSSL", ap_set_flag_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, require_ssl), OR_AUTHCFG, "whether to refuse non-HTTPS requests"), AP_INIT_FLAG("TKTAuthCookieSecure", ap_set_flag_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, secure_cookie), OR_AUTHCFG, "whether to set secure flag on ticket cookies"), AP_INIT_ITERATE("TKTAuthToken", set_auth_tkt_token, (void *)APR_OFFSETOF(auth_tkt_dir_conf, auth_token), OR_AUTHCFG, "token required to access this area (NULL for none)"), AP_INIT_ITERATE("TKTAuthTimeout", set_auth_tkt_timeout, (void *)APR_OFFSETOF(auth_tkt_dir_conf, timeout_sec), OR_AUTHCFG, "ticket inactivity timeout, in seconds or units [smhdwMy]"), AP_INIT_TAKE1("TKTAuthTimeoutMin", set_auth_tkt_timeout_min, NULL, OR_AUTHCFG, "ticket inactivity timeout, in minutes (deprecated)"), AP_INIT_TAKE1("TKTAuthTimeoutRefresh", set_auth_tkt_timeout_refresh, NULL, OR_AUTHCFG, "ticket timeout refresh flag (0-1)"), AP_INIT_TAKE1("TKTAuthSecret", setup_secret, NULL, RSRC_CONF, "secret key to use in digest"), AP_INIT_TAKE1("TKTAuthSecretOld", setup_old_secret, NULL, RSRC_CONF, "old/alternative secret key to check in digests"), AP_INIT_TAKE1("TKTAuthDigestType", setup_digest_type, NULL, RSRC_CONF, "digest type to use [MD5|SHA256|SHA512], default: MD5"), AP_INIT_FLAG("TKTAuthGuestLogin", ap_set_flag_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, guest_login), OR_AUTHCFG, "whether to log people in as guest if no other auth available"), AP_INIT_FLAG("TKTAuthGuestCookie", ap_set_flag_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, guest_cookie), OR_AUTHCFG, "whether to set a cookie when accepting guest users (default: off)"), AP_INIT_TAKE1("TKTAuthGuestUser", ap_set_string_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, guest_user), OR_AUTHCFG, "username to use for guest logins"), AP_INIT_FLAG("TKTAuthGuestFallback", ap_set_flag_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, guest_fallback), OR_AUTHCFG, "whether to fall back to guest on an expired ticket (default: off)"), AP_INIT_FLAG("TKTAuthGuestEmpty", ap_set_flag_slot, (void *)APR_OFFSETOF(auth_tkt_dir_conf, guest_empty), OR_AUTHCFG, "whether to use username of '' for guests (default: off)"), AP_INIT_ITERATE("TKTAuthDebug", set_auth_tkt_debug, (void *)APR_OFFSETOF(auth_tkt_dir_conf, debug), OR_AUTHCFG, "debug level (1-3, higher for more debug output)"), AP_INIT_TAKE1("TKTAuthQuerySeparator", setup_query_separator, (void *)APR_OFFSETOF(auth_tkt_dir_conf, query_separator), OR_AUTHCFG, "Character used in query strings to separate arguments (default: ';')"), {NULL}, }; /* ----------------------------------------------------------------------- */ /* Support functions */ /* Parse cookie. Returns 1 if valid, and details in *parsed; 0 if not */ static int parse_ticket(request_rec *r, char **magic, auth_tkt *parsed) { int sepidx, sep2idx; char *ticket = *magic; int len = strlen(ticket); auth_tkt_serv_conf *sconf = ap_get_module_config(r->server->module_config, &auth_tkt_module); auth_tkt_dir_conf *conf = ap_get_module_config(r->per_dir_config, &auth_tkt_module); /* For some reason (some clients?), tickets sometimes come in quoted */ if (ticket[len-1] == '"') ticket[len-1] = 0; if (ticket[0] == '"') *magic = ++ticket; /* Basic length check for min size */ if (len <= (sconf->digest_sz + TSTAMP_SZ)) return 0; /* See if there is a uid/data separator */ sepidx = ap_ind(ticket, SEPARATOR); if (sepidx == -1) { /* Ticket either uri-escaped, base64-escaped, or bogus */ if (strstr(ticket, SEPARATOR_HEX)) { ap_unescape_url(ticket); sepidx = ap_ind(ticket, SEPARATOR); } else { /* base64 encoded string always longer than original, so len+1 sufficient */ char *buf = (char *) apr_palloc(r->pool, len+1); apr_base64_decode(buf, ticket); sepidx = ap_ind(buf, SEPARATOR); /* If still no sepidx, must be bogus */ if (sepidx == -1) return 0; /* Update ticket and *magic to decoded version */ ticket = *magic = buf; } /* Reset len */ len = strlen(ticket); } /* Recheck length */ if (len <= (sconf->digest_sz + TSTAMP_SZ) || sepidx < (sconf->digest_sz + TSTAMP_SZ)) return 0; if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT parse_ticket decoded ticket: '%s'", ticket); } /* Get the user id */ parsed->uid = apr_palloc(r->pool, sepidx - (sconf->digest_sz + TSTAMP_SZ) + 1); memcpy(parsed->uid, &ticket[(sconf->digest_sz + TSTAMP_SZ)], sepidx - (sconf->digest_sz + TSTAMP_SZ)); parsed->uid[sepidx - (sconf->digest_sz + TSTAMP_SZ)] = '\0'; /* Check for tokens */ sep2idx = ap_ind(&ticket[sepidx+1], SEPARATOR); if (sep2idx == -1) { if (conf->debug >= 2) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT parse_ticket: no tokens"); } parsed->tokens = apr_palloc(r->pool, 1); *parsed->tokens = '\0'; } else { /* Swap sepidx and sep2idx */ int tmp = sepidx; sepidx = tmp + sep2idx + 1; sep2idx = tmp; if (conf->debug >= 2) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT parse_ticket: tokens found - sep2=%d, sep=%d, len=%d", sep2idx, sepidx, len); } /* Copy tokens to parsed->tokens */ parsed->tokens = apr_palloc(r->pool, sepidx-sep2idx); apr_snprintf(parsed->tokens, sepidx-sep2idx, "%s", &ticket[sep2idx+1]); if (conf->debug >= 2) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT parse_ticket tokens: '%s'", parsed->tokens); } } /* Copy user data to parsed->user_data */ parsed->user_data = apr_palloc(r->pool, len-sepidx+1); apr_snprintf(parsed->user_data, len-sepidx+1, "%s", &ticket[sepidx+1]); /* Copy timestamp to parsed->timestamp */ sscanf(&ticket[sconf->digest_sz], "%8x", &(parsed->timestamp)); return 1; } /* Search cookie headers for our ticket */ static int cookie_match(void *result, const char *key, const char *cookie) { cookie_res * cr = (cookie_res *) result; auth_tkt_dir_conf *conf = ap_get_module_config(cr->r->per_dir_config, &auth_tkt_module); if (cookie != NULL) { char *cookie_name, *value, *cookiebuf, *end; if (conf->debug >= 2) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, cr->r, "TKT cookie_match, key %s against <%s> (name=%s)", key, cookie, cr->cookie_name); } cookie_name = apr_palloc(cr->r->pool, strlen(cr->cookie_name) + 2); strncpy(cookie_name, cr->cookie_name, strlen(cr->cookie_name)); cookie_name[strlen(cr->cookie_name)] = '='; cookie_name[strlen(cr->cookie_name) + 1] = '\0'; value = (char*) cookie; while ((value = strstr(value, cookie_name))) { /* cookie_name must be preceded by a space or a semicolon or be at the very beginning */ if (value > cookie && (*(value-1) != ' ' && *(value-1) != ';')) { value++; continue; } /* Cookie includes our cookie_name - copy (first) value into cookiebuf */ value += strlen(cookie_name); cookiebuf = apr_pstrdup(cr->r->pool, value); end = ap_strchr(cookiebuf, ';'); if (end) *end = '\0'; /* Ignore anything after the next ; */ /* Skip empty cookies (such as with misconfigured logoffs) */ if (strlen(cookiebuf)) { cr->cookie = cookiebuf; if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, cr->r, "TKT cookie_match: found '%s'", cookiebuf); } return(0); } } } if (conf->debug >= 2) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, cr->r, "TKT cookie_match: NOT found"); } return (1); } /* Return the domain to use in cookies */ char * get_domain(request_rec *r, auth_tkt_dir_conf *conf) { /* Set the cookie domain to the first set of TKTAuthDomain, X-Forwarded-Host, Host, or server hostname. Viljo Viitanen pointed out that using the wildcard domain is a security hole in the event that other servers on your domain are hostile. */ char *domain = conf->auth_domain; char *p; if (!domain) domain = (char *) apr_table_get(r->headers_in, "X-Forwarded-Host"); if (!domain) domain = (char *) apr_table_get(r->headers_in, "Host"); if (domain) { /* Ignore any trailing port in domain */ if ((p = ap_strchr(domain, ':'))) { *p = '\0'; } } else { domain = (char *) r->hostname; } return domain; } /* Send an auth cookie with the given value */ static void send_auth_cookie(request_rec *r, char *value) { auth_tkt_dir_conf *conf = ap_get_module_config(r->per_dir_config, &auth_tkt_module); char *cookie, *expires; char *domain = get_domain(r,conf); char *secure_cookie = conf->secure_cookie > 0 ? "; secure" : ""; /* Set cookie domain */ domain = domain ? apr_psprintf(r->pool, "; domain=%s", domain) : ""; /* Set cookie expires */ expires = ""; #ifndef APACHE13 if (conf->cookie_expires > 0) { apr_time_exp_t tms; apr_time_exp_gmt(&tms, r->request_time + apr_time_from_sec(conf->cookie_expires)); expires = apr_psprintf(r->pool, "; expires=%s, %.2d-%s-%.2d %.2d:%.2d:%.2d GMT", apr_day_snames[tms.tm_wday], tms.tm_mday, apr_month_snames[tms.tm_mon], tms.tm_year % 100, tms.tm_hour, tms.tm_min, tms.tm_sec ); } #endif /* Send the cookie */ cookie = apr_psprintf(r->pool, "%s=%s; path=/%s%s%s", conf->auth_cookie_name, value, domain, expires, secure_cookie); apr_table_setn(r->err_headers_out, "Set-Cookie", cookie); if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT: sending cookie: %s=%s; path=/%s%s%s", conf->auth_cookie_name, value, domain, expires, secure_cookie); } } /* Look for a url ticket */ static char * get_url_ticket(request_rec *r) { auth_tkt_dir_conf *conf = ap_get_module_config(r->per_dir_config, &auth_tkt_module); const char *args = NULL; /* url arguments string */ const char *key, *val; char *ticket = NULL; /* Use main request args if subrequest */ request_rec *r_main = r->main == NULL ? r : r->main; if (r_main->args != NULL) { args = apr_pstrdup(r->pool, r_main->args); } if (args != NULL) { if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT: looking for ticket in url: <%s>", args); } while (*args && (val = ap_getword(r->pool, &args, '&'))) { key = ap_getword(r->pool, &val, '='); if (strcmp(key,conf->auth_cookie_name) == 0) { if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT: found url ticket: <%s>", val); } /* Setup auth cookie using ticket value */ send_auth_cookie(r, (char *) val); /* Found ticket - ignore rest of arguments */ ticket = (char *) val; break; } } } return ticket; } /* Look for a cookie ticket */ static char * get_cookie_ticket(request_rec *r) { auth_tkt_serv_conf *sconf = ap_get_module_config(r->server->module_config, &auth_tkt_module); auth_tkt_dir_conf *conf = ap_get_module_config(r->per_dir_config, &auth_tkt_module); /* Walk cookie headers looking for matching ticket */ cookie_res *cr = apr_palloc(r->pool, sizeof(*cr)); cr->r = r; cr->cookie = NULL; cr->cookie_name = conf->auth_cookie_name; apr_table_do(cookie_match, (void *) cr, r->headers_in, "Cookie", NULL); /* Give up if cookie not found or too short */ if (! cr->cookie) { return NULL; } if (strlen(cr->cookie) < sconf->digest_sz + TSTAMP_SZ) { if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT get_cookie_tkt: found cookie ticket, " "but it's too short for a %s digest (%zu < %d)", sconf->digest_type, strlen(cr->cookie), sconf->digest_sz + TSTAMP_SZ); } return NULL; } return cr->cookie; } /* Generate a ticket digest string from the given details */ static char * ticket_digest(request_rec *r, auth_tkt *parsed, unsigned int timestamp, const char *secret) { auth_tkt_serv_conf *sconf = ap_get_module_config(r->server->module_config, &auth_tkt_module); auth_tkt_dir_conf *conf = ap_get_module_config(r->per_dir_config, &auth_tkt_module); char *uid = parsed->uid; char *tokens = parsed->tokens; char *user_data = parsed->user_data; unsigned char *buf = apr_palloc(r->pool, TSTAMP_SZ + strlen(secret) + strlen(uid) + 1 + strlen(tokens) + 1 + strlen(user_data) + 1); unsigned char *buf2 = apr_palloc(r->pool, sconf->digest_sz + strlen(secret)); int len = 0; char *digest = NULL; #if AP_MODULE_MAGIC_AT_LEAST(20111130,0) /* Apache 2.4 removed conn->remote_ip, replacing it with: * - request_rec->useragent_ip - the ip address of the remote user agent, either directly * or via a transparent proxy or load balancer * - conn_rec->client_ip - the client directly connected to the server, which might be the * user agent or a load balancer / proxy * So we want useragent_ip here, assuming it can be trusted. * See http://httpd.apache.org/docs/2.4/developer/new_api_2_4.html */ char *remote_ip = conf->ignore_ip > 0 ? "0.0.0.0" : r->useragent_ip; #else char *remote_ip = conf->ignore_ip > 0 ? "0.0.0.0" : r->connection->remote_ip; #endif unsigned long ip; struct in_addr ia; char *d; /* Convert remote_ip to unsigned long */ if (inet_aton(remote_ip, &ia) == 0) { return (NULL); } ip = ntohl(ia.s_addr); if (timestamp == 0) timestamp = parsed->timestamp; if (conf->debug >= 2) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT ticket_digest: using secret '%s', ip '%s', ts '%d'", secret, remote_ip, timestamp); } /* Fatals */ if (buf == NULL) return (NULL); if (ip == APR_INADDR_NONE) return (NULL); /* First 8 bytes for ip address + timestamp */ buf[0] = (unsigned char ) ((ip & 0xff000000) >> 24); buf[1] = (unsigned char ) ((ip & 0xff0000) >> 16); buf[2] = (unsigned char ) ((ip & 0xff00) >> 8); buf[3] = (unsigned char ) ((ip & 0xff)); buf[4] = (unsigned char ) ((timestamp & 0xff000000) >> 24); buf[5] = (unsigned char ) ((timestamp & 0xff0000) >> 16); buf[6] = (unsigned char ) ((timestamp & 0xff00) >> 8); buf[7] = (unsigned char ) ((timestamp & 0xff)); len = 8; /* Append remaining components to buf */ strcpy((char *)&buf[len], secret); len += strlen(secret); strcpy((char *)&buf[len], uid); len += strlen(uid); buf[len++] = 0; strcpy((char *)&buf[len], tokens); len += strlen(tokens); buf[len++] = 0; strcpy((char *)&buf[len], user_data); len += strlen(user_data); buf[len] = 0; /* Generate the initial digest */ if (strcmp(sconf->digest_type, "SHA256") == 0) { d = apr_palloc(r->pool, SHA256_DIGEST_STRING_LENGTH); digest = mat_SHA256_Data(buf, len, d); } else if (strcmp(sconf->digest_type, "SHA512") == 0) { d = apr_palloc(r->pool, SHA512_DIGEST_STRING_LENGTH); digest = mat_SHA512_Data(buf, len, d); } else { digest = ap_md5_binary(r->pool, buf, len); } if (conf->debug >= 3) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT ticket_digest: digest0: '%s' (input length %d)", digest, len); } /* Copy digest + secret into buf2 */ len = sconf->digest_sz + strlen(secret); memcpy(buf2, digest, sconf->digest_sz); memcpy(&buf2[sconf->digest_sz], secret, len - sconf->digest_sz); /* Generate the second digest */ if (strcmp(sconf->digest_type, "SHA256") == 0) { d = apr_palloc(r->pool, SHA256_DIGEST_STRING_LENGTH); digest = mat_SHA256_Data(buf2, len, d); } else if (strcmp(sconf->digest_type, "SHA512") == 0) { d = apr_palloc(r->pool, SHA512_DIGEST_STRING_LENGTH); digest = mat_SHA512_Data(buf2, len, d); } else { digest = ap_md5_binary(r->pool, buf2, len); } if (conf->debug >= 3) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT ticket_digest: digest: '%s'", digest); } /* Should be noop, but just in case ... */ if (strlen(digest) > sconf->digest_sz) digest[sconf->digest_sz] = 0; return (digest); } /* Check if this is a parseable and valid ticket * Returns 1 if valid, and the parsed ticket in parsed, 0 if not */ static int valid_ticket(request_rec *r, const char *source, char *ticket, auth_tkt *parsed, int *force_refresh) { char *digest; auth_tkt_serv_conf *sconf = ap_get_module_config(r->server->module_config, &auth_tkt_module); auth_tkt_dir_conf *conf = ap_get_module_config(r->per_dir_config, &auth_tkt_module); /* Attempt to parse ticket */ if (! parse_ticket(r, &ticket, parsed)) { if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, r, "TKT valid_ticket: unparseable %s ticket found ('%s')", source, ticket); } return 0; } if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT valid_ticket: (parsed) uid '%s', tokens '%s', user_data '%s', ts '%d'", parsed->uid, parsed->tokens, parsed->user_data, parsed->timestamp); } /* Check ticket hash against a calculated digest using the current secret */ digest = ticket_digest(r, parsed, 0, sconf->secret); if (memcmp(ticket, digest, sconf->digest_sz) != 0) { /* Digest mismatch - if no old secret set, fail */ if(sconf->old_secret == NULL) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, r, "TKT valid_ticket: ticket hash (current secret) is invalid, and no old secret set " "- digest '%s', ticket '%s'", digest, ticket); return 0; } /* Digest mismatch - if old_secret is set, recalculate using that */ else { if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT valid_ticket: ticket hash (current secret) is invalid, but old_secret is set - checking ticket digest against that"); } digest = ticket_digest(r, parsed, 0, sconf->old_secret); if (memcmp(ticket, digest, sconf->digest_sz) != 0) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, r, "TKT valid_ticket: ticket hash (old secret) is also invalid - digest '%s', ticket '%s'", digest, ticket); return 0; } /* Ticket validates against old_secret, so we should force a cookie refresh */ else { if (force_refresh != NULL) { if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT valid_ticket: ticket_digest validated with old_secret - forcing a cookie refresh"); } *force_refresh = 1; } } } } return 1; } /* Check for required auth tokens * Returns 1 on success, 0 on failure */ static int check_tokens(request_rec *r, char *tokens) { auth_tkt_dir_conf *conf = ap_get_module_config(r->per_dir_config, &auth_tkt_module); char *next_parsed_token; const char *t = NULL; int match = 0; /* Success if no tokens required */ if (conf->auth_token->nelts == 0 || strcmp(((char **) conf->auth_token->elts)[0], "NULL") == 0) { return 1; } /* Failure if required and no user tokens found */ if (tokens == NULL || strlen(tokens) == 0) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT: no matching tokens! (no user tokens found)"); return 0; } t = apr_pstrdup(r->pool, tokens); while (*t && (next_parsed_token = ap_getword(r->pool, &t, ','))) { char ** auth_tokens = (char **) conf->auth_token->elts; int i; for (i=0; i < conf->auth_token->nelts; i++) { int token_len = strlen(auth_tokens[i]); if (strncmp(auth_tokens[i], next_parsed_token, token_len) == 0 && next_parsed_token[token_len] == 0) { match = 1; break; } } if (match) break; } if (conf->debug >= 1 && ! match) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT: no matching tokens! (user tokens '%s')", tokens); } return match; } /* Refresh the auth cookie if timeout refresh is set */ static void refresh_cookie(request_rec *r, auth_tkt *parsed, int timeout, int force_flag) { auth_tkt_serv_conf *sconf = ap_get_module_config(r->server->module_config, &auth_tkt_module); auth_tkt_dir_conf *conf = ap_get_module_config(r->per_dir_config, &auth_tkt_module); /* The timeout refresh is a double between 0 and 1, signifying what * proportion of the timeout should be left before we refresh i.e. * 0 means never refresh (hard timeouts); 1 means always refresh; * .33 means only refresh if less than a third of the timeout * period remains. */ unsigned int now = time(NULL); int remainder = parsed->timestamp + timeout - now; double refresh_sec = conf->timeout_refresh * timeout; if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT refresh_cookie: timeout %d, refresh %.3f, remainder %d, refresh_sec %.3f, force_flag %d", timeout, conf->timeout_refresh, remainder, refresh_sec, force_flag); } /* If less than our refresh_sec threshold, freshen the cookie */ if (force_flag || remainder < refresh_sec) { char *ticket, *ticket_base64; char *digest = ticket_digest(r, parsed, now, sconf->secret); if (parsed->tokens) { ticket = apr_psprintf(r->pool, "%s%08x%s%c%s%c%s", digest, now, parsed->uid, SEPARATOR, parsed->tokens, SEPARATOR, parsed->user_data); } else { ticket = apr_psprintf(r->pool, "%s%08x%s%c%s", digest, now, parsed->uid, SEPARATOR, parsed->user_data); } ticket_base64 = ap_pbase64encode(r->pool, ticket); send_auth_cookie(r, ticket_base64); } } /* Check whether the given timestamp has timed out * Returns 1 if okay, 0 if timed out */ static int check_timeout(request_rec *r, auth_tkt *parsed) { char *timeout_date, *timeout_cookie; auth_tkt_dir_conf *conf = ap_get_module_config(r->per_dir_config, &auth_tkt_module); unsigned int now = time(NULL); unsigned int timestamp = parsed->timestamp; char *domain = get_domain(r,conf); char *secure_cookie = conf->secure_cookie > 0 ? "; secure" : ""; int timeout; /* Return OK if no timeout configured */ if (conf->timeout_sec == 0) return 1; timeout = conf->timeout_sec == -1 ? DEFAULT_TIMEOUT_SEC : conf->timeout_sec; /* Check whether timestamp is still fresh */ if (timestamp + timeout >= now) { if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT: cookie timeout still good: now %d, timeout: %d, tstamp: %d", now, timeout, timestamp); } /* Check whether to refresh the cookie */ if (conf->timeout_refresh > 0) refresh_cookie(r, parsed, timeout, CHECK_REFRESH); return 1; } if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT: ticket timed out: now %d, timeout: %d, tstamp: %d", now, timeout, timestamp); } /* Delete cookie (set expired) if invalid, in case we want to set from url */ timeout_date = ap_ht_time(r->pool, now - 3600, "%a %d %b %Y %T %Z", 0); timeout_cookie = domain ? apr_psprintf(r->pool, "%s=; path=/; domain=%s; expires=%s%s", conf->auth_cookie_name, domain, timeout_date, secure_cookie) : apr_psprintf(r->pool, "%s=; path=/; expires=%s%s", conf->auth_cookie_name, timeout_date, secure_cookie); apr_table_setn(r->err_headers_out, "Set-Cookie", timeout_cookie); return 0; } /* Strip specified query args from a url */ static char * query_strip(request_rec *r, const char *strip) { const char *args = NULL; /* url arguments string */ const char *key, *val; char *new_args = ""; char *p; /* Use main request args if subrequest */ request_rec *r_main = r->main == NULL ? r : r->main; if (r_main->args == NULL || strip == NULL) return NULL; args = apr_pstrdup(r->pool, r_main->args); /* Convert all '&' to ';' */ while ((p = ap_strchr(args, '&'))) *p = ';'; /* Split into individual args */ while (*args && (val = ap_getword(r->pool, &args, ';'))) { key = ap_getword(r->pool, &val, '='); /* Add to new_args only if key != strip */ if (strlen(strip) != strlen(key) || strncmp(key,strip,strlen(strip)) != 0) new_args = apr_psprintf(r->pool, "%s&%s=%s", new_args, key, val); } if (strlen(new_args) > 0) return new_args + 1; return NULL; } /* Hex conversion, from httpd util.c */ static const char c2x_table[] = "0123456789abcdef"; static APR_INLINE unsigned char * c2x(unsigned what, unsigned char *where) { #if APR_CHARSET_EBCDIC what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what); #endif /*APR_CHARSET_EBCDIC*/ *where++ = '%'; *where++ = c2x_table[what >> 4]; *where++ = c2x_table[what & 0xf]; return where; } /* Extra escaping - variant of httpd util.c ap_escape_path_segment */ static char * escape_extras(apr_pool_t *p, const char *segment) { char *copy = apr_palloc(p, 3 * strlen(segment) + 1); const unsigned char *s = (const unsigned char *)segment; unsigned char *d = (unsigned char *)copy; unsigned c; while ((c = *s)) { if (c == '=' || c == '&' || c == ':') { d = c2x(c, d); } else { *d++ = c; } ++s; } *d = '\0'; return copy; } /* External redirect to the given url, setting back cookie or arg */ static int redirect(request_rec *r, char *location) { auth_tkt_dir_conf *conf = ap_get_module_config(r->per_dir_config, &auth_tkt_module); char *domain = get_domain(r,conf); char *back_cookie_name = conf->back_cookie_name; char *back_arg_name = conf->back_arg_name; char *url = location; char *cookie, *back; const char *hostinfo = 0; int port; /* Get the scheme we use (http or https) */ const char *scheme = ap_http_method(r); /* Strip any auth_cookie_name arguments from the current args */ char *query = query_strip(r, conf->auth_cookie_name); if (query == NULL) { query = ""; } else if (strlen(query) > 0) { query = apr_psprintf(r->pool, "?%s", query); } /* Build back URL */ /* Use X-Forward-Host header for host:port info if available */ /* Failing that, use Host header */ hostinfo = apr_table_get(r->headers_in, "X-Forwarded-Host"); if (! hostinfo) hostinfo = apr_table_get(r->headers_in, "Host"); if (! hostinfo) { /* Fallback to using r->hostname and the server port. This usually works, but behind a reverse proxy the port may well be wrong. On the other hand, it's really the proxy's problem, not ours. */ ap_log_rerror(APLOG_MARK, APLOG_INFO, APR_SUCCESS, r, "TKT: could not find Host header, falling back to hostname/server port"); port = ap_get_server_port(r); hostinfo = port == apr_uri_default_port_for_scheme(scheme) ? apr_psprintf(r->pool, "%s", r->hostname) : apr_psprintf(r->pool, "%s:%d", r->hostname, port); } /* If no scheme, assume location is relative and expand using scheme and hostinfo */ if (strncasecmp(location, "http", 4) != 0) { char *old_location = apr_pstrdup(r->pool, location); location = apr_psprintf(r->pool, "%s://%s/%s", scheme, hostinfo, location); if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT relative URL '%s' expanded to '%s'", old_location, location); } } /* Setup back URL */ back = apr_psprintf(r->pool, "%s://%s%s%s", scheme, hostinfo, r->uri, query); if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT: back url '%s'", back); } /* Escape testing */ back = ap_escape_path_segment(r->pool, back); back = escape_extras(r->pool, back); /* Set back cookie if name is not null */ if (back_cookie_name) { cookie = domain ? apr_psprintf(r->pool, "%s=%s; path=/; domain=%s", back_cookie_name, back, domain) : apr_psprintf(r->pool, "%s=%s; path=/", back_cookie_name, back); apr_table_setn(r->err_headers_out, "Set-Cookie", cookie); url = location; } /* If back_cookie_name not set, add a back url argument to url */ else if (back_arg_name) { char sep = '?'; if (ap_strchr(location, sep)) sep = conf->query_separator ? conf->query_separator[0] : QUERY_SEPARATOR; url = apr_psprintf(r->pool, "%s%c%s=%s", location, sep, back_arg_name, back); } if (conf->debug >= 2) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "TKT: redirect '%s'", url); } apr_table_setn(r->headers_out, "Location", url); return HTTP_TEMPORARY_REDIRECT; } /* Determine the guest username */ static char * get_guest_uid(request_rec *r, auth_tkt_dir_conf *conf) { #ifndef APACHE13 char *guest_user; int guest_user_length; apr_uuid_t *uuid; char *uuid_str, *uuid_length_str; #if AP_MODULE_MAGIC_AT_LEAST(20030213,1) ap_regex_t *uuid_regex; ap_regmatch_t regm[UUID_SUBS]; #else regex_t *uuid_regex; regmatch_t regm[UUID_SUBS]; #endif int uuid_length = -1; char *uuid_pre, *uuid_post; #endif /* if guest_empty, uid is just "" */ if(conf->guest_empty > 0) return ""; /* no guest user specified via config, use the default */ if (! conf->guest_user) { return DEFAULT_GUEST_USER; } #ifdef APACHE13 /* We don't support %U under apache1 at this point */ return conf->guest_user; #else /* use UUID if configured */ guest_user = apr_pstrdup(r->pool, conf->guest_user); uuid_regex = ap_pregcomp(r->pool, "%([0-9]*)U", 0); if (!ap_regexec(uuid_regex, guest_user, UUID_SUBS, regm, 0)) { /* Check whether a UUID length was specified */ if (regm[1].rm_so != -1) { uuid_length_str = ap_pregsub(r->pool, "$1", guest_user, UUID_SUBS, regm); if (uuid_length_str) uuid_length = atoi(uuid_length_str); } if (uuid_length <= 0 || uuid_length > APR_UUID_FORMATTED_LENGTH) { uuid_length = APR_UUID_FORMATTED_LENGTH; } if (conf->debug >= 1) { ap_log_rerror(APLOG_MARK, APLOG_INFO, APR_SUCCESS, r, "TKT: %%U found in guest user (length %d)", uuid_length); } /* Generate the UUID */ uuid = apr_palloc(r->pool, sizeof(*uuid)); uuid_str = apr_palloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1); apr_uuid_get(uuid); apr_uuid_format(uuid_str, uuid); if (uuid_length < APR_UUID_FORMATTED_LENGTH) uuid_str[uuid_length] = '\0'; /* Generate the new guest_user string */ guest_user_length = strlen(guest_user); if (regm[0].rm_so > 1) { guest_user[regm[1].rm_so-1] = '\0'; uuid_pre = guest_user; } else uuid_pre = ""; if (regm[0].rm_eo < guest_user_length) uuid_post = guest_user + regm[0].rm_eo; else uuid_post = ""; return apr_psprintf(r->pool, "%s%s%s", uuid_pre, uuid_str, uuid_post); } /* Otherwise, it's just a plain username. Return that. */ return conf->guest_user; #endif /* ! APACHE13 */ } /* Set up the guest user info */ static int setup_guest(request_rec *r, auth_tkt_dir_conf *conf, auth_tkt *tkt) { /* Only applicable if guest access on */ if (conf->guest_login <= 0) { return 0; } tkt->uid = get_guest_uid(r, conf); tkt->user_data = ""; tkt->tokens = ""; ap_log_rerror(APLOG_MARK, APLOG_INFO, APR_SUCCESS, r, "TKT: no valid ticket found - accepting as guest user '%s'", tkt->uid); return 1; } /* ----------------------------------------------------------------------- */ /* Debug routines */ void dump_config(request_rec *r, auth_tkt_serv_conf *sconf, auth_tkt_dir_conf *conf) { /* Dump config settings */ fprintf(stderr,"[ mod_auth_tkt config ]\n"); fprintf(stderr,"URI: %s\n", r->uri); fprintf(stderr,"Filename: %s\n", r->filename); fprintf(stderr,"TKTAuthSecret: %s\n", sconf->secret); fprintf(stderr,"TKTAuthSecretOld: %s\n", sconf->old_secret); fprintf(stderr,"TKTAuthDigestType: %s\n", sconf->digest_type); fprintf(stderr,"digest_sz: %d\n", sconf->digest_sz); fprintf(stderr,"directory: %s\n", conf->directory); fprintf(stderr,"TKTAuthLoginURL: %s\n", conf->login_url); fprintf(stderr,"TKTAuthTimeoutURL: %s\n", conf->timeout_url); fprintf(stderr,"TKTAuthPostTimeoutURL: %s\n", conf->post_timeout_url); fprintf(stderr,"TKTAuthUnauthURL: %s\n", conf->unauth_url); fprintf(stderr,"TKTAuthCookieName: %s\n", conf->auth_cookie_name); fprintf(stderr,"TKTAuthDomain: %s\n", conf->auth_domain); fprintf(stderr,"TKTAuthCookieExpires: %d\n", conf->cookie_expires); fprintf(stderr,"TKTAuthBackCookieName: %s\n", conf->back_cookie_name); fprintf(stderr,"TKTAuthBackArgName: %s\n", conf->back_arg_name); fprintf(stderr,"TKTAuthIgnoreIP: %d\n", conf->ignore_ip); fprintf(stderr,"TKTAuthRequireSSL: %d\n", conf->require_ssl); fprintf(stderr,"TKTAuthCookieSecure: %d\n", conf->secure_cookie); fprintf(stderr,"TKTAuthTimeoutMin: %d\n", conf->timeout_sec); fprintf(stderr,"TKTAuthTimeoutRefresh: %f\n", conf->timeout_refresh); fprintf(stderr,"TKTAuthGuestLogin: %d\n", conf->guest_login); fprintf(stderr,"TKTAuthGuestCookie: %d\n", conf->guest_cookie); fprintf(stderr,"TKTAuthGuestUser: %s\n", conf->guest_user); fprintf(stderr,"TKTAuthGuestFallback %d\n", conf->guest_fallback); fprintf(stderr,"TKTAuthGuestEmpty %d\n", conf->guest_empty); fprintf(stderr,"TKTAuthQuerySeparator: %s\n", conf->query_separator); if (conf->auth_token->nelts > 0) { char ** auth_token = (char **) conf->auth_token->elts; int i; for (i = 0; i < conf->auth_token->nelts; i++) { fprintf(stderr, "TKTAuthToken: %s\n", auth_token[i]); } } fprintf(stderr,"TKTAuthDebug: %d\n", conf->debug); fflush(stderr); } /* ----------------------------------------------------------------------- */ /* Main ticket authentication */ static int auth_tkt_check(request_rec *r) { char *ticket; auth_tkt *parsed = apr_palloc(r->pool, sizeof(*parsed)); auth_tkt_dir_conf *conf = ap_get_module_config(r->per_dir_config, &auth_tkt_module); auth_tkt_serv_conf *sconf = ap_get_module_config(r->server->module_config, &auth_tkt_module); const char *scheme = ap_http_method(r); int guest = 0; int timeout; int force_cookie_refresh = 0; char *url = NULL; /* Default digest_type if not set */ if (! sconf->digest_type) { sconf->digest_type = DEFAULT_DIGEST_TYPE; setup_digest_sz(sconf); } /* Map "None" back_arg_name to NULL */ if (conf->back_arg_name && strcmp(conf->back_arg_name, "None") == 0) conf->back_arg_name = NULL; /* Dump config if debugging */ if (conf->debug >= 2) dump_config(r, sconf, conf); /* Module not configured unless login_url or guest_login is set */ if (! conf->login_url && conf->guest_login <= 0) { return DECLINED; } /* Module misconfigured unless secret set */ if (! sconf->secret) { ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r, "TKT: TKTAuthSecret missing"); return HTTP_INTERNAL_SERVER_ERROR; } /* Redirect/login if scheme not "https" and require_ssl is set */ if (conf->require_ssl > 0 && strcmp(scheme,"https") != 0) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, r, "TKT: redirect/login - unsecured request, TKTAuthRequireSSL is on"); return redirect(r, conf->login_url); } /* Backwards compatibility mode for TKTAuthRequireSSL */ if (conf->require_ssl > 0 && conf->secure_cookie == -1) { /* Set secure_cookie flag if require_ssl is set and secure_cookie is undefined (as opposed to 'off') */ ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, r, "TKT: TKTAuthRequireSSL on, but no TKTAuthCookieSecure found - " "please set TKTAuthCookieSecure explicitly, assuming 'on'"); conf->secure_cookie = 1; } /* Check for url ticket - either found (accept) or empty (reset/login) */ ticket = get_url_ticket(r); if (! ticket || ! valid_ticket(r, "url", ticket, parsed, &force_cookie_refresh)) { ticket = get_cookie_ticket(r); if (! ticket || ! valid_ticket(r, "cookie", ticket, parsed, &force_cookie_refresh)) { if (conf->guest_login > 0) { guest = setup_guest(r, conf, parsed); } if (! guest) { if (conf->login_url) { ap_log_rerror(APLOG_MARK, APLOG_INFO, APR_SUCCESS, r, "TKT: no valid ticket found - redirecting to login url"); return redirect(r, conf->login_url); } else { /* Fatal error: guest setup failed, but we have no login url defined */ ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r, "TKT: guest login failed and no login url to fall back to - aborting"); return HTTP_INTERNAL_SERVER_ERROR; } } } } /* Valid ticket, check timeout - redirect/timed-out if so */ if (! guest && ! check_timeout(r, parsed)) { /* Timeout! Check for guest access and guest_fallback */ if (conf->guest_login > 0 && conf->guest_fallback > 0) { guest = setup_guest(r, conf, parsed); } if (!guest) { /* Special timeout URL can be defined for POST requests */ if (strcmp(r->method, "POST") == 0 && conf->post_timeout_url) { url = conf->post_timeout_url; } else { url = conf->timeout_url ? conf->timeout_url : conf->login_url; } if (url) { return redirect(r, url); } else { /* Fatal error: guest setup failed, but we have no url to redirect to */ ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r, "TKT: ticket timeout, guest login failed, and no url to fall back to - aborting"); return HTTP_INTERNAL_SERVER_ERROR; } } } /* Valid ticket, check tokens - redirect/unauthorised if so */ if (! check_tokens(r, parsed->tokens)) { return redirect(r, conf->unauth_url ? conf->unauth_url : conf->login_url); } /* If force_cookie_refresh flag is set (because the current ticket is using TKTAuthSecretOld), * or this is a new guest login and the guest_cookie flag is set, force a cookie refresh */ if (force_cookie_refresh || (guest && conf->guest_cookie > 0)) { timeout = conf->timeout_sec == -1 ? DEFAULT_TIMEOUT_SEC : conf->timeout_sec; refresh_cookie(r, parsed, timeout, FORCE_REFRESH); } /* Setup apache user, auth_type, and environment variables */ #ifdef APACHE13 r->connection->user = parsed->uid; r->connection->ap_auth_type = "Basic"; #else r->user = parsed->uid; r->ap_auth_type = "Basic"; #endif apr_table_set(r->subprocess_env, REMOTE_USER_ENV, parsed->uid); apr_table_set(r->subprocess_env, REMOTE_USER_DATA_ENV, parsed->user_data); apr_table_set(r->subprocess_env, REMOTE_USER_TOKENS_ENV, parsed->tokens); return OK; } /* ----------------------------------------------------------------------- */ /* Setup main module data structure */ #ifdef APACHE13 /* Apache 1.3 style */ module MODULE_VAR_EXPORT auth_tkt_module = { STANDARD_MODULE_STUFF, auth_tkt_version, /* initializer */ create_auth_tkt_config, /* create per-dir config structures */ merge_auth_tkt_config, /* merge per-dir config structures */ create_auth_tkt_serv_config, /* create per-server config structures */ merge_auth_tkt_serv_config, /* merge per-server config structures */ auth_tkt_cmds, /* table of config file commands */ NULL, /* handlers */ NULL, /* filename translation */ auth_tkt_check, /* check user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* chitkt_init */ NULL, /* chitkt_exit */ NULL /* post read-request */ }; #else /* Apache 2.0 style */ /* Register hooks */ static void auth_tkt_register_hooks (apr_pool_t *p) { ap_hook_post_config(auth_tkt_version, NULL, NULL, APR_HOOK_MIDDLE); #if AP_MODULE_MAGIC_AT_LEAST(20080403,1) ap_hook_check_authn(auth_tkt_check, NULL, NULL, APR_HOOK_FIRST, AP_AUTH_INTERNAL_PER_CONF); #else ap_hook_check_user_id(auth_tkt_check, NULL, NULL, APR_HOOK_FIRST); #endif } /* Declare and populate the main module data structure */ module AP_MODULE_DECLARE_DATA auth_tkt_module = { STANDARD20_MODULE_STUFF, create_auth_tkt_config, /* create per-dir config structures */ merge_auth_tkt_config, /* merge per-dir config structures */ create_auth_tkt_serv_config, /* create per-server config structures */ merge_auth_tkt_serv_config, /* merge per-server config structures */ auth_tkt_cmds, /* table of config file commands */ auth_tkt_register_hooks /* register hooks */ }; #endif /* * vim:sw=2:sm:et */ mod_auth_tkt-2.3.99b1/src/sha2.c000066400000000000000000001120431255657270700163340ustar00rootroot00000000000000/* SHA2 support, from apr 1.2.7, for use by mod_auth_tkt. Unfortunately * this is not a public/exported library in current versions of apr * (despite discussion to that effect since 2005), so for now we're just * using a private copy. */ /* Copyright 2003-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * FILE: sha2.c * AUTHOR: Aaron D. Gifford * * A licence was granted to the ASF by Aaron on 4 November 2003. */ #include /* memcpy()/memset() or bcopy()/bzero() */ #include /* assert() */ #include "sha2.h" /* * ASSERT NOTE: * Some sanity checking code is included using assert(). On my FreeBSD * system, this additional code can be removed by compiling with NDEBUG * defined. Check your own systems manpage on assert() to see how to * compile WITHOUT the sanity checking code on your system. * * UNROLLED TRANSFORM LOOP NOTE: * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform * loop version for the hash transform rounds (defined using macros * later in this file). Either define on the command line, for example: * * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c * * or define below: * * #define SHA2_UNROLL_TRANSFORM * */ /*** SHA-256/384/512 Machine Architecture Definitions *****************/ typedef apr_byte_t sha2_byte; /* Exactly 1 byte */ typedef apr_uint32_t sha2_word32; /* Exactly 4 bytes */ typedef apr_uint64_t sha2_word64; /* Exactly 8 bytes */ /*** SHA-256/384/512 Various Length Definitions ***********************/ /* NOTE: Most of these are in sha2.h */ #define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) #define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) #define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) /*** ENDIAN REVERSAL MACROS *******************************************/ #if !APR_IS_BIGENDIAN #define REVERSE32(w,x) { \ sha2_word32 tmp = (w); \ tmp = (tmp >> 16) | (tmp << 16); \ (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ } #define REVERSE64(w,x) { \ sha2_word64 tmp = (w); \ tmp = (tmp >> 32) | (tmp << 32); \ tmp = ((tmp & APR_UINT64_C(0xff00ff00ff00ff00)) >> 8) | \ ((tmp & APR_UINT64_C(0x00ff00ff00ff00ff)) << 8); \ (x) = ((tmp & APR_UINT64_C(0xffff0000ffff0000)) >> 16) | \ ((tmp & APR_UINT64_C(0x0000ffff0000ffff)) << 16); \ } #endif /* !APR_IS_BIGENDIAN */ /* * Macro for incrementally adding the unsigned 64-bit integer n to the * unsigned 128-bit integer (represented using a two-element array of * 64-bit words): */ #define ADDINC128(w,n) { \ (w)[0] += (sha2_word64)(n); \ if ((w)[0] < (n)) { \ (w)[1]++; \ } \ } /* * Macros for copying blocks of memory and for zeroing out ranges * of memory. Using these macros makes it easy to switch from * using memset()/memcpy() and using bzero()/bcopy(). * * Please define either SHA2_USE_MEMSET_MEMCPY or define * SHA2_USE_BZERO_BCOPY depending on which function set you * choose to use: */ #if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) /* Default to memset()/memcpy() if no option is specified */ #define SHA2_USE_MEMSET_MEMCPY 1 #endif #if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) /* Abort with an error if BOTH options are defined */ #error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! #endif #ifdef SHA2_USE_MEMSET_MEMCPY #define MEMSET_BZERO(p,l) memset((p), 0, (l)) #define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) #endif #ifdef SHA2_USE_BZERO_BCOPY #define MEMSET_BZERO(p,l) bzero((p), (l)) #define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) #endif /*** THE SIX LOGICAL FUNCTIONS ****************************************/ /* * Bit shifting and rotation (used by the six SHA-XYZ logical functions: * * NOTE: The naming of R and S appears backwards here (R is a SHIFT and * S is a ROTATION) because the SHA-256/384/512 description document * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this * same "backwards" definition. */ /* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ #define R(b,x) ((x) >> (b)) /* 32-bit Rotate-right (used in SHA-256): */ #define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) /* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ #define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) /* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ #define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) #define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) /* Four of six logical functions used in SHA-256: */ #define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) #define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) #define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) #define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) /* Four of six logical functions used in SHA-384 and SHA-512: */ #define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) #define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) #define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) #define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) /*** INTERNAL FUNCTION PROTOTYPES *************************************/ /* NOTE: These should not be accessed directly from outside this * library -- they are intended for private internal visibility/use * only. */ void mat_SHA512_Last(SHA512_CTX*); void mat_SHA256_Transform(SHA256_CTX*, const sha2_word32*); void mat_SHA512_Transform(SHA512_CTX*, const sha2_word64*); /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ /* Hash constant words K for SHA-256: */ const static sha2_word32 K256[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; /* Initial hash value H for SHA-256: */ const static sha2_word32 sha256_initial_hash_value[8] = { 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL }; /* Hash constant words K for SHA-384 and SHA-512: */ const static sha2_word64 K512[80] = { APR_UINT64_C(0x428a2f98d728ae22), APR_UINT64_C(0x7137449123ef65cd), APR_UINT64_C(0xb5c0fbcfec4d3b2f), APR_UINT64_C(0xe9b5dba58189dbbc), APR_UINT64_C(0x3956c25bf348b538), APR_UINT64_C(0x59f111f1b605d019), APR_UINT64_C(0x923f82a4af194f9b), APR_UINT64_C(0xab1c5ed5da6d8118), APR_UINT64_C(0xd807aa98a3030242), APR_UINT64_C(0x12835b0145706fbe), APR_UINT64_C(0x243185be4ee4b28c), APR_UINT64_C(0x550c7dc3d5ffb4e2), APR_UINT64_C(0x72be5d74f27b896f), APR_UINT64_C(0x80deb1fe3b1696b1), APR_UINT64_C(0x9bdc06a725c71235), APR_UINT64_C(0xc19bf174cf692694), APR_UINT64_C(0xe49b69c19ef14ad2), APR_UINT64_C(0xefbe4786384f25e3), APR_UINT64_C(0x0fc19dc68b8cd5b5), APR_UINT64_C(0x240ca1cc77ac9c65), APR_UINT64_C(0x2de92c6f592b0275), APR_UINT64_C(0x4a7484aa6ea6e483), APR_UINT64_C(0x5cb0a9dcbd41fbd4), APR_UINT64_C(0x76f988da831153b5), APR_UINT64_C(0x983e5152ee66dfab), APR_UINT64_C(0xa831c66d2db43210), APR_UINT64_C(0xb00327c898fb213f), APR_UINT64_C(0xbf597fc7beef0ee4), APR_UINT64_C(0xc6e00bf33da88fc2), APR_UINT64_C(0xd5a79147930aa725), APR_UINT64_C(0x06ca6351e003826f), APR_UINT64_C(0x142929670a0e6e70), APR_UINT64_C(0x27b70a8546d22ffc), APR_UINT64_C(0x2e1b21385c26c926), APR_UINT64_C(0x4d2c6dfc5ac42aed), APR_UINT64_C(0x53380d139d95b3df), APR_UINT64_C(0x650a73548baf63de), APR_UINT64_C(0x766a0abb3c77b2a8), APR_UINT64_C(0x81c2c92e47edaee6), APR_UINT64_C(0x92722c851482353b), APR_UINT64_C(0xa2bfe8a14cf10364), APR_UINT64_C(0xa81a664bbc423001), APR_UINT64_C(0xc24b8b70d0f89791), APR_UINT64_C(0xc76c51a30654be30), APR_UINT64_C(0xd192e819d6ef5218), APR_UINT64_C(0xd69906245565a910), APR_UINT64_C(0xf40e35855771202a), APR_UINT64_C(0x106aa07032bbd1b8), APR_UINT64_C(0x19a4c116b8d2d0c8), APR_UINT64_C(0x1e376c085141ab53), APR_UINT64_C(0x2748774cdf8eeb99), APR_UINT64_C(0x34b0bcb5e19b48a8), APR_UINT64_C(0x391c0cb3c5c95a63), APR_UINT64_C(0x4ed8aa4ae3418acb), APR_UINT64_C(0x5b9cca4f7763e373), APR_UINT64_C(0x682e6ff3d6b2b8a3), APR_UINT64_C(0x748f82ee5defb2fc), APR_UINT64_C(0x78a5636f43172f60), APR_UINT64_C(0x84c87814a1f0ab72), APR_UINT64_C(0x8cc702081a6439ec), APR_UINT64_C(0x90befffa23631e28), APR_UINT64_C(0xa4506cebde82bde9), APR_UINT64_C(0xbef9a3f7b2c67915), APR_UINT64_C(0xc67178f2e372532b), APR_UINT64_C(0xca273eceea26619c), APR_UINT64_C(0xd186b8c721c0c207), APR_UINT64_C(0xeada7dd6cde0eb1e), APR_UINT64_C(0xf57d4f7fee6ed178), APR_UINT64_C(0x06f067aa72176fba), APR_UINT64_C(0x0a637dc5a2c898a6), APR_UINT64_C(0x113f9804bef90dae), APR_UINT64_C(0x1b710b35131c471b), APR_UINT64_C(0x28db77f523047d84), APR_UINT64_C(0x32caab7b40c72493), APR_UINT64_C(0x3c9ebe0a15c9bebc), APR_UINT64_C(0x431d67c49c100d4c), APR_UINT64_C(0x4cc5d4becb3e42b6), APR_UINT64_C(0x597f299cfc657e2a), APR_UINT64_C(0x5fcb6fab3ad6faec), APR_UINT64_C(0x6c44198c4a475817) }; /* Initial hash value H for SHA-384 */ const static sha2_word64 sha384_initial_hash_value[8] = { APR_UINT64_C(0xcbbb9d5dc1059ed8), APR_UINT64_C(0x629a292a367cd507), APR_UINT64_C(0x9159015a3070dd17), APR_UINT64_C(0x152fecd8f70e5939), APR_UINT64_C(0x67332667ffc00b31), APR_UINT64_C(0x8eb44a8768581511), APR_UINT64_C(0xdb0c2e0d64f98fa7), APR_UINT64_C(0x47b5481dbefa4fa4) }; /* Initial hash value H for SHA-512 */ const static sha2_word64 sha512_initial_hash_value[8] = { APR_UINT64_C(0x6a09e667f3bcc908), APR_UINT64_C(0xbb67ae8584caa73b), APR_UINT64_C(0x3c6ef372fe94f82b), APR_UINT64_C(0xa54ff53a5f1d36f1), APR_UINT64_C(0x510e527fade682d1), APR_UINT64_C(0x9b05688c2b3e6c1f), APR_UINT64_C(0x1f83d9abfb41bd6b), APR_UINT64_C(0x5be0cd19137e2179) }; /* * Constant used by SHA256/384/512_End() functions for converting the * digest to a readable hexadecimal character string: */ static const char *sha2_hex_digits = "0123456789abcdef"; /*** SHA-256: *********************************************************/ void mat_SHA256_Init(SHA256_CTX* context) { if (context == (SHA256_CTX*)0) { return; } MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); context->bitcount = 0; } #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-256 round macros: */ #if !APR_IS_BIGENDIAN #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ REVERSE32(*data++, W256[j]); \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ K256[j] + W256[j]; \ (d) += T1; \ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ #else /* APR_IS_BIGENDIAN */ #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ K256[j] + (W256[j] = *data++); \ (d) += T1; \ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ #endif /* APR_IS_BIGENDIAN */ #define ROUND256(a,b,c,d,e,f,g,h) \ s0 = W256[(j+1)&0x0f]; \ s0 = sigma0_256(s0); \ s1 = W256[(j+14)&0x0f]; \ s1 = sigma1_256(s1); \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ void mat_SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { sha2_word32 a, b, c, d, e, f, g, h, s0, s1; sha2_word32 T1, *W256; int j; W256 = (sha2_word32*)context->buffer; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { /* Rounds 0 to 15 (unrolled): */ ROUND256_0_TO_15(a,b,c,d,e,f,g,h); ROUND256_0_TO_15(h,a,b,c,d,e,f,g); ROUND256_0_TO_15(g,h,a,b,c,d,e,f); ROUND256_0_TO_15(f,g,h,a,b,c,d,e); ROUND256_0_TO_15(e,f,g,h,a,b,c,d); ROUND256_0_TO_15(d,e,f,g,h,a,b,c); ROUND256_0_TO_15(c,d,e,f,g,h,a,b); ROUND256_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds to 64: */ do { ROUND256(a,b,c,d,e,f,g,h); ROUND256(h,a,b,c,d,e,f,g); ROUND256(g,h,a,b,c,d,e,f); ROUND256(f,g,h,a,b,c,d,e); ROUND256(e,f,g,h,a,b,c,d); ROUND256(d,e,f,g,h,a,b,c); ROUND256(c,d,e,f,g,h,a,b); ROUND256(b,c,d,e,f,g,h,a); } while (j < 64); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void mat_SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { sha2_word32 a, b, c, d, e, f, g, h, s0, s1; sha2_word32 T1, T2, *W256; int j; W256 = (sha2_word32*)context->buffer; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { #if !APR_IS_BIGENDIAN /* Copy data while converting to host byte order */ REVERSE32(*data++,W256[j]); /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; #else /* APR_IS_BIGENDIAN */ /* Apply the SHA-256 compression function to update a..h with copy */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); #endif /* APR_IS_BIGENDIAN */ T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W256[(j+1)&0x0f]; s0 = sigma0_256(s0); s1 = W256[(j+14)&0x0f]; s1 = sigma1_256(s1); /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 64); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void mat_SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { unsigned int freespace, usedspace; if (len == 0) { /* Calling with no data is valid - we do nothing */ return; } /* Sanity check: */ assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); usedspace = (unsigned int)((context->bitcount >> 3) % SHA256_BLOCK_LENGTH); if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA256_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); context->bitcount += freespace << 3; len -= freespace; data += freespace; mat_SHA256_Transform(context, (sha2_word32*)context->buffer); } else { /* The buffer is not yet full */ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); context->bitcount += len << 3; /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA256_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ mat_SHA256_Transform(context, (sha2_word32*)data); context->bitcount += SHA256_BLOCK_LENGTH << 3; len -= SHA256_BLOCK_LENGTH; data += SHA256_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ MEMCPY_BCOPY(context->buffer, data, len); context->bitcount += len << 3; } /* Clean up: */ usedspace = freespace = 0; } void mat_SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { sha2_word32 *d = (sha2_word32*)digest; unsigned int usedspace; /* Sanity check: */ assert(context != (SHA256_CTX*)0); /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { usedspace = (unsigned int)((context->bitcount >> 3) % SHA256_BLOCK_LENGTH); #if !APR_IS_BIGENDIAN /* Convert FROM host byte order */ REVERSE64(context->bitcount,context->bitcount); #endif if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA256_BLOCK_LENGTH) { MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ mat_SHA256_Transform(context, (sha2_word32*)context->buffer); /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); } } else { /* Set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Set the bit count: */ *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; /* Final transform: */ mat_SHA256_Transform(context, (sha2_word32*)context->buffer); #if !APR_IS_BIGENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 8; j++) { REVERSE32(context->state[j],context->state[j]); *d++ = context->state[j]; } } #else MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); #endif } /* Clean up state data: */ MEMSET_BZERO(context, sizeof(context)); usedspace = 0; } char *mat_SHA256_End(SHA256_CTX* context, char buffer[]) { sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; char *b = buffer; int i; /* Sanity check: */ assert(context != (SHA256_CTX*)0); if (b != (char*)0) { mat_SHA256_Final(digest, context); for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { *b++ = sha2_hex_digits[(*d & 0xf0) >> 4]; *b++ = sha2_hex_digits[*d & 0x0f]; d++; } *b = (char)0; } else { MEMSET_BZERO(context, sizeof(context)); } MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); return buffer; } char* mat_SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { SHA256_CTX context; mat_SHA256_Init(&context); mat_SHA256_Update(&context, data, len); return mat_SHA256_End(&context, digest); } /*** SHA-512: *********************************************************/ void mat_SHA512_Init(SHA512_CTX* context) { if (context == (SHA512_CTX*)0) { return; } MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-512 round macros: */ #if !APR_IS_BIGENDIAN #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ REVERSE64(*data++, W512[j]); \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ K512[j] + W512[j]; \ (d) += T1, \ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ j++ #else /* APR_IS_BIGENDIAN */ #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ K512[j] + (W512[j] = *data++); \ (d) += T1; \ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ j++ #endif /* APR_IS_BIGENDIAN */ #define ROUND512(a,b,c,d,e,f,g,h) \ s0 = W512[(j+1)&0x0f]; \ s0 = sigma0_512(s0); \ s1 = W512[(j+14)&0x0f]; \ s1 = sigma1_512(s1); \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ j++ void mat_SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; int j; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { ROUND512_0_TO_15(a,b,c,d,e,f,g,h); ROUND512_0_TO_15(h,a,b,c,d,e,f,g); ROUND512_0_TO_15(g,h,a,b,c,d,e,f); ROUND512_0_TO_15(f,g,h,a,b,c,d,e); ROUND512_0_TO_15(e,f,g,h,a,b,c,d); ROUND512_0_TO_15(d,e,f,g,h,a,b,c); ROUND512_0_TO_15(c,d,e,f,g,h,a,b); ROUND512_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds up to 79: */ do { ROUND512(a,b,c,d,e,f,g,h); ROUND512(h,a,b,c,d,e,f,g); ROUND512(g,h,a,b,c,d,e,f); ROUND512(f,g,h,a,b,c,d,e); ROUND512(e,f,g,h,a,b,c,d); ROUND512(d,e,f,g,h,a,b,c); ROUND512(c,d,e,f,g,h,a,b); ROUND512(b,c,d,e,f,g,h,a); } while (j < 80); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void mat_SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { sha2_word64 a, b, c, d, e, f, g, h, s0, s1; sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; int j; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { #if !APR_IS_BIGENDIAN /* Convert TO host byte order */ REVERSE64(*data++, W512[j]); /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; #else /* APR_IS_BIGENDIAN */ /* Apply the SHA-512 compression function to update a..h with copy */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); #endif /* APR_IS_BIGENDIAN */ T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W512[(j+1)&0x0f]; s0 = sigma0_512(s0); s1 = W512[(j+14)&0x0f]; s1 = sigma1_512(s1); /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 80); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void mat_SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { unsigned int freespace, usedspace; if (len == 0) { /* Calling with no data is valid - we do nothing */ return; } /* Sanity check: */ assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); usedspace = (unsigned int)((context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH); if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA512_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); ADDINC128(context->bitcount, freespace << 3); len -= freespace; data += freespace; mat_SHA512_Transform(context, (sha2_word64*)context->buffer); } else { /* The buffer is not yet full */ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); ADDINC128(context->bitcount, len << 3); /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA512_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ mat_SHA512_Transform(context, (sha2_word64*)data); ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); len -= SHA512_BLOCK_LENGTH; data += SHA512_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ MEMCPY_BCOPY(context->buffer, data, len); ADDINC128(context->bitcount, len << 3); } /* Clean up: */ usedspace = freespace = 0; } void mat_SHA512_Last(SHA512_CTX* context) { unsigned int usedspace; usedspace = (unsigned int)((context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH); #if !APR_IS_BIGENDIAN /* Convert FROM host byte order */ REVERSE64(context->bitcount[0],context->bitcount[0]); REVERSE64(context->bitcount[1],context->bitcount[1]); #endif if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA512_BLOCK_LENGTH) { MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ mat_SHA512_Transform(context, (sha2_word64*)context->buffer); /* And set-up for the last transform: */ MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); } } else { /* Prepare for final transform: */ MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Store the length of input data (in bits): */ *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; /* Final transform: */ mat_SHA512_Transform(context, (sha2_word64*)context->buffer); } void mat_SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { sha2_word64 *d = (sha2_word64*)digest; /* Sanity check: */ assert(context != (SHA512_CTX*)0); /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { mat_SHA512_Last(context); /* Save the hash data for output: */ #if !APR_IS_BIGENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 8; j++) { REVERSE64(context->state[j],context->state[j]); *d++ = context->state[j]; } } #else /* APR_IS_BIGENDIAN */ MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); #endif /* APR_IS_BIGENDIAN */ } /* Zero out state data */ MEMSET_BZERO(context, sizeof(context)); } char *mat_SHA512_End(SHA512_CTX* context, char buffer[]) { sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; char *b = buffer; int i; /* Sanity check: */ assert(context != (SHA512_CTX*)0); if (b != (char*)0) { mat_SHA512_Final(digest, context); for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { *b++ = sha2_hex_digits[(*d & 0xf0) >> 4]; *b++ = sha2_hex_digits[*d & 0x0f]; d++; } *b = (char)0; } else { MEMSET_BZERO(context, sizeof(context)); } MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); return buffer; } char* mat_SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { SHA512_CTX context; mat_SHA512_Init(&context); mat_SHA512_Update(&context, data, len); return mat_SHA512_End(&context, digest); } /*** SHA-384: *********************************************************/ void mat_SHA384_Init(SHA384_CTX* context) { if (context == (SHA384_CTX*)0) { return; } MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } void mat_SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { mat_SHA512_Update((SHA512_CTX*)context, data, len); } void mat_SHA384_Final(sha2_byte digest[], SHA384_CTX* context) { sha2_word64 *d = (sha2_word64*)digest; /* Sanity check: */ assert(context != (SHA384_CTX*)0); /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { mat_SHA512_Last((SHA512_CTX*)context); /* Save the hash data for output: */ #if !APR_IS_BIGENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 6; j++) { REVERSE64(context->state[j],context->state[j]); *d++ = context->state[j]; } } #else /* APR_IS_BIGENDIAN */ MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH); #endif /* APR_IS_BIGENDIAN */ } /* Zero out state data */ MEMSET_BZERO(context, sizeof(context)); } char *mat_SHA384_End(SHA384_CTX* context, char buffer[]) { sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; char *b = buffer; int i; /* Sanity check: */ assert(context != (SHA384_CTX*)0); if (b != (char*)0) { mat_SHA384_Final(digest, context); for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { *b++ = sha2_hex_digits[(*d & 0xf0) >> 4]; *b++ = sha2_hex_digits[*d & 0x0f]; d++; } *b = (char)0; } else { MEMSET_BZERO(context, sizeof(context)); } MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH); return buffer; } char* mat_SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { SHA384_CTX context; mat_SHA384_Init(&context); mat_SHA384_Update(&context, data, len); return mat_SHA384_End(&context, digest); } mod_auth_tkt-2.3.99b1/src/sha2.h000066400000000000000000000064051255657270700163450ustar00rootroot00000000000000/* SHA2 support, from apr 1.2.7, for use by mod_auth_tkt. Unfortunately * this is not a public/exported library in current versions of apr * (despite discussion to that effect since 2005), so for now we're just * using a private copy. */ /* Copyright 2003-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * FILE: sha2.h * AUTHOR: Aaron D. Gifford * * A licence was granted to the ASF by Aaron on 4 November 2003. */ #ifndef __SHA2_H__ #define __SHA2_H__ #ifdef __cplusplus extern "C" { #endif #include "apr.h" /*** SHA-256/384/512 Various Length Definitions ***********************/ #define SHA256_BLOCK_LENGTH 64 #define SHA256_DIGEST_LENGTH 32 #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) #define SHA384_BLOCK_LENGTH 128 #define SHA384_DIGEST_LENGTH 48 #define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) #define SHA512_BLOCK_LENGTH 128 #define SHA512_DIGEST_LENGTH 64 #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) /*** SHA-256/384/512 Context Structures *******************************/ typedef struct _SHA256_CTX { apr_uint32_t state[8]; apr_uint64_t bitcount; apr_byte_t buffer[SHA256_BLOCK_LENGTH]; } SHA256_CTX; typedef struct _SHA512_CTX { apr_uint64_t state[8]; apr_uint64_t bitcount[2]; apr_byte_t buffer[SHA512_BLOCK_LENGTH]; } SHA512_CTX; typedef SHA512_CTX SHA384_CTX; /*** SHA-256/384/512 Function Prototypes ******************************/ void mat_SHA256_Init(SHA256_CTX *); void mat_SHA256_Update(SHA256_CTX *, const apr_byte_t *, size_t); void mat_SHA256_Final(apr_byte_t [SHA256_DIGEST_LENGTH], SHA256_CTX *); char* mat_SHA256_End(SHA256_CTX *, char [SHA256_DIGEST_STRING_LENGTH]); char* mat_SHA256_Data(const apr_byte_t *, size_t, char [SHA256_DIGEST_STRING_LENGTH]); void mat_SHA384_Init(SHA384_CTX *); void mat_SHA384_Update(SHA384_CTX *, const apr_byte_t *, size_t); void mat_SHA384_Final(apr_byte_t [SHA384_DIGEST_LENGTH], SHA384_CTX *); char* mat_SHA384_End(SHA384_CTX *, char [SHA384_DIGEST_STRING_LENGTH]); char* mat_SHA384_Data(const apr_byte_t *, size_t, char [SHA384_DIGEST_STRING_LENGTH]); void mat_SHA512_Init(SHA512_CTX *); void mat_SHA512_Update(SHA512_CTX *, const apr_byte_t *, size_t); void mat_SHA512_Final(apr_byte_t [SHA512_DIGEST_LENGTH], SHA512_CTX *); char* mat_SHA512_End(SHA512_CTX *, char [SHA512_DIGEST_STRING_LENGTH]); char* mat_SHA512_Data(const apr_byte_t *, size_t, char [SHA512_DIGEST_STRING_LENGTH]); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __SHA2_H__ */ mod_auth_tkt-2.3.99b1/t/000077500000000000000000000000001255657270700150065ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/t/00_public.t000066400000000000000000000005221255657270700167470ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest 'GET_BODY'; plan tests => 2; ok 1; # simple load test my $url = '/public.html'; my $data = GET_BODY $url; ok t_cmp($data, qr/^This is public/, 'GET on public file'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/01_basic.t000066400000000000000000000034571255657270700165650ustar00rootroot00000000000000#!/usr/bin/env perl # # Basic mod_auth_tkt testing, with minimal config # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt 2.1; plan tests => 7, need_lwp; # Setup cookie jar, turn off automatic redirection following my $jar = HTTP::Cookies->new; Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $url = '/secret_basic/index.html'; my $res; my $ticket; # No cookie - should be redirected $res = GET $url; ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate good ticket - should NOT redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket'); # Retry with non-base64-escaped ticket - should NOT redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1', base64 => 0); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with non-base64 ticket'); # Retest with munged ticket - should redirect $ticket =~ s/^../XX/; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with munged cookie'); # Retest with bad ip address - should redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '192.168.0.1'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with incorrect IP address'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/01_relative.t000066400000000000000000000042131255657270700173060ustar00rootroot00000000000000#!/usr/bin/env perl # # Basic mod_auth_tkt testing, with minimal config # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; plan tests => 10, need_lwp; # Setup cookie jar, turn off automatic redirection following my $jar = HTTP::Cookies->new; Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $url = '/secret_relative_url/index.html'; my $res = GET $url; my $ticket; # No cookie - should be redirected ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); ok t_cmp($res->header('Location'), qr!^http://localhost.localdomain//pub/login.cgi!, 'redirect is to absolute url'); # Generate good ticket - should NOT redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket'); # Retry with non-base64-escaped ticket - should NOT redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1', base64 => 0); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with non-base64 ticket'); # Retest with munged ticket - should redirect $ticket =~ s/^../XX/; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with munged cookie'); ok t_cmp($res->header('Location'), qr!^http://localhost.localdomain//pub/login.cgi!, 'redirect is to absolute url'); # Retest with bad ip address - should redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '192.168.0.1'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with incorrect IP address'); ok t_cmp($res->header('Location'), qr!^http://localhost.localdomain//pub/login.cgi!, 'redirect is to absolute url'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/02_bad.t000066400000000000000000000035541255657270700162310ustar00rootroot00000000000000#!/usr/bin/env perl # # Test various bad ticket formats # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; plan tests => 8, need_lwp; # Turn off automatic redirection following Apache::TestRequest::user_agent( requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $url = '/secret_basic/index.html'; my $res = GET $url; # Test no cookie - should be redirected ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate ticket and cookie jar my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); my $jar = HTTP::Cookies->new; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); # print $jar->as_string; # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Test good ticket - should NOT redirect $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with good ticket'); # Test with empty ticket $jar->set_cookie(1, 'auth_tkt', '', '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with empty ticket'); # Test very small ticket I $jar->set_cookie(1, 'auth_tkt', 'X', '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with very small ticket I'); # Test very small ticket II $jar->set_cookie(1, 'auth_tkt', 'ABC', '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with very small ticket II'); # Test very large ticket $jar->set_cookie(1, 'auth_tkt', 'X' x 1025, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with very large ticket'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/03_ignore_ip.t000066400000000000000000000031041255657270700174460ustar00rootroot00000000000000#!/usr/bin/env perl # # Testing with TKTAuthIgnoreIP on # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; plan tests => 6, need_lwp; # Turn off automatic redirection following Apache::TestRequest::user_agent( requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $url = '/secret_ignore_ip/index.html'; my $res = GET $url; # No cookie - should be redirected ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate ticket and cookie jar my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); my $jar = HTTP::Cookies->new; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); # print $jar->as_string; # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Test with cookie - should redirect, since TKTAuthIgnoreIP on $res = GET $url; ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'ip addr ticket: redirect to login'); # Create ticket with 0.0.0.0 ip address - accepted with TKTAuthIgnoreIP on $ticket = $at->ticket(uid => 'testuser', ip_addr => '0.0.0.0'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with 0.0.0.0 ip ticket'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/04_back.t000066400000000000000000000025171255657270700164030ustar00rootroot00000000000000#!/usr/bin/env perl # # Back argument testing # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt 2.1; plan tests => 7, need_lwp; # Setup cookie jar, turn off automatic redirection following my $jar = HTTP::Cookies->new; Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $url; my $res; # Default config - should be redirected with standard back argument $url = '/secret_basic/index.html'; $res = GET $url; ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*\?back=http/is, 'redirect, default back argument set'); # Explicit back arg - should be redirected with non-standard back argument $url = '/secret_back_explicit/'; $res = GET $url; ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*\?redirect_to=http/is, 'redirect, non-standard back argument set'); # Null back arg - should be redirected without any back argument $url = '/secret_back_none/'; $res = GET $url; ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login\.cgi"/is, 'redirect, NO back argument set'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/05_tokens.t000066400000000000000000000056131255657270700170070ustar00rootroot00000000000000#!/usr/bin/env perl # # Token testing # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; plan tests => 13, need_lwp; # Turn off automatic redirection following Apache::TestRequest::user_agent( requests_redirectable => 0, reset => 1, ); ok 1; # simple load test # URL requires 'finance' or 'admin' tokens my $url = '/secret_tokens/index.html'; my $res = GET $url; # No cookie - should be redirected ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate ticket and cookie jar my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); my $jar = HTTP::Cookies->new; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); # print $jar->as_string; # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Retest with valid but tokenless cookie - should redirect $res = GET $url; ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no tokens: redirect to login'); # Test valid token $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1', tokens => 'finance'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'accepted with single token'); ok t_cmp($res->content, qr/^This is secret_tokens/i, 'content ok'); # Test valid token in list $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1', tokens => 'audit,management,finance'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'accepted with valid token in list'); # Test multiple valid tokens in list $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1', tokens => 'audit, management, finance, admin'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'accepted with multiple valid tokens'); # Test no valid tokens in list - should be redirected $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1', tokens => 'audit,management'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirected with no valid tokens'); ok t_cmp($res->content, qr/redirect.*login/is, 'no valid tokens: redirect to login'); # Test long token - should be redirected $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1', tokens => 'financevil'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirected with long token'); ok t_cmp($res->content, qr/redirect.*login/is, 'long token: redirect to login'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/07_guest_login.t000066400000000000000000000027241255657270700200250ustar00rootroot00000000000000#!/usr/bin/env perl # # Guest login testing # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; plan tests => 6, need_lwp; # Turn off automatic redirection following Apache::TestRequest::user_agent( requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $url = '/secret_guest/index.cgi'; my $res = GET $url; # Generate ticket and cookie jar my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); my $jar = HTTP::Cookies->new; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); # print $jar->as_string; # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Retest with valid cookie - should NOT redirect $res = GET $url; ok t_cmp($res->code, 200, 'accepted with valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are testuser/i, 'accepted testuser'); # Test with no cookie - should accept as guest login, and set auth_tkt cookie $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are guest/i, 'accepted as guest'); ok t_cmp($jar->as_string, qr/^Set-Cookie3:\s*auth_tkt=/, 'auth_tkt cookie set'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/07_guest_login_nocookie.t000066400000000000000000000042621255657270700217120ustar00rootroot00000000000000#!/usr/bin/env perl # # Guest login testing # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; plan tests => 11, need_lwp; # Turn off automatic redirection following Apache::TestRequest::user_agent( requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $url = '/secret_guest_nocookie/index.cgi'; my $res = GET $url; # Generate ticket and cookie jar my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); my $jar = HTTP::Cookies->new; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); # print $jar->as_string; # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Retest with valid cookie - should NOT redirect $res = GET $url; ok t_cmp($res->code, 200, 'accepted with valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest_nocookie, you are testuser/i, 'accepted testuser'); # Test with no cookie - should accept as guest login, but NOT set auth_tkt cookie $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest_nocookie, you are guest/i, 'accepted as guest'); ok t_cmp($jar->as_string, '', 'NO auth_tkt cookie set'); # nocookie2 version - no TKTAuthGuestCookie, default is 'off' $url = '/secret_guest_nocookie2/index.cgi'; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); # Retest with valid cookie - should NOT redirect $res = GET $url; ok t_cmp($res->code, 200, 'accepted with valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest_nocookie2, you are testuser/i, 'accepted testuser'); # Test with no cookie - should accept as guest login, but NOT set auth_tkt cookie $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest_nocookie2, you are guest/i, 'accepted as guest'); ok t_cmp($jar->as_string, '', 'NO auth_tkt cookie set'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/08_guest_user.t000066400000000000000000000130601255657270700176670ustar00rootroot00000000000000#!/usr/bin/env perl # # Guest user testing # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; use DateTime; plan tests => 22, need_lwp; # Turn off automatic redirection following Apache::TestRequest::user_agent( requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $url = '/secret_guest_user/index.cgi'; my $res = GET $url; # Generate ticket and cookie jar my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); my $jar = HTTP::Cookies->new; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); # print $jar->as_string; # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Retest with valid cookie - should NOT redirect $res = GET $url; ok t_cmp($res->code, 200, 'accepted with valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest_user, you are testuser/i, 'accepted testuser'); # Test with no cookie - should accept as guest login $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest_user, you are aguestbyanyothername/i, 'accepted as TKTAuthGuestUser'); # Simple cookie expiry test my ($cookie) = ($jar->as_string =~ m/^(Set-Cookie3: auth_tkt=.*)$/); my ($expires) = ($cookie =~ m/expires="?([^;]*?)"?;/) if $cookie; # print "$expires\n"; my $tomorrow = DateTime->now(time_zone => 'GMT')->add(days => 1)->strftime('%Y-%m-%d'); # print "$tomorrow\n"; if (have_apache 2) { ok t_cmp($expires, qr/^$tomorrow/, 'cookie expires field set to tomorrow'); } else { ok t_cmp($expires, undef, 'cookie expires field not set on apache 1'); } # UUID tests - simple %U UUID $url = '/secret_guest_user_uuid1/index.cgi'; $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); if (have_apache 2) { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.$/, 'accepted as UUIDed TKTAuthGuestUser'); } else { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-%U/, 'accepted as guest-%U (uuid unsupported on apache 1.3.x)'); } # Check partial match $url = '/secret_guest_user_uuid2/index.cgi'; $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-12U/, 'partial match ignored'); # Standard size-limited UUID (%12U) $url = '/secret_guest_user_uuid3/index.cgi'; $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); if (have_apache 2) { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-[0-9a-f]{8}-[0-9a-f]{3}\.$/, 'size limited UUID (%12U) ok'); } else { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-%12U/, 'accepted as guest-%12U (uuid unsupported on apache 1.3.x)'); } # Edge conditions with size-limited UUIDs (%0U, %1U) $url = '/secret_guest_user_uuid4/index.cgi'; $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); if (have_apache 2) { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.$/, 'zero size limited UUID (%0U) treated as %U'); } else { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-%0U/, 'accepted as guest-%0U (uuid unsupported on apache 1.3.x)'); } $url = '/secret_guest_user_uuid5/index.cgi'; $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); if (have_apache 2) { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-[0-9a-f]\.$/, '%1U size-limited UUID ok'); } else { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-%1U/, 'accepted as guest-%1U (uuid unsupported on apache 1.3.x)'); } # Various size-limited UUIDs (%24U, %36U, %50U) $url = '/secret_guest_user_uuid6/index.cgi'; $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); if (have_apache 2) { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\.$/, '%24U size-limited UUID ok'); } else { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-%24U/, 'accepted as guest-%24U (uuid unsupported on apache 1.3.x)'); } $url = '/secret_guest_user_uuid7/index.cgi'; $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); if (have_apache 2) { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.$/, '%36U size-limited UUID ok'); } else { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-%36U/, 'accepted as guest-%36U (uuid unsupported on apache 1.3.x)'); } $url = '/secret_guest_user_uuid8/index.cgi'; $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); if (have_apache 2) { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.$/, '%50U size-limited UUID truncated to %U'); } else { ok t_cmp($res->content, qr/^This is secret_guest_user_uuid, you are guest-%50U/, 'accepted as guest-%50U (uuid unsupported on apache 1.3.x)'); } # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/09_guest_not_allowed.t000066400000000000000000000025121255657270700212210ustar00rootroot00000000000000#!/usr/bin/env perl # # Test guest exclusion # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; plan tests => 5, need_lwp; # Turn off automatic redirection following Apache::TestRequest::user_agent( requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $url = '/secret_noguest/index.cgi'; my $res = GET $url; # No cookie - should be logged in as guest, but redirected ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate ticket and cookie jar my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1', tokens => 'user'); my $jar = HTTP::Cookies->new; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); # print $jar->as_string; # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Retest with valid cookie - should NOT redirect $res = GET $url; ok t_cmp($res->code, 200, 'accepted with valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are testuser/i, 'accepted testuser'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/10_cookie_expiry.t000066400000000000000000000150411255657270700203450ustar00rootroot00000000000000#!/usr/bin/env perl # # Cookie expiry testing # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; use DateTime; plan tests => 28, need 'LWP', need_apache 2; ok 1; # simple load test my $jar = HTTP::Cookies->new; my ($url, $res, $cookie, $expires, $calc); # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Test cookie expiry with no units $jar->clear; undef $expires; $url = '/secret_cookie_expiry1/index.cgi'; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are guest/i, 'accepted as guest'); print "jar: " . $jar->as_string; ($cookie) = ($jar->as_string =~ m/^(Set-Cookie3: auth_tkt=.*)$/); ($expires) = ($cookie =~ m/expires="?([^;]*?)"?;/) if $cookie; #print "expires: $expires\n" if $expires; $calc = DateTime->now(time_zone => 'GMT')->add(days => 1)->strftime('%Y-%m-%d'); #print "calc: $calc\n"; ok t_cmp($expires, qr/^$calc/, 'cookie expires field bare ok'); # Test cookie expiry with seconds (86400s) $jar->clear; undef $expires; $url = '/secret_cookie_expiry2/index.cgi'; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are guest/i, 'accepted as guest'); #print "jar: " . $jar->as_string; ($cookie) = ($jar->as_string =~ m/^(Set-Cookie3: auth_tkt=.*)$/); ($expires) = ($cookie =~ m/expires="?([^;]*?)"?;/) if $cookie; #print "expires: $expires\n" if $expires; $calc = DateTime->now(time_zone => 'GMT')->add(days => 1)->strftime('%Y-%m-%d'); #print "calc: $calc\n"; ok t_cmp($expires, qr/^$calc/, 'cookie expires field seconds ok'); # Test cookie expiry with minutes (120m) $jar->clear; $url = '/secret_cookie_expiry3/index.cgi'; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are guest/i, 'accepted as guest'); #print "jar: " . $jar->as_string; ($cookie) = ($jar->as_string =~ m/^(Set-Cookie3: auth_tkt=.*)$/); ($expires) = ($cookie =~ m/expires="?([^;]*?)"?;/) if $cookie; #print "expires: $expires\n"; $calc = DateTime->now(time_zone => 'GMT')->add(minutes => 120)->strftime('%Y-%m-%d %H:%M'); print "calc: $calc\n"; ok t_cmp($expires, qr/^$calc/, 'cookie expires field minutes ok'); # Test cookie expiry with hours (3h) $jar->clear; $url = '/secret_cookie_expiry4/index.cgi'; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are guest/i, 'accepted as guest'); #print "jar: " . $jar->as_string; ($cookie) = ($jar->as_string =~ m/^(Set-Cookie3: auth_tkt=.*)$/); ($expires) = ($cookie =~ m/expires="?([^;]*?)"?;/) if $cookie; #print "expires: $expires\n"; $calc = DateTime->now(time_zone => 'GMT')->add(hours => 3)->strftime('%Y-%m-%d %H'); #print "calc: $calc\n"; ok t_cmp($expires, qr/^$calc/, 'cookie expires field hours ok'); # Test cookie expiry with days (2d) $jar->clear; $url = '/secret_cookie_expiry5/index.cgi'; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are guest/i, 'accepted as guest'); #print "jar: " . $jar->as_string; ($cookie) = ($jar->as_string =~ m/^(Set-Cookie3: auth_tkt=.*)$/); ($expires) = ($cookie =~ m/expires="?([^;]*?)"?;/) if $cookie; #print "expires: $expires\n"; $calc = DateTime->now(time_zone => 'GMT')->add(days => 2)->strftime('%Y-%m-%d'); #print "calc: $calc\n"; ok t_cmp($expires, qr/^$calc/, 'cookie expires field days ok'); # Test cookie expiry with weeks (3w) $jar->clear; $url = '/secret_cookie_expiry6/index.cgi'; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are guest/i, 'accepted as guest'); #print "jar: " . $jar->as_string; ($cookie) = ($jar->as_string =~ m/^(Set-Cookie3: auth_tkt=.*)$/); ($expires) = ($cookie =~ m/expires="?([^;]*?)"?;/) if $cookie; #print "expires: $expires\n"; $calc = DateTime->now(time_zone => 'GMT')->add(weeks => 3)->strftime('%Y-%m-%d'); #print "calc: $calc\n"; ok t_cmp($expires, qr/^$calc/, 'cookie expires field weeks ok'); # Test cookie expiry with months (3M) $jar->clear; $url = '/secret_cookie_expiry7/index.cgi'; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are guest/i, 'accepted as guest'); #print "jar: " . $jar->as_string; ($cookie) = ($jar->as_string =~ m/^(Set-Cookie3: auth_tkt=.*)$/); ($expires) = ($cookie =~ m/expires="?([^;]*?)"?;/) if $cookie; #print "expires: $expires\n"; $calc = DateTime->now(time_zone => 'GMT')->add(days => 90)->strftime('%Y-%m-%d'); #print "calc: $calc\n"; ok t_cmp($expires, qr/^$calc/, 'cookie expires field months ok'); # Test cookie expiry with years (1y) $jar->clear; $url = '/secret_cookie_expiry8/index.cgi'; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are guest/i, 'accepted as guest'); #print "jar: " . $jar->as_string; ($cookie) = ($jar->as_string =~ m/^(Set-Cookie3: auth_tkt=.*)$/); ($expires) = ($cookie =~ m/expires="?([^;]*?)"?;/) if $cookie; #print "expires: $expires\n"; $calc = DateTime->now(time_zone => 'GMT')->add(days => 365)->strftime('%Y-%m'); #print "calc: $calc\n"; ok t_cmp($expires, qr/^$calc/, 'cookie expires field years ok'); # Test cookie expiry with multiple units (2y 1m 3w 4d) $jar->clear; $url = '/secret_cookie_expiry9/index.cgi'; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are guest/i, 'accepted as guest'); #print "jar: " . $jar->as_string; ($cookie) = ($jar->as_string =~ m/^(Set-Cookie3: auth_tkt=.*)$/); ($expires) = ($cookie =~ m/expires="?([^;]*?)"?;/) if $cookie; $expires =~ s/\s.*//; my @expires = split /-/, $expires; my $expires_dt = DateTime->new(year => $expires[0], month => $expires[1], day => $expires[2]); printf "expires: %s\n", $expires_dt->strftime("%Y-%m-%d"); $calc = DateTime->now(time_zone => 'GMT')->add(years => 2, months => 1, weeks => 3, days => 4); printf "calc: %s\n", $calc->strftime("%Y-%m-%d"); my $diff = $expires_dt - $calc; printf "diff: %s\n", $diff->delta_days; ok t_cmp(abs $diff->delta_days, qr/^[012]$/, 'cookie expires field years ok (' . $diff->delta_days . ')'); #ok t_cmp($expires, qr/^$calc/, 'cookie expires field years ok'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/11_guest_empty.t000066400000000000000000000027521255657270700200470ustar00rootroot00000000000000#!/usr/bin/env perl # # Guest login testing # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; plan tests => 6, need_lwp; # Turn off automatic redirection following Apache::TestRequest::user_agent( requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $url = '/secret_guest_empty/index.cgi'; my $res = GET $url; # Generate ticket and cookie jar my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); my $jar = HTTP::Cookies->new; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); # print $jar->as_string; # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Retest with valid cookie - should NOT redirect $res = GET $url; ok t_cmp($res->code, 200, 'accepted with valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest_empty, you are testuser\./i, 'accepted testuser'); # Test with no cookie - should accept as guest login, but username should be '' # and not set a cookie $jar->clear; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest_empty, you are \./i, 'accepted as empty guest'); ok t_cmp($jar->as_string, '', 'NO auth_tkt cookie set'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/12_cookie_secure.t000066400000000000000000000027711255657270700203230ustar00rootroot00000000000000#!/usr/bin/env perl # # Testing TKTAuthCookieSecure flag # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; use DateTime; plan tests => 8, need_lwp; ok 1; # simple load test my $jar = HTTP::Cookies->new; my ($url, $res, $cookie); # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Test TKTAuthCookieSecure on $jar->clear; undef $cookie; $url = '/secret_cookie_secure1/index.cgi'; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are guest/i, 'accepted as guest'); #print "jar: " . $jar->as_string . "\n"; ($cookie) = ($jar->as_string =~ m/^(Set-Cookie3: auth_tkt=.*)$/); #print "cookie: $cookie\n"; ok t_cmp($cookie, qr/; secure;/, 'secure flag found'); # Test TKTAuthCookieSecure off $jar->clear; undef $cookie; $url = '/secret_cookie_secure2/index.cgi'; $res = GET $url; ok t_cmp($res->code, 200, 'accepted without valid ticket'); ok t_cmp($res->content, qr/^This is secret_guest, you are guest/i, 'accepted as guest'); #print "jar: " . $jar->as_string . "\n"; ($cookie) = ($jar->as_string =~ m/^(Set-Cookie3: auth_tkt=.*)$/); #print "cookie: $cookie\n"; ok t_cmp($cookie, qr/auth_tkt=/, 'cookie found'); ok ! t_cmp($cookie, qr/; secure;/, 'no secure flag found'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/15_secret_old.t000066400000000000000000000043011255657270700176210ustar00rootroot00000000000000#!/usr/bin/env perl # # Testing fallback to secret_old # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt 2.1; plan tests => 9, need_lwp; # Setup cookie jar, turn off automatic redirection following my $jar = HTTP::Cookies->new; Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $url = '/secret_basic/index.html'; my $res; my $ticket; my $cookie; # No ticket - should be redirected $res = GET $url; ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate ticket with current secret - should NOT redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket'); # Check that the cookie in the response matches our ticket $jar->extract_cookies($res); $jar->scan(sub { $cookie = $_[2] if $_[1] eq 'auth_tkt' }); ok t_cmp($ticket, $cookie, "cookie in jar matches ticket i.e. no refresh"); # Generate ticket with old secret - should NOT redirect $at->secret( $at->secret_old ); $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket'); # Check that the cookie in the response does NOT match our ticket $jar->extract_cookies($res); $jar->scan(sub { $cookie = $_[2] if $_[1] eq 'auth_tkt' }); ok ! t_cmp($ticket, $cookie, "cookie in jar does NOT match ticket i.e. cookie has been refreshed"); # Now redo the test with the refreshed $cookie - it should use the current secret, so NOT redirect $ticket = $cookie; $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket'); # Check that the cookie in the response matches our ticket $jar->extract_cookies($res); $jar->scan(sub { $cookie = $_[2] if $_[1] eq 'auth_tkt' }); ok t_cmp($ticket, $cookie, "cookie in jar matches ticket i.e. no refresh"); mod_auth_tkt-2.3.99b1/t/20_timeout.t000066400000000000000000000043241255657270700171650ustar00rootroot00000000000000#!/usr/bin/env perl # # Test auth ticket timeouts (TKTAuthTimeoutMin set to 1) # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET POST); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; use File::Basename; plan tests => 10, need 'LWP', { "env variable MAT_TEST_TIMEOUTS not set" => $ENV{MAT_TEST_TIMEOUTS} }; # Turn off automatic redirection following Apache::TestRequest::user_agent( requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $url = '/secret_timeout/index.html'; my $res = GET $url; # No cookie - should be redirected ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate ticket and cookie jar my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); my $jar = HTTP::Cookies->new; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); # print $jar->as_string; # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Retest with our cookie - should NOT redirect $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket take 1'); sub nap { my ($t) = @_; print "(sleeping for $t seconds ...)\n"; sleep $t; } # Sleep for 20 seconds and retry (timeout is 1 minute) - should be accepted nap 20; $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket take 2'); # Sleep for another 20 seconds and retry (timeout is 1 minute) - should be accepted nap 20; $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket take 3'); # Sleep for another 25 seconds and retry (timeout is 1 minute) - should be # redirected to TKTAuthTimeoutURL nap 25; $res = GET $url; ok t_cmp($res->code, 307); ok t_cmp($res->content, qr/redirect.*timeout\.cgi/is, 'take 4: redirect to timeout.cgi'); # try a POST request to make sure we go to the TKTAuthPostTimeoutURL $res = POST $url; ok t_cmp($res->code, 307); ok t_cmp($res->content, qr/redirect.*timeout\.cgi\?post=1/is, 'take 5: redirect to timeout.cgi?post=1'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/21_timeout_refresh.t000066400000000000000000000042451255657270700207060ustar00rootroot00000000000000#!/usr/bin/env perl # # Test auth ticket timeouts (TKTAuthTimeoutMin set to 1) # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; use File::Basename; plan tests => 9, need 'LWP', { "env variable MAT_TEST_TIMEOUTS not set" => $ENV{MAT_TEST_TIMEOUTS} }; # Turn off automatic redirection following Apache::TestRequest::user_agent( reset => 1, requests_redirectable => 0, ); ok 1; # simple load test my $url = '/secret_timeout_refresh/index.html'; my $res = GET $url; # No cookie - should be redirected ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate ticket and cookie jar my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); my $jar = HTTP::Cookies->new; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( reset => 1, cookie_jar => $jar, requests_redirectable => 0, ); # Helper subs sub nap { my ($t) = @_; print "(sleeping for $t seconds ...)\n"; sleep $t; } # Retest with our cookie - should NOT redirect $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket take 1'); # Sleep for 20 seconds and retry (timeout is 1 minute) - should be accepted nap 20; $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket take 2'); # Sleep for another 20 seconds and retry (timeout is 1 minute) - should be accepted nap 20; $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket take 3'); # Sleep for another 25 seconds and retry (timeout is 1 minute) - should also be # okay, because the ticket will have been refreshed nap 25; $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket take 4'); # Finally sleep for a full 65 seconds, which should force the timeout nap 65; $res = GET $url; ok t_cmp($res->code, 307); ok t_cmp($res->content, qr/redirect.*timeout\.cgi/is, 'take 5: redirect to timeout.cgi'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/22_timeout_guest_fallback.t000066400000000000000000000046231255657270700222170ustar00rootroot00000000000000#!/usr/bin/env perl # # Test auth ticket timeouts with Guest Fallback on (TKTAuthTimeoutMin set to 1) # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET POST); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; use File::Basename; plan tests => 9, need 'LWP', { "env variable MAT_TEST_TIMEOUTS not set" => $ENV{MAT_TEST_TIMEOUTS} }; # Turn off automatic redirection following Apache::TestRequest::user_agent( requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $url = '/secret_timeout_guest_fallback/index.cgi'; my $res = GET $url; # No cookie - should be redirected #ok t_cmp($res->code, 307, 'redirected'); #ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate ticket and cookie jar my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); my $jar = HTTP::Cookies->new; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); # print $jar->as_string; # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Retest with our cookie - should NOT redirect $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket take 1'); ok t_cmp($res->content, qr/^This is secret_timeout_guest_fallback, you are testuser/, 'user is testuser'); sub nap { my ($t) = @_; print "(sleeping for $t seconds ...)\n"; sleep $t; } # Sleep for 20 seconds and retry (timeout is 1 minute) - should be accepted nap 20; $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket take 2'); ok t_cmp($res->content, qr/^This is secret_timeout_guest_fallback, you are testuser/, 'user is testuser'); # Sleep for another 20 seconds and retry (timeout is 1 minute) - should be accepted nap 20; $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket take 3'); ok t_cmp($res->content, qr/^This is secret_timeout_guest_fallback, you are testuser/, 'user is testuser'); # Sleep for another 25 seconds and retry (timeout is 1 minute) - should # timeout, not be directed, and be reauthenticated as guest nap 25; $res = GET $url; ok t_cmp($res->code, 200); ok t_cmp($res->content, qr/^This is secret_timeout_guest_fallback, you are guest/, "timed out, user is now 'guest'"); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/30_vhost_local_secret.t000066400000000000000000000040131255657270700213550ustar00rootroot00000000000000#!/usr/bin/env perl # # Virtual host mod_auth_tkt testing, local secret # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; plan tests => 7, need_lwp; # Setup cookie jar, turn off automatic redirection following my $jar = HTTP::Cookies->new; Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); ok 1; # simple load test # Figure out host/port for vhost my $vhost = 'VHostLocalSecret'; my $config = Apache::Test::config(); Apache::TestRequest::module($vhost); my $hostport = Apache::TestRequest::hostport($config); my $url = "http://$hostport/index.html"; my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf', secret => 'vhostlocalsecret'); my $res = GET $url; my $ticket; # No cookie - should be redirected ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate good ticket - should NOT redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket'); # Retry with non-base64-escaped ticket - should NOT redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1', base64 => 0); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with non-base64 ticket'); # Retest with munged ticket - should redirect $ticket =~ s/^../XX/; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with munged cookie'); # Retest with bad ip address - should redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '192.168.0.1'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with incorrect IP address'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/31_vhost_global_secret.t000066400000000000000000000037541255657270700215370ustar00rootroot00000000000000#!/usr/bin/env perl # # Virtual host mod_auth_tkt testing, global secret # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; plan tests => 7, need_lwp; # Setup cookie jar, turn off automatic redirection following my $jar = HTTP::Cookies->new; Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); ok 1; # simple load test # Figure out host/port for vhost my $vhost = 'VHostGlobalSecret'; my $config = Apache::Test::config(); Apache::TestRequest::module($vhost); my $hostport = Apache::TestRequest::hostport($config); my $url = "http://$hostport/index.html"; my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $res = GET $url; my $ticket; # No cookie - should be redirected ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate good ticket - should NOT redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket'); # Retry with non-base64-escaped ticket - should NOT redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1', base64 => 0); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with non-base64 ticket'); # Retest with munged ticket - should redirect $ticket =~ s/^../XX/; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with munged cookie'); # Retest with bad ip address - should redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '192.168.0.1'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with incorrect IP address'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/40_htaccess.t000066400000000000000000000036771255657270700173100ustar00rootroot00000000000000#!/usr/bin/env perl # # Configuration via .htaccess file # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; plan tests => 9, need_lwp; # Setup cookie jar, turn off automatic redirection following my $jar = HTTP::Cookies->new; Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $url = '/secret_htaccess/index.html'; my $res = GET $url; my $ticket; # No cookie - should be redirected ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate good ticket - should NOT redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with ticket'); ok t_cmp($res->content, qr/^This is secret_htaccess/i, 'this is secret_htaccess'); # Retry with non-base64-escaped ticket - should NOT redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1', base64 => 0); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with non-base64 ticket'); ok t_cmp($res->content, qr/^This is secret_htaccess/i, 'this is secret_htaccess'); # Retest with munged ticket - should redirect $ticket =~ s/^../XX/; $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with munged cookie'); # Retest with bad ip address - should redirect $ticket = $at->ticket(uid => 'testuser', ip_addr => '192.168.0.1'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $res = GET $url; ok t_cmp($res->code, 307, 'redirect with incorrect IP address'); # vim:sw=2:et:sm:smartindent:ft=perl mod_auth_tkt-2.3.99b1/t/50_bug_cookie_name.t000066400000000000000000000027471255657270700206170ustar00rootroot00000000000000#!/usr/bin/env perl # # Bug in mod_auth_tkt <= 2.0.99b1 would match a partial cookie name, # using the wrong ticket to try and authenticate against, resulting # in an auth failure, even if you had a valid ticket. # use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest qw(GET); use HTTP::Cookies; use lib "cgi"; use Apache::AuthTkt; plan tests => 4, need_lwp; # Turn off automatic redirection following Apache::TestRequest::user_agent( requests_redirectable => 0, reset => 1, ); ok 1; # simple load test my $url = '/secret_basic/index.html'; my $res = GET $url; # Test no cookie - should be redirected ok t_cmp($res->code, 307, 'redirected'); ok t_cmp($res->content, qr/redirect.*login/is, 'no ticket: redirect to login'); # Generate ticket and cookie jar my $at = Apache::AuthTkt->new(conf => 't/conf/extra.conf'); my $ticket = $at->ticket(uid => 'testuser', ip_addr => '127.0.0.1'); my $jar = HTTP::Cookies->new; $jar->set_cookie(1, 'a_dodgy_auth_tkt', 'foobar_dodgy', '/', '.localdomain'); $jar->set_cookie(1, 'auth_tkt', $ticket, '/', '.localdomain'); $jar->set_cookie(1, 'bad_auth_tkt', 'foobar_bad', '/', '.localdomain'); #print $jar->as_string; # Reset the TestRequest user_agent to use our cookie jar Apache::TestRequest::user_agent( cookie_jar => $jar, requests_redirectable => 0, reset => 1, ); # Test good ticket - should NOT redirect $res = GET $url; ok t_cmp($res->code, 200, 'not redirected with good ticket'); mod_auth_tkt-2.3.99b1/t/Makefile000066400000000000000000000024231255657270700164470ustar00rootroot00000000000000 include ../Makedefs MODULE=modules/mod_auth_tkt.so ../src/$(TARGET): ../src/mod_auth_tkt.c cd ../src && make $(MODULE): ../src/$(TARGET) mkdir -p modules $(APXS) -S LIBEXECDIR=$(BASEDIR)/t/modules -i ../src/$(TARGET) test_md5: $(MODULE) ./TEST -clean @echo '***********************' @echo @echo Testing digest_type MD5 @echo @echo '***********************' cp extra.conf.$(VERSION).in conf/extra.conf.in ./TEST -apxs $(APXS) -conf ./TEST # ./TEST 01_basic.t # ./TEST 01_basic.t # ./TEST 30_vhost_local_secret.t # ./TEST 31_vhost_global_secret.t test_sha256: $(MODULE) ./TEST -clean @echo '**************************' @echo @echo Testing digest_type SHA256 @echo @echo '**************************' cp extra.conf.$(VERSION).in conf/extra.conf.in perl -i -pe 's/MD5/SHA256/' conf/extra.conf.in ./TEST -apxs $(APXS) -conf ./TEST test_sha512: $(MODULE) ./TEST -clean @echo '**************************' @echo @echo Testing digest_type SHA512 @echo @echo '**************************' cp extra.conf.$(VERSION).in conf/extra.conf.in perl -i -pe 's/MD5/SHA512/' conf/extra.conf.in ./TEST -apxs $(APXS) -conf ./TEST test: $(MODULE) test_md5 test_sha256 test_sha512 clean: ./TEST -clean rm -f conf/extra.conf.in realclean: ./TEST -clean rm -f $(MODULE) # vim:noet mod_auth_tkt-2.3.99b1/t/README.md000066400000000000000000000011061255657270700162630ustar00rootroot00000000000000Test Instructions ================= Requirements: - Apache::TestRun, from the mod_perl project 1. To run the test suite against the currently configured apache version: make test # (see the Makefile for details, but it's basically just running ./TEST) 2. To run a single unit test e.g. 01_basic.t: ./TEST 01_basic.t 3. To run a single unit test through gdb: # (make sure you've run with './configure --debug' for debug symbols) ./TEST -start-httpd -one-process # in another window gdb /usr/sbin/httpd PID # in test window ./TEST 01_basic.t mod_auth_tkt-2.3.99b1/t/TEST000077500000000000000000000010311255657270700155060ustar00rootroot00000000000000#!/usr/bin/env perl package MAT::TestRun; use base 'Apache::TestRun'; use Apache::TestConfig; __PACKAGE__->new->run(@ARGV); # See 'perldoc Apache::TestRun' sub pre_configure { my $self = shift; Apache::TestConfig::autoconfig_skip_module_add('mod_auth_tkt.c'); $self->SUPER::pre_configure(); } # Explicitly set servername, since we require .localdomain for our cookies sub new_test_config { my $self = shift; $self->{conf_opts}->{servername} = 'localhost.localdomain'; return $self->SUPER::new_test_config; } mod_auth_tkt-2.3.99b1/t/conf/000077500000000000000000000000001255657270700157335ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/t/conf/.gitignore000066400000000000000000000000071255657270700177200ustar00rootroot00000000000000*conf* mod_auth_tkt-2.3.99b1/t/extra.conf.1.in000066400000000000000000000166341255657270700175560ustar00rootroot00000000000000 LoadModule auth_tkt_module modules/mod_auth_tkt.so # Test secret TKTAuthSecret "This is my shiny test secret" TKTAuthSecretOld "This is my older less-shiny test secret" TKTAuthDigestType "MD5" # secret_basic - minimal config AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthDebug 2 # secret_relative_url - test relative URL expansion AuthType None require valid-user TKTAuthLoginURL /pub/login.cgi TKTAuthDebug 1 # secret_ignore_ip - ignore ip testing AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthIgnoreIP on # secret_tokens - token testing AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthToken finance TKTAuthToken admin # secret_guest - guest testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on # secret_guest_nocookie - guest testing, no cookies (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie off # secret_guest_nocookie2 - guest testing, no cookies (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on # secret_guest_empty - empty guest testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestEmpty on # secret_guest_user - guest user testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser aguestbyanyothername # secret_guest_user_uuid1 - simple guest user uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%U # secret_guest_user_uuid2 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-12U # secret_guest_user_uuid3 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%12U # secret_guest_user_uuid4 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%0U # secret_guest_user_uuid5 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%1U # secret_guest_user_uuid6 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%24U # secret_guest_user_uuid7 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%36U # secret_guest_user_uuid8 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%50U # secret_cookie_secure1 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieSecure on # secret_cookie_secure2 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieSecure off # secret_noguest - guest exclusion testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthGuestLogin on TKTAuthGuestCookie on # Allow only tickets with a 'user' token i.e. no guests TKTAuthToken user # secret_timeout - timeout testing AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthTimeoutURL http://localhost/pub/timeout.cgi TKTAuthPostTimeoutURL http://localhost/pub/timeout.cgi?post=1 TKTAuthTimeout 60 TKTAuthTimeoutRefresh 0 # secret_timeout_refresh - timeout refresh testing AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthTimeoutURL http://localhost/pub/timeout.cgi TKTAuthTimeout 1m # with 20s sleeps and a 1 minute, timeout refresh should be > .66 TKTAuthTimeoutRefresh .75 # secret_timeout_guest_fallback - timeout testing with guest fallback on (CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthTimeoutURL http://localhost/pub/timeout.cgi TKTAuthPostTimeoutURL http://localhost/pub/timeout.cgi?post=1 TKTAuthTimeout 60 TKTAuthTimeoutRefresh 0 TKTAuthGuestLogin on TKTAuthGuestCookie off TKTAuthGuestFallback on # secret_back_explicit - explicit TKTAuthBackArgName AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthBackArgName redirect_to TKTAuthDebug 2 # secret_back_none - null TKTAuthBackArgName AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthBackArgName None TKTAuthDebug 2 # virtual host testing - with per-host secret TKTAuthSecret "vhostlocalsecret" DocumentRoot @documentroot@/vhost_local_secret AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi # virtual host testing - with global secret DocumentRoot @documentroot@/vhost_global_secret AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthDebug 3 # secret_htaccess - config via .htaccess file AllowOverride AuthConfig mod_auth_tkt-2.3.99b1/t/extra.conf.2.2.in000077700000000000000000000000001255657270700224372extra.conf.2.inustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/t/extra.conf.2.4.in000077700000000000000000000000001255657270700224412extra.conf.2.inustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/t/extra.conf.2.in000066400000000000000000000232451255657270700175530ustar00rootroot00000000000000 LoadModule auth_tkt_module modules/mod_auth_tkt.so # Test secret TKTAuthSecret "This is my shiny test secret" TKTAuthSecretOld "This is my older less-shiny test secret" TKTAuthDigestType "MD5" # secret_basic - minimal config AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthDebug 2 # secret_relative_url - test relative URL expansion AuthType None require valid-user TKTAuthLoginURL /pub/login.cgi # secret_ignore_ip - ignore ip testing AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthIgnoreIP on # secret_tokens - token testing AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthToken finance TKTAuthToken admin # secret_guest - guest testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on # secret_guest_nocookie - guest testing, no cookies (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie off # secret_guest_nocookie2 - guest testing, no cookies (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on # secret_guest_empty - empty guest testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestEmpty on # secret_guest_user - guest user testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser aguestbyanyothername TKTAuthCookieExpires 86400 # secret_guest_user_uuid1 - simple guest user uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%U # secret_guest_user_uuid2 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-12U TKTAuthCookieExpires 86400 # secret_guest_user_uuid3 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%12U TKTAuthCookieExpires 86400 # secret_guest_user_uuid4 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%0U TKTAuthCookieExpires 86400 # secret_guest_user_uuid5 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%1U TKTAuthCookieExpires 86400 # secret_guest_user_uuid6 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%24U TKTAuthCookieExpires 86400 # secret_guest_user_uuid7 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%36U TKTAuthCookieExpires 86400 # secret_guest_user_uuid8 - guest user size-limited uuid testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthGuestUser guest-%50U TKTAuthCookieExpires 86400 # secret_cookie_expiry1 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieExpires 86400 # secret_cookie_expiry2 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieExpires 86400s # secret_cookie_expiry3 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieExpires 120m # secret_cookie_expiry4 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieExpires 3h # secret_cookie_expiry5 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieExpires 2d # secret_cookie_expiry6 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieExpires 3w # secret_cookie_expiry7 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieExpires 3M # secret_cookie_expiry8 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieExpires 1y # secret_cookie_expiry9 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieExpires 2y 1M 3w 4d # secret_cookie_secure1 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieSecure on # secret_cookie_secure2 AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthGuestLogin on TKTAuthGuestCookie on TKTAuthCookieSecure off # secret_noguest - guest exclusion testing (uses a CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthGuestLogin on TKTAuthGuestCookie on # Allow only tickets with a 'user' token i.e. no guests TKTAuthToken user # secret_timeout - timeout testing AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthTimeoutURL http://localhost/pub/timeout.cgi TKTAuthPostTimeoutURL http://localhost/pub/timeout.cgi?post=1 TKTAuthTimeout 60 TKTAuthTimeoutRefresh 0 # secret_timeout_refresh - timeout refresh testing AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthTimeoutURL http://localhost/pub/timeout.cgi TKTAuthTimeout 1m # with 20s sleeps and a 1 minute, timeout refresh should be > .66 TKTAuthTimeoutRefresh .75 # secret_timeout_guest_fallback - timeout testing with guest fallback on (CGI) AddHandler cgi-script .cgi Options +ExecCGI AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthTimeoutURL http://localhost/pub/timeout.cgi TKTAuthPostTimeoutURL http://localhost/pub/timeout.cgi?post=1 TKTAuthTimeout 60 TKTAuthTimeoutRefresh 0 TKTAuthGuestLogin on TKTAuthGuestCookie off TKTAuthGuestFallback on # secret_back_explicit - explicit TKTAuthBackArgName AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthBackArgName redirect_to TKTAuthDebug 2 # secret_back_none - null TKTAuthBackArgName AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi TKTAuthBackArgName None TKTAuthDebug 2 # virtual host testing - with per-host secret DocumentRoot @documentroot@/vhost_local_secret TKTAuthSecret "vhostlocalsecret" AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi # TKTAuthDebug 3 # virtual host testing - with global secret DocumentRoot @documentroot@/vhost_global_secret AuthType None require valid-user TKTAuthLoginURL http://localhost/pub/login.cgi # TKTAuthDebug 3 # secret_htaccess - config via .htaccess file AllowOverride AuthConfig mod_auth_tkt-2.3.99b1/t/htdocs/000077500000000000000000000000001255657270700162725ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/t/htdocs/.gitignore000066400000000000000000000000131255657270700202540ustar00rootroot00000000000000index.html mod_auth_tkt-2.3.99b1/t/htdocs/public.html000066400000000000000000000000171255657270700204340ustar00rootroot00000000000000This is public mod_auth_tkt-2.3.99b1/t/htdocs/secret_basic/000077500000000000000000000000001255657270700207205ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/t/htdocs/secret_basic/index.html000066400000000000000000000000251255657270700227120ustar00rootroot00000000000000This is secret_basic mod_auth_tkt-2.3.99b1/t/htdocs/secret_cookie_expiry1/000077500000000000000000000000001255657270700225715ustar00rootroot00000000000000mod_auth_tkt-2.3.99b1/t/htdocs/secret_cookie_expiry1/index.cgi000077500000000000000000000001571255657270700243720ustar00rootroot00000000000000#!/usr/bin/env perl print <