Some stuff for developers:

1) CookieCreatorAction (to create or remove cookies)
2) CookieValidatorAction (to validate cookies like
RequestValidatorAction does with request parameters)
3) NewDatabaseAuthenticatorAction (a modified version of
DatabaseAuthenticatorAction that supports a new attribute named
'append-session' to specify to append or replace an existing session if
authentication don't fail; feel free to rename it)
4) DatabaseCookieAuthenticatorAction (to do user authentication with
cookies and a database connection like NewDatabaseAuthenticatorAction
does with request parameters)

I hope you'll find these useful.

I thing the next changes to the actions should be rewriting more generic
actions that supports multiple sources of couples of data (session
attributes, request parameters, sitemap parameters or cookies values)
without rewriting a new action. This should be done with a simple "src"
attribute (session/request/sitemap/cookie). 

The same thing should be applied to the database authenticator action.
"from-cookie", "from-request", "from-session", "from-sitemap" should be
added like "to-cookie" and so on...

What do you think?

ByeBye,
Paolo Scaffardi
AIRVENT SAM S.p.A.

/*****************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 *****************************************************************************/
 package net.arsenio.cocoon.acting;

import java.util.Map;
import org.apache.cocoon.Constants;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.acting.*;
import org.apache.cocoon.environment.Cookie;
import org.apache.cocoon.environment.Response;

/**
 * The CookieCreatorAction class create or remove cookies.
 * The action needs these parameters:
 *
 * <dl>
 *   <dt>name</dt>
 *   <dd>the cookie name</dd>
 *   <dt>value</dt>
 *   <dd>the cookie value</dd>
 *   <dt>comment</dt>
 *   <dd>a comment to the cookie</dd>
 *   <dt>domain</dt>
 *   <dd>the domain the cookie is sent to</dd>
 *   <dt>path</dt>
 *   <dd>the path of the domain the cookie is sent to</dd>
 *   <dt>secure</dt>
 *   <dd>use a secure transport protocol (default is false)</dd>
 *   <dt>maxage</dt>
 *   <dd>Age in seconds. Use -1 to remove cookie. (default is 0; cookie lives
 *   within the session and it is not stored)</dd>
 *   <dt>version</dt>
 *   <dd>version of cookie(default is 0)</dd>
 * </dl>
 *
 * If you want to set a cookie you only need to specify the cookie name.
 * Its value is an empty string as default. The maxage is 0 that means the
 * cookie will live until the session is invalidated.
 *
 * If you want to remove a cookie set its maxage to -1.
 *
 * @author Paolo Scaffardi &lt;[EMAIL PROTECTED]&gt;
 * @version CVS $Revision: 1.0.0.0 $ $Date: 2001/10/18 12:00:00 $
 */

public class CookieCreatorAction extends ComposerAction {

  public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String src, Parameters parameters) throws java.lang.Exception {

    Response res = (Response) objectModel.get(Constants.RESPONSE_OBJECT);

    /* check response validity */
    if (res == null) {
      getLogger ().debug ("COOKIECREATOR: no response object");
      return null;
    }

    String 	cookieName = null,
        	cookieValue = null,
                cookieComment = null,
	    	cookieDomain = null,
        	cookiePath = null;

    try {
        cookieName = parameters.getParameter("name");
        }
    catch (Exception e) {
      getLogger().debug("COOKIECREATOR: cannot retrieve cookie name attribute");
      return null;
      }

   cookieValue = parameters.getParameter("value","");

   Cookie cookie = res.createCookie(cookieName, cookieValue) ;

   try {
        if ((cookieComment = parameters.getParameter("comment")) != null)
          cookie.setComment(cookieComment);
    }
    catch (org.apache.avalon.framework.parameters.ParameterException pe) {
    }

    try {
        if ((cookieDomain = parameters.getParameter("domain")) != null)
          cookie.setDomain(cookieDomain);
    }
    catch (org.apache.avalon.framework.parameters.ParameterException pe) {
    }

    try {
        if ((cookiePath = parameters.getParameter("path")) != null)
          cookie.setPath(cookiePath);
    }
    catch (org.apache.avalon.framework.parameters.ParameterException pe) {
    }

    cookie.setSecure(parameters.getParameterAsBoolean("secure",false)) ;
    cookie.setMaxAge(parameters.getParameterAsInteger("maxage",0));
    cookie.setVersion(parameters.getParameterAsInteger("version",0));

    res.addCookie (cookie);

    if (cookie.getMaxAge() == 0)
      getLogger().debug("COOKIECREATOR: '" + cookieName + "' cookie has been removed");
    else
      getLogger().debug("COOKIECREATOR: '" + cookieName + "' cookie created with value '"
        +  cookieValue +"' (version "+ cookie.getVersion() + "; it will expire in "
        + cookie.getMaxAge()+" seconds)");

    return null ;
  }
}
/*****************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 *****************************************************************************/
 package net.arsenio.cocoon.acting;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.logger.AbstractLoggable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.acting.*;
import org.apache.cocoon.Constants;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.util.Tokenizer;
import org.apache.log.Logger;
import org.apache.cocoon.components.language.markup.xsp.XSPCookieHelper;

/**
 * This is the action used to validate Cookie parameters (values).
 * The parameters are described via the external xml
 * file (its format is defined in AbstractValidatorAction).
 *
 * <h3>Variant 1</h3>
 * <pre>
 * &lt;map:act type="cookie-validator"&gt;
 *         &lt;parameter name="descriptor" value="context://descriptor.xml"&gt;
 *         &lt;parameter name="validate" value="username,password"&gt;
 * &lt;/map:act&gt;
 * </pre>
 * The list of parameters to be validated is specified as a comma separated
 * list of their names. descriptor.xml can therefore be used among many
 * various actions.
 *
 * <h3>Variant 2</h3>
 * <pre>
 * <pre>
 * &lt;map:act type="cookie-validator"&gt;
 *         &lt;parameter name="descriptor" value="context://descriptor.xml"&gt;
 *         &lt;parameter name="validate-set" value="is-logged-in"&gt;
 * &lt;/map:act&gt;
 * </pre>
 *
 * The parameter "validate-set" tells to take a given "constraint-set"
 * from description
 * file and test all parameters against given criteria. This variant is more
 * powerful, more aspect oriented and more flexibile than the previous one,
 * becuase it allows the comparsion constructs, etc. See
 * AbstractValidatorAction documentation.
 *
 * This action returns null when validation fails, otherwise it provides
 * all validated parameters to the sitemap via {name} expression.
 *
 * @author Paolo Scaffardi &lt;[EMAIL PROTECTED]&gt;
 * @version CVS $Revision: 1.0.0.0 $ $Date: 2001/10/18 12:00:00 $
 */

public class CookieValidatorAction extends AbstractValidatorAction {

  public CookieValidatorAction() {
  }
  public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String src, Parameters parameters)
  throws java.lang.Exception {
        Request req = (Request)
            objectModel.get (Constants.REQUEST_OBJECT);

        if (req == null) {
            getLogger ().debug ("COOKIEVALIDATOR: no request object");
            return null;
        }

     // read global parameter settings
    boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
    if (this.settings.containsKey("reloadable"))
        reloadable = Boolean.getBoolean((String) this.settings.get("reloadable"));
    String valsetstr = (String) this.settings.get("validate-set");
    String valstr = (String) this.settings.get("validate");

        try {
            Configuration conf = this.getConfiguration (
                    parameters.getParameter ("descriptor", (String) this.settings.get("descriptor")),
            parameters.getParameterAsBoolean("reloadable",reloadable));
            valstr = parameters.getParameter ("validate", valstr);
            valsetstr = parameters.getParameter ("validate-set", valsetstr);
            Configuration[] desc = conf.getChildren ("parameter");
            Configuration[] csets = conf.getChildren ("constraint-set");
            HashMap actionMap = new HashMap ();
            /*
             * old obsoleted method
             */
            if (!"".equals (valstr.trim ())) {
                getLogger ().debug ("COOKIEVALIDATOR: validating parameters "
                        + "as specified via 'validate' parameter");
                /* get list of params to be validated */
                String[] rparams = Tokenizer.tokenize (valstr, ",", false);

                /* perform actuall validation */
                ValidatorActionHelper result = null;
                String name = null;
                HashMap params = new HashMap (rparams.length);
                /* put required params into hash */
                for (int i = 0; i < rparams.length; i ++) {
                    name = rparams[i];
                    if (name == null || "".equals (name.trim ())) {
                        getLogger ().debug ("COOKIEVALIDATOR: "
                        + "wrong syntax of the 'validate' parameter");
                        return null;
                    }
                    name = name.trim ();

 /*                   String cookieValue = XSPCookieHelper.getValue(objectModel, name,-1) ;

                   getLogger().debug("COOKIE(" + name + ")=" + cookieValue + "(" +
                      XSPCookieHelper.getCookie (objectModel, name, -1).getValue()
                      +")");
*/
                    params.put (name, XSPCookieHelper.getCookie (objectModel, name, -1).getValue());

                }
                for (int i = 0; i < rparams.length; i ++) {
                    name = rparams[i].trim ();
                    result = validateParameter (name, null, desc,
                            params, false);
                    if (!result.isOK()) {
                        getLogger().debug ("COOKIEVALIDATOR: "
                                + "validation failed for parameter " + name);
                        return null;
                    }
                    actionMap.put (name, result.getObject());
                }
            }
            /*
             * new set-based method
             */
            if (valsetstr != null && !"".equals (valsetstr.trim ())) {
                getLogger ().debug ("COOKIEVALIDATOR: validating parameters "
                        + "from given constraint-set " + valsetstr);
                Configuration cset = null;
                String setname = null;
                int j = 0;
                boolean found = false;
                for (j = 0; j < csets.length; j ++) {
                    setname = csets[j].getAttribute ("name", "");
                    if (valsetstr.trim().equals (setname.trim ())) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    getLogger ().debug ("COOKIEVALIDATOR: given set "
                            + valsetstr
                            + " does not exist in a description file");
                    return null;
                }
                cset = csets[j];
                /* get the list of params to be validated */
                Configuration[] set = cset.getChildren ("validate");

                /* perform actuall validation */
                ValidatorActionHelper result = null;
                String name = null;
                HashMap params = new HashMap (set.length);
                getLogger ().debug ("COOKIEVALIDATOR: given set "
                        + valsetstr
                        + " contains " + set.length + " rules");
                /* put required params into hash */
                for (int i = 0; i < set.length; i ++) {
                    name = set[i].getAttribute ("name", "");
                    if ("".equals (name.trim ())) {
                        getLogger ().debug ("COOKIEVALIDATOR: wrong syntax "
                                + " of 'validate' children nr. " + i);
                        return null;
                    }
                    name = name.trim ();
                    params.put (name, XSPCookieHelper.getCookie (objectModel, name, -1).getValue());
                }
                for (int i = 0; i < set.length; i ++) {
                    name = set[i].getAttribute ("name", null);
                    result = validateParameter (name, set[i],
                            desc, params, false);
                    if (!result.isOK()) {
                        getLogger().debug ("COOKIEVALIDATOR: "
                                + "validation failed for cookie '" + name+"'");
                        return null;
                    }
                    actionMap.put (name, result.getObject());
                }
            }
            getLogger().debug ("COOKIEVALIDATOR: all cookies validated");
            return Collections.unmodifiableMap (actionMap);
        } catch (Exception e) {
            getLogger().debug ("exception: ", e);
        }
        return null;
    }
}
/*****************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 *****************************************************************************/
package net.arsenio.cocoon.acting;

import org.apache.cocoon.acting.*;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.environment.SourceResolver;

import org.apache.cocoon.components.language.markup.xsp.XSPCookieHelper;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * This action is used to authenticate user by comparing several cookie
 * values (username, password) with the values in database. The description of
 * the process is given via external xml description file simiar to the one
 * used for all actions derived from AbstractDatabaseAction.
 * <pre>
 * &lt;root&gt;
*         &lt;connection&gt;personnel&lt;/connection&gt;
*         &lt;table name="users_table&gt;
*                 &lt;select dbcol="username" cookie-name="username"
*                 to-session="username"/&gt;
*                 &lt;select dbcol="password" cookie-name="password"
*                 nullable="yes"/&gt;
*                 &lt;select dbcol="role" to-session="role" type="string"/&gt;
*                 &lt;select dbcol="skin" to-session="skin" type="string"/&gt;
*         &lt;/table&gt;
 * &lt;/root&gt;
 * </pre>
 * The values specified via "cookie-name" describe the name of the cookie,
 * "dbcol" indicates matching database column, "nullable" means
 * that cookie-name which is null or empty will not be included in the WHERE
 * clause. This way you can enable accounts with empty passwords, etc.
 * "to-session" attribute indicates under which name the value obtained from
 * database should be stored in the session. Of course new session is created
 * when authorization is successfull. The "type" attribute can be either
 * string, long or double and alters the type of object stored in session.
 * Additionally all parameters that are
 * propagated to the session are made available to the sitemap via {name}
 * expression.
 *
 * If there is no need to touch the session object, providing just one-time
 * verification, you can specify action parameter "create-session" to "no" or
 * "false". No values are then propagated to the sesion and session object is
 * not verified.
 *
 * If you want to append attributes to the session without creating a new one,
 * specify action parameter "append-session" to "yes" or "true".
 *
 * @author Paolo Scaffardi &lt;[EMAIL PROTECTED]&gt;
 * @version CVS $Revision: 1.3.2.10 $ $Date: 2001/10/18 12:00:00 $
 */
public class DatabaseCookieAuthenticatorAction extends AbstractDatabaseAction implements ThreadSafe
{
    /**
     * Main invocation routine.
     */
    public Map act (Redirector redirector, SourceResolver resolver, Map objectModel, String src,
            Parameters parameters) throws Exception {
        DataSourceComponent datasource = null;
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        // read global parameter settings
        boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;

        if (this.settings.containsKey("reloadable")) {
            reloadable = Boolean.getBoolean((String) this.settings.get("reloadable"));
        }

        // read local settings
        try {
            Configuration conf = this.getConfiguration (
                    parameters.getParameter ("descriptor", (String) this.settings.get("descriptor")),
                    parameters.getParameterAsBoolean("reloadable",reloadable));
                  boolean cs = true, as= false ;
            String create_session = parameters.getParameter ("create-session",
                    (String) this.settings.get("create-session")),
                   append_session = parameters.getParameter ("append-session",
                    (String) this.settings.get("append-session"));

            if (create_session != null &&
                    ("no".equals (create_session.trim ()) || "false".equals (create_session.trim ()))) {
                cs = false;
            }
            if (append_session != null &&
                    ("yes".equals (append_session.trim ()) || "true".equals (append_session.trim ()))) {
                as = true;
            }

            datasource = this.getDataSource(conf);
            conn = datasource.getConnection();
            Request req = (Request) objectModel.get(Constants.REQUEST_OBJECT);

            /* check request validity */
            if (req == null) {
                getLogger ().debug ("DBCOOKIEAUTH: no request object");
                return null;
            }

            String query = this.getAuthQuery (objectModel, conf, req);
            if (query == null) {
                getLogger ().debug ("DBCOOKIEAUTH: have not got query");
                req.setAttribute("message", "The authenticator is misconfigured");
                return null;
            }

            getLogger ().debug ("DBCOOKIEAUTH: query is: " + query);
            st = conn.createStatement ();
            rs = st.executeQuery (query);

            if (rs.next ()) {
                getLogger ().debug ("DBCOOKIEAUTH: authorized successfully");
                Session session = null;

                if (cs) {
                    session = req.getSession (false);
                    if (session != null)
                    {
                      if (as == false)
                      {
                          session.invalidate ();
                          session = req.getSession (true);
                          getLogger ().debug ("DBCOOKIEAUTH: session invalidated");
                      }
                    }
                      else
                    session = req.getSession (true);

                    if (session == null)
                      return null;

                    if (as)
                      getLogger ().debug ("DBCOOKIEAUTH: appending to session");
                    else
                      getLogger ().debug ("DBCOOKIEAUTH: session created");

                } else {
                    getLogger ().debug ("DBCOOKIEAUTH: leaving session untouched");
                }

                HashMap actionMap = this.propagateParameters (conf, rs,
                        session);
                if(!conn.getAutoCommit()) {
                    conn.commit();
                }
                return Collections.unmodifiableMap (actionMap);
            }
            if(!conn.getAutoCommit()) {
                conn.rollback();
            }

            req.setAttribute("message", "The username or password were incorrect, please check your CAPS LOCK key and try again.");
            getLogger ().debug ("DBCOOKIEAUTH: no results for query");
        } catch (Exception e) {
            if (conn != null) {
                try {
                    if(!conn.getAutoCommit()) {
                        conn.rollback();
                    }
                } catch (Exception se) {/* ignore */}
            }
            getLogger().debug ("exception: ", e);
            return null;
        } finally {
            if (rs != null) rs.close();
            if (st != null) st.close();
            if (conn != null) {
                try {
                    conn.close();
                } catch (Exception e) {/* ignore */}
            }
        }
        return null;
    }

    private String getAuthQuery (Map objectModel, Configuration conf, Request req) {
        boolean first_constraint = true;
        StringBuffer queryBuffer = new StringBuffer ("SELECT ");
        StringBuffer queryBufferEnd = new StringBuffer ("");
        String dbcol, cookie_name, cookie_value, nullstr;
        boolean nullable = false;
        Configuration table = conf.getChild ("table");
        Configuration[] select = table.getChildren ("select");
        try {
            for (int i = 0; i < select.length; i ++) {
                if (i != 0)
                    queryBuffer.append (", ");
                dbcol = select[i].getAttribute ("dbcol");
                queryBuffer.append (dbcol);
                try {
                    cookie_name = select[i].getAttribute ("cookie-name");
                    if (cookie_name == null ||
                            cookie_name.trim().equals ("")) {
                        continue;
                    }
                } catch (Exception e) {
                    continue;
                }
                try {
                    nullstr = select[i].getAttribute ("nullable");
                    if (nullstr != null) nullstr = nullstr.trim ();
                    if ("yes".equals (nullstr) || "true".equals (nullstr)) {
                        nullable = true;
                    }
                } catch (Exception e1) {
                }
                /* if there is a cookie name,
                 * but not the value, we exit immediately do
                 * that authorization fails authomatically */
                cookie_value = XSPCookieHelper.getCookie (objectModel, cookie_name, -1).getValue();

                if (cookie_value == null || cookie_value.trim().equals ("")) {
                    // value is null
                    if (!nullable) {
                        getLogger ().debug ("DBCOOKIEAUTH: cookie-name "
                                + cookie_name + " does not exist");
                        return null;
                    }
                } else {
                    if (!first_constraint)
                        queryBufferEnd.append (" AND ");
                    queryBufferEnd.append (dbcol + "='" + cookie_value + "'");
                    first_constraint = false;
                }
            }
            queryBuffer.append (" FROM ");
            queryBuffer.append (table.getAttribute ("name"));
            if (!queryBufferEnd.toString ().trim ().equals (""))
                queryBuffer.append (" WHERE ").append (queryBufferEnd);
            return queryBuffer.toString ();
        } catch (Exception e) {
            getLogger ().debug ("DBCOOKIEAUTH: got exception: " + e);
            return null;
        }
    }

    private HashMap propagateParameters (Configuration conf, ResultSet rs,
            Session session) {
        Configuration table = conf.getChild ("table");
        Configuration[] select = table.getChildren ("select");
        String dbcol, session_param, type;
        HashMap map = new HashMap();
        try {
            for (int i = 0; i < select.length; i ++) {
                dbcol = select[i].getAttribute ("dbcol");
                try {
                    session_param = select[i].getAttribute ("to-session");
                    if (session_param != null &&
                            !session_param.trim().equals ("")) {
                        String s = rs.getString (i + 1);
                        /* propagate to session */
                        try {
                            type = select[i].getAttribute ("type");
                        } catch (Exception e) {
                            type = null;
                        }
                        if (type == null || "".equals (type.trim ())) {
                            type = "string";
                        }
                        Object o = null;
                        if ("string".equals (type)) {
                            o = s;
                        } else if ("long".equals (type)) {
                            Long l = Long.decode (s);
                            o = l;
                        } else if ("double".equals (type)) {
                            Double d = Double.valueOf (s);
                            o = d;
                        }
                        if (session != null) {
                            session.setAttribute (session_param, o);
                            getLogger ().debug ("DBCOOKIEAUTH: propagating param "
                                    + session_param + "=" + s);
                        }
                        map.put (session_param, o);
                    }
                } catch (Exception e) {
                }
            }
            return map;
        } catch (Exception e) {
            getLogger().debug("exception: ", e);
        }
        return null;
    }
}

// $Id: DatabaseAuthenticatorAction.java,v 1.3.2.9 2001/08/25 13:35:24 mman Exp $
// vim: set et ts=4 sw=4:
/*****************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 *****************************************************************************/
package net.arsenio.cocoon.acting;

import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.Constants;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.acting.*;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * This action is used to authenticate user by comparing several request
 * fields (username, password) with the values in database. The description of
 * the process is given via external xml description file simiar to the one
 * used for all actions derived from AbstractDatabaseAction.
 * <pre>
 * &lt;root&gt;
*         &lt;connection&gt;personnel&lt;/connection&gt;
*         &lt;table name="users_table&gt;
*                 &lt;select dbcol="username" request-param="username"
*                 to-session="username"/&gt;
*                 &lt;select dbcol="password" request-param="password"
*                 nullable="yes"/&gt;
*                 &lt;select dbcol="role" to-session="role" type="string"/&gt;
*                 &lt;select dbcol="skin" to-session="skin" type="string"/&gt;
*         &lt;/table&gt;
 * &lt;/root&gt;
 * </pre>
 * The values specified via "request-param" describe the name of HTTP request
 * parameter, "dbcol" indicates matching database column, "nullable" means
 * that request-param which is null or empty will not be included in the WHERE
 * clause. This way you can enable accounts with empty passwords, etc.
 * "to-session" attribute indicates under which name the value obtained from
 * database should be stored in the session. Of course new session is created
 * when authorization is successfull. The "type" attribute can be either
 * string, long or double and alters the type of object stored in session.
 * Additionally all parameters that are
 * propagated to the session are made available to the sitemap via {name}
 * expression.
 *
 * If there is no need to touch the session object, providing just one-time
 * verification, you can specify action parameter "create-session" to "no" or
 * "false". No values are then propagated to the session and session object is
 * not verified.
 *
 * If you want to append attributes to the session without creating a new one,
 * specify action parameter "append-session" to "yes" or "true".
 *
 * @author Paolo Scaffardi &lt;[EMAIL PROTECTED]&gt;
 * @version CVS $Revision: 1.3.2.10 $ $Date: 2001/10/18 12:00:00 $
 */
public class NewDatabaseAuthenticatorAction extends AbstractDatabaseAction implements ThreadSafe
{
    /**
     * Main invocation routine.
     */
    public Map act (Redirector redirector, SourceResolver resolver, Map objectModel, String src,
            Parameters parameters) throws Exception {
        DataSourceComponent datasource = null;
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        // read global parameter settings
        boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;

        if (this.settings.containsKey("reloadable")) {
            reloadable = Boolean.getBoolean((String) this.settings.get("reloadable"));
        }

        // read local settings
        try {
            Configuration conf = this.getConfiguration (
                    parameters.getParameter ("descriptor", (String) this.settings.get("descriptor")),
                    parameters.getParameterAsBoolean("reloadable",reloadable));
            boolean cs = true, as= false ;
            String create_session = parameters.getParameter ("create-session",
                    (String) this.settings.get("create-session")),
                   append_session = parameters.getParameter ("append-session",
                    (String) this.settings.get("append-session"));

            if (create_session != null &&
                    ("no".equals (create_session.trim ()) || "false".equals (create_session.trim ()))) {
                cs = false;
            }
            if (append_session != null &&
                    ("yes".equals (append_session.trim ()) || "true".equals (append_session.trim ()))) {
                as = true;
            }

            datasource = this.getDataSource(conf);
            conn = datasource.getConnection();
            Request req = (Request) objectModel.get(Constants.REQUEST_OBJECT);

            /* check request validity */
            if (req == null) {
                getLogger ().debug ("NEWDBAUTH: no request object");
                return null;
            }

            String query = this.getAuthQuery (conf, req);
            if (query == null) {
                getLogger ().debug ("NEWDBAUTH: have not got query");
                req.setAttribute("message", "The authenticator is misconfigured");
                return null;
            }

            getLogger ().debug ("NEWDBAUTH: query is: " + query);
            st = conn.createStatement ();
            rs = st.executeQuery (query);

            if (rs.next ()) {
                getLogger ().debug ("NEWDBAUTH: authorized successfully");
                Session session = null;

                if (cs) {
                    session = req.getSession (false);
                    if (session != null)
                    {
                      if (as == false)
                      {
                          session.invalidate ();
                          session = req.getSession (true);
                          getLogger ().debug ("NEWDBAUTH: session invalidated");
                      }
                    }
                      else
                    session = req.getSession (true);

                    if (session == null)
                      return null;

                    if (as)
                      getLogger ().debug ("NEWDBAUTH: appending to session");
                    else
                      getLogger ().debug ("NEWDBAUTH: session created");

                } else {
                    getLogger ().debug ("NEWDBAUTH: leaving session untouched");
                }

                HashMap actionMap = this.propagateParameters (conf, rs,
                        session);
                if(!conn.getAutoCommit()) {
                    conn.commit();
                }
                return Collections.unmodifiableMap (actionMap);
            }
            if(!conn.getAutoCommit()) {
                conn.rollback();
            }

            req.setAttribute("message", "The username or password were incorrect, please check your CAPS LOCK key and try again.");
            getLogger ().debug ("NEWDBAUTH: no results for query");
        } catch (Exception e) {
            if (conn != null) {
                try {
                    if(!conn.getAutoCommit()) {
                        conn.rollback();
                    }
                } catch (Exception se) {/* ignore */}
            }
            getLogger().debug ("exception: ", e);
            return null;
        } finally {
            if (rs != null) rs.close();
            if (st != null) st.close();
            if (conn != null) {
                try {
                    conn.close();
                } catch (Exception e) {/* ignore */}
            }
        }
        return null;
    }

    private String getAuthQuery (Configuration conf, Request req) {
        boolean first_constraint = true;
        StringBuffer queryBuffer = new StringBuffer ("SELECT ");
        StringBuffer queryBufferEnd = new StringBuffer ("");
        String dbcol, request_param, request_value, nullstr;
        boolean nullable = false;
        Configuration table = conf.getChild ("table");
        Configuration[] select = table.getChildren ("select");
        try {
            for (int i = 0; i < select.length; i ++) {
                if (i != 0)
                    queryBuffer.append (", ");
                dbcol = select[i].getAttribute ("dbcol");
                queryBuffer.append (dbcol);
                try {
                    request_param = select[i].getAttribute ("request-param");
                    if (request_param == null ||
                            request_param.trim().equals ("")) {
                        continue;
                    }
                } catch (Exception e) {
                    continue;
                }
                try {
                    nullstr = select[i].getAttribute ("nullable");
                    if (nullstr != null) nullstr = nullstr.trim ();
                    if ("yes".equals (nullstr) || "true".equals (nullstr)) {
                        nullable = true;
                    }
                } catch (Exception e1) {
                }
                /* if there is a request parameter name,
                 * but not the value, we exit immediately do
                 * that authorization fails authomatically */
                request_value = req.getParameter (
                        request_param);
                if (request_value == null || request_value.trim().equals ("")) {
                    // value is null
                    if (!nullable) {
                        getLogger ().debug ("NEWDBAUTH: request-param "
                                + request_param + " does not exist");
                        return null;
                    }
                } else {
                    if (!first_constraint)
                        queryBufferEnd.append (" AND ");
                    queryBufferEnd.append (dbcol + "='" + request_value + "'");
                    first_constraint = false;
                }
            }
            queryBuffer.append (" FROM ");
            queryBuffer.append (table.getAttribute ("name"));
            if (!queryBufferEnd.toString ().trim ().equals (""))
                queryBuffer.append (" WHERE ").append (queryBufferEnd);
            return queryBuffer.toString ();
        } catch (Exception e) {
            getLogger ().debug ("NEWDBAUTH: got exception: " + e);
            return null;
        }
    }

    private HashMap propagateParameters (Configuration conf, ResultSet rs,
            Session session) {
        Configuration table = conf.getChild ("table");
        Configuration[] select = table.getChildren ("select");
        String dbcol, session_param, type;
        HashMap map = new HashMap();
        try {
            for (int i = 0; i < select.length; i ++) {
                dbcol = select[i].getAttribute ("dbcol");
                try {
                    session_param = select[i].getAttribute ("to-session");
                    if (session_param != null &&
                            !session_param.trim().equals ("")) {
                        String s = rs.getString (i + 1);
                        /* propagate to session */
                        try {
                            type = select[i].getAttribute ("type");
                        } catch (Exception e) {
                            type = null;
                        }
                        if (type == null || "".equals (type.trim ())) {
                            type = "string";
                        }
                        Object o = null;
                        if ("string".equals (type)) {
                            o = s;
                        } else if ("long".equals (type)) {
                            Long l = Long.decode (s);
                            o = l;
                        } else if ("double".equals (type)) {
                            Double d = Double.valueOf (s);
                            o = d;
                        }
                        if (session != null) {
                            session.setAttribute (session_param, o);
                            getLogger ().debug ("NEWDBAUTH: propagating param "
                                    + session_param + "=" + s);
                        }
                        map.put (session_param, o);
                    }
                } catch (Exception e) {
                }
            }
            return map;
        } catch (Exception e) {
            getLogger().debug("exception: ", e);
        }
        return null;
    }
}

// $Id: DatabaseAuthenticatorAction.java,v 1.3.2.9 2001/08/25 13:35:24 mman Exp $
// vim: set et ts=4 sw=4:

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]

Reply via email to