001 package org.esupportail.cas.server.handlers.database;
002
003 import org.dom4j.Element;
004 import org.esupportail.cas.server.util.MisconfiguredHandlerException;
005 import org.esupportail.cas.server.util.crypt.Crypt;
006 import org.esupportail.cas.server.util.log.Log;
007
008 /**
009 * This class implements a query database handler class.
010 *
011 * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
012 * @author Arunas Stockus <arunas.stockus at univ-lr.fr>
013 */
014 public class QueryDatabaseHandler extends DatabaseHandler {
015
016 /**
017 * This token is replaced by the users' login when executing queries on the database.
018 */
019 static final String SQL_LOGIN_TOKEN = "%u";
020
021 /**
022 * the string used to query the database. This query is supposed
023 * to return a single VARCHAR column.
024 */
025 private String sqlQuery;
026 /**
027 * the encryption used for stored passwords.
028 */
029 private String encryption;
030 /**
031 * the username to use to bind to the database.
032 */
033 private String bindUsername;
034 /**
035 * the password to use to bind to the database.
036 */
037 private String bindPassword;
038
039 /**
040 * Constructor.
041 *
042 * @param handlerElement the XML element that declares the handler
043 * in the configuration file
044 * @param configDebug debugging mode of the global configuration
045 * @throws Exception Exception
046 */
047 public QueryDatabaseHandler(
048 final Element handlerElement,
049 final Boolean configDebug) throws Exception {
050 super(handlerElement, configDebug);
051 traceBegin();
052
053 sqlQuery = readSqlQueryFromConfig();
054 trace("sql_query = " + sqlQuery);
055 if (sqlQuery.indexOf(SQL_LOGIN_TOKEN) < 0) {
056 Log.warn("The SQL query should contain at least one \""
057 + SQL_LOGIN_TOKEN
058 + "\"; assuming the user knows what he does.");
059 }
060
061 bindUsername = getConfigSubElementContent("bind_username", false/*not needed*/);
062 if (bindUsername.equals("")) {
063 trace("An anonymous connection to the database will be used.");
064 bindPassword = "";
065 } else {
066 bindPassword = getConfigSubElementContent("bind_password", false/*not needed*/);
067 }
068 trace("bind_username = " + bindUsername);
069 trace("bind_password = " + bindPassword);
070
071 encryption = getConfigSubElementContent("encryption", false/*not needed*/);
072 if (encryption.equals("")) {
073 encryption = "md5";
074 }
075 if (!Crypt.isEncryptionSupported(encryption)) {
076 traceThrow(new MisconfiguredHandlerException(
077 "Encryption \""
078 + encryption
079 + "\" is not supported."));
080 }
081 trace("encryption = " + encryption);
082 if (encryption.equals("plain")) {
083 Log.warn("Passwords should be encrypted. Be sure to keep the database out of danger!");
084 }
085
086 // add the database servers
087 addServers(true/*serverElementNeeded*/, getClass().getPackage().getName() + ".QueryDatabaseServer");
088
089 traceEnd();
090 }
091
092 /**
093 * Read the SQL query from the configuration.
094 * @return a String.
095 * @throws Exception Exception
096 */
097 protected String readSqlQueryFromConfig() throws Exception {
098 traceBegin();
099 String query = getConfigSubElementContent("sql_query", true/*needed*/);
100 // Remove all tailing semi-colons (they hurt some JDBC drivers).
101 boolean semiColonFound = false;
102 while (query.endsWith(";")) {
103 query.substring(0, query.length() - 1).trim();
104 semiColonFound = true;
105 }
106 if (semiColonFound) {
107 Log.warn("Trailing semi-colons are not allowed in SQL queries, they will be ignored.");
108 }
109 traceEnd(query);
110 return query;
111 }
112
113 /**
114 * Returns the SQL expression that must be executed to
115 * retrieve the password of the user with the given name.
116 * @param username the user's id
117 * @return a String.
118 */
119 final String getUserSqlQuery(final String username) {
120 return sqlQuery.replaceAll(SQL_LOGIN_TOKEN, username);
121 }
122
123 /**
124 * Retrieve the encryption used to store passwords.
125 *
126 * @return a String Object.
127 */
128 final String getEncryption() {
129 return encryption;
130 }
131
132 /**
133 * Retrieve the username to use to bind to the database.
134 *
135 * @return a String Object.
136 */
137 final String getBindUsername() {
138 return bindUsername;
139 }
140
141 /**
142 * Retrieve the password to use to bind to the database.
143 *
144 * @return a String Object.
145 */
146 final String getBindPassword() {
147 return bindPassword;
148 }
149
150 }
151