PAPI - Guide for Beginners

DESCRIPTION

PAPI is a system for providing access control to restricted information resources across the Internet. It intends to keep authentication as an issue local to the organization the user belongs to, while leaving the information providers full control over the resources they offer. The authentication mechanisms are designed to be as flexible as possible, allowing each organization to use its own authentication schema, keeping user privacy, and offering information providers data enough for statistics. Moreover, access control mechanisms are transparent to the user and compatible with the most commonly employed Web browsers, i.e., Netscape/MSIE/Lynx, and any operating system.

The system consists of two independent elements: the authentication server (AS) and the point of access (PoA). This structure makes the final system much more flexible and able to be integrated to different environments. There is no need of a one-to-one mapping between ASes and PoAs: a given PoA may manage to deal with requests from any number of ASes and direct them to any number of web servers.

The purpose of the AS is to provide users with a single authentication point and make available to them (in a completely transparent manner) all the temporary keys that will let them access the services they are authorized to.

The PoA manages actual access control to a set of web locations for a given organization. The information provider (or the owner of the web servers) have the responsibility of managing this point of access. A PAPI PoA can be adapted to any web server, whatever its implementation is. Moreover, a given web server can have more than one PoA, and a PoA can control more than one web server. PoAs can be hierarchically combined into groups controlled by a group-wide PoA (a GPoA), where initial access attempts are to be validated. This way, only the temporary keys for the GPoAs at the top of the hierarchy must be initially loaded by the user's browser. A PoA can also be configured to directly query authentication servers for information about users, so no initial loading of temporary keys is needed. This ability can be, of course, integrated within PoA hierarchies as well.

Other important property of this system is that it is completely compatible with any other access control system in use, since it does not impose any constraints on additional procedures used for these purposes. In other words, PAPI access control is completely orthogonal to procedures such as password protection, IP filters, TLS-based access control, etc.

The central motto for PAPI is ``Authentication is a local matter, and authorization too''.

Authentication occurs at the user's organization, possibly accessing data that must not be disclosed in any case. Once authenticated, the user is automatically pointed to the entry point of the PoA. It is important to remark that the AS is not sending any user-provided data to the PoA. It prepares an assertion (as required by the PoA) about the user and signs it using its private key. The only constraint that any PoA imposes on an AS assertion about an user is that the identifier must be unique at least during the lifetime of the tokens the PoA is going to provide. Of course, information should be also enough to pass through the rules the PoA enforces, but the AS is never required to disclose any private information.

The PoA receives this chunk of information, signed by the AS, and decides whether to grant access to the user or not. It is important to note that when we refer to a PoA trusting an AS, we are not talking about a PoA permitting any access request coming from that AS, but about the PoA trusting the assertions the AS makes. That means that, if a PoA trusts an AS, the (digitally signed) assertion of ``This is user X of group Y'' made by the AS is going to be trusted by the PoA. And the PoA decides, according to the assertion and its policy, to grant access or not. Authorization is, again, a local matter to the organization operating the PoA.

BUILDING AND INSTALLING PAPI COMPONENTS

Building and installing the PAPI components is straightforward. You just have to unzip and untar the distribution, go the PAPI source directory and execute the following commands:

 # perl Makefile.PL
 # make
 # make install

The installation procedures check for the availability of the required elements you have to install on your system prior to PAPI. These elements are:

Perl >= 5.6
openssl >= 0.9.5 (openssl >= 0.9.6g is recommended)
The Perl CGI::Lite package
The Perl Convert::ASN1 package
The Perl DB_File package
The Perl Digest::MD5 package
The Perl MIME::Base64 package
The Perl URI::Escape package

These elements are only required if building a PAPI PoA:

Apache >= 1.3.8
The current version of PAPI only runs on Apache (and mod_perl) versions 1.x. A port of PAPI to Apache 2 is under development.
Apache's mod_perl >= 1.20
When building mod_perl, remember to build it with EVERYTHING=1.
The Perl Data::Dumper package
The Perl HTML::TokeParser package
The Perl HTTP::Cookies package
The Perl HTTP::Request::Form package
The Perl LWP::UserAgent package (>= 2.001)
The Perl MLDBM package
The Perl MLDBM::Sync package
The Perl URI::URL package
The SPOCP authorization server
If you plan to implement your authorization policy by means of a SPOCP server (see http://www.spocp.org/).

These elements are only required if building a PAPI AS:

The Perl Sys::Syslog package
If Unix syslog-based logging is required.
The Perl Net::LDAP package (>= 0.30)
The Perl Net::LDAP::Entry package
The Perl Net::LDAP::Message package
The Perl Net::LDAP::Search package
If LDAP-based authentication is required.
The Perl Mail::POP3Client package
If POP-based authentication is required.
The Perl Net::IMAP::Simple package
If IMAP-based authentication is required.
The Perl Time::Local package
If X509 certificate-based authentication is required.

The installation procedures install the PAPI library packages and the components of the PoA according to your host Perl installation, so you can use them from any program (including Apache itself for running the PoA) using standard Perl procedures, like use.

NOTE

In some installations, problems have been reported about the building and installation of the PAPI components, mainly related to changes in Perl module names and location of include files and/or libraries. We keep a list of known installation issues.

SETTING PAPI FOR THE FIRST TIME

You can install as many ASes and PoAs as you need, in different or the same box, as long as you follow the guidelines we include here.

The PAPI Authentication Server included in this distribution is a Perl program intended to be run as a CGI by the Web server. You should install the file AuthServer (the AS executable file) in any location your Web server is able to execute CGIs from. The authentication server and its associated files are installed in the directory selected during the configuration phase, when the command perl Makefile.PL was executed (by default, /usr/local/apache/cgi-bin). You can copy (or move) them as required.

A PAPI Point of Access grants or denies the access to the network resources it controls using the cryptographic tokens defined by the PAPI protocol. The PoA included in this distribution is designed to be used with Apache's mod_perl, and makes an extensive use of the Apache Perl API.

CALLING THE AUTHENTICATION SERVER

The AuthServer program included with this distribution is a highly configurable HTML-form based PAPI Authentication Server designed to run as a CGI, although it can also be run inside Apache's mod_perl.

When AuthServer is accessed through the user browser, it uses three types of parameters to determine its behavior:

The operation code
Is selected by setting a form variable with the name of the operation requested to any non-null value. If no operation is specified, the AuthServer assumes an initial request has been performed, and shows the initial page defined by the configuration variable loginTemplate (see below). The recognized variable names are (case is significant):
LOGIN
Is the operation by default. Directs the server to perform user authentication and redirect PAPI requests to the appropriate PoAs.
ATTREQ
Corresponds to a request for user attributes coming from a PoA. Directs the server to validate the request, authenticate the user if not already authenticated, and send the results back to the requesting PoA.
TEST
Directs the server to verify current access rights with the appropriate PoAs.
LOGOUT
Directs the server to request access right cancellations from the appropriate PoAs.
The original URL at the requesting PoA
If the AuthServer is being called by a PoA in order to perform an ATTREQ operation, two parameters, called PAPIPOAURL and PAPIPOAREF, are used to send the response back to the PoA and allow it to fulfill the original user's request.
PAPIPOAURL
Is the URL that fired the query from the PoA to the AuthServer. This value is used by the AuthServer to:
1. Determine the data to be sent back to the requesting PoA, by means of the assertion formats defined for the user and the requesting site.
2. Establish the URL to which the assertion will be sent by means of a HTTP redirect.
3. Send it back to the requesting PoA along with the assertion, so the PoA can continue the processing of the request that caused the ATTREQ query.
PAPIPOAREF
Is the reference for the original user's request at the PoA querying the AuthServer. This value is returned to the PoA once the answer to the ATTREQ is built, so the PoA can rebuild the original request that caused the query.
The referring page
The AuthServer may also use the value of the variable PAPIrefURL as the original URL the user was trying to access when it was redirected to the AuthServer by means of an Apache error handler. This variable is passed as the AuthServer performs user authentication, and can be used for automatically redirecting the user to the resource (s)he originally intended to access upon successful authentication.
For example, if a user is redirected to the AuthServer when trying to access http://www.dom.ain/papiresource/, and you want AuthServer to know about it and pass this value through the form variable PAPIrefURL so the user can be redirected back to the original URL, you should refer to AuthServer using:
 http://papi.dom.ain/cgi/AuthServer?PAPIrefURL=http%3A%2F%2Fwww%2Edom%2Eain%2Fpapiresource%2F
(Assuming, of course, that http://papi.dom.ain/cgi/AuthServer is the location of your AuthServer).

CONFIGURING THE AUTHENTICATION SERVER

The configuration of the AuthServer is stored into a configuration file, with the same name as the AuthServer itself and the extension .cf, living in the same directory the AuthServer does. This means that, if you run the AuthServer with its default name, the configuration file is called AuthServer.cf. The configuration file itself is a Perl source file, so you can use whatever Perl statements to configure the AuthServer. Configuration is stored inside a hash named %PAPI::AuthServer::cfgVar, so the statements into the configuration file should end writing to this hash.

Specific additional per-PoA configuration files can be used for ATTREQ operations. Since the ATTREQ operation carries the requesting PoA identifier, the AuthServer will try to load a configuration file specific to the PoA with the name

 $0-<PoAName>.cf

That is, if a ATTREQ operation is received from a PoA identified as ThisPoA, and the AuthServer is located in a file called is inside a file named /usr/local/PAPI/AS/AuthServer, it will try to load an additional configuration file named /usr/local/PAPI/AS/AuthServer-ThisPoA.cf

Let's have a look on the sample configuration file included with the distribution and analyze the values provided there:

 #  PAPI Authentication Server. Sample configuration file
 # (c) 2001-2007 RedIRIS
 #
 # This is the PAPI AS configuration file, a Perl source
 # file that essentially contains assignments to a hash named
 # PAPI::AuthServer::cfgVar.
 # This sample configuration tries to illustrate the different authentication
 # methods available in the distribution.
 
 # Include here the modules referenced by the elements inside the configuration
 #
 use PAPI::BasicAuth;
 use PAPI::POPAuth;
 use PAPI::IMAPAuth;
 use PAPI::LDAPAuth;
 use PAPI::CertAuth;

These four use sentences make reference to the four authentication libraries that are currently part of the PAPI AS distribution, so they can be used in the rest of the configuration file.

 # Just convenience
 #
 $cfg = \%PAPI::AuthServer::cfgVar;

This is just for the convenience of writing $$cfg{something} instead of $PAPI::AuthServer::cfgVar{something} when setting a configuration variable.

Working Directory

 # The definition of the working directory should be the first configuration
 # assignment. It must be writable by the Web server user only if authCookieDB
 # and/or log files go there.
 # AuthServer will chdir() here, so all pathnames are relative to it.
 #
 $$cfg{workingDirectory} = '/usr/local/PAPI/AS/etc';

The working directory is the place where the AS will look for all the templates, key files, etc. configured below, unless you use absolute paths inside their values. This directory must be created with (at least) r-x permissions for the UID the CGI is going to run with.

HTML Variables

 # Admin data (included in the HTML templates)
 #
 $$cfg{adminContact} = '<b>papiadmin@dom.ain</b>';

The administrative contact will be included inside the AS templates when sent to users, if the templates are configured to do so. This is an example of any variable you want to appear substituted inside the templates. You can freely use any HTML construct as value for these variables.

HTML Templates

 # HTML templates
 #
 $$cfg{loginTemplate} = fromFile("login.html");
 $$cfg{acceptTemplate} = fromFile("accept.html");
 $$cfg{testTemplate} = fromFile("test.html");
 $$cfg{logoutTemplate} = fromFile("logout.html");
 $$cfg{rejectTemplate} = fromURL("http://www.dom.ain/PAPIreject.html";);
 $$cfg{siteInfoTemplate} =
 '<tr><td><img src="<papi var="poaURL"/>"></td>
  <td><a href="<papi var="poa"/><papi var="location"/><papi var="accessURI"/>"
       target="<papi var="service"/>"><papi var="desc"/></a></td></tr>';

These variables define the templates to be used when interacting with the user. Note the use, in most cases, of the Perl functions fromFile and fromURL, that permit the use of files and/or URLs containing the templates.

The loginTemplate is sent to the user when the AS is first contacted. It should contain a form with the appropriate fields as requested by the authentication methods used by the AS. The form must point to the URL identified by the configuration variable asLocation.

The acceptTemplate is sent to the user when the authentication request has been accepted. To ease user's access to resources available through the AS, the special variable PAPIsiteList can be included. This variable is updated by the AS software to include a list of the sites the user can access and the result of the request for access tokens. The list is built according to the service identifier assigned to each site: sites with blank service identifierss will not be included in the list. This allows for including a comprehensive list of available sites in the data back-end (papiSite objects in LDAP, for example), but only contacting those relevant at the moment of authentication (only top-level GPoA(s), for example).

The testTemplate is sent to the user as a response to a TEST operation, that is, whenever the user asks for a verification of the status of the PAPI tokens held by the browser. Again, the special variable PAPIsiteList can be included in this template, to give the user an idea of the current access permissions.

The logoutTemplate is sent to the user as a response to a LOGOUT operation, that is, whenever the user decides to erase any PAPI token from the browser. The PAPIsiteList can be included to provide a per-site report of the logout process.

The rejectTemplate is sent to the user when the authentication data the AS has received were not valid.

The siteInfoTemplate is used by the AS to build the contents of the PAPIsiteList variable. When using the siteInfoTemplate, the AS employs the fields that define a PoA in its context:

poa
The URL for the PoA itself, without any local part.
poaURL
The local part of the URL for requesting the access tokens to the PoA.
location
The local part of the URL of the resource to be accessed through the PoA.
service
The service name of this resource at the PoA. Bear in mind that using a blank service name makes the AuthServer to skip this site from the list of PoAs contacted upon successful authentication.
desc
A user-oriented description of the resource.

When processing a template, the AS substitutes any reference of the form:

 <papi var="variableName"/>

by the value of a user-provided variable (read from a previous HTML form) named variableName, or by the value of the configuration variable referenced by variableName. The AS also honors the Shell and Perl backtick convention. Any string enclosed between backuotes (the character `) will be substituted by the result of executing the corresponding command in the system. This way, a template containing:

 `date`

Will have it substituted by the current date and time.

Sample HTML templates are included in the AS/etc directory under the PAPI distribution tree.

Properties of the AS

 # Properties of this AS that must be configured in the PoA(s)
 #
 $$cfg{asLocation} = 'https://as.papi.dom.ain/';
 $$cfg{serverID} = 'SampleAS';
 # YOU MUST GENERATE THIS FILE AND THE CORRESPONDING PUBLIC KEY
 # It is the pubkey what must be sent to tha PoA(s), and stored
 # (in the case of mod_perl PoAs) as $Pubkeys_Path/${serverID}_pubkey.pem
 $$cfg{privateKey} = 'askey.pem';
 #
 # Comment these if you do not require split (thus SSL-capable) mode
 #
 $$cfg{splitModeURL} = 'http://as.papi.dom.ain/';
 $$cfg{splitModeParamList} = 'username';
 # Content that the PoA will return to when granting (in this case along with
 # the cookies) or rejecting access. The are tipically little green and
 # red little balls.
 # They have precedence over Accept_File/Reject_File configured in the PoA(s)
 $$cfg{acceptURL} = 'http://as.papi.dom.ain/accept-file';
 $$cfg{rejectURL} = 'http://as.papi.dom.ain/reject-file';
 #
 # Values for the authentication cookie (so that you are not required to
 # re-authenticate if you are returned to this AS in less than
 # authCookieTimeToLive seconds).
 # Comment them if you do not require its use.
 #
 $$cfg{authCookie} = 'PAPIuid,username';
 $$cfg{authCookieDB} = '/usr/local/PAPI/AS/etc/PAPIAuthenCookies';
 $$cfg{authCookieTimeToLive} = 3600;
 #
 # Value of the AS symmetric key
 # Used in split mode and for en-/de-crypting the authentication cookie
 # It is highly advisable that you change this value
 #
 $$cfg{symKey} = 'ca1813914a25b12a14ca121516e26180';
 #
 # The connection variable holding user id (for TEST and LOGOUT)
 $$cfg{uidVar} = 'username';

The asLocation defines the way for calling the AS CGI from the forms inside the templates. Thus, it should contain the full URL for the AS you are configuring.

The serverID is the identification of this AS, as it will be sent to PoAs inside the signed URLs that request the PAPI access tokens. This name is used by the PoA for obtaining the appropriate AS public key.

The privateKey is the name of the file containing the private key that this AS will use for signing its requests to PoAs. You may generate it using the following openssl command:

 openssl genrsa 1024 -out privateKey.pem

for a 1024 bit key. Remember that the file must be readable by the UID the AS CGI runs with, and that it is not a good idea to encrypt the private key: in that case you have to manage to incorporate the passphrase inside the AS code. Bear also in mind that this file contains very sensitive information, so be very careful with its access permissions.

Once you have generated your AS private key, you must send the corresponding public key to the PoAs your AS will request access tokens from, so they can recognize requests signed by your AS private key. You may derive the public key corresponding to the private key you have just generated by using the following openssl command:

 openssl rsa -in privateKey.pem -pubout -out publicKey.pem

and deliver the key stored in publicKey.pem to the operators of the PoAs your AS is going to work with. This distribution of public keys must be performed any time you change the private key for your AS.

Sample private and public keys are included in the AS/etc directory under the PAPI distribution tree.

The PAPI AS is able to accept authentication data through TLS. This means that the URL for the AS can be a TLS-based one (i.e., one that uses the https method). To do so while returning different authorization tokens from the PoAs by means of cookies, split mode has to be used.

In split mode, the AS automatically redirects itself to another URL (usually the non-TLS counterpart of the original), defined by splitModeURL when it receives user authentication data through the TLS secure channel. The redirection passes data about the user encrypted using the server private key. The data to be passed to the second phase in split mode is defined by the list of variables names contained in splitModeParamList. The connection variables PAPIop and PAPIrefURL (if set) are always passed.

Even in the case that TLS is not used, split mode implies an additional level of security, since the redirection to the splitModeURL is only valid for a very short period of time defined by splitModeTimeout (by default, 5 seconds). This way, using the ``reload'' button on a browser showing the acceptance page from the AS will not reload authentication tokens.

acceptURL and rejectURL are used to tell the PoAs to be contacted by this AS which are the URLs for the objects to be loaded into the user's browser along with the cookies containing the temporary keys. These are default values to be used if no specific URLs are defined for individual PoAs (as defined by the attributes papiSiteAcceptURL and papiSiteRejectURL in the papiSite LDAP class). Furthermore, if the AS does not provide either acceptURL or rejectURL in its request, the PoA will use its own default values, defined by its parameters Accept_File and Reject_File.

A common approach is to make reference to images indicating whether a certain resource is available or not, but do not forget you can use any object able to be embedded into an HTML page. For example, using different JavaScript files for acceptURL and rejectURL, each containing different implementations of the same function (called from the page contained in acceptTemplate), can provide a very powerful and user-friendly interface.

Inside acceptURL and rejectURL, any backtick calls and the constructs <papi var=``VarName''/> are substituted in the same way they are in the case of HTML templates, i.e., by the results of executing the correspondig or the variable identified by VarName inside the Authentication Server, whether coming from connectionor configuration data. This permits further personalization, since data for the users and/or their roles are available in the moment the Authentication Server processes these values.

Upon successful authentication, the PAPI AuthServer is able to set a HTTP cookie to store data about the user. The contents of this cookie are used to answer to ATTREQ queries coming from different PoAs without requiring user re-authentication. This cookie is named PAPIAuthNcook and is a session cookie that is set at the user's browser and re-coded each time an ATTREQ query is answered to difficult unauthorized access by cookie copying. If a LOGOUT operation is requested, the cookie is invalidated.

The format of the authentication cookie is:

 varList::nonce::TTL::clientAddress

Where:

varList
Is a list of connection variables, established at the moment of the user's authentication. It is built as follows:
 variable1Name:variable1Value::variable2Name:variable2Value:: . . .
The variables to be use are defined in the (comma separated) list held by the configuration variable authCookie.
nonce
Is a nonce, generated each time that the cookie has to be coded or re-coded. The value of the nonce is stored in the cookie database (defined by the configuration variable authCookieDB), so only an instance of the authentication cookie is valid at a given moment for a given user. Since the file defined by authCookieDB (and locks related to it) has to be written by the UID the Apache server is running with, you need to grant this UID with write permissions in the directory the file is defined.
TTL
Is the time at which the cookie will become invalid (in seconds since the 1st January 1970). Whenever the cookie is generated for the first time, this value is derived from the configuration variable authCookieTimeToLive. The TTL is not recalculated at successive re-generations of the cookie.
clientAddress
The IP address of the client this cookie was generated for. A cookie coming from a client not matching its clientAddress is considered invalid.

The AuthServer uses a symmetric key to encrypt those data to be reused between different requests of the user's browser, like connection data in split mode and authentication cookies. The value of this key is defined by the configuration variable symKey. To generate the value of this variable you may use the GNU program md5sum, that builds a MD5 checksum from an arbitrary stream of data. Since the MD5 checksum is 32 bytes long and the command outputs it in hex format, you can use this output directly to set the key.

For example, this command will produce a MD5 checksum of the files located in the /var/tmp directory, a reasonable approximation to a randomly generated symmetric key:

 cat `find /var/tmp -type f -print` | md5sum

When performing operations that do not require complete user identification (TEST and LOGOUT), the AuthServer needs a way to assign an user identifier (eventually employed by any active hooks). If the variable uidVar is set, the AuthServer will look for this user identifier in the connection variable with that name. If uidVar is not set, the default value nologin will be assumed as the user identification for these operations.

Default PoA

 # Default values for the PoA(s). Used when you do not declare them in
 # basicAuthDB or in LDAP.
 $$cfg{defTimeToLive} = 1800;
 $$cfg{defLocation} = '/';
 $$cfg{defService}= 'serv';
 $$cfg{defPoA} = 'http://poa.papi.dom.ain';
 $$cfg{defDescription} = 'Sample PAPI PoA';
 $$cfg{defAuthURI} = 'PAPI/cookie_handler.cgi';
 $$cfg{defAccessURI} = 'index.html';
 #
 # Default assertion about users to be sent to PoA(s)
 $$cfg{defAssertion} = '<papi var="PAPIuid"/>';

This section of the configuration file allows the definition of default values for the PoAs this AS is going to access. These default values configure the ``default PoA'' for this AS, and correspond to the elements that define any PoA to the AS in the different databases that can be used. These elements are:

PoA
The access method and domain name for the PoA, written in URL syntax.
Location
Is the URI for the location the PoA is controlling access to. It must have the same value as the Location section the PoA definition is in.
AuthURI
Is the URI for requesting the access tokens from the PoA. It must have the same value as the Auth_Location parameter in the PoA configuration. When the PoA receives a request for this URI it does not perform the usual access token checking, but verifies the parameters it has received along with the request (including the encrypted part that authenticates the AS) and generates the access tokens if appropriate, sending them to the user browser.
AccessURI
If requested to do so, the AS will (upon successful authentication) show a page in which links to the authorized PoAs will be included. This URI will be used in building this links, and it should point to the initial page of the contents protected by the PoA.
TimeToLive
Is the time-to-live for the access tokens to be requested to the PoA. Bear in mind that a PoA can further limit this value by means of its Max_TTL configuration parameter.
Service
Is the service identifier used by the PoA to identify itself inside the access token database. Bear in mind that using a blank service identifier makes the AuthServer to skip this site from the list of PoAs contacted upon successful authentication. If set to a non-blank value, it must have the same value as the Service_ID parameter in the PoA configuration.
Assertion
The format of the assertion about the user to be sent to the PoAs, if no other is defined by means of specific site definitons. Inside this string, the constructs <papi var=``VarName''/> are substituted by the value of the variable identified by 'VarName' inside the Authentication Server, whether coming from connection or configuration data. Furthermore, backtick expansion for system commands is also supported. If not set (and no other format has been obtained for a PoA), the assertion sent is equivalent to:

 <papi var="PAPIuid"/>-<papi var="PAPIgid"/>
The assertions defined by papiQualifiedAssertion and papiAssertion in the LDAP classes support a richer set of constructs, involving the use of LDAP attributes, as described below.
Description
Is a free-text description of the resource the PoA controls access to. Its main purpose is to provide the user with a friendly link to the resources behind the PoA when authentication is accepted.

Hooks and Hook Configuration

This section of the sample configuration file includes three alternatives for the authentication and log functions, based on the different authentication methods provided with this distribution. It also illustrates the use of internal variables to make a general configuration file that can be applied in different situations.

There are four different points where external functions can be hooked to the AS:

authenticationHook
The function hooked here must decide about the authentication data provided by the user. In its more common implementation, it will check the username and password provided by the user against an internal or external database. In split mode, it is executed during the first phase.
credentialHook
This function must provide the AS with a list of the PoAs this user can request access tokens from. The function may use an internal or external database, plus the default values provided inside the configuration file. In split mode, it is executed during the second phase. The variables passed by means of splitModeParamList are intended to be used by this function.
attrRequestHook
The function hooked here is in charge of finding a suitable PoA definition in the AuthServer and to build the appropriate assertion to be sent back in response to an ATTREQ query to the requesting PoA. Typically, it should use the PAPIPOAURL connection variable to determine the appropriate PoA definition, and the variables stored into PAPIAuthNcook to establish user identity, and compose the appropriate assertion.
logHook
The function hooked here is intended to perform the necessary logging activity. Since it is called from inside the AS, it has access to all configuration variables and to any values provided by the user.

It is important to note that you can freely mix different flavors of authentication, attribute request handling and credential provision. For example, it is possible to use a POP3 server for validating user names and passwords, a LDAP server to answer attribute requests, and generate the initial list of PoAs a user can access from the default settings.

POP3-based Authentication

 $$cfg{authenticationHook} = \&PAPI::POPAuth::POP3User;
 $$cfg{credentialHook} = \&PAPI::BasicAuth::DefCredentials;
 $$cfg{attrRequestHook} = \&PAPI::BasicAuth::DefAttributes;
 $$cfg{pop3Server} = "pop.dom.ain";
 # Uncomment this to use a TLS connextion to the POP3 server
 #$$cfg{pop3SSL} = 1;
 # Uncomment any of these to use a specific POP3 validation method.
 # By default, the "PASS" method is used
 # Use plain POP3 login (send USER and PASS commands in clear)
 #$$cfg{pop3Method} = 'PASS';
 # Use the APOP procedure
 #$$cfg{pop3Method} = 'APOP';
 # Use CRAM-MD5 when sending the password
 #$$cfg{pop3Method} = 'CRAM-MD5';
 # Query server capabilities (preference order is APOP, CRAM-MD5, and PASS)
 #$$cfg{pop3Method} = 'BEST';

The PAPI::POPAuth::POP3User function validates a user against a POP3 server (identified by the variable pop3Server). The function can be configured to use TLS and/or employ a certain POP3 method for validation by means of pop3SSL and pop3Method, respectively.

If you request ``pure POP3-based authentication'', it is not possible to use other credential-provision function than PAPI::BasicAuth::DefCredentials, or other attribute provider than PAPI::BasicAuth::DefAttributes, which just return values as defined for the default PoA inside the configuration file.

IMAP-based Authentication

 $$cfg{authenticationHook} = \&PAPI::IMAPAuth::IMAPUser;
 $$cfg{credentialHook} = \&PAPI::BasicAuth::DefCredentials;
 $$cfg{attrRequestHook} = \&PAPI::BasicAuth::DefAttributes;
 $$cfg{IMAPServer} = "imap.dom.ain";

The PAPI::IMAPAuth::IMAPUser function validates a user against a IMAP server (identified by the variable IMAPServer). If you request ``pure IMAP-based authentication'', it is not possible to use other credential-provision function than PAPI::BasicAuth::DefCredentials, or other attribute provider than PAPI::BasicAuth::DefAttributes, which just return values as defined for the default PoA inside the configuration file.

LDAP-based Authentication

 $$cfg{authenticationHook} = \&PAPI::LDAPAuth::VerifyUser;
 $$cfg{credentialHook} = \&PAPI::LDAPAuth::UserCredentials;
 $$cfg{attrRequestHook} = \&PAPI::LDAPAuth::UserAttributes;
 $$cfg{LDAPserver} = "ldap.dom.ain";
 $$cfg{LDAPport} = 389;
 $$cfg{LDAPUSERtemplate} = 'uid=<papi var="username"/>';
 $$cfg{LDAPAuthSearchBase} = 'ou=people,dc=dom,dc=ain';
 $$cfg{LDAPAuthScope} = 'sub';
 $$cfg{LDAPsearchBase} = 'dc=papi,dc=dom,dc=ain';
 # Uncomment these if you need simple authentication to access the LDAP server
 #$$cfg{LDAPbindDN} = "dc=papias,dc=papi,dc=dom,dc=ain';";
 #$$cfg{LDAPbindPassword} = "papipassword";
 # Uncomment these to use a TLS connection and verify server identity
 #$$cfg{LDAPS} = 1;
 #$$cfg{LDAPSverify} = 'require';
 #$$cfg{LDAPScafile} = '/etc/PAPI/CAs/MyRoot.pem';

The LDAP-based authentication functions use objects served by an LDAP server for performing user validation, credential provision, and attribute request handling. The server to be used is identified by the configuration variables LDAPserver and LDAPport. Functions can bind to the LDAP server using simple authentication (if LDAPbindDN and LDAPbindPassword are set), or anonymously. The LDAP schema for the objects used by these functions is described in the file LDAPAuth/papi.schema under the PAPI distribution tree. Three classes are defined there:

papiUser
Models an individual and their access rights to resources protected by PAPI PoAs. It may have a set of papiSites the user has access to, and/or a set of papiGroups the user belongs to. It may also contain a set of papiQualifiedAssertions defining what information to be sent to which PoAs when requesting access tokens to them.
papiGroup
Models a group of users with similar characteristics. It has a set of associated papiSites that users in the group have access to. It may also contain a set of papiQualifiedAssertions, applicable to users in the group that do not have a specific assertion format for a certain PoA.
papiSite
Models an information resource that must be accessed using a PAPI PoA. It may contain the URLs to be sent (along with access tokens if applicable) when access through the PoA is granted or denied. It may also contain a papiAssertion, defining the information about users to be sent to the PoA, if there is no other more specific assertions defined.

Assertions (either defined by papiQualifiedAssertion or papiAssertion) are arbitrary text strings where references to user entry attributes and/or connection and configuration values are substituted according to the following patterns:

<papi var=``VarName''/>
Is substituted by the connection or configuration variable identified by 'VarName'.
<papi attr=``AttrName'' default=``DefValue''/>
Is substituted by the value of the attribute 'AttrName' in the user's entry. If 'AttrName' is multivalued, the first value returned by the LDAP server is used. If no value is found for 'AttrName', the default value is provided through the (optional) 'DefValue'. If this default value is not set and no value is found for 'AttrName', the construct is substituted by the empty string.
<papi attrlist=``AttrName'' sep=``String'' default=``DefValue''/>
Is substituted by a string built by composing the values of attribute 'AttrName' in the user's entry using the value of 'String' as separator. If no value is found for 'AttrName', the default value is provided through the (optional) 'DefValue'. If this default value is not set and no value is found for 'AttrName', the construct is substituted by the empty string.
<papi hashedattr=``AttrName'' default=``DefValue''/>
Is substituted by a string built by running a hash algorithm on the values of attribute 'AttrName' in the user's entry. The current implementation uses MD5. If no value is found for 'AttrName', the default value is provided through the (optional) 'DefValue'. If this default value is not set and no value is found for 'AttrName', the construct is substituted by the empty string.
`SystemCommand`
Is substituted by the result of executing 'SystemCommand' in the context of the AS.

The values of papiAssertions contain strings as described above, while papiQualifiedAssertions consist of pairs (siteID, assertionFormat), where siteID must correspond to one papiSiteID and assertionFormat describes the assertion to be used for that site in the above described format. The separator of both parts is made of any number of whitespace characters (spaces or tabs). Only a papiQualifiedAssertion can be used for a given papiSite in a papiUser or papiGroup object.

As an example, the following value in the papiAssertion attribute of a papiSite named samplePoA will send the (comma separated list of) values of the POSIX groups the user belongs to:

 groups=<papi attrlist="gid" sep=","/>

While, for a certain user or group (defined by the corresponding papiUser or papiGroup) the use of the following value in the papiQualifiedAssertion will additionally send the POSIX uid. If no value for uid is found, the value 'nobody' will be used:

 samplePoa uid=<papi attr="uid" default="nobody"/>,groups=<papi attrlist="gid" sep=","/>
 
The function B<PAPI::LDAPAuth::VerifyUser> is intended to perform
user validation, using the corresponding B<papiUser> object in the
LDAP server. It binds to the LDAP server and searches for an entry under
B<LDAPAuthSearchBase> of class B<PAPIuser> (using the scope defined by
B<LDAPAuthScope>) that matches the filter defined by the configuration
variable B<LDAPUSERtemplate>. This template uses the same substitution
patterns as described above for HTML templates in order to incorporate
configuration and/or user-provided variables (as the case of B<username> in
the sample configuration lines above). Once this entry has been found, the
function tries to bind using the DN of the entry and the value of the
B<password> variable, as provided by the user.

Three different LDAP-based credential provision functions may be used. They bind to the LDAP server and use the configuration variable LDAPsearchBase for requesting the appropriate objects.

PAPI::LDAPAuth::UserCredentials
It returns the list of PoAs a specific user has access to, taking into account the groups the user is included in. The entry for the user is located using the same procedure described above for PAPI::LDAP::VerifyUser.
PAPI::LDAPAuth::GroupList
It returns the list of PoAs defined for a list of papiGroup objects. The groups to be used are defined inside the configuration variable groupList. The list must be comma-separated:
 $$cfg{groupList} = 'faculty, staff';
PAPI::LDAPAuth::AllSites
It returns a list of PoAs built from all the papiSite objects known to the LDAP server.

Three LDAP-based attribute request handlers are also included in the PAPI distribution. Each of them uses the LDAP base defined by the configuration variables LDAPserver, LDAPport and LDAPsearchBase to search for a suitable papiSite definition, taking the longest match of the value of the connection variable PAPIPOAURL against their papiSitePoA attribute. The differences among them are in how the list of site definitions to be searched is built:

PAPI::LDAPAuth::UserAttributes
The search is performed on the sites defined for a certain user, whose entry is determined by means of the same procedures described above for PAPI::LDAPAuth::VerifyUser.
PAPI::LDAPAuth::GroupListAttributes
The search is performed on those papiSite objects belonging to the papiGroups whose identifiers are included in the configuration variable groupList.
PAPI::LDAPAuth::AllSiteAttributes
The search is performed on all the papiSite objects defined for the LDAP search base. No user context is considered for building assertions.
PAPI::LDAPAuth::AnySiteAttributes
The search is performed on all the papiSite objects defined for the LDAP search base. User data (as described above for PAPI::LDAPAuth::UserAttributes) is used for building assertions.

If a suitable site is found, these functions return the applicable assertion format, and the time-to-live defined for the site. If no site is found matching the requesting URL, they set the PAPIerror variable and a negative value is returned.

To decide which assertion is going to be sent to a given PoA, the following procedure is applied:

1. Use the format defined by the attribute papiQualifiedAssertion matching the papiSiteID for the corresponding site defined in the papiUser entry.

2. If (1) is not applicable, use the format defined by the attribute papiQualifiedAssertion that matches the papiSiteID for the corresponding site in any of the applicable papiGroup objects.

3. If (2) is not applicable, use the format defined by the attribute papiAssertion of the papiSite object for the corresponding site.

4. If (3) is not applicable, leave the assertion empty, so the default value defined in the AuthServer configuration is used (see above).

Using TLS in the LDAP connection

The LDAPS configuration variable, if set to 1, directs the above functions to use TLS (and a implicit default LDAPport value of 636) when connecting to the LDAP server.

LDAPS* variables are used to configure the TLS parameters used by the Net::LDAP supporting module. Each of these variables corresponds to a TLS-configuring value, defined by the suffix in its name. That is, the PAPI AuthServer configuration variable LDAPSfoo sets the value of the TLS connection variable foo for Net::LDAP.

Although you should refer to the documentation of your installed Net::LDAP module for more details, these are some of the more significative:

LDAPSverify 'none'|'optional'|'require'
Set the Net::LDAP variable verify, defining how to verify the server's certificate:
none: The server may provide a certificate but it will not be checked
optional: Verify only when the server offers a certificate
require: The server must provide a certificate, and it must be valid.
LDAPSclientcert pathToCert
LDAPSclientkey pathTokey
If you want to use the client to offer a certificate to the server for SSL authentication, these variables set the Net::LDAP variables clientcert and clientkey to the files holding the certificate and the private key, respectively. These files must be in PEM format.
LDAPScapath pathToCADirectory
LDAPScafile pathToCACertificate
When verifying the server's certificate, either set the Net::LDAP variable capatht to the pathname of the directory containing CA certificates, or set cafile to the filename containing the certificate of a CA recognized to sign the server's certificate. These certificates must all be in PEM format.

Authentication based on X.509 certificates

 $$cfg{authenticationHook} = \&PAPI::CertAuth::ValidateCert;
 # Read user data from LDAP using the certificate subject DN
 $$cfg{credentialHook} =  \&PAPI::LDAPAuth::UserCredentials;
 $$cfg{CertValidateMethod} = "client_DN";
 $$cfg{client_DNPattern}="(dc=dom,dc=ain).*(uniqueIdentifier=.*)";
 # Config variables for using the certificate subject DN within
 # PAPI::LDAPAuth::UserCredentials
 $$cfg{LDAPserver} = "ldap.dom.ain";
 $$cfg{LDAPport} = "389";
 $$cfg{LDAPUSERtemplate} = 'uid=<papi var="PAPIuid"/>';
 $$cfg{LDAPAuthSearchBase} = 'ou=people,dc=dom,dc=ain';
 $$cfg{LDAPsearchBase} = 'dc=papi,dc=dom,dc=ain';

The authentication function that uses X.509 certificates directly relies on the Apache SSL module. You have to configure Apache to ask for a user certificate whenever an access to the AuthServer is attempted. This is done by means of the Apache configuration directive SSLVerifyClient. The function also requires the use of the option CompatEnvVars in the SSLOptions directive.

The function does not perform any kind of certificate verification. This is left to Apache. Certificate data is read from the standard environment variables that Apache uses to communicate them to its components and matched against the validation criteria defined by the configuration variable CertValidateMethod. This variable contains a list of the validation methods to be used. Each method identifier is separated by spaces. Methods are applied in the same order they appear in the list. If any of them fail, authentication is rejected. Method dentifiers not known to the system cause authenticaton to be rejected. Valid method identifiers are:

remote_addr
The IP address of the client must match one of the IP addresses or networks in the list defined by the configuration variable remote_addrPattern. The general format of this parameter consists of a blank-separated list of IP addresses and networks, as in the following example:
 $$cfg{remote_addrPattern} = "1.2.3.4 5.6.7.8/30 9.10.11.12";
start_date
The certificate must have been issued after the date defined by the start_datePattern configuration variable. Dates must be expressed in the format Month Day hh:mm:ss Year GMT.
end_date
The certificate must have been issued before the date defined by the end_datePattern configuration variable. Dates must be expressed in the format Month Day hh:mm:ss Year GMT.
issuer_DN
The DN of the certification authority that issued the certificate must match against the regular expression defined by the issuer_DNPattern configuration variable.
client_DN
The subject DN of the certificate must match against the regular expression defined by the client_DNPattern variable.

As en example, the following lines makes the function accept only valid certificates issued by the CA ``cn=MainCA,dc=dom,dc=ain'' after 1st January 2002:

 $$cfg{CertValidateMethod} = "issuer_DN start_date";
 $$cfg{issuer_DNPattern}="cn=MainCA,dc=dom,dc=ain";
 $$cfg{start_datePattern}="January 01 00:00:00 2000 GMT";

Once the certificate data has been validated, identity data must be established to allow the building of the assertion about the user. The configuration variable IdAttribute permits to establish which data is to be returned:

1. If set to any value, this value wil be used for extracting an attribute with that name from the subject DN of the certificate. If such attribute is not found in the subject DN, undef is returned.

2. If the variable is not set, the whole certificate subject DN is returned. This is the default.

Obviously, assertion building must use other mechanisms. Since there is a natural binding between X.509 certificates and directory systems, the use of LDAP authentication procedures is strongly recommended. In fact, the default behavior when returning identity data is intended for that purpose.

Basic Authentication

 $$cfg{authenticationHook} = \&PAPI::BasicAuth::VerifyUser;
 $$cfg{credentialHook} = \&PAPI::BasicAuth::UserCredentials;
 $$cfg{attrRequestHook} = \&PAPI::BasicAuth::UserAttributes;
 $$cfg{basicAuthDB} = "Basic.pdb";

This authentication method is based on an internal database that use the Perl DB_File functions. The database holds entries similar to the user, group and site objects described for the LDAP case. The location of the database is defined by the configuration variable basicAuthDB.

The function PAPI::BasicAuth::VerifyUser is intended to perform user validation, using the corresponding user entry into the database, and four different credential provision functions are defined by the basic authentication module:

PAPI::BasicAuth::UserCredentials
It returns the list of PoAs a specific user has access to, taking into account the groups the user is included in.
PAPI::BasicAuth::GroupList
It returns the list of PoAs defined for a list of group entries. The groups to be used are defined inside the configuration variable groupList. The list must be comma-separated.
PAPI::BasicAuth::AllSites
It returns a list of PoAs built from all the site entries in the database.
PAPI::BasicAuth::DefCredentials
It returns the default PoA values set in the configuration file. It is intended to be used as a stub when no other more sophisticated credentials provision methods are required.

Three attribute request handlers based on the internal database are also provided. Each of them uses the contents of the database defined by the configuration variable basicAuthDB to search for a suitable site definition, taking the longest match of the value of the connection variable PAPIPOAURL against the POA field. The differences among them are in how the list of site definitions to be searched is built:

PAPI::BasicAuth::UserAttributes
The search is performed on the sites defined for a certain user, determined by means of the contents of PAPIuid.
PAPI::BasicAuth::GroupListAttributes
The search is performed on those sites belonging to the groups whose identifiers are included in the configuration variable groupList.
PAPI::BasicAuth::AllSiteAttributes
The search is performed on all the sites defined in the database.

If a suitable site is found, these functions return the assertion format and the time-to-live defined for the site. If no site is found matching the requesting URL, they set the PAPIerror variable and a negative value is returned.

The function PAPI::BasicAuth::DefAttributes is provided as a fall-back for attribute request handling. It uses the connection variable PAPIPOAURL to match against the default site defined for the AuthServer. If a the match succeeds, the default assertion and default TTL are returned. Otherwise, an error is signaled by means of PAPIerror and a negative return value.

There are two utility programs, pdimport and pdexport, for importing and exporting text files to and from a PAPI basic authentication database. They are located in the BasicAuth directory under the PAPI distribution tree, and you can copy them to any appropriate location if you plan to use them. The installation procedures install them under the etc file in the directory selected for the AS installation when running perl Makefile.PL (by default, /usr/local/bin). A sample source text file is also installed in that directory.

Logging AS Activity

You can log the activity of the AS by including a reference to an appropriate function in the logHook configuration variable. The current distribution includes a couple of these functions:

PAPI::BasicLog::SysLog
For logging the AS activity through the standard Unix daemon syslog. The syslog facility and priority to be used are defined by the configuration variables syslogFacility and syslogPriority, respectively (``local7'' and ``info'' by default).
PAPI::BasicLog::FileLog
For logging the AS activity directly to a file. The name of the file to be used is defined by the configuration variable logFile.

Each PAPI operation is logged separately, including the username provided, the requested operation, and its result. If the operation was rejected, a cause for the failure is also included.

CONFIGURING THE POINT OF ACCESS

The configuration of the PoA is made directly inside the Apache configuration file. To activate PAPI configuration directives you must include the following directive before using any of them:

 PerlModule PAPI::Conf

The recommended practice is to provide a set of common or default values for all the PoAs hosted by the Apache server using the section <PAPI_Main>:

 <PAPI_Main>
 . . .
 [Common/default PAPI PoA directives]
 . . .
 </PAPI_Main>

To establish a PAPI PoA you just have to add the following two lines inside the appropriate <Location> section in the Apache configuration file:

 PerlSendHeader  On
 PerlAccessHandler PAPI::Main

The PoA will be activated for controlling access to any URI below this location, unless other access control methods (another PAPI PoA or any other else) are specified within a deeper <Location> section. Using the section <PAPI_Local> after the two PoA activation lines it is possible to apply specific PAPI directives to this PoA:

 <PAPI_Local>
 . . .
 [Specific PAPI PoA directives]
 . . .
 </PAPI_Local>

General Configuration Directives

The following directives may be applied to any kind of PoA.

HKEY_File filename
Defines the name of the file containing the encryption key for the Hcook tokens. The file must contain a single line with a string of up to 32 hexadecimal characters ([0-9a-fA-F]), and it should have very restrictive access permissions.
LKEY_File filename
Defines the name of the file containing the encryption key for the Lcook tokens. The file must contain a single line with a string of up to 32 hexadecimal characters ([0-9a-fA-F]), and it should have very restrictive access permissions.

These two directives define the pair of symmetric keys that the PoA uses for encrypting the access tokens (Hcook and Lcook). To generate the contents of these key files you may use the GNU program md5sum, that builds a MD5 checksum from an arbitrary stream of data. Since the MD5 checksum is 32 bytes long and the command outputs it in hex format, you can use this output directly to build the keys.

For example, this command will produce a MD5 checksum of the files located in the /var/tmp directory, a reasonable approximation to a randomly generated symmetric key:

 cat `find /var/tmp -type f -print` | md5sum
Service_ID serverName
This is the name the PAPI system will use for internally identifying the PoA.
Hcook_DB filename
Defines the name of the file where the PoA is going to record the Hcook tokens and their properties, in order to detect access attempts using copied tokens. Since this file (and locks related to it) has to be written by the UID the Apache server is running with, you need to grant this UID with write permissions in the directory the file is defined.
Auth_Location location
URI for dealing with direct requests from PAPI authentication servers. When a request for this URI is received, the PoA analyzes its parameters, validates the digital signature of the AS and decides whether to accept or reject the request. Three different operations are currently supported: LOGIN (a request for access tokens, containing an assertion about attributes of the user trying to gain access), TEST (a request for validating the access tokens held by a browser), and LOGOUT (a request for invalidating the access tokens held by a browser).
By default, the value /PAPI/cookie_handler.cgi is used.
When the PoA receives an HTTP request for performing one of these operations, it is usually a request for an HTML object (image, script,...) that has been embedded by the AS inside a page it sends to the user browser. The following two directives allow the definition of the objects to be sent back to the user when a request is processed.
Signoff_Location regularExpression URL
Requests that fire a sign-off process.
When a request for a location matching the regular expression is received the PoA will proceed to invalidate access tokens and redirect the requesting client to URL, where the sign-off process can be continued.
This directive permits to directly request sign-off at any PoA and progress this request to either:
1. Up in the GPoA hierarchy, requesting a equivalent location at the GPoA.
2. The AS, so it invalidates the initial user identification.
3. Any other PoA in a known set of PoAs, requesting an equivalent location there.
4. A specific sign-off procedure for a proxied resource.
5. A page informing the user that sign-off has taken place.
6. Any combination of the above, given an appropriate handler is available at URL
Any number of sign-off locations can be defined for a PoA, allowing for different procedures to be applied through the use of different continuation URLs. In any case, all sign-off locations will invalidate access tokens for this PoA.
Pass_URL_Pattern
Since PAPI access control has to be configured for a whole Apache Location, it may be handy to avoid PAPI access checks for certain documents and/or branches below it. This directive allows the definition of a regular expression that will be matched against the requested URL. If the expression matches, the PAPI access checkings are not performed and access is automatically granted.
Accept_File filename
Defines the file holding the default object to be sent to the user browser when a request is accepted and the AS did not define a specific URL for this purpose.
Reject_File filename
Defines the file holding the default object to be sent to the user browser when a request is rejected and the AS did not define a specific URL for this purpose.
Pubkeys_Path directoryName
Defines the directory where public keys of the authentication servers are stored. Each recognized authentication server public key must be stored in a separate file under this directory. The file name must be ASName_pubkey.pem, where ASName is the name assigned to the authentication server (by means of PAPI_AS). The key must be in PEM format.
If this PoA belongs to a group controlled by a GPoA (see below), the public key for its GPoA must also be stored in this directory. In this case, the file holding the GPoA key must be called _GPoA_pubkey.pem.
Domain domainName
It must be set to the domain name of the web server this PoA belongs to, since this parameter is the domain field used whenever cookies holding tokens are generated. This is a fall-back value, to be used when the name that Apache internally stores does not match the domain name of the server.
Hcook_Handler regularExpression
This directive allows the definition of URIs containing elements that require the contents of Hcook. Locations matching the regular expression will receive the current value of the assertion contained into Hcook, through:
1. An Apache note, with identifier PAPIHcook.
2. A header, called X-PAPI-Hcook, added to the request.
The contents of both the note and the header are the same. Depending on the nature of the handler (a Apache module, a mod_perl handler, a CGI program, a PHP script, a servlet, a JSP, etc) you can decide to use one or the other.
Hcook_Generator functionName
With this directive, it is possible to use an external function to generate the contents of the access tokens. This way, data only known to the PoA can be included into the cookies, and used by PAPI itself or the PAPI-enabled applications through the use of Hcook_Handler. A typical example of the use of this directive could be the inclusion of database-access passwords inside the access tokens, according to the database privileges of the user. Bear in mind that data is circumscribed to the PoA environment and encrypted using the access token keys.
The function name must be fully qualified according to Perl conventions (the usual form is Package::Function). It receives two input parameters: the contents of the assertion as received from the AS/GPoA, and the identifier of the AS that originally created it. It must return the string that will be included into the access tokens.
Lcook_Timeout seconds
Period of time during which Lcook tokens are valid.
CRC_Timeout seconds
Period of time during which URL requests with Hcook tokens containing an old random control block are considered valid by the PoA.
URL_Timeout seconds
Period of time during which a signed URL generated by an authentication server is valid. This time is measured from the moment the authentication server created the signed URL.
Max_TTL seconds
Maximum time-to-live for the access tokens generated at the PoA. If this parameter is used, any longer TTL value requested by any AS will be cut to the Max_TTL value.
PAPI_AS ASName ASURL ASDescription
Definition of a PAPI Authentication Server that is valid for this PoA. The name is used to locate the appropriate public key. The URL may be used to directly query the authentication server from the PoA (if a WAYF service is defined, see below). In the current implementation, the description is just an informative (but mandatory!) string.
PAPI_Filter regularExpression => [accept|reject]
This directive allows the definition of filters applicable to assertion evaluation at this PoA. When a request for new access tokens is received (through the URI defined by Auth_Location), the PoA tries to match the assertion received within it against the regular expressions defined for the filters. When a filter matches, the PoA applies the corresponding result: accept implies that request may proceed and access tokens will be generated, while reject implies that the request will be refused. In both cases, no further filters will be checked.
Filters are applied in the same order they appear in the configuration, first local filters defined inside the <PAPI_Local> section, and then global filters defined inside the <PAPI_Main> section. For backward compatibility, a catch-all implicit filter equivalent to:
 PAPI_Filter .* => accept
is assumed
So, if you want a PoA to reject all requests holding assertions containing the string role=student, and accept all other, simply add the following line:
 PAPI_Filter role=student => reject
Conversely, if you want a PoA to only accept those requests holding assertions containing the string role=student, you must use:
 PAPI_Filter role=student => accept
 PAPI_Filter .* => reject
Cookie_Reject regularExpression
With this directive, you can define access token filters to be applied by the PoA. If the user data included inside the access cookies matches against the regular expression, the request for access will be denied. This allow for immediate revocation of user's rights.
This immediate filters are applied in the same order they appear in the configuration: first local filters defined inside the <PAPI_Local> section, and then global filters defined inside the <PAPI_Main> section.
Hash_User_Data [1|0]
If set to 1, the user data received from the AS is transformed through a hash function. This way, access to the cookies (even decrypting them) does not reveal data about users. Since it also applies to assertions sent to subordinated PoAs by their GPoA, this directive may help in preserving user privacy.
Nevertheless, you must bear in mind that filters (either at the potential subordinated PoAs or immediate filters using Cookie_Reject) are going to be applied on the hashed data. It is also important to note that this feature may have undesirable interactions with some other ones, like the use of Hcook_Handler and the generation of request headers holding user attributes.
User_Data_Rewrite regularExpression replacementString
The assertion received for a certain request (either from an AS or a parent GPoA) can be rewritten prior to the generation of access tokens by means of this directive. This way, data necessary for the authorization phase (when evaluating the assertion through filters) but not required by access control procedures is no longer conveyed by the access tokens, improving privacy preservation and keeping access tokens more compact.
As many directives of this kind as required may be defined. They are applied in the usual order: locally defined first, global ones after them, in the same order they appear in the configuration file. All of them are applied, each on the current value of the assertion in the moment the rewrite was called. Consider a PoA using this couple of rewrites:
 User_Data_Rewrite role=staff role=employee
 User_Data_Rewrite role=employee internalUser
An assertion with either the string role=staff or role=employee will produce access tokens containing the string internalUser.
Client_Address_In_Tokens [1|0]
If set to 1, client IP address is included into the user data conveyed by access cookies, and verified upon reception. A mismatch makes access to be denied.
It allows the binding of a PAPI session to a certain address, what may be a requirement for certain applications (and a problem for others).
Attribute_Separator separatorString
Value_Separator separatorString
Certain PoA functions (like the use of an external authorization server, or specific authentication procedures in proxy mode) require the extraction of individual attributes from the assertions the PoA receives. These two directives define the way in which individual attribute names and values have to be extracted. Attribute_Separator defines the characters that will be used by the PoA to identify each individual attribute (a name/value pair) inside an assertion. Value_Separator defines the characters that will be used by the PoA to identify the attribute name and value for each individual attribute. Blanks are always included among the separators in both cases.
The PoA passes all attribute values in specific Apache notes as well as in specific requests headers. Notes have the identifier PAPIAttr-ATTNAME and headers are called X-PAPIAttr-ATTNAME.
If set to their default values (``,'' for Attribute_Separator, and ``='' for Value_Separator), an assertion like this:
 user=Joe Melon, role = staff
will yield the following attribute name/value pairs:
 "user" -> "Joe Melon"
 "role" -> "staff"
And they will be available as Apache notes as follows:
 PAPIAttr-user -> "Joe Melon"
 PAPIAttr-role -> "staff"
And as if the request had come with the following HTTP headers:
 X-PAPIAttr-user: Joe Melon
 X-PAPIAttr-role: staff
If Attribute_Separator is set to ``;'', and Value_Separator to ``:'', an assertion like:
 DN: cn=joe,ou=staff; UID : joemelon
will yield the following attribute name/value pairs:
 "DN"  -> "cn=joe,ou=staff"
 "UID" -> "joemelon"
the following Apache notes:
 PAPIAttr-DN  -> "cn=joe,ou=staff"
 PAPIAttr-UID -> "joemelon"
and the following request headers:
 X-PAPIAttr-DN: cn=joe,ou=staff
 X-PAPIAttr-UID: joemelon
Max_Nonce_Errors number
The PAPI PoA includes a nonce inside access tokens to avoid invalid access by means of cookie duplication. Once new access tokens are generated, the nonce is stored inside a database. Nonces inside tokens and in the database are compared and re-generated according to the value of Lcook_Timeout. If a mismatch is detected in this comparison, an algorithm is started to detect whether this mismatch is caused by an invalid access attempt or because the user's browser did not update cookies properly.
This parameter defines the maximum number of mismatches that are allowed for the detection algorithm. By default, its value is 3. Higher values may lead to some invalid access to pass through the PAPI PoA, while lower ones may cause false positives in the invalid access detection procedures.
Debug [1|0]
If set to 1, debug mode is activated.

PoA under a GPoA

When a PoA is defined to belong to a group of PoAs controlled by a group-wide PoA (GPoA) the following directives can be used.

GPoA_URL URL
This directive defines where to redirect requests arriving to this PoA without authorization tokens. In this case, authorization is passed up in the GPoA hierarchy, redirecting the request to the URL defined in the directive. The value of this URL should be that defined by Auth_Location at the GPoA.
Req_DB filename
Defines the name of a file the PoA will use for recording the request data prior to redirect it to the GPoA. Since the GPoA is going to redirect back the request to the PoA once the authorization procedures are completed, this record will allow to rebuild the request as it came from the user. This is specially applicable to requests using the POST method. Since this file (and locks related to it) has to be written by the UID the Apache server is running with, you need to grant this UID with write permissions in the directory the file is defined.

As mentioned above, the public key (in PEM format) for the GPoA must be stored in the directory defined by Pubkeys_Path. The file holding the GPoA key must be called _GPoA_pubkey.pem.

Using a WAYF service

The GPoA_URL directive is also used to configure a PoA to directly query authentication servers. The reason for this is that, in functional terms, what the PoA is doing is the same in both cases: redirecting the user's request to another point where information about the user (an assertion) can be obtained. Anyway, the process of querying the authentication server implies an additional step: establishing which is the appropriate authentication server to query. This step, that will normally require user intervention, is assumed to be performed by the WAYF service.

WAYF is an acronym originated within the Shibboleth project that stands for the initials of the question Where Are You From?. A WAYF service is in charge of establishing the appropriate authentication server for the user, and progress the query about their attributes along with all the data required to receive and process back the answer at the PoA. PAPI supports both internal (running in the same server and with knowledge about the PAPI configuration) and external WAYF services. For each of them, an interface based on HTTP redirections is defined here.

To configure a PAPI PoA to directly query authentication servers for assertions about users, the special method name wayf can be used inside the value of the GPoA_URL directive. The string following the wayf method determines the class of WAYF service to be used to locate authentication servers:

The string 'built-in'
A built-in internal WAYF that shows a simple list of the ASes known to the PoA, asking the user to select one
An arbitrary pathname
An internal WAYF implemented by the file pointed by the pathname.
Any other URL
An external WAYF implemented at that location.

Therefore, a definition of this type:

 GPoA_URL wayf:built-in

Will show a list of known authentication servers in response to any connection attempt without valid access tokens.

While this one:

 GPoA_URL wayf:/usr/local/PAPI/coolWayf.php

Will redirect users to the WAYF service implemented by that local file.

And:

 GPoA_URL wayf:https://wayf.common.domain/wayf?community=CoolCommunity

Will redirect users to the external WAYF service located there.

GPoA Configuration Directives

A PAPI Point of Access can be configured to control the access to a group of other PAPI PoAs. In this case, the PoA is called a group-wide PoA, or GPoA. To define a GPoA it is necessary to:

1. Build a keypair.

2. Distribute the public key to the PoAs controlled by the GPoA. Each PoA must install the key in the file _GPoA_pubkey.pem under the directory defined by Pubkeys_Path

3. Install the GPoA private key at the location defined by GPoA_Priv_Key.

The directives that control the behavior of a GPoA are:

GPoA_Priv_Key filename
This is the configuration directive you must use to define the location of the GPoA private key. The permissions for filename must be similar to those defined by HKey_File and LKey_File.
GPoA_Rewrite PoARegExp regExp => replacementString
By means of this directive, a GPoA can control the information that it sends to its subordinated PoAs. When processing a request for authorization data of a child PoA, the GPoA looks for GPoA_Rewrite rules in which the PoA name matches against the value of PoARegExp. If these rules are found, the rewrites specified by the rules are applied to the user data held in the GPoA access tokens prior to sending them as an assertion to the requesting PoA.
As in the case of User_Data_Rewrite, as many directives of this kind as required may be defined. They are applied in the usual order: locally defined first, global ones after them, in the same order they appear in the configuration file. All of them are applied, each on the current value of the data in the moment the rewrite was called
GPoA_Hash_User_Data [1|0]
If set to 1, user data is transformed through a hash function prior to sending it to the subordinated PoA. This way, children PoAs cannot access actual data about users. This implies that subordinated PoAs must completely trust their ancestor GPoAs and can only apply their own filters to a very limited extent. This feature may also have undesirable interactions with some other ones, like the use of Hcook_Handler and the generation of request headers holding user attributes.

PAPI and Athens interconnection (PADATH)

PAPI is able to provide access to Athens-enabled resources by means of the mechanisms defined by Athens Devolved Authentication (AthensDA), through a set of procedures that allows a PAPI PoA to receive and send identity assertion to Athens. These procedures are implemented in a specific PAPI module called PADATH (PAPI Adaptor to Athens), based on the AthensDA Perl package distributed by Eduserv. When a PoA is configured to connect to Athens, it is able to act as a Athens XAP (eXtensible Authentication Point), both in HDD (Home Domain Discovery) and LAA (Local Authentication Assertion) modes.

To run PADATH, you need a valid institutional ID and a valid key to run Athens Devolved Authentication procedures. See http://www.athensams.net/ and http://www.athensams.net/development/devolved_authentication/ for more details about these requirements and AthensDA protocols and support (including the Perl AthensDA module).

The following configuration directives are used to define PAPI-Athens interoperation:

PADATH_LAA_Handler location
The URI which will trigger Athens interactions in LAA mode. When a request for this location is received and accepted by the PAPI authorization mechanisms, the PoA will contact the AAP (Athens Authentication Point) in order to establish a Athens session. During this session, the PoA will send an assertion derived from the attributes of the user (as stored in the access tokens) and process the response of the AAP.
PADATH_HDD_Handler location
The URI which will answer AAP queries in HDD mode. When a request for this location is received and accepted by the PAPI authorization mechanisms, the PoA will assume it is coming from the AAP, validate the HDD query, and produce the appropriate response (including an assertion derived from user attributes set in the access tokens), sending it back to the AAP.
PADATH_Institution_ID AthensIdentifier
The Athens institution ID to be used, as provided by Athens.
PADATH_Athens_AuthPoint URL
The URL for the AAP, where queries and responses are sent by the PADATH functions. It must follow the specification of Athens for your institution. The default value is ``https://auth.athensams.net/''.
PADATH_Key filename
The name of the file containing the encryption key used for the interactions of PADATH with the AAP. It must contain the data provided by your Athens Devolved Authentication agreeement, in the format expected by the AthensDA package: a single line consisting of a string composed of the cipher identifier (AES is the only currently supported cipher), a colon, and the value of the key as supplied by Athens. The following line provides an example of the valid content of such file:
 AES:8T9y3ARmyojj3/wcyQVc1P==
PADATH_Permission_Set_Attribute attributeName
The attribute, from those included inside the user assertion the PoA is using, that contains the Athens permission set to be used in the interactions with the AAP. By default, it takes the value ``AthensPermissionSet''.
PADATH_User_Id_Attribute attributeName
The attribute, from those included inside the user assertion the PoA is using, that contains the value to be sent to the AAP as user identifier. By default, it takes the value ``uid''.
PADATH_AAP_TTL seconds
Defines the maximum acceptable shift in the timestamps of AthensDA packets received from the AAP. By default, it takes the value recommended by the AthensDA documents: 60 seconds.

Using an external authorization server (SPOCP)

Authorization is a very complex task that may well involve a fairly sensitive and huge set of rules. That implies that a central definition of authorization policies is highly desirable in most environments. But such a common set of authorization rules is difficult to export and enforce at several different points, each of one with a specific local configuration. A central authorization server, aware of the organizational authorization rules, and performing decisions directed by them, is a solution to this problem. PAPI PoAs are able to use one of these external authorization servers, called SPOCP (more information on SPOCP is available at http://www.spocp.org/), to make their authorization decisions.

When an assertion is received, the PAPI PoA can (if configured to do so) prepare a query for the defined SPOCP server, send it and use its outcome to decide whether to accept or not the access request. SPOCP evaluates if a certain subject is authorized to perform a certain action on a certain resource, according to a set of rules.

Queries to SPOCP are built by the PAPI PoA using the following format:

 (papi (poa Service_ID) (action SPOCP_Action)
  (subject (Attr1 Attr1Value) . . . (AttrN AttrNValue)))

The resource is taken from the value of the Service_ID directive, and the action from the value of the SPOCP_Action directive (see below). The subject is built from the attribute list extracted from the assertion using the separators set by Attribute_Separator and Value_Separator. This formats permits the use of a single SPOCP server (or SPOCP ruleset) for several different PoAs. Of course, the rules at the SPOCP server must have a compatible structure.

As an example, consider a PoA with a Service_ID of ``spocppoa'' and that uses the default value for SPOCP_Action, accept, using the default settings for Attribute_Separator and Value_Separator. For an assertion like:

 user=Joe Melon, role = staff

The query sent to the SPOCP server would be:

 (papi (poa spocppoa) (action accept) (subject (user Joe Melon)(role staff)))

There are three directives related to SPOCP-based authorization:

SPOCP_Server serverSpec
Defines the location of the SPOCP server to be used. Two formats can be used to specify the server location:
1. If serverSpec begins with the '/' character, an internal socket (in the ``UNIX'' domain) is assumed, and the SPOCP server will be contacted using it.
2. In any other case, a TCP connection will be attempted, and the well-known format host:port shall be used to define it.
SPOCP_Action actionName
Defines the name of the action to be used when querying the SPOCP server (by default, it takes the value accept).
SPOCP_Accept_If_Down [1|0]
If set to 1, a failure in connecting to the SPOCP server will be considered a positive response to any authorization query. If set to 0 (the default), a failure in connecting to the SPOCP server will cause the PoA to reject the solicited access.

Proxy Configuration Directives

The following tags are only applicable to PoAs acting as proxies, controlling the access to external resources.

Remote_URL URL
The remote server this PoA redirect requests to.
Remote_Domain domain
Make the PoA to proxy access to an entire domain, mapping forth and back URLs of the form:
 http://proxy.poa/host/location/...
into
 http://host.remote.domain/location/...

As you may expect, the use of either Remote_URL or Remote_Domain when configuring a PoA implies its use in proxy mode.

Local_IP_Address IP

If this parameter is set, the PoA will use the local defined IP address to
connect to the remote site(s). This allow for using different IP addresses
when accessing the same resource for different user groups (communities,
institutions, etc.) by means of a single PAPI-enabled proxy system.
Proxy_Server URL
Defines a HTTP proxy server to direct all requests through. This way, it is possible to take advantage of proxy-cache meshes when using a PAPI PoA in proxy mode.
No_XML [1|0]
The PoA in proxy mode is able to deal with XHTML tags, but that implies that certain sloppy practices (tolerated by browsers but out of the standards) may cause problems in the rewriting process. Setting this directive to 1, XML/XHTML processing is disabled.
Reject_URL_Pattern regularExpression
A PAPI PoA in proxy mode fetches and returns remote URLs for the whole remote server (or even domain), with the sole limitation of the value of the Location it is defined within. If you want a finer control over proxied URLs, or want to apply a different access schema than those applied by the remote server, the use of this directive allows it.
If a URL requested through a PAPI proxy PoA matches any of the regular expressions defined by the Reject_URL_Pattern applicable directives, the PoA will return a 403 FORBIDDEN as result of the request.
As an example, consider the following configuration:
 <Location /myLoc>
  . . .
  <PAPI_Local>
   . . .
   Remote_URL http://remote.dom.ain
   Reject_URL_Pattern ^(?!/proxiedLoc)
   . . .
  </PAPI_Local>
 </Location>
Only requests to /myLoc/proxiedLoc/* will be satisfied. A request to any other location (e.g. /myLoc/otherLoc) will return a 403 result.
HTTP_Auth realm::username::password
When using a PAPI PoA in proxy mode, you may need to access resources protected by means of HTTP authentication (RFC2617). This directive allows the definition of HTTP authentication data (username and password) for any security realm to be accessed.
Both basic and digest authentication schemas are supported, and the HTTP authentication parameters are applicable either to remote servers (defined by Remote_URL or Remote_Domain) or proxies (defined by Proxy_Server).
Form_Processor urlre=>regularExpression match=>regularExpression form=>formId buttonName=>name buttonIndex=>index field=>(field1, value1) field=>(field2, value2) . . .
When using a PAPI PoA in proxy mode, you can make it pass through HTML forms, automatically providing values for the form variables (usernames, passwords,...). This directive enables the execution of the PAPI form processor for a certain form inside an URL.
Use the values defined by value1...valueN to fill the fields identified by field1...fieldN in the form named formId (or the form of index formIdx) at the URLs matching regularExpression. Once the values are set, they are submitted to the remote server by activating the button identified by name or index.
Whenever the user requests a matching URL, the PAPI proxy will fill the appropriate values and send the form data to the remote server, sending back to the user the result of this process. formId and formIdx allow for identifying one form in those pages with more than one of them, and buttonName or buttonIndex allow for using a particular button within the form to submit the data. If formId and formIdx are omitted, the first form in the page is used. If buttonName and buttonIndex are omitted, the first button in the form is used.
If the optional parameter match is present, these rules will only be applied if the content of the page being processed matches regularExpression.
PAPI_Redirect regularExpression replacementString
Definition of a rule for rewriting URLs through this PoA. URLs matching the regular expression defined by the first parameter are rewritten using the replacement string defined by the second parameter.
PAPI_Redirect_by_URL URLPattern regularExpression replacementString
This is a slightly more sophisticated version of the above PAPI_Redirect. The rewriting rule is only applied for those URLs matching URLPattern.
PAPI_Request_Redirect regularExpression replacementString
Similar to PAPI_Redirect above, but the rewriting rule is applied to the URL being requested through the proxy: while the two previous directives apply to the content received from the remote server, PAPI_Request_Redirect applies to request received from the client.
PAPI_POST_Redirect regularExpression replacementString
The rewriting rule will be applied to data sent through this PoA using the HTTP POST Method. When rewriting POST contents, bear in mind that browsers use specific data encodings, so rules must take into account them.
PAPI_Header_Redirect headerPattern regularExpression replacementString
The rewriting rule will be applied to the contents of the headers sent through this PoA that match the header pattern.
When dealing with redirects bear in mind that:
1. Redirects are applied in the order they appear in the configuration file.
2. Local redirects (defined inside <PAPI_Local>) are evaluated prior to global redirects (defined inside <PAPI_Main>).
3. Both the regular expression and the replacement string follow Perl conventions.
Eval_Proxy_Redirects [1|0]
If this directive is set to 1, the strings used as values in the above six directives (HTTP_Auth, Form_Processor, PAPI_Redirect, PAPI_Request_Redirect, PAPI_Redirect_by_URL, Rewrite_URL_Pattern, and Reject_URL_Pattern) are evaluated in the current Perl environment (using the Perl eval function) prior to be applied. This means that it is possible to use any internal PoA variable in any of the values of the directives.
Since the PAPI main handler fills a set of Apache notes with the attribute values contained in the access tokens (see Attribute_Separator and Value_Separator) prior to calling the proxy module, it is also possible to apply user's attributes (as stored inside the access tokens) in these directives by using the construction:
 $r->notes(PAPIAttr-<ATTRIBUTENAME>)
As an example, the following directive makes the proxy PoA use the values of the attributes basicname and basicpass (as contained in the PAPI access tokens) for HTTP authentication to URLs in the realm theRealm:
 HTTP_Auth theRealm::$r->notes(PAPIAttr-basicname)::$r->notes(PAPIAttr-basicpass)
Strip_Location [1|0]
When a PoA in proxy mode receives a request, it passes the URI unaltered to the remote server. If this directive is set to 1, the PoA will strip the value of the local Location from the URL to be requested from the remote site.
Consider a PoA at http://poa.dom.ain defined as follows:
 <Location /myLoc>
  . . .
  <PAPI_Local>
   . . .
   Remote_URL http://remote.dom.ain
   . . .
  </PAPI_Local>
 </Location>
A request for http://poa.dom.ain/myLoc/page.html will retrieve
1. http://remote.dom.ain/myLoc/page.html if Strip_Location is not set, or set to 0 (the default).
2. http://remote.dom.ain/page.html if Strip_Location is set to 1.
Redirect_All [1|0]
If set to 1, redirect substitutions are applied using aggressive mode, i. e., to the whole contents of the retrieved document. If set to 0 (which is the default), redirect substitutions are only applied to direct references (attributes like href or src in specific tags, URLs received in HTTP redirects, and contents of script elements. For a complete reference, see the documentation of the PAPI proxy module).
Although Redirect_All may be very useful when dealing, for example, with the use of absolute URLs as references, its use may slow down the performance of the PoA and have unexpected side effects. We recommend a very careful use of this feature.
Rewrite_MIME_Types MIMEtype MIMEtype . . .
Rewrite_URL_Pattern regularExpression
By default, a PoA in proxy mode only applies its rewriting engine to HTML/XHTML contents. It may be necessary to use the rewriting engine on some other content types (JavaScript is the most salient example). In some other cases, it is not possible (or desirable) to do so on a content-type basis, and an approach based on the URL being retrieved has to be applied. This couple of directives allows the definition of:
1. A (blank separated) list of MIME types to be compared with the content type of the response, in the case of Rewrite_MIME_Types.
2. A regular expression to be matched against the requested URL, in the case of Rewrite_URL_Pattern. As many of these directives as necessary can be used.
If any of the conditions expressed by means of the above directives is met, the rewriting engine (as specified by PAPI_Redirect and PAPI_Redirect_by_URL directives) will be applied on the contents prior to sending them to the client.
As an example, consider the following configuration directives inside the definition of a PAPI PoA in proxy mode:
 . . .
 PAPI_Redirect external.domain internal.papi
 Rewrite_MIME_Types application/x-javascript
 . . .
Then, a reference to www.external.domain inside a JavaScript file will be transformed into www.internal.papi
Proxy_Chunk_Size bytes
When accessing large contents in proxy mode it is possible to do so in chunks, passing them to the requesting browser as they become available at the proxy. This directive defines the size in bytes of these chunks. By default, it takes the value 32768 (32 KB).

Logging PoA Activity

The PoA logs its activity by two different mechanisms. First, it logs any relevant event to the Apache standard ErrorLog as defined by the mod_perl API. Second, it takes advantage of the Apache notes facility to make possible the inclusion of PAPI events in any log defined by the Apache configuration file. PAPI events are logged using the string ``PAPI'' followed by an internal id distinguishing the request that produced them.

The identifier for the Apache note used for logging is PAPI, so a log format specification like this:

 LogFormat "%h %t \"%r\" %>s\t%{PAPI}n" papi

Will record the host, time, request (between quotes), result code, and the PAPI event if available.