/* * Copyright 2012 The Apache Software Foundation. * * Licensed 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.manifoldcf.authorities.authorities.jdbc; import java.io.IOException; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.manifoldcf.agents.interfaces.ServiceInterruption; import org.apache.manifoldcf.authorities.authorities.BaseAuthorityConnector; import org.apache.manifoldcf.authorities.interfaces.AuthorizationResponse; import org.apache.manifoldcf.core.cachemanager.BaseDescription; import org.apache.manifoldcf.core.interfaces.BinaryInput; import org.apache.manifoldcf.core.interfaces.CacheManagerFactory; import org.apache.manifoldcf.core.interfaces.ConfigParams; import org.apache.manifoldcf.core.interfaces.ICacheCreateHandle; import org.apache.manifoldcf.core.interfaces.ICacheDescription; import org.apache.manifoldcf.core.interfaces.ICacheHandle; import org.apache.manifoldcf.core.interfaces.ICacheManager; import org.apache.manifoldcf.core.interfaces.IHTTPOutput; import org.apache.manifoldcf.connectorcommon.interfaces.IKeystoreManager; import org.apache.manifoldcf.core.interfaces.IPostParameters; import org.apache.manifoldcf.core.interfaces.IThreadContext; import org.apache.manifoldcf.connectorcommon.interfaces.KeystoreManagerFactory; import org.apache.manifoldcf.core.interfaces.ManifoldCFException; import org.apache.manifoldcf.core.interfaces.StringSet; import org.apache.manifoldcf.core.interfaces.TimeMarker; import org.apache.manifoldcf.core.interfaces.IResultRow; import org.apache.manifoldcf.jdbc.JDBCConnection; import org.apache.manifoldcf.jdbc.JDBCConstants; import org.apache.manifoldcf.jdbc.IDynamicResultSet; import org.apache.manifoldcf.jdbc.IDynamicResultRow; import org.apache.manifoldcf.authorities.system.Logging; /** * * @author krycek */ public class JDBCAuthority extends BaseAuthorityConnector { public static final String _rcsid = "@(#)$Id: JDBCAuthority.java $"; protected JDBCConnection connection = null; protected String jdbcProvider = null; protected String accessMethod = null; protected String host = null; protected String databaseName = null; protected String rawDriverString = null; protected String userName = null; protected String password = null; protected String idQuery = null; protected String tokenQuery = null; private long responseLifetime = 60000L; //60sec private int LRUsize = 1000; /** * Cache manager. */ private ICacheManager cacheManager = null; /** * Set thread context. */ @Override public void setThreadContext(IThreadContext tc) throws ManifoldCFException { super.setThreadContext(tc); cacheManager = CacheManagerFactory.make(tc); } /** * Connect. The configuration parameters are included. * * @param configParams are the configuration parameters for this connection. */ @Override public void connect(ConfigParams configParams) { super.connect(configParams); jdbcProvider = configParams.getParameter(JDBCConstants.providerParameter); accessMethod = configParams.getParameter(JDBCConstants.methodParameter); host = configParams.getParameter(JDBCConstants.hostParameter); databaseName = configParams.getParameter(JDBCConstants.databaseNameParameter); rawDriverString = configParams.getParameter(JDBCConstants.driverStringParameter); userName = configParams.getParameter(JDBCConstants.databaseUserName); password = configParams.getObfuscatedParameter(JDBCConstants.databasePassword); idQuery = configParams.getParameter(JDBCConstants.databaseUserIdQuery); tokenQuery = configParams.getParameter(JDBCConstants.databaseTokensQuery); } /** * Check status of connection. */ @Override public String check() throws ManifoldCFException { try { getSession(); // Attempt to fetch a connection; if this succeeds we pass connection.testConnection(); return super.check(); } catch (ServiceInterruption e) { if (Logging.authorityConnectors.isDebugEnabled()) { Logging.authorityConnectors.debug("Service interruption in check(): " + e.getMessage(), e); } return "Transient error: " + e.getMessage(); } } /** * Close the connection. Call this before discarding the repository connector. */ @Override public void disconnect() throws ManifoldCFException { connection = null; host = null; jdbcProvider = null; accessMethod = null; databaseName = null; rawDriverString = null; userName = null; password = null; super.disconnect(); } /** * Set up a session */ protected void getSession() throws ManifoldCFException, ServiceInterruption { if (connection == null) { if (jdbcProvider == null || jdbcProvider.length() == 0) { throw new ManifoldCFException("Missing parameter '" + JDBCConstants.providerParameter + "'"); } if ((host == null || host.length() == 0) && (rawDriverString == null || rawDriverString.length() == 0)) throw new ManifoldCFException("Missing parameter '"+JDBCConstants.hostParameter+"' or '"+JDBCConstants.driverStringParameter+"'"); connection = new JDBCConnection(jdbcProvider,(accessMethod==null || accessMethod.equals("name")),host,databaseName,rawDriverString,userName,password); } } private String createCacheConnectionString() { StringBuilder sb = new StringBuilder(); sb.append(jdbcProvider).append("|") .append((host==null)?"":host).append("|") .append((databaseName==null)?"":databaseName).append("|") .append((rawDriverString==null)?"":rawDriverString).append("|") .append(userName); return sb.toString(); } /** * Obtain the access tokens for a given user name. * * @param userName is the user name or identifier. * @return the response tokens (according to the current authority). (Should * throws an exception only when a condition cannot be properly described * within the authorization response object.) */ @Override public AuthorizationResponse getAuthorizationResponse(String userName) throws ManifoldCFException { // Construct a cache description object ICacheDescription objectDescription = new JdbcAuthorizationResponseDescription(userName, createCacheConnectionString(), idQuery, tokenQuery, this.responseLifetime, this.LRUsize); // Enter the cache ICacheHandle ch = cacheManager.enterCache(new ICacheDescription[]{objectDescription}, null, null); try { ICacheCreateHandle createHandle = cacheManager.enterCreateSection(ch); try { // Lookup the object AuthorizationResponse response = (AuthorizationResponse) cacheManager.lookupObject(createHandle, objectDescription); if (response != null) { return response; } // Create the object. response = getAuthorizationResponseUncached(userName); // Save it in the cache cacheManager.saveObject(createHandle, objectDescription, response); // And return it... return response; } finally { cacheManager.leaveCreateSection(createHandle); } } finally { cacheManager.leaveCache(ch); } } public AuthorizationResponse getAuthorizationResponseUncached(String userName) throws ManifoldCFException { try { getSession(); VariableMap vm = new VariableMap(); addConstant(vm, JDBCConstants.idReturnVariable, JDBCConstants.idReturnColumnName); addVariable(vm, JDBCConstants.userNameVariable, userName); // Find user id ArrayList paramList = new ArrayList(); StringBuilder sb = new StringBuilder(); substituteQuery(idQuery, vm, sb, paramList); IDynamicResultSet idSet; try { idSet = connection.executeUncachedQuery(sb.toString(),paramList,-1); } catch (ServiceInterruption e) { return RESPONSE_UNREACHABLE; } catch (ManifoldCFException e) { throw e; } String uid; try { IDynamicResultRow row = idSet.getNextRow(); if (row == null) return RESPONSE_USERNOTFOUND; try { Object oUid = row.getValue(JDBCConstants.idReturnColumnName); if (oUid == null) throw new ManifoldCFException("Bad id query; doesn't return $(IDCOLUMN) column. Try using quotes around $(IDCOLUMN) variable, e.g. \"$(IDCOLUMN)\"."); uid = JDBCConnection.readAsString(oUid); } finally { row.close(); } } finally { idSet.close(); } if (uid.isEmpty()) { return RESPONSE_USERNOTFOUND; } // now check tokens vm = new VariableMap(); addConstant(vm, JDBCConstants.tokenReturnVariable, JDBCConstants.tokenReturnColumnName); addVariable(vm, JDBCConstants.userNameVariable, userName); addVariable(vm, JDBCConstants.userIDVariable, uid); sb = new StringBuilder(); paramList = new ArrayList(); substituteQuery(tokenQuery, vm, sb, paramList); try { idSet = connection.executeUncachedQuery(sb.toString(),paramList,-1); } catch (ServiceInterruption e) { return RESPONSE_UNREACHABLE; } catch (ManifoldCFException e) { throw e; } ArrayList<String> tokenArray = new ArrayList<String>(); try { while (true) { IDynamicResultRow row = idSet.getNextRow(); if (row == null) break; try { Object oToken = row.getValue(JDBCConstants.tokenReturnColumnName); if (oToken == null) throw new ManifoldCFException("Bad token query; doesn't return $(TOKENCOLUMN) column. Try using quotes around $(TOKENCOLUMN) variable, e.g. \"$(TOKENCOLUMN)\"."); String token = JDBCConnection.readAsString(oToken); if (!token.isEmpty()) { tokenArray.add(token); } } finally { row.close(); } } } finally { idSet.close(); } return new AuthorizationResponse(tokenArray.toArray(new String[0]), AuthorizationResponse.RESPONSE_OK); } catch (ServiceInterruption e) { Logging.authorityConnectors.warn("JDBCAuthority: Service interruption: "+e.getMessage(),e); return RESPONSE_UNREACHABLE; } } // UI support methods. // // These support methods come in two varieties. The first bunch is involved in setting up connection configuration information. The second bunch // is involved in presenting and editing document specification information for a job. The two kinds of methods are accordingly treated differently, // in that the first bunch cannot assume that the current connector object is connected, while the second bunch can. That is why the first bunch // receives a thread context argument for all UI methods, while the second bunch does not need one (since it has already been applied via the connect() // method, above). /** * Output the configuration header section. This method is called in the head * section of the connector's configuration page. Its purpose is to add the * required tabs to the list, and to output any javascript methods that might * be needed by the configuration editing HTML. * * @param threadContext is the local thread context. * @param out is the output to which any HTML should be sent. * @param parameters are the configuration parameters, as they currently * exist, for this connection being configured. * @param tabsArray is an array of tab names. Add to this array any tab names * that are specific to the connector. */ @Override public void outputConfigurationHeader(IThreadContext threadContext, IHTTPOutput out, Locale locale, ConfigParams parameters, List<String> tabsArray) throws ManifoldCFException, IOException { tabsArray.add(Messages.getString(locale, "JDBCAuthority.DatabaseType")); tabsArray.add(Messages.getString(locale, "JDBCAuthority.Server")); tabsArray.add(Messages.getString(locale, "JDBCAuthority.Credentials")); tabsArray.add(Messages.getString(locale, "JDBCAuthority.Queries")); out.print( "<script type=\"text/javascript\">\n"+ "<!--\n"+ "function checkConfigForSave()\n"+ "{\n"+ " if (editconnection.databasehost.value == \"\" && editconnection.rawjdbcstring.value == \"\")\n"+ " {\n"+ " alert(\"" + Messages.getBodyJavascriptString(locale, "JDBCAuthority.PleaseFillInADatabaseServerName") + "\");\n"+ " SelectTab(\"" + Messages.getBodyJavascriptString(locale, "JDBCAuthority.Server") + "\");\n"+ " editconnection.databasehost.focus();\n"+ " return false;\n"+ " }\n"+ " if (editconnection.databasename.value == \"\" && editconnection.rawjdbcstring.value == \"\")\n"+ " {\n"+ " alert(\"" + Messages.getBodyJavascriptString(locale, "JDBCAuthority.PleaseFillInTheNameOfTheDatabase") + "\");\n"+ " SelectTab(\"" + Messages.getBodyJavascriptString(locale, "JDBCAuthority.Server") + "\");\n"+ " editconnection.databasename.focus();\n"+ " return false;\n"+ " }\n"+ " if (editconnection.username.value == \"\")\n"+ " {\n"+ " alert(\"" + Messages.getBodyJavascriptString(locale, "JDBCAuthority.PleaseSupplyTheDatabaseUsernameForThisConnection") + "\");\n"+ " SelectTab(\"" + Messages.getBodyJavascriptString(locale, "JDBCAuthority.Credentials") + "\");\n"+ " editconnection.username.focus();\n"+ " return false;\n"+ " }\n"+ " return true;\n"+ "}\n"+ "\n"+ "//-->\n"+ "</script>\n" ); } /** * Output the configuration body section. This method is called in the body * section of the connector's configuration page. Its purpose is to present * the required form elements for editing. The coder can presume that the HTML * that is output from this configuration will be within appropriate <html>, * <body>, and <form> tags. The name of the form is "editconnection". * * @param threadContext is the local thread context. * @param out is the output to which any HTML should be sent. * @param parameters are the configuration parameters, as they currently * exist, for this connection being configured. * @param tabName is the current tab name. */ @Override public void outputConfigurationBody(IThreadContext threadContext, IHTTPOutput out, Locale locale, ConfigParams parameters, String tabName) throws ManifoldCFException, IOException { String lJdbcProvider = parameters.getParameter(JDBCConstants.providerParameter); if (lJdbcProvider == null) { lJdbcProvider = "oracle:thin:@"; } String lAccessMethod = parameters.getParameter(JDBCConstants.methodParameter); if (lAccessMethod == null) lAccessMethod = "name"; String lHost = parameters.getParameter(JDBCConstants.hostParameter); if (lHost == null) { lHost = "localhost"; } String lDatabaseName = parameters.getParameter(JDBCConstants.databaseNameParameter); if (lDatabaseName == null) { lDatabaseName = "database"; } String rawJDBCString = parameters.getParameter(JDBCConstants.driverStringParameter); if (rawJDBCString == null) rawJDBCString = ""; String databaseUser = parameters.getParameter(JDBCConstants.databaseUserName); if (databaseUser == null) { databaseUser = ""; } String databasePassword = parameters.getObfuscatedParameter(JDBCConstants.databasePassword); if (databasePassword == null) { databasePassword = ""; } else { databasePassword = out.mapPasswordToKey(databasePassword); } String lIdQuery = parameters.getParameter(JDBCConstants.databaseUserIdQuery); if (lIdQuery == null) { lIdQuery = "SELECT idfield AS $(IDCOLUMN) FROM usertable WHERE login = $(USERNAME)"; } String lTokenQuery = parameters.getParameter(JDBCConstants.databaseTokensQuery); if (lTokenQuery == null) { lTokenQuery = "SELECT groupnamefield AS $(TOKENCOLUMN) FROM grouptable WHERE user_id = $(UID) OR login = $(USERNAME)"; } // "Database Type" tab if (tabName.equals(Messages.getString(locale, "JDBCAuthority.DatabaseType"))) { out.print( "<table class=\"displaytable\">\n"+ " <tr><td class=\"separator\" colspan=\"2\"><hr/></td></tr>\n"+ " <tr>\n"+ " <td class=\"description\"><nobr>" + Messages.getBodyString(locale, "JDBCAuthority.DatabaseType2") + "</nobr></td><td class=\"value\">\n"+ " <select multiple=\"false\" name=\"databasetype\" size=\"2\">\n"+ " <option value=\"oracle:thin:@\" " + (lJdbcProvider.equals("oracle:thin:@") ? "selected=\"selected\"" : "") + ">Oracle</option>\n"+ " <option value=\"postgresql://\" " + (lJdbcProvider.equals("postgresql:") ? "selected=\"selected\"" : "") + ">Postgres SQL</option>\n"+ " <option value=\"jtds:sqlserver://\" " + (lJdbcProvider.equals("jtds:sqlserver:") ? "selected=\"selected\"" : "") + ">MS SQL Server (> V6.5)</option>\n"+ " <option value=\"jtds:sybase://\" " + (lJdbcProvider.equals("jtds:sybase:") ? "selected=\"selected\"" : "") + ">Sybase (>= V10)</option>\n"+ " <option value=\"mysql://\" " + (lJdbcProvider.equals("mysql:") ? "selected=\"selected\"" : "") + ">MySQL (>= V5)</option>\n"+ " </select>\n"+ " </td>\n"+ " </tr>\n"+ " <tr><td class=\"separator\" colspan=\"2\"><hr/></td></tr>\n"+ " <tr>\n"+ " <td class=\"description\"><nobr>" + Messages.getBodyString(locale,"JDBCAuthority.AccessMethod") + "</nobr></td><td class=\"value\">\n"+ " <select multiple=\"false\" name=\"accessmethod\" size=\"2\">\n"+ " <option value=\"name\" "+(lAccessMethod.equals("name")?"selected=\"selected\"":"")+">"+Messages.getBodyString(locale,"JDBCAuthority.ByName")+"</option>\n"+ " <option value=\"label\" "+(lAccessMethod.equals("label")?"selected=\"selected\"":"")+">"+Messages.getBodyString(locale,"JDBCAuthority.ByLabel")+"</option>\n"+ " </select>\n"+ " </td>\n"+ " </tr>\n"+ "</table>\n"); } else { out.print( "<input type=\"hidden\" name=\"databasetype\" value=\"" + lJdbcProvider + "\"/>\n"+ "<input type=\"hidden\" name=\"accessmethod\" value=\""+lAccessMethod+"\"/>\n" ); } // "Server" tab if (tabName.equals(Messages.getString(locale, "JDBCAuthority.Server"))) { out.print( "<table class=\"displaytable\">\n"+ " <tr><td class=\"separator\" colspan=\"2\"><hr/></td></tr>\n"+ " <tr>\n"+ " <td class=\"description\"><nobr>" + Messages.getBodyString(locale, "JDBCAuthority.DatabaseHostAndPort") + "</nobr></td><td class=\"value\"><input type=\"text\" size=\"64\" name=\"databasehost\" value=\"" + org.apache.manifoldcf.ui.util.Encoder.attributeEscape(lHost) + "\"/></td>\n"+ " </tr>\n"+ " <tr>\n"+ " <td class=\"description\"><nobr>" + Messages.getBodyString(locale, "JDBCAuthority.DatabaseServiceNameOrInstanceDatabase") + "</nobr></td><td class=\"value\"><input type=\"text\" size=\"32\" name=\"databasename\" value=\"" + org.apache.manifoldcf.ui.util.Encoder.attributeEscape(lDatabaseName) + "\"/></td>\n"+ " </tr>\n"+ " <tr>\n"+ " <td class=\"description\"><nobr>" + Messages.getBodyString(locale,"JDBCAuthority.RawDatabaseConnectString") + "</nobr></td><td class=\"value\"><input type=\"text\" size=\"80\" name=\"rawjdbcstring\" value=\""+org.apache.manifoldcf.ui.util.Encoder.attributeEscape(rawJDBCString)+"\"/></td>\n"+ " </tr>\n"+ "</table>\n" ); } else { out.print( "<input type=\"hidden\" name=\"databasehost\" value=\"" + org.apache.manifoldcf.ui.util.Encoder.attributeEscape(lHost) + "\"/>\n"+ "<input type=\"hidden\" name=\"databasename\" value=\"" + org.apache.manifoldcf.ui.util.Encoder.attributeEscape(lDatabaseName) + "\"/>\n"+ "<input type=\"hidden\" name=\"rawjdbcstring\" value=\""+org.apache.manifoldcf.ui.util.Encoder.attributeEscape(rawJDBCString)+"\"/>\n" ); } // "Credentials" tab if (tabName.equals(Messages.getString(locale, "JDBCAuthority.Credentials"))) { out.print( "<table class=\"displaytable\">\n" + " <tr><td class=\"separator\" colspan=\"2\"><hr/></td></tr>\n" + " <tr>\n" + " <td class=\"description\"><nobr>" + Messages.getBodyString(locale, "JDBCAuthority.UserName") + "</nobr></td><td class=\"value\"><input type=\"text\" size=\"32\" name=\"username\" value=\"" + org.apache.manifoldcf.ui.util.Encoder.attributeEscape(databaseUser) + "\"/></td>\n" + " </tr>\n" + " <tr>\n" + " <td class=\"description\"><nobr>" + Messages.getBodyString(locale, "JDBCAuthority.Password") + "</nobr></td><td class=\"value\"><input type=\"password\" size=\"32\" name=\"password\" value=\"" + org.apache.manifoldcf.ui.util.Encoder.attributeEscape(databasePassword) + "\"/></td>\n" + " </tr>\n" + "</table>\n"); } else { out.print( "<input type=\"hidden\" name=\"username\" value=\"" + org.apache.manifoldcf.ui.util.Encoder.attributeEscape(databaseUser) + "\"/>\n" + "<input type=\"hidden\" name=\"password\" value=\"" + org.apache.manifoldcf.ui.util.Encoder.attributeEscape(databasePassword) + "\"/>\n"); } if (tabName.equals(Messages.getString(locale, "JDBCAuthority.Queries"))) { out.print( "<table class=\"displaytable\">\n" + " <tr><td class=\"separator\" colspan=\"2\"><hr/></td></tr>\n" + " <tr>\n" + " <td class=\"description\"><nobr>" + Messages.getBodyString(locale, "JDBCAuthority.UserIdQuery") + "</nobr><br/><nobr>" + Messages.getBodyString(locale, "JDBCAuthority.returnUserIdOrEmptyResultset") + "</nobr></td>\n" + " <td class=\"value\"><textarea name=\"idquery\" cols=\"64\" rows=\"6\">" + org.apache.manifoldcf.ui.util.Encoder.bodyEscape(lIdQuery) + "</textarea></td>\n" + " </tr>\n" + " <tr>\n" + " <td class=\"description\"><nobr>" + Messages.getBodyString(locale, "JDBCAuthority.TokenQuery") + "</nobr><br/><nobr>" + Messages.getBodyString(locale, "JDBCAuthority.returnTokensForUser") + "</nobr></td>\n" + " <td class=\"value\"><textarea name=\"tokenquery\" cols=\"64\" rows=\"6\">" + org.apache.manifoldcf.ui.util.Encoder.bodyEscape(lTokenQuery) + "</textarea></td>\n" + " </tr>\n" + "</table>\n"); } else { out.print( "<input type=\"hidden\" name=\"idquery\" value=\"" + org.apache.manifoldcf.ui.util.Encoder.attributeEscape(lIdQuery) + "\"/>\n" + "<input type=\"hidden\" name=\"tokenquery\" value=\"" + org.apache.manifoldcf.ui.util.Encoder.attributeEscape(lTokenQuery) + "\"/>\n"); } } /** * Process a configuration post. This method is called at the start of the * connector's configuration page, whenever there is a possibility that form * data for a connection has been posted. Its purpose is to gather form * information and modify the configuration parameters accordingly. The name * of the posted form is "editconnection". * * @param threadContext is the local thread context. * @param variableContext is the set of variables available from the post, * including binary file post information. * @param parameters are the configuration parameters, as they currently * exist, for this connection being configured. * @return null if all is well, or a string error message if there is an error * that should prevent saving of the connection (and cause a redirection to an * error page). */ @Override public String processConfigurationPost(IThreadContext threadContext, IPostParameters variableContext, Locale locale, ConfigParams parameters) throws ManifoldCFException { String type = variableContext.getParameter("databasetype"); if (type != null) { parameters.setParameter(JDBCConstants.providerParameter, type); } String accessMethod = variableContext.getParameter("accessmethod"); if (accessMethod != null) parameters.setParameter(JDBCConstants.methodParameter,accessMethod); String lHost = variableContext.getParameter("databasehost"); if (lHost != null) { parameters.setParameter(JDBCConstants.hostParameter, lHost); } String lDatabaseName = variableContext.getParameter("databasename"); if (lDatabaseName != null) { parameters.setParameter(JDBCConstants.databaseNameParameter, lDatabaseName); } String rawJDBCString = variableContext.getParameter("rawjdbcstring"); if (rawJDBCString != null) parameters.setParameter(JDBCConstants.driverStringParameter,rawJDBCString); String lUserName = variableContext.getParameter("username"); if (lUserName != null) { parameters.setParameter(JDBCConstants.databaseUserName, lUserName); } String lPassword = variableContext.getParameter("password"); if (lPassword != null) { parameters.setObfuscatedParameter(JDBCConstants.databasePassword, variableContext.mapKeyToPassword(lPassword)); } String lIdQuery = variableContext.getParameter("idquery"); if (lIdQuery != null) { parameters.setParameter(JDBCConstants.databaseUserIdQuery, lIdQuery); } String lTokenQuery = variableContext.getParameter("tokenquery"); if (lTokenQuery != null) { parameters.setParameter(JDBCConstants.databaseTokensQuery, lTokenQuery); } return null; } /** * View configuration. This method is called in the body section of the * connector's view configuration page. Its purpose is to present the * connection information to the user. The coder can presume that the HTML * that is output from this configuration will be within appropriate <html> * and <body> tags. * * @param threadContext is the local thread context. * @param out is the output to which any HTML should be sent. * @param parameters are the configuration parameters, as they currently * exist, for this connection being configured. */ @Override public void viewConfiguration(IThreadContext threadContext, IHTTPOutput out, Locale locale, ConfigParams parameters) throws ManifoldCFException, IOException { out.print( "<table class=\"displaytable\">\n" + " <tr>\n" + " <td class=\"description\" colspan=\"1\"><nobr>" + Messages.getBodyString(locale, "JDBCAuthority.Parameters") + "</nobr></td>\n" + " <td class=\"value\" colspan=\"3\">\n"); Iterator iter = parameters.listParameters(); while (iter.hasNext()) { String param = (String) iter.next(); String value = parameters.getParameter(param); if (param.length() >= "password".length() && param.substring(param.length() - "password".length()).equalsIgnoreCase("password")) { out.print( " <nobr>" + org.apache.manifoldcf.ui.util.Encoder.bodyEscape(param) + "=********</nobr><br/>\n"); } else if (param.length() >= "keystore".length() && param.substring(param.length() - "keystore".length()).equalsIgnoreCase("keystore")) { IKeystoreManager kmanager = KeystoreManagerFactory.make("", value); out.print( " <nobr>" + org.apache.manifoldcf.ui.util.Encoder.bodyEscape(param) + "=<" + Integer.toString(kmanager.getContents().length) + " certificate(s)></nobr><br/>\n"); } else { out.print( " <nobr>" + org.apache.manifoldcf.ui.util.Encoder.bodyEscape(param) + "=" + org.apache.manifoldcf.ui.util.Encoder.bodyEscape(value) + "</nobr><br/>\n"); } } out.print( " </td>\n" + " </tr>\n" + "</table>\n"); } /** * Given a query, and a parameter map, substitute it. Each variable * substitutes the string, and it also substitutes zero or more query * parameters. */ protected static void substituteQuery(String inputString, VariableMap inputMap, StringBuilder outputQuery, ArrayList outputParams) throws ManifoldCFException { // We are looking for strings that look like this: $(something) // Right at the moment we don't care even about quotes, so we just want to look for $(. int startIndex = 0; while (true) { int nextIndex = inputString.indexOf("$(", startIndex); if (nextIndex == -1) { outputQuery.append(inputString.substring(startIndex)); break; } int endIndex = inputString.indexOf(")", nextIndex); if (endIndex == -1) { outputQuery.append(inputString.substring(startIndex)); break; } String variableName = inputString.substring(nextIndex + 2, endIndex); VariableMapItem item = inputMap.getVariable(variableName); if (item == null) { throw new ManifoldCFException("No such substitution variable: $(" + variableName + ")"); } outputQuery.append(inputString.substring(startIndex, nextIndex)); outputQuery.append(item.getValue()); ArrayList inputParams = item.getParameters(); if (inputParams != null) { int i = 0; while (i < inputParams.size()) { Object x = inputParams.get(i++); outputParams.add(x); } } startIndex = endIndex + 1; } } /** * Add string query variables */ protected static void addVariable(VariableMap map, String varName, String variable) { ArrayList params = new ArrayList(); params.add(variable); map.addVariable(varName, "?", params); } /** * Add string query constants */ protected static void addConstant(VariableMap map, String varName, String value) { map.addVariable(varName, value, null); } // pass params to preparedStatement protected static void loadPS(PreparedStatement ps, ArrayList data) throws java.sql.SQLException, ManifoldCFException { if (data != null) { for (int i = 0; i < data.size(); i++) { // If the input type is a string, then set it as such. // Otherwise, if it's an input stream, we make a blob out of it. Object x = data.get(i); if (x instanceof String) { String value = (String) x; // letting database do lame conversion! ps.setString(i + 1, value); } if (x instanceof BinaryInput) { BinaryInput value = (BinaryInput) x; // System.out.println("Blob length on write = "+Long.toString(value.getLength())); // The oracle driver does a binary conversion to base 64 when writing data // into a clob column using a binary stream operator. Since at this // point there is no way to distinguish the two, and since our tests use CLOB, // this code doesn't work for them. // So, for now, use the ascii stream method. //ps.setBinaryStream(i+1,value.getStream(),(int)value.getLength()); ps.setAsciiStream(i + 1, value.getStream(), (int) value.getLength()); } if (x instanceof java.util.Date) { ps.setDate(i + 1, new java.sql.Date(((java.util.Date) x).getTime())); } if (x instanceof Long) { ps.setLong(i + 1, ((Long) x).longValue()); } if (x instanceof TimeMarker) { ps.setTimestamp(i + 1, new java.sql.Timestamp(((Long) x).longValue())); } if (x instanceof Double) { ps.setDouble(i + 1, ((Double) x).doubleValue()); } if (x instanceof Integer) { ps.setInt(i + 1, ((Integer) x).intValue()); } if (x instanceof Float) { ps.setFloat(i + 1, ((Float) x).floatValue()); } } } } /** * Variable map entry. */ protected static class VariableMapItem { protected String value; protected ArrayList params; /** * Constructor. */ public VariableMapItem(String value, ArrayList params) { this.value = value; this.params = params; } /** * Get value. */ public String getValue() { return value; } /** * Get parameters. */ public ArrayList getParameters() { return params; } } /** * Variable map. */ protected static class VariableMap { protected Map variableMap = new HashMap(); /** * Constructor */ public VariableMap() { } /** * Add a variable map entry */ public void addVariable(String variableName, String value, ArrayList parameters) { VariableMapItem e = new VariableMapItem(value, parameters); variableMap.put(variableName, e); } /** * Get a variable map entry */ public VariableMapItem getVariable(String variableName) { return (VariableMapItem) variableMap.get(variableName); } } protected static StringSet emptyStringSet = new StringSet(); /** * This is the cache object descriptor for cached access tokens from this * connector. */ protected class JdbcAuthorizationResponseDescription extends BaseDescription { /** * The user name */ protected final String userName; /** * LDAP connection string with server name and base DN */ protected final String connectionString; /** The user query. */ protected final String userQuery; /** The token query. */ protected final String tokenQuery; /** * The response lifetime */ protected final long responseLifetime; /** * The expiration time */ protected long expirationTime = -1; /** * Constructor. */ public JdbcAuthorizationResponseDescription(String userName, String connectionString, String userQuery, String tokenQuery, long responseLifetime, int LRUsize) { super("JDBCAuthority", LRUsize); this.userName = userName; this.connectionString = connectionString; this.userQuery = userQuery; this.tokenQuery = tokenQuery; this.responseLifetime = responseLifetime; } /** * Return the invalidation keys for this object. */ public StringSet getObjectKeys() { return emptyStringSet; } /** * Get the critical section name, used for synchronizing the creation of the * object */ public String getCriticalSectionName() { StringBuilder sb = new StringBuilder(getClass().getName()); sb.append("-").append(userName).append("-").append(connectionString).append("-") .append(userQuery).append("-").append(tokenQuery); return sb.toString(); } /** * Return the object expiration interval */ @Override public long getObjectExpirationTime(long currentTime) { if (expirationTime == -1) { expirationTime = currentTime + responseLifetime; } return expirationTime; } @Override public int hashCode() { return userName.hashCode() + connectionString.hashCode() + userQuery.hashCode() + tokenQuery.hashCode(); } @Override public boolean equals(Object o) { if (!(o instanceof JdbcAuthorizationResponseDescription)) { return false; } JdbcAuthorizationResponseDescription ard = (JdbcAuthorizationResponseDescription) o; if (!ard.userName.equals(userName)) { return false; } if (!ard.connectionString.equals(connectionString)) { return false; } if (!ard.userQuery.equals(userQuery)) { return false; } if (!ard.tokenQuery.equals(tokenQuery)) { return false; } return true; } } }