Browse Source

Add xsrf token header if cookie is present (#11040)

Fixes #9471
tags/7.7.14
Ilia Motornyi 5 years ago
parent
commit
11fcfa5a5d

+ 2
- 0
client/src/main/java/com/vaadin/client/communication/Heartbeat.java View File

@@ -90,6 +90,8 @@ public class Heartbeat {

final RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, uri);

XhrConnection.addXsrfHeaderFromCookie(rb);

final RequestCallback callback = new RequestCallback() {

@Override

+ 14
- 0
client/src/main/java/com/vaadin/client/communication/XhrConnection.java View File

@@ -22,6 +22,7 @@ import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.Window.ClosingEvent;
@@ -51,6 +52,9 @@ import elemental.json.JsonObject;
*/
public class XhrConnection {

private static final String XSRF_HEADER_NAME = "X-XSRF-TOKEN";
private static final String XSRF_COOKIE_NAME = "XSRF-TOKEN";

private ApplicationConnection connection;

/**
@@ -189,6 +193,9 @@ public class XhrConnection {
*/
public void send(JsonObject payload) {
RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, getUri());

addXsrfHeaderFromCookie(rb);

// TODO enable timeout
// rb.setTimeoutMillis(timeoutMillis);
// TODO this should be configurable
@@ -250,6 +257,13 @@ public class XhrConnection {
return connection.getMessageHandler();
}

public static void addXsrfHeaderFromCookie(RequestBuilder rb) {
String xsrfTokenVal = Cookies.getCookie(XSRF_COOKIE_NAME);
if (xsrfTokenVal != null && !xsrfTokenVal.isEmpty()) {
rb.setHeader(XSRF_HEADER_NAME, xsrfTokenVal);
}
}

private static native boolean resendRequest(Request request)
/*-{
var xhr = request.@com.google.gwt.http.client.Request::xmlHttpRequest

+ 108
- 100
server/src/main/resources/VAADIN/vaadinBootstrap.js View File

@@ -2,8 +2,8 @@
var apps = {};
var themesLoaded = {};
var widgetsets = {};
var log;
if (typeof console === "undefined" || !window.location.search.match(/[&?]debug(&|$)/)) {
//If no console.log present, just use a no-op
@@ -17,30 +17,35 @@
//In IE, its a native function for which apply is not defined, but it works without a proper 'this' reference
log = console.log;
}
var loadTheme = function(url, version) {
if(!themesLoaded[url]) {
log("loadTheme", url, version);
var href = url + '/styles.css';
if (version) {
href += '?v=' + version;
}
var stylesheet = document.createElement('link');
stylesheet.setAttribute('rel', 'stylesheet');
stylesheet.setAttribute('type', 'text/css');
stylesheet.setAttribute('href', href);
document.getElementsByTagName('head')[0].appendChild(stylesheet);
themesLoaded[url] = true;
}
}
};
var isWidgetsetLoaded = function(widgetset) {

var getCookie = function (cname) {
var b = document.cookie.match('(^|;)\\s*' + cname + '\\s*=\\s*([^;]+)');
return b ? b.pop() : '';
};

var isWidgetsetLoaded = function(widgetset) {
var className = widgetset.replace(/\./g, "_");
return (typeof window[className]) != "undefined";
};
var loadWidgetset = function(url, widgetset, ready) {
if (widgetsets[widgetset]) {
return;
@@ -60,12 +65,12 @@
}
}
}, 15000);
var scriptTag = document.createElement('script');
scriptTag.setAttribute('type', 'text/javascript');
scriptTag.setAttribute('src', url);
document.getElementsByTagName('head')[0].appendChild(scriptTag);
widgetsets[widgetset] = {
pendingApps: []
};
@@ -79,7 +84,7 @@
for ( var i = 0; i < appDiv.childElementCount; i++) {
var className = appDiv.childNodes[i].className;
// If the app div contains a child with the class
// "v-app-loading" we have only received the HTML
// "v-app-loading" we have only received the HTML
// but not yet started the widget set
// (UIConnector removes the v-app-loading div).
if (className && className.indexOf("v-app-loading") != -1) {
@@ -92,7 +97,7 @@
window.vaadin = window.vaadin || {
initApplication: function(appId, config) {
var testbenchId = appId.replace(/-\d+$/, '');
if (apps[appId]) {
if (window.vaadin && window.vaadin.clients && window.vaadin.clients[testbenchId] && window.vaadin.clients[testbenchId].initializing) {
throw "Application " + appId + " is already being initialized";
@@ -103,19 +108,19 @@
}

log("init application", appId, config);
window.vaadin.clients[testbenchId] = {
isActive: function() {
return true;
},
initializing: true
};
var getConfig = function(name) {
var value = config[name];
return value;
};
var fetchRootConfig = function(callback) {
log('Fetching root config');
var url = getConfig('browserDetailsUrl');
@@ -124,8 +129,8 @@
url = window.location.href.replace(/#.*/,'');
}
// Timestamp to avoid caching
url += ((/\?/).test(url) ? "&" : "?") + "v-" + (new Date()).getTime();
url += ((/\?/).test(url) ? "&" : "?") + "v-" + (new Date()).getTime();
var params = "v-browserDetails=1";
var rootId = getConfig("v-rootId");
if (rootId !== undefined) {
@@ -137,16 +142,16 @@
if (theme !== undefined) {
params += '&theme=' + encodeURIComponent(theme);
}
params += "&v-appId=" + appId;
var extraParams = getConfig('extraParams')
if (extraParams !== undefined) {
params += extraParams;
}
params += '&' + vaadin.getBrowserDetailsParameters(appId, getConfig('sendUrlsAsParameters'));
params += '&' + vaadin.getBrowserDetailsParameters(appId, getConfig('sendUrlsAsParameters'));
var r;
try {
r = new XMLHttpRequest();
@@ -154,7 +159,7 @@
r = new ActiveXObject("MSXML2.XMLHTTP.3.0");
}
r.open('POST', url, true);
r.onreadystatechange = function (aEvt) {
r.onreadystatechange = function (aEvt) {
if (r.readyState == 4) {
// Save responseStatus so as Offline Applications know what happened
// when loading root configuration from server, and depending on the
@@ -166,91 +171,94 @@
if (r.status == 200){
log("Got root config response", text);
var updatedConfig = JSON.parse(text);
// Copy new properties to the config object
for (var property in updatedConfig) {
if (updatedConfig.hasOwnProperty(property)) {
config[property] = updatedConfig[property];
}
}
// Try bootstrapping again, this time without fetching missing info
bootstrapApp(false);
} else {
log('Error', r.statusText, text);
//Let TB waitForVaadin work again
delete window.vaadin.clients[testbenchId];
// Show the error in the app's div
var appDiv = document.getElementById(appId);
appDiv.innerHTML = text;
appDiv.style['overflow'] = 'auto';
}

// Run the fetchRootConfig callback if present.
callback && callback(r);
}
};
// send parameters as POST data
r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
r.send(params);
log('sending request to ', url);
};
//Export public data
var app = {
getConfig: getConfig,
// Used when the app was started in offline, so as it is possible
// to defer root configuration loading until network is available.
fetchRootConfig: fetchRootConfig
};
apps[appId] = app;
if (!window.name) {
window.name = appId + '-' + Math.random();
}
var bootstrapApp = function(mayDefer) {
var vaadinDir = getConfig('vaadinDir');
var versionInfo = getConfig('versionInfo');
var themeUri = vaadinDir + 'themes/' + getConfig('theme');
loadTheme(themeUri, versionInfo && versionInfo['vaadinVersion']);
var widgetset = getConfig('widgetset');
var widgetsetUrl = getConfig('widgetsetUrl');
if (!widgetsetUrl) {
widgetsetUrl = vaadinDir + 'widgetsets/' + widgetset + "/" + widgetset + ".nocache.js?" + new Date().getTime();
}
var widgetsetReady = getConfig('widgetsetReady');
loadWidgetset(widgetsetUrl, widgetset, widgetsetReady);
if (getConfig('uidl') === undefined) {
if (mayDefer) {
fetchRootConfig();
} else {
throw "May not defer bootstrap any more";
}
} else {
if (widgetsets[widgetset].callback) {
log("Starting from bootstrap", appId);
widgetsets[widgetset].callback(appId);
} else {
log("Setting pending startup", appId);
widgetsets[widgetset].pendingApps.push(appId);
}
}
};
bootstrapApp(true);
// Run the fetchRootConfig callback if present.
callback && callback(r);
}
};
// send parameters as POST data
r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var xsrfToken = getCookie("XSRF-TOKEN");
if (xsrfToken && xsrfToken.length > 0) {
r.setRequestHeader("X-XSRF-TOKEN", xsrfToken);
}r.send(params);

log('sending request to ', url);
};

//Export public data
var app = {
getConfig: getConfig,
// Used when the app was started in offline, so as it is possible
// to defer root configuration loading until network is available.
fetchRootConfig: fetchRootConfig
};
apps[appId] = app;

if (!window.name) {
window.name = appId + '-' + Math.random();
}

var bootstrapApp = function (mayDefer) {
var vaadinDir = getConfig('vaadinDir');

var versionInfo = getConfig('versionInfo');

var themeUri = vaadinDir + 'themes/' + getConfig('theme');
loadTheme(themeUri, versionInfo && versionInfo['vaadinVersion']);

var widgetset = getConfig('widgetset');
var widgetsetUrl = getConfig('widgetsetUrl');
if (!widgetsetUrl) {
widgetsetUrl = vaadinDir + 'widgetsets/' + widgetset + "/" + widgetset + ".nocache.js?" + new Date().getTime();
}
var widgetsetReady = getConfig('widgetsetReady');
loadWidgetset(widgetsetUrl, widgetset, widgetsetReady);

if (getConfig('uidl') === undefined) {
if (mayDefer) {
fetchRootConfig();
} else {
throw "May not defer bootstrap any more";
}
} else {
if (widgetsets[widgetset].callback) {
log("Starting from bootstrap", appId);
widgetsets[widgetset].callback(appId);
} else {
log("Setting pending startup", appId);
widgetsets[widgetset].pendingApps.push(appId);
}
}
};
bootstrapApp(true);

if (getConfig("debug")) {
// TODO debug state is now global for the entire page, but should somehow only be set for the current application
// TODO debug state is now global for the entire page, but should somehow only be set for the current application
window.vaadin.debug = true;
}
return app;
},
clients: {},
@@ -284,7 +292,7 @@
// Screen height and width
var params = 'v-sh=' + window.screen.height;
params += '&v-sw=' + window.screen.width;
// Window height and width
var cw = 0;
var ch = 0;
@@ -298,16 +306,16 @@
ch = document.documentElement.clientHeight;
}
params += '&v-cw=' + cw + '&v-ch=' + ch;

var d = new Date();
params += '&v-curdate=' + d.getTime();
var tzo1 = d.getTimezoneOffset(); // current offset
var dstDiff = 0;
var rtzo = tzo1;
for (var m=12;m>0;m--) {
d.setUTCMonth(m);
var tzo2 = d.getTimezoneOffset();
@@ -320,22 +328,22 @@

// Time zone offset
params += '&v-tzo=' + tzo1;
// DST difference
params += '&v-dstd=' + dstDiff;
// Raw time zone offset
params += '&v-rtzo=' + rtzo;
// DST in effect?
params += '&v-dston=' + (tzo1 != rtzo);
var pe = document.getElementById(parentElementId);
if (pe) {
params += '&v-vw=' + pe.offsetWidth;
params += '&v-vh=' + pe.offsetHeight;
}
// Location
if (sendUrlsAsParameters !== false) {
params += '&v-loc=' + encodeURIComponent(location.href);
@@ -345,7 +353,7 @@
if (window.name) {
params += '&v-wn=' + encodeURIComponent(window.name);
}
// Detect touch device support
var supportsTouch = false;
try {
@@ -360,10 +368,10 @@
if (supportsTouch) {
params += "&v-td=1";
}
return params;
}
};
log('Vaadin bootstrap loaded');
})();

Loading…
Cancel
Save