/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package 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.Cookie; import org.apache.cocoon.environment.ObjectModelHelper; 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.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; 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> * <root> * <connection>personnel</connection> * <table name="users_table> * <select dbcol="username" cookie-name="username" * to-session="username"/> * <select dbcol="password" cookie-name="password" * nullable="yes"/> * <select dbcol="role" to-session="role" type="string"/> * <select dbcol="skin" to-session="skin" type="string"/> * </table> * </root> * </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 <a href="mailto:paolo@arsenio.net">Paolo Scaffardi</a> * @version CVS $Id$ */ public class DatabaseCookieAuthenticatorAction extends AbstractDatabaseAction implements ThreadSafe { /** * Main invocation routine. * * @param redirector Description of Parameter * @param resolver Description of Parameter * @param objectModel Description of Parameter * @param src Description of Parameter * @param parameters Description of Parameter * @return Description of the Returned Value * @exception Exception Description of Exception */ 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.valueOf((String) this.settings.get("reloadable")).booleanValue(); } // read local settings try { Configuration conf = this.getConfiguration( parameters.getParameter("descriptor", (String) this.settings.get("descriptor")), resolver, parameters.getParameterAsBoolean("reloadable", reloadable)); String create_session = parameters.getParameter("create-session", (String)this.settings.get("create-session")); String append_session = parameters.getParameter("append-session", (String)this.settings.get("append-session")); boolean cs = true; if (create_session != null) { cs = BooleanUtils.toBoolean(create_session.trim()); } boolean as = BooleanUtils.toBoolean(append_session.trim()); datasource = this.getDataSource(conf); conn = datasource.getConnection(); Request req = ObjectModelHelper.getRequest(objectModel); /* * check request validity */ if (req == null) { if (getLogger().isDebugEnabled()) { getLogger().debug("DBCOOKIEAUTH: no request object"); } return null; } String query = this.getAuthQuery(objectModel, conf, req); if (query == null) { if (getLogger().isDebugEnabled()) { getLogger().debug("DBCOOKIEAUTH: have not got query"); } req.setAttribute("message", "The authenticator is misconfigured"); return null; } if (getLogger().isDebugEnabled()) { getLogger().debug("DBCOOKIEAUTH: query is: " + query); } st = conn.createStatement(); rs = st.executeQuery(query); if (rs.next()) { if (getLogger().isDebugEnabled()) { 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); if (getLogger().isDebugEnabled()) { getLogger().debug("DBCOOKIEAUTH: session invalidated"); } } } else { session = req.getSession(true); } if (session == null) { return null; } if (getLogger().isDebugEnabled()) { if (as) { getLogger().debug("DBCOOKIEAUTH: appending to session"); } else { getLogger().debug("DBCOOKIEAUTH: session created"); } } } else { if (getLogger().isDebugEnabled()) { 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."); if (getLogger().isDebugEnabled()) { getLogger().debug("DBCOOKIEAUTH: no results for query"); } } catch (Exception e) { if (conn != null) { try { if (!conn.getAutoCommit()) { conn.rollback(); } } catch (Exception se) { // ignore } } getLogger().error("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; } /** * Gets the authQuery attribute of the DatabaseCookieAuthenticatorAction * object * * @param objectModel Description of Parameter * @param conf Description of Parameter * @param req Description of Parameter * @return The authQuery value */ private String getAuthQuery(Map objectModel, Configuration conf, Request req) { boolean first_constraint = true; StringBuffer queryBuffer = new StringBuffer("SELECT "); StringBuffer queryBufferEnd = new StringBuffer(""); String dbcol; String cookie_name; String cookie_value; String 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); cookie_name = select[i].getAttribute("cookie-name", ""); if (StringUtils.isEmpty(cookie_name.trim())) { continue; } nullstr = select[i].getAttribute("nullable", ""); if (BooleanUtils.toBoolean(nullstr.trim())) { nullable = true; } /* * if there is a cookie name, * but not the value, we exit immediately do * that authorization fails authomatically */ cookie_value = getCookie(objectModel, cookie_name).getValue(); if (cookie_value == null || cookie_value.trim().length() == 0) { // value is null if (!nullable) { if (getLogger().isDebugEnabled()) { 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().error("Exception: ",e); return null; } } public static Cookie getCookie(Map objectModel, String cookieName) { Request request = ObjectModelHelper.getRequest(objectModel); Cookie[] cookies = request.getCookies(); if (cookies != null) { for(int count = 0; count < cookies.length; count++) { Cookie currentCookie = cookies[count]; if (currentCookie.getName().equals(cookieName)) { return currentCookie; } } } return null; } /** * Description of the Method * * @param conf Description of Parameter * @param rs Description of Parameter * @param session Description of Parameter * @return Description of the Returned Value */ private HashMap propagateParameters(Configuration conf, ResultSet rs, Session session) { Configuration table = conf.getChild("table"); Configuration[] select = table.getChildren("select"); String session_param; HashMap map = new HashMap(); try { for (int i = 0; i < select.length; i++) { 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 */ Object o = null; String type = select[i].getAttribute("type", ""); // "string" is the default type if (StringUtils.isEmpty(type.trim()) || "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); if (getLogger().isDebugEnabled()) { getLogger().debug("DBCOOKIEAUTH: propagating param " + session_param + "=" + s); } } map.put(session_param, o); } } catch (Exception e) { // ignore } } return map; } catch (Exception e) { getLogger().error("Exception: ", e); } return null; } }