Welcome to spin_auth for mod_spin from Rexursive(R)
===================================================

This application provides convenient authentication bridge for other mod_spin
applications. It doesn't in itself do any authentication - instead it uses
basic Apache authentication mechanisms to do that. Its role is confined to
conversion of parameters supplied on an (X)HTML form into what Apache basic
authentication can understand, and to manipulation of a variable inside the
session state file used to communicate success/failure of authentication to
the application using this provider. It goes without saying that sessions need
to be enabled (i.e. SpinCookie configuration parameter needs to be set and
user agent needs accept cookies) for all resources that are to be protected.

IMPORTANT NOTE:
===============
This authentication provider only works with resources under mod_spin
applications that have been explicitly written for this authentication
mechanism. Any attempt to protect other resources will be unsuccessful.

You must configure mod_spin as a handler for the auth_URL location.
Configuring mod_spin as a filter for this location won't work.
---------------

The authentication application will look for two form parameters:
spin_username and spin_password. If it finds them, it will create an internal
subrequest (using GET method), to a URI specified in the configuration file
(auth_URI), with basic authentication headers calculated from the above form
parameters. If this subrequest is successful (i.e. the return code is 200), it
will write a value of spin_username for the key auth_user into the current
session state file. In all other cases, it will delete that key from the
session file. It will also write auth_time into the session state file, or
delete it if authentication was unsuccessuful. Please note that this
subrequest never runs the handler, only the hooks that fall under
ap_process_request_internal() call.

If spin_username and/or spin_password aren't found, regular template processing
occurs. Meaning, you get the login page, designed to your liking (that's the
auth_URL page, see below). The auth_failed reference will be in the context if
the authentication previously failed for this session, so it is easy to notify
users on the login page (see example below).

During this regular template processing, a session variable auth_return (which
is the return URL) is checked to see if has been set before (either by this
authenticaton application or by the application being authenticated). If it
hasn't, a parameter named return will be taken as the return URL and stored
in session variable auth_return. Note that it may not be practical for the
application being authenticated to store auth_return, as it may not have a
valid session at that point. That is the purpose of the return parameter -
to facilitate return URL without the need to have an initially valid session
in the application that is being authenticated.

Obviously, the auth_URI has to be a real URI that has basic Apache
authentication configured. For all intents and purposes, the request to this
URI will come from the real client, using internal Apache request machinery.

Both successful and unsuccessful authentication will redirect back to the the
return URL (auth_return), via an external redirect (303: SEE OTHER), using the
GET method. Keep in mind that it is the responsibility of the application
that is using this mechanism to remember any parameters originally received in
the GET/POST method. Without the return URL, this application will produce
code 500: INTERNAL SERVER ERROR and will not authenticate at all.

Applications using this authentication provider should do the following to
verify user authenticity:

1. Attempt to get the value of 'auth_user' from the session state file. If it
   exists, the user should be considered authenticated.

2. If auth_user doesn't exisit, user should be redirected to an authentication
   URL (auth_URL), the one behind which authentication provider application is
   configured.

Following the above algorithm for the authenticaton application, user will be
stuck in the authentication loop until she can provide a successful
username/password combination.

Variables
=========

Application variable auth_URL is the URL used for authentication. It is the
URL that the application should redirect to unless it can find auth_user in
the session store. The value should be specified in the application
configuration file (XML).

Application variable auth_URI is where you configured basic Apache
authentication which will be used by this authentication application to verify
usernames and passwords.

Session variable auth_user is set to the value of authenticated user. If the
user cannot be authenticated, this variable won't exist in the session store.

Session variable auth_time is the timestamp (64-bit APR time, as the number of
microseconds since 00:00 on 1 Jan 1970 UTC, printed using APR_TIME_T_FMT
format) when the authentication occured. Application can arbitrarily enforce
login timeouts based on this variable.

Session variable auth_failed will be non-NULL if any authentication before
the current attempt failed. It can be used in the authentication template,
the (X)HTML, to notify the user that the previous authentication attempt
failed.

Session variable auth_return contains return URL. The place to go after this
authentication application finished with its business.

Encryption
==========

It is highly recommended that both auth_URL and auth_URI be resources that are
only available via SSL/TLS. Otherwise, a mistaken attempt to authenticate over
an unecrypted line can lead to username and/or password disclosure. Even
applications that do not need encryption can use auth_URL and auth_URI over
SSL/TLS. That is because once the users are authenticated, their identity is
confirmed through the valid session id, which is reasonably difficult to fake
as it is "signed" by an MD5 checksum of the id and a secret salt.

Example configuration
=====================

This is what Apache configuration would look like:

<Files auth.sm>
    SpinApplication /usr/local/libexec/spinapps/spin_auth.so
    SpinAppConfig /usr/local/etc/spinapps/spin_someapp.xml
    SpinStore sqlite3:/var/tmp/someapp/store.db
    SpinCookie SpinSession
</Files>

The above is the configuration of auth_URL. What follows is the configuration
of auth_URI:

<Files auth.html>
    AuthType Basic
    AuthName "Restricted Files"
    AuthUserFile /usr/local/apache2/auth.users
    Require valid-user
</Files>

Please note that auth.sm has to be a proper (X)HTML file like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
  <title>Authentication</title>
</head>
<body>
  <center>
    <h1>Login:</h1>
    #if(${auth_failed})
      <p><b>Previous authentication attempt failed. Please try again.</b></p>
    #end
    <form method="post">
      <table>
        <tr>
          <td>Username:</td>
          <td><input n="spin_username" type="text" /></td>
       </tr>
       <tr>
          <td>Password:</td>
          <td><input n="spin_password" type="password" /></td>
       </tr>
       <tr>
          <td>&nbsp;</td>
          <td><input n="submit" type="submit" /></td>
       </tr>
      </table>
    </form>
  </center>
</body>
</html>

The auth_URI file only has to exist (in order to avoid 404: NOT FOUND).
Otherwise, it can be an empty file. In fact, if you want to prevent logins
altogether, you can simply remove that file.

IMPORTANT: If you don't configure Apache basic authentication correctly for
auth.html, ALL USERS WILL BE ABLE TO LOGIN, no matter what username and
password they supply. TEST YOUR SETUP BEFORE GOING LIVE!

Application configuration file would then contain the following parameters
(among others):

<?xml version="1.0"?>
<!DOCTYPE spin [
  <!ELEMENT s (p*)>
  <!ELEMENT p (#PCDATA)>
  <!ATTLIST p n CDATA #REQUIRED>
]>
<s>
  <p n="auth_URL">https://www.example.com/auth.sm</p>
  <p n="auth_URI">/auth.html</p>
</s>

Example code
============

Below is the sample code that an application using this authentication
mechanism could use for any mod_spin resource it wants to protect:

***************
** IMPORTANT **
***************
For mod_spin 1.0.x branch, there is no prepare stage, so the code would simply
be put in rxv_spin_service() function.
***************

int rxv_spin_prepare(rxv_spin_ctx_t *ctx){
  char *auth_URL,*user=NULL;
  request_rec *r=ctx->r;

  /* if there is authentication configuration, use it */
  if((auth_URL=rxv_spin_app_strget(ctx,"auth_URL"))){
    if(!(user=rxv_spin_ses_strget(ctx,"auth_user"))){
      char *full_URL,*this_URL;

      /* full URL is auth_URL + return URL */
      if(!((this_URL=ap_construct_url(r->pool,r->parsed_uri.path,r)) &&
           (full_URL=apr_pstrcat(r->pool,auth_URL,"?return=",this_URL,NULL))))
        return HTTP_INTERNAL_SERVER_ERROR;

      apr_table_add(r->err_headers_out,"Location",full_URL);
      return HTTP_SEE_OTHER;
    }
  }

  return OK;
}

Obviously, you may want to extend the above code with some logging or maybe
even something more fancy, but the general idea remains the same. The above
code is executed as the prepare function, so it will work even for resources
that are not handled by mod_spin handler, but fall under the mod_spin
application umbrella (this feature not available in mod_spin 1.0.x).
