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