CSRF protection for Wikidata extension
This commit is contained in:
parent
24feda600a
commit
1ee5068f0d
@ -56,7 +56,7 @@ ManageAccountDialog.display = function(logged_in_username, saved_credentials, ca
|
|||||||
|
|
||||||
elmts.loginButton.click(function() {
|
elmts.loginButton.click(function() {
|
||||||
frame.hide();
|
frame.hide();
|
||||||
$.post(
|
Refine.postCSRF(
|
||||||
"command/wikidata/login",
|
"command/wikidata/login",
|
||||||
elmts.loginForm.serialize(),
|
elmts.loginForm.serialize(),
|
||||||
function(data) {
|
function(data) {
|
||||||
@ -71,7 +71,7 @@ ManageAccountDialog.display = function(logged_in_username, saved_credentials, ca
|
|||||||
});
|
});
|
||||||
|
|
||||||
elmts.logoutButton.click(function() {
|
elmts.logoutButton.click(function() {
|
||||||
$.post(
|
Refine.postCSRF(
|
||||||
"command/wikidata/login",
|
"command/wikidata/login",
|
||||||
"logout=true",
|
"logout=true",
|
||||||
function(data) {
|
function(data) {
|
||||||
|
@ -94,7 +94,7 @@ PerformEditsDialog.checkAndLaunch = function () {
|
|||||||
ManageAccountDialog.ensureLoggedIn(function(logged_in_username) {
|
ManageAccountDialog.ensureLoggedIn(function(logged_in_username) {
|
||||||
if (logged_in_username) {
|
if (logged_in_username) {
|
||||||
var discardWaiter = DialogSystem.showBusy($.i18n('perform-wikidata-edits/analyzing-edits'));
|
var discardWaiter = DialogSystem.showBusy($.i18n('perform-wikidata-edits/analyzing-edits'));
|
||||||
$.post(
|
Refine.postCSRF(
|
||||||
"command/wikidata/preview-wikibase-schema?" + $.param({ project: theProject.id }),
|
"command/wikidata/preview-wikibase-schema?" + $.param({ project: theProject.id }),
|
||||||
{ engine: JSON.stringify(ui.browsingEngine.getJSON()) },
|
{ engine: JSON.stringify(ui.browsingEngine.getJSON()) },
|
||||||
function(data) {
|
function(data) {
|
||||||
|
@ -1283,7 +1283,7 @@ SchemaAlignmentDialog.preview = function() {
|
|||||||
$('.invalid-schema-warning').show();
|
$('.invalid-schema-warning').show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$.post(
|
Refine.postCSRF(
|
||||||
"command/wikidata/preview-wikibase-schema?" + $.param({ project: theProject.id }),
|
"command/wikidata/preview-wikibase-schema?" + $.param({ project: theProject.id }),
|
||||||
{ schema: JSON.stringify(schema), engine: JSON.stringify(ui.browsingEngine.getJSON()) },
|
{ schema: JSON.stringify(schema), engine: JSON.stringify(ui.browsingEngine.getJSON()) },
|
||||||
function(data) {
|
function(data) {
|
||||||
|
@ -41,6 +41,11 @@ public class LoginCommand extends Command {
|
|||||||
@Override
|
@Override
|
||||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
if(!hasValidCSRFToken(request)) {
|
||||||
|
respondCSRFError(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String username = request.getParameter("wb-username");
|
String username = request.getParameter("wb-username");
|
||||||
String password = request.getParameter("wb-password");
|
String password = request.getParameter("wb-password");
|
||||||
String remember = request.getParameter("remember-credentials");
|
String remember = request.getParameter("remember-credentials");
|
||||||
|
@ -46,6 +46,13 @@ import com.google.refine.model.Project;
|
|||||||
|
|
||||||
public class PreviewWikibaseSchemaCommand extends Command {
|
public class PreviewWikibaseSchemaCommand extends Command {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This command uses POST but is left CSRF-unprotected since it does not
|
||||||
|
* incur a side effect or state change in the backend.
|
||||||
|
* The reason why it uses POST is to make sure large schemas and engines
|
||||||
|
* can be passed as parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
@ -46,6 +46,10 @@ public class SaveWikibaseSchemaCommand extends Command {
|
|||||||
@Override
|
@Override
|
||||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
if(!hasValidCSRFToken(request)) {
|
||||||
|
respondCSRFError(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Project project = getProject(request);
|
Project project = getProject(request);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.openrefine.wikidata.commands;
|
package org.openrefine.wikidata.commands;
|
||||||
|
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -9,6 +10,9 @@ import javax.servlet.ServletException;
|
|||||||
import org.testng.annotations.BeforeMethod;
|
import org.testng.annotations.BeforeMethod;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.refine.commands.Command;
|
||||||
|
import com.google.refine.util.TestUtils;
|
||||||
|
|
||||||
public class LoginCommandTest extends CommandTest {
|
public class LoginCommandTest extends CommandTest {
|
||||||
|
|
||||||
@BeforeMethod
|
@BeforeMethod
|
||||||
@ -18,8 +22,16 @@ public class LoginCommandTest extends CommandTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoCredentials() throws ServletException, IOException {
|
public void testNoCredentials() throws ServletException, IOException {
|
||||||
|
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||||
|
|
||||||
command.doPost(request, response);
|
command.doPost(request, response);
|
||||||
|
|
||||||
assertEquals("{\"logged_in\":false,\"username\":null}", writer.toString());
|
assertEquals("{\"logged_in\":false,\"username\":null}", writer.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCsrfProtection() throws ServletException, IOException {
|
||||||
|
command.doPost(request, response);
|
||||||
|
TestUtils.assertEqualAsJson("{\"code\":\"error\",\"message\":\"Missing or invalid csrf_token parameter\"}", writer.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,9 @@ import javax.servlet.ServletException;
|
|||||||
import org.testng.annotations.BeforeMethod;
|
import org.testng.annotations.BeforeMethod;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.refine.commands.Command;
|
||||||
|
import com.google.refine.util.TestUtils;
|
||||||
|
|
||||||
public class SaveWikibaseSchemaCommandTest extends SchemaCommandTest {
|
public class SaveWikibaseSchemaCommandTest extends SchemaCommandTest {
|
||||||
|
|
||||||
@BeforeMethod
|
@BeforeMethod
|
||||||
@ -44,6 +47,8 @@ public class SaveWikibaseSchemaCommandTest extends SchemaCommandTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testValidSchema()
|
public void testValidSchema()
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||||
|
|
||||||
String schemaJson = jsonFromFile("schema/inception.json").toString();
|
String schemaJson = jsonFromFile("schema/inception.json").toString();
|
||||||
when(request.getParameter("schema")).thenReturn(schemaJson);
|
when(request.getParameter("schema")).thenReturn(schemaJson);
|
||||||
|
|
||||||
@ -54,6 +59,8 @@ public class SaveWikibaseSchemaCommandTest extends SchemaCommandTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidSchema() throws ServletException, IOException {
|
public void testInvalidSchema() throws ServletException, IOException {
|
||||||
|
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||||
|
|
||||||
String schemaJson = "{\"itemDocuments\":[{\"statementGroups\":[{\"statements\":[]}],"
|
String schemaJson = "{\"itemDocuments\":[{\"statementGroups\":[{\"statements\":[]}],"
|
||||||
+"\"nameDescs\":[]}],\"wikibasePrefix\":\"http://www.wikidata.org/entity/\"}";
|
+"\"nameDescs\":[]}],\"wikibasePrefix\":\"http://www.wikidata.org/entity/\"}";
|
||||||
|
|
||||||
@ -62,4 +69,13 @@ public class SaveWikibaseSchemaCommandTest extends SchemaCommandTest {
|
|||||||
|
|
||||||
assertTrue(writer.toString().contains("\"error\""));
|
assertTrue(writer.toString().contains("\"error\""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCsrfProtection() throws ServletException, IOException {
|
||||||
|
String schemaJson = jsonFromFile("schema/inception.json").toString();
|
||||||
|
when(request.getParameter("schema")).thenReturn(schemaJson);
|
||||||
|
|
||||||
|
command.doPost(request, response);
|
||||||
|
TestUtils.assertEqualAsJson("{\"code\":\"error\",\"message\":\"Missing or invalid csrf_token parameter\"}", writer.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import javax.servlet.ServletException;
|
|||||||
|
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.refine.commands.Command;
|
||||||
import com.google.refine.util.ParsingUtilities;
|
import com.google.refine.util.ParsingUtilities;
|
||||||
|
|
||||||
public abstract class SchemaCommandTest extends CommandTest {
|
public abstract class SchemaCommandTest extends CommandTest {
|
||||||
@ -39,9 +40,11 @@ public abstract class SchemaCommandTest extends CommandTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testNoSchema()
|
public void testNoSchema()
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||||
|
|
||||||
command.doPost(request, response);
|
command.doPost(request, response);
|
||||||
|
|
||||||
assertEquals("{\"code\":\"error\",\"message\":\"No Wikibase schema provided.\"}", writer.toString());
|
assertEquals(writer.toString(), "{\"code\":\"error\",\"message\":\"No Wikibase schema provided.\"}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -56,7 +56,11 @@ Refine.wrapCSRF = function(onCSRF) {
|
|||||||
Refine.postCSRF = function(url, data, success, dataType, failCallback) {
|
Refine.postCSRF = function(url, data, success, dataType, failCallback) {
|
||||||
return Refine.wrapCSRF(function(token) {
|
return Refine.wrapCSRF(function(token) {
|
||||||
var fullData = data || {};
|
var fullData = data || {};
|
||||||
fullData['csrf_token'] = token;
|
if (typeof fulldata == 'string') {
|
||||||
|
fullData = fullData + $.param({csrf_token: token});
|
||||||
|
} else {
|
||||||
|
fullData['csrf_token'] = token;
|
||||||
|
}
|
||||||
var req = $.post(url, fullData, success, dataType);
|
var req = $.post(url, fullData, success, dataType);
|
||||||
if (failCallback !== undefined) {
|
if (failCallback !== undefined) {
|
||||||
req.fail(failCallback);
|
req.fail(failCallback);
|
||||||
|
@ -55,7 +55,11 @@ Refine.wrapCSRF = function(onCSRF) {
|
|||||||
Refine.postCSRF = function(url, data, success, dataType, failCallback) {
|
Refine.postCSRF = function(url, data, success, dataType, failCallback) {
|
||||||
return Refine.wrapCSRF(function(token) {
|
return Refine.wrapCSRF(function(token) {
|
||||||
var fullData = data || {};
|
var fullData = data || {};
|
||||||
fullData['csrf_token'] = token;
|
if (typeof fulldata == 'string') {
|
||||||
|
fullData = fullData + $.param({csrf_token: token});
|
||||||
|
} else {
|
||||||
|
fullData['csrf_token'] = token;
|
||||||
|
}
|
||||||
var req = $.post(url, fullData, success, dataType);
|
var req = $.post(url, fullData, success, dataType);
|
||||||
if (failCallback !== undefined) {
|
if (failCallback !== undefined) {
|
||||||
req.fail(failCallback);
|
req.fail(failCallback);
|
||||||
|
@ -420,7 +420,11 @@ Refine.wrapCSRF = function(onCSRF) {
|
|||||||
Refine.postCSRF = function(url, data, success, dataType) {
|
Refine.postCSRF = function(url, data, success, dataType) {
|
||||||
Refine.wrapCSRF(function(token) {
|
Refine.wrapCSRF(function(token) {
|
||||||
var fullData = data || {};
|
var fullData = data || {};
|
||||||
fullData['csrf_token'] = token;
|
if (typeof fulldata == 'string') {
|
||||||
|
fullData = fullData + $.param({csrf_token: token});
|
||||||
|
} else {
|
||||||
|
fullData['csrf_token'] = token;
|
||||||
|
}
|
||||||
$.post(url, fullData, success, dataType);
|
$.post(url, fullData, success, dataType);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user