Merge pull request #2151 from tcbuzor/tcbuzor_orefine_xss_tr
Database Extension: input validation for database connection data
This commit is contained in:
commit
1a79176942
@ -44,5 +44,10 @@
|
||||
"database-parsing/limit-next": "Load at most",
|
||||
"database-parsing/limit": "row(s) of data",
|
||||
"database-parsing/store-row": "Store blank rows",
|
||||
"database-parsing/store-cell": "Store blank cells as nulls"
|
||||
"database-parsing/store-cell": "Store blank cells as nulls",
|
||||
"database-source/alert-conn-name-invalid-character": "Connection Name Input Error: Illegal Character in Input. Only [a-zA-Z0-9._-] Allowed",
|
||||
"database-source/alert-db-host-invalid-character": "Database Host Error: Illegal Character in Input. Only Alphanumeric characters allowed",
|
||||
"database-source/alert-db-user-invalid-character": "Database User Error: Illegal Character in Input. Only Alphanumeric characters allowed",
|
||||
"database-source/alert-db-port-invalid-character": "Database Port Error: Illegal Character in Input. Only Numeric values allowed."
|
||||
|
||||
}
|
||||
|
@ -127,11 +127,11 @@ Refine.DatabaseSourceUI.prototype.attachUI = function(body) {
|
||||
this._elmts.saveConnectionButton.click(function(evt) {
|
||||
|
||||
if(self._validateNewConnectionForm() == true){
|
||||
var connectionNameInput = $.trim(self._elmts.connectionNameInput[0].value);
|
||||
var connectionNameInput = $.trim(self._elmts.connectionNameInput[0].value);
|
||||
if (connectionNameInput.length === 0) {
|
||||
window.alert($.i18n('database-source/alert-connection-name'));
|
||||
} else{
|
||||
self._saveConnection(self._getConnectionInfo());
|
||||
self._saveConnection(self._getConnectionInfo());
|
||||
}
|
||||
|
||||
}
|
||||
@ -148,19 +148,11 @@ Refine.DatabaseSourceUI.prototype.attachUI = function(body) {
|
||||
jdbcQueryInfo.databasePassword = $( "#currentDatabasePasswordInput" ).val();
|
||||
jdbcQueryInfo.initialDatabase = $( "#currentInitialDatabaseInput" ).val();
|
||||
jdbcQueryInfo.query = $.trim($( "#queryTextArea" ).val());
|
||||
|
||||
// if(jdbcQueryInfo.query && jdbcQueryInfo.query.length > 0 ) {
|
||||
// self._executeQuery(jdbcQueryInfo);
|
||||
// }else{
|
||||
// window.alert($.i18n('database-source/alert-query'));
|
||||
// }
|
||||
|
||||
|
||||
if(self.validateQuery(jdbcQueryInfo.query)) {
|
||||
self._executeQuery(jdbcQueryInfo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
@ -249,15 +241,15 @@ Refine.DatabaseSourceUI.prototype._editConnection = function(connectionInfo) {
|
||||
success: function(settings) {
|
||||
if(settings){
|
||||
$( "#menuListUl" ).empty();
|
||||
var menuList = $('#menuListUl');
|
||||
var items = [];
|
||||
$.each(settings.savedConnections,function(index,savedConnection){
|
||||
// items.push('<a href="#" class="list-group-item list-group-item-action">'
|
||||
// + '<span class="context-menu-one context-menu-text" >' + savedConnection.connectionName + '</span>'
|
||||
// + '<span class="sc-context-more-vert pull-right"> </span> </a>');
|
||||
|
||||
items.push('<li class="pure-menu-item sc-list"><a href="#" class="pure-menu-link context-menu-one">'
|
||||
+ '<span class="context-menu-text" >' + savedConnection.connectionName + '</span>'
|
||||
+ '<span class="sc-context-more-vert pull-right"> </span></a></li>');
|
||||
|
||||
var li = $('<li class="pure-menu-item sc-list"></li>').appendTo(menuList);
|
||||
var a = $('<a href="#" class="pure-menu-link context-menu-one"></a>').appendTo(li);
|
||||
$('<span class="context-menu-text"></span>').text(savedConnection.connectionName)
|
||||
.appendTo(a);
|
||||
$('<span class="sc-context-more-vert pull-right"> </span>').appendTo(a);
|
||||
})
|
||||
|
||||
$( "#menuListUl" ).append(items.join(''));
|
||||
@ -275,26 +267,23 @@ Refine.DatabaseSourceUI.prototype._executeQuery = function(jdbcQueryInfo) {
|
||||
//remove start line
|
||||
|
||||
var dismiss = DialogSystem.showBusy($.i18n('database-import/checking'));
|
||||
//$("#executeQueryBtn").text('Please wait ...').attr('disabled','disabled');
|
||||
|
||||
|
||||
$.post(
|
||||
"command/database/test-query",
|
||||
jdbcQueryInfo,
|
||||
function(jdbcConnectionResult) {
|
||||
// $("#executeQueryBtn").text('Preview Query Result').removeAttr('disabled');
|
||||
|
||||
dismiss();
|
||||
self._controller.startImportingDocument(jdbcQueryInfo);
|
||||
|
||||
},
|
||||
"json"
|
||||
).fail(function( jqXhr, textStatus, errorThrown ){
|
||||
//$("#executeQueryBtn").text('Preview Query Result').removeAttr('disabled');
|
||||
|
||||
dismiss();
|
||||
alert( textStatus + ':' + errorThrown );
|
||||
});
|
||||
//remove end line
|
||||
|
||||
//self._controller.startImportingDocument(jdbcQueryInfo);
|
||||
|
||||
}
|
||||
|
||||
Refine.DatabaseSourceUI.prototype._saveConnection = function(jdbcConnectionInfo) {
|
||||
@ -304,16 +293,11 @@ Refine.DatabaseSourceUI.prototype._saveConnection = function(jdbcConnectionInfo)
|
||||
jdbcConnectionInfo,
|
||||
function(settings) {
|
||||
if(settings){
|
||||
|
||||
// self._elmts.scListGroupDiv.empty();
|
||||
|
||||
self._elmts.menuListUl.empty();
|
||||
var items = [];
|
||||
$.each(settings.savedConnections,function(index,savedConnection){
|
||||
|
||||
// items.push('<a href="#" class="list-group-item list-group-item-action">'
|
||||
// + '<span class="context-menu-one context-menu-text" >' + savedConnection.connectionName + '</span>'
|
||||
// + '<span class="sc-context-more-vert pull-right"> </span> </a>');
|
||||
|
||||
|
||||
items.push('<li class="pure-menu-item sc-list"><a href="#" class="pure-menu-link context-menu-one">'
|
||||
+ '<span class="context-menu-text" >' + savedConnection.connectionName + '</span>'
|
||||
+ '<span class="sc-context-more-vert pull-right"> </span></a></li>');
|
||||
@ -339,14 +323,10 @@ Refine.DatabaseSourceUI.prototype._loadSavedConnections = function() {
|
||||
if(settings){
|
||||
|
||||
self._elmts.menuListUl.empty();
|
||||
//self._elmts.scListGroupDiv.empty();
|
||||
|
||||
var items = [];
|
||||
$.each(settings.savedConnections,function(index,savedConnection){
|
||||
|
||||
// items.push('<a href="#" class="list-group-item list-group-item-action context-menu-one">'
|
||||
// + '<span class="context-menu-text" >' + savedConnection.connectionName + '</span>'
|
||||
// + '<span class="sc-context-more-vert pull-right"> </span> </a>');
|
||||
|
||||
items.push('<li class="pure-menu-item sc-list"><a href="#" class="pure-menu-link context-menu-one">'
|
||||
+ '<span class="context-menu-text" >' + savedConnection.connectionName + '</span>'
|
||||
+ '<span class="sc-context-more-vert pull-right"> </span></a></li>');
|
||||
@ -354,7 +334,7 @@ Refine.DatabaseSourceUI.prototype._loadSavedConnections = function() {
|
||||
})
|
||||
|
||||
self._elmts.menuListUl.append(items.join(''));
|
||||
// self._elmts.scListGroupDiv.append(items.join(''));
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
@ -407,12 +387,10 @@ Refine.DatabaseSourceUI.prototype._connect = function(jdbcConnectionInfo) {
|
||||
+ jdbcConnectionInfo.databasePort + "/"
|
||||
+ jdbcConnectionInfo.initialDatabase;
|
||||
|
||||
//alert("connectionParam::" + connectionParam);
|
||||
|
||||
$( "#connectionParameterSpan" ).text(connectionParam);
|
||||
// self._body.find('.newConnectionDiv').hide();
|
||||
// self._body.find('.sqlEditorDiv').show();
|
||||
$( "#newConnectionDiv" ).hide();
|
||||
$( "#sqlEditorDiv" ).show();
|
||||
$( "#newConnectionDiv" ).hide();
|
||||
$( "#sqlEditorDiv" ).show();
|
||||
|
||||
}else{
|
||||
window.alert("Unable to establish connection to database");
|
||||
@ -428,20 +406,21 @@ Refine.DatabaseSourceUI.prototype._connect = function(jdbcConnectionInfo) {
|
||||
};
|
||||
|
||||
Refine.DatabaseSourceUI.prototype._getConnectionInfo = function() {
|
||||
var self = this;
|
||||
var jdbcConnectionInfo = {};
|
||||
jdbcConnectionInfo.connectionName = $.trim(self._elmts.connectionNameInput[0].value);
|
||||
jdbcConnectionInfo.databaseType = $.trim(self._elmts.databaseTypeSelect[0].value);
|
||||
jdbcConnectionInfo.databaseServer = $.trim(self._elmts.databaseHostInput[0].value);
|
||||
jdbcConnectionInfo.databasePort = $.trim(self._elmts.databasePortInput[0].value);
|
||||
jdbcConnectionInfo.databaseUser = $.trim(self._elmts.databaseUserInput[0].value);
|
||||
jdbcConnectionInfo.databasePassword = $.trim(self._elmts.databasePasswordInput[0].value);
|
||||
jdbcConnectionInfo.initialDatabase = $.trim(self._elmts.initialDatabaseInput[0].value);
|
||||
jdbcConnectionInfo.initialSchema = $.trim(self._elmts.initialSchemaInput[0].value);
|
||||
return jdbcConnectionInfo;
|
||||
var self = this;
|
||||
var jdbcConnectionInfo = {};
|
||||
jdbcConnectionInfo.connectionName = $.trim(self._elmts.connectionNameInput[0].value);
|
||||
jdbcConnectionInfo.databaseType = $.trim(self._elmts.databaseTypeSelect[0].value);
|
||||
jdbcConnectionInfo.databaseServer = $.trim(self._elmts.databaseHostInput[0].value);
|
||||
jdbcConnectionInfo.databasePort = $.trim(self._elmts.databasePortInput[0].value);
|
||||
jdbcConnectionInfo.databaseUser = $.trim(self._elmts.databaseUserInput[0].value);
|
||||
jdbcConnectionInfo.databasePassword = $.trim(self._elmts.databasePasswordInput[0].value);
|
||||
jdbcConnectionInfo.initialDatabase = $.trim(self._elmts.initialDatabaseInput[0].value);
|
||||
jdbcConnectionInfo.initialSchema = $.trim(self._elmts.initialSchemaInput[0].value);
|
||||
return jdbcConnectionInfo;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Refine.DatabaseSourceUI.prototype._validateNewConnectionForm = function() {
|
||||
|
||||
var self = this;
|
||||
@ -454,21 +433,36 @@ Refine.DatabaseSourceUI.prototype._validateNewConnectionForm = function() {
|
||||
var initialDatabaseInput = $.trim(self._elmts.initialDatabaseInput[0].value);
|
||||
var initialSchemaInput = $.trim(self._elmts.initialSchemaInput[0].value);
|
||||
|
||||
if (databaseHostInput.length === 0) {
|
||||
var alphaNumRE = /^[a-zA-Z0-9._-]*$/;
|
||||
var numRE = /^[0-9]*$/;
|
||||
|
||||
var alphaNumConnNameTestResult = alphaNumRE.test(connectionNameInput);
|
||||
var databaseHostTestResult = alphaNumRE.test(databaseHostInput);
|
||||
var databasePortTestResult = numRE.test(databasePortInput);
|
||||
var databaseUserTestResult = alphaNumRE.test(databaseUserInput);
|
||||
|
||||
if(alphaNumConnNameTestResult == false){
|
||||
window.alert($.i18n('database-source/alert-conn-name-invalid-character'));
|
||||
return false;
|
||||
}else if (databaseHostInput.length === 0) {
|
||||
window.alert($.i18n('database-source/alert-server'));
|
||||
return false;
|
||||
}else if(databasePortInput.length === 0){
|
||||
window.alert($.i18n('database-source/alert-port'));
|
||||
return false;
|
||||
window.alert($.i18n('database-source/alert-port'));
|
||||
return false;
|
||||
}else if(databaseUserInput.length === 0){
|
||||
window.alert($.i18n('database-source/alert-user'));
|
||||
return false;
|
||||
window.alert($.i18n('database-source/alert-user'));
|
||||
return false;
|
||||
}else if(initialDatabaseInput.length === 0){
|
||||
window.alert($.i18n('database-source/alert-initial-database'));
|
||||
return false;
|
||||
window.alert($.i18n('database-source/alert-initial-database'));
|
||||
return false;
|
||||
}else if(databasePortTestResult == false){
|
||||
window.alert($.i18n('database-source/alert-db-port-invalid-character'));
|
||||
return false;
|
||||
|
||||
}
|
||||
else{
|
||||
return true;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
@ -166,6 +166,13 @@
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.owasp.encoder</groupId>
|
||||
<artifactId>encoder</artifactId>
|
||||
<version>1.2.2</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
|
@ -314,7 +314,7 @@ public class DatabaseUtils {
|
||||
String fileSep = System.getProperty("file.separator");
|
||||
String filename = dir.getPath() + fileSep + DATABASE_EXTENSION_DIR + fileSep + SETTINGS_FILE_NAME;
|
||||
|
||||
// logger.info("** extension file name: {} **", filename);
|
||||
logger.debug("** extension file name: {} **", filename);
|
||||
return filename;
|
||||
}
|
||||
public static String getExtensionFolder(){
|
||||
|
@ -31,12 +31,15 @@ package com.google.refine.extension.database.cmd;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.owasp.encoder.Encode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -50,6 +53,9 @@ public class SavedConnectionCommand extends DatabaseCommand {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("SavedConnectionCommand");
|
||||
|
||||
private static final Pattern CONN_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9._-]*");
|
||||
private static final Pattern DATABASE_PORT_PATTERN = Pattern.compile("^[0-9]*");
|
||||
|
||||
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
@ -126,26 +132,24 @@ public class SavedConnectionCommand extends DatabaseCommand {
|
||||
writer.writeArrayFieldStart(DatabaseUtils.SAVED_CONNECTION_KEY);
|
||||
|
||||
writer.writeStartObject();
|
||||
writer.writeStringField("connectionName", savedConnection.getConnectionName());
|
||||
|
||||
|
||||
writer.writeStringField("connectionName", savedConnection.getConnectionName());
|
||||
writer.writeStringField("databaseType", savedConnection.getDatabaseType());
|
||||
|
||||
writer.writeStringField("databaseHost", savedConnection.getDatabaseHost());
|
||||
|
||||
writer.writeNumberField("databasePort", savedConnection.getDatabasePort());
|
||||
|
||||
writer.writeStringField("databaseName", savedConnection.getDatabaseName());
|
||||
|
||||
|
||||
|
||||
String dbPasswd = savedConnection.getDatabasePassword();
|
||||
if(dbPasswd != null && !dbPasswd.isEmpty()) {
|
||||
dbPasswd = DatabaseUtils.decrypt(savedConnection.getDatabasePassword());
|
||||
}
|
||||
writer.writeStringField("databasePassword", dbPasswd);
|
||||
|
||||
writer.writeStringField("databaseSchema", savedConnection.getDatabaseSchema());
|
||||
|
||||
writer.writeStringField("databaseSchema", savedConnection.getDatabaseSchema());
|
||||
writer.writeStringField("databaseUser", savedConnection.getDatabaseUser());
|
||||
|
||||
|
||||
writer.writeEndObject();
|
||||
writer.writeEndArray();
|
||||
|
||||
@ -228,6 +232,7 @@ public class SavedConnectionCommand extends DatabaseCommand {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("doPost Connection: {}", request.getParameter("connectionName"));
|
||||
}
|
||||
|
||||
|
||||
DatabaseConfiguration jdbcConfig = getJdbcConfiguration(request);
|
||||
|
||||
@ -240,6 +245,21 @@ public class SavedConnectionCommand extends DatabaseCommand {
|
||||
response.flushBuffer();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!validateInput(jdbcConfig.getConnectionName(), CONN_NAME_PATTERN)) {
|
||||
logger.warn("Invalid Connection Name: {}", jdbcConfig.getConnectionName());
|
||||
response.sendError(HttpStatus.SC_BAD_REQUEST, "Connection Name is Invalid. Expecting [a-zA-Z0-9._-]");
|
||||
response.flushBuffer();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!validateInput("" + jdbcConfig.getDatabasePort(), DATABASE_PORT_PATTERN)) {
|
||||
logger.warn("Invalid Database Port: {}", jdbcConfig.getDatabasePort());
|
||||
response.sendError(HttpStatus.SC_BAD_REQUEST, "Database Port Invalid. Expecting Numeric values only");
|
||||
response.flushBuffer();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
DatabaseConfiguration savedConn = DatabaseUtils.getSavedConnection(jdbcConfig.getConnectionName());
|
||||
if(savedConn != null) {
|
||||
@ -266,8 +286,14 @@ public class SavedConnectionCommand extends DatabaseCommand {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private boolean validateInput(String input, Pattern pattern){
|
||||
Matcher matcher = pattern.matcher(input);
|
||||
if(matcher.matches()){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPut(HttpServletRequest request, HttpServletResponse response)
|
||||
|
@ -1,6 +1,10 @@
|
||||
package com.google.refine.extension.database.cmd;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -11,6 +15,7 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.testng.Assert;
|
||||
@ -154,8 +159,11 @@ public class SavedConnectionCommandTest extends DBExtensionTests{
|
||||
SUT.doPost(request, response);
|
||||
|
||||
String result = sw.getBuffer().toString().trim();
|
||||
|
||||
assertNotNull(result);
|
||||
assertFalse(result.isEmpty(), "Valid response Message expected!");
|
||||
|
||||
ObjectNode json = ParsingUtilities.mapper.readValue(result, ObjectNode.class);
|
||||
// System.out.println("json:" + json);
|
||||
|
||||
ArrayNode savedConnections = (ArrayNode) json.get("savedConnections");
|
||||
Assert.assertNotNull(savedConnections);
|
||||
@ -229,7 +237,6 @@ public class SavedConnectionCommandTest extends DBExtensionTests{
|
||||
Assert.assertEquals(savedConnections.size(), 1);
|
||||
|
||||
ObjectNode sc = (ObjectNode)savedConnections.get(0);
|
||||
System.out.println("sc" + sc);
|
||||
String newDbHost = sc.get("databaseHost").asText();
|
||||
Assert.assertEquals(newDbHost, newHost);
|
||||
}
|
||||
@ -276,8 +283,6 @@ public class SavedConnectionCommandTest extends DBExtensionTests{
|
||||
|
||||
SUT.doDelete(request, response);
|
||||
|
||||
// String result = sw.getBuffer().toString().trim();
|
||||
|
||||
ObjectNode json = ParsingUtilities.mapper.createObjectNode();
|
||||
|
||||
Assert.assertNotNull(json);
|
||||
@ -288,5 +293,34 @@ public class SavedConnectionCommandTest extends DBExtensionTests{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Added to check XSS invalid tokens
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Test
|
||||
public void testDoPostInvalidConnectionName() throws IOException, ServletException {
|
||||
|
||||
when(request.getParameter("connectionName")).thenReturn("<img></img>");
|
||||
when(request.getParameter("databaseType")).thenReturn(MySQLDatabaseService.DB_NAME);
|
||||
when(request.getParameter("databaseServer")).thenReturn(testDbConfig.getDatabaseHost());
|
||||
when(request.getParameter("databasePort")).thenReturn("" + testDbConfig.getDatabasePort());
|
||||
when(request.getParameter("databaseUser")).thenReturn(testDbConfig.getDatabaseUser());
|
||||
when(request.getParameter("databasePassword")).thenReturn(testDbConfig.getDatabasePassword());
|
||||
when(request.getParameter("initialDatabase")).thenReturn(testDbConfig.getDatabaseName());
|
||||
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
|
||||
when(response.getWriter()).thenReturn(pw);
|
||||
|
||||
SUT.doPost(request, response);
|
||||
|
||||
verify(response, times(1)).sendError(HttpStatus.SC_BAD_REQUEST, "Connection Name is Invalid. Expecting [a-zA-Z0-9._-]");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user