*
@@ -150,7 +150,7 @@ export default {
selectedAccounts: [],
selectedProjects: [],
selectedAccountsList: '',
- selectedOperation: this.$t('label.add'),
+ selectedOperation: 'add',
selectedShareWith: this.$t('label.account'),
accountError: false,
projectError: false,
@@ -163,7 +163,7 @@ export default {
accountsList () {
return this.accounts.length > 0 ? this.accounts
.filter(a =>
- this.selectedOperation === this.$t('label.add')
+ this.selectedOperation === 'add'
? !this.permittedAccounts.includes(a.name)
: this.permittedAccounts.includes(a.name)
) : this.accounts
@@ -171,7 +171,7 @@ export default {
projectsList () {
return this.projects > 0 ? this.projects
.filter(p =>
- this.selectedOperation === this.$t('label.add')
+ this.selectedOperation === 'add'
? !this.permittedProjects.includes(p.id)
: this.permittedProjects.includes(p.id)
) : this.projects
@@ -252,7 +252,7 @@ export default {
})
},
handleChange (selectedItems) {
- if (this.selectedOperation === this.$t('label.add') || this.selectedOperation === this.$t('label.remove')) {
+ if (this.selectedOperation === 'add' || this.selectedOperation === 'remove') {
if (this.selectedShareWith === this.$t('label.account')) {
this.selectedAccounts = selectedItems
} else {
diff --git a/ui/src/views/infra/UpdatePrimaryStorage.vue b/ui/src/views/infra/UpdatePrimaryStorage.vue
index 7c026630a99..16de255a988 100644
--- a/ui/src/views/infra/UpdatePrimaryStorage.vue
+++ b/ui/src/views/infra/UpdatePrimaryStorage.vue
@@ -121,7 +121,6 @@ export default {
},
created () {
this.initForm()
- this.form.name = this.resource.name
},
computed: {
canUpdateNFSMountOpts () {
@@ -136,7 +135,14 @@ export default {
methods: {
initForm () {
this.formRef = ref()
- this.form = reactive({ })
+ this.form = reactive({
+ name: this.resource.name,
+ tags: this.resource.tags,
+ isTagARule: this.resource.istagarule,
+ capacityBytes: this.resource.disksizetotal,
+ capacityIOPS: this.resource.capacityiops,
+ nfsMountOpts: this.resource.nfsmountopts
+ })
this.rules = reactive({ })
},
isAdmin () {
diff --git a/ui/tests/unit/components/view/ActionButton.spec.js b/ui/tests/unit/components/view/ActionButton.spec.js
index 7e41f0bd2f8..1565b471548 100644
--- a/ui/tests/unit/components/view/ActionButton.spec.js
+++ b/ui/tests/unit/components/view/ActionButton.spec.js
@@ -23,6 +23,16 @@ import mockData from '../../../mockData/ActionButton.mock.json'
import ActionButton from '@/components/view/ActionButton'
jest.mock('axios', () => mockAxios)
+jest.mock('@/vue-app', () => ({
+ vueProps: {
+ $localStorage: {
+ set: jest.fn((key, value) => {}),
+ get: jest.fn((key) => {
+ return null
+ })
+ }
+ }
+}))
let router, store, i18n
const state = {
diff --git a/ui/tests/unit/views/compute/MigrateWizard.spec.js b/ui/tests/unit/views/compute/MigrateWizard.spec.js
index f352b2de2c4..d3ee49426dc 100644
--- a/ui/tests/unit/views/compute/MigrateWizard.spec.js
+++ b/ui/tests/unit/views/compute/MigrateWizard.spec.js
@@ -23,6 +23,16 @@ import mockData from '../../../mockData/MigrateWizard.mock'
import MigrateWizard from '@/views/compute/MigrateWizard'
jest.mock('axios', () => mockAxios)
+jest.mock('@/vue-app', () => ({
+ vueProps: {
+ $localStorage: {
+ set: jest.fn((key, value) => {}),
+ get: jest.fn((key) => {
+ return null
+ })
+ }
+ }
+}))
let i18n
let store
diff --git a/ui/vue.config.js b/ui/vue.config.js
index c74218b4bcf..9cae2ff66fb 100644
--- a/ui/vue.config.js
+++ b/ui/vue.config.js
@@ -142,7 +142,11 @@ const vueConfig = {
secure: false,
ws: false,
changeOrigin: true,
- proxyTimeout: 10 * 60 * 1000 // 10 minutes
+ proxyTimeout: 10 * 60 * 1000, // 10 minutes
+ cookieDomainRewrite: '*',
+ cookiePathRewrite: {
+ '/client': '/'
+ }
}
},
https: process.env.HTTPS_KEY ? {
diff --git a/usage/pom.xml b/usage/pom.xml
index 13c3fc30ebb..1dbd8ce64de 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -24,7 +24,7 @@
org.apache.cloudstack
cloudstack
- 4.20.0.0-SNAPSHOT
+ 4.20.0.0
diff --git a/utils/pom.xml b/utils/pom.xml
index 66257e87d4b..43dc6690d58 100755
--- a/utils/pom.xml
+++ b/utils/pom.xml
@@ -24,7 +24,7 @@
org.apache.cloudstack
cloudstack
- 4.20.0.0-SNAPSHOT
+ 4.20.0.0
../pom.xml
diff --git a/utils/src/main/java/com/cloud/utils/HttpUtils.java b/utils/src/main/java/com/cloud/utils/HttpUtils.java
index 434296c1900..1cbc4c79c17 100644
--- a/utils/src/main/java/com/cloud/utils/HttpUtils.java
+++ b/utils/src/main/java/com/cloud/utils/HttpUtils.java
@@ -38,6 +38,14 @@ public class HttpUtils {
public static final String JSON_CONTENT_TYPE = "application/json; charset=UTF-8";
public static final String XML_CONTENT_TYPE = "text/xml; charset=UTF-8";
+ public enum ApiSessionKeySameSite {
+ Lax, Strict, NoneAndSecure, Null
+ }
+
+ public enum ApiSessionKeyCheckOption {
+ CookieOrParameter, ParameterOnly, CookieAndParameter
+ }
+
public static void addSecurityHeaders(final HttpServletResponse resp) {
if (resp.containsHeader("X-Content-Type-Options")) {
resp.setHeader("X-Content-Type-Options", "nosniff");
@@ -104,23 +112,43 @@ public class HttpUtils {
return null;
}
- public static boolean validateSessionKey(final HttpSession session, final Map params, final Cookie[] cookies, final String sessionKeyString) {
+ public static boolean validateSessionKey(final HttpSession session, final Map params, final Cookie[] cookies, final String sessionKeyString, final ApiSessionKeyCheckOption apiSessionKeyCheckLocations) {
if (session == null || sessionKeyString == null) {
return false;
}
+ final String jsessionidFromCookie = HttpUtils.findCookie(cookies, "JSESSIONID");
+ if (jsessionidFromCookie != null
+ && !(jsessionidFromCookie.equals(session.getId()) || jsessionidFromCookie.startsWith(session.getId() + '.'))) {
+ LOGGER.error("JSESSIONID from cookie is invalid.");
+ return false;
+ }
final String sessionKey = (String) session.getAttribute(sessionKeyString);
+ if (sessionKey == null) {
+ LOGGER.error("sessionkey attribute of the session is null.");
+ return false;
+ }
final String sessionKeyFromCookie = HttpUtils.findCookie(cookies, sessionKeyString);
+ boolean isSessionKeyFromCookieValid = sessionKeyFromCookie != null && sessionKey.equals(sessionKeyFromCookie);
+
String[] sessionKeyFromParams = null;
if (params != null) {
sessionKeyFromParams = (String[]) params.get(sessionKeyString);
}
- if ((sessionKey == null)
- || (sessionKeyFromParams == null && sessionKeyFromCookie == null)
- || (sessionKeyFromParams != null && !sessionKey.equals(sessionKeyFromParams[0]))
- || (sessionKeyFromCookie != null && !sessionKey.equals(sessionKeyFromCookie))) {
- return false;
+ boolean isSessionKeyFromParamsValid = sessionKeyFromParams != null && sessionKey.equals(sessionKeyFromParams[0]);
+
+ switch (apiSessionKeyCheckLocations) {
+ case CookieOrParameter:
+ return (sessionKeyFromCookie != null || sessionKeyFromParams != null)
+ && (sessionKeyFromCookie == null || isSessionKeyFromCookieValid)
+ && (sessionKeyFromParams == null || isSessionKeyFromParamsValid);
+ case ParameterOnly:
+ return sessionKeyFromParams != null && isSessionKeyFromParamsValid
+ && (sessionKeyFromCookie == null || isSessionKeyFromCookieValid);
+ case CookieAndParameter:
+ default:
+ return sessionKeyFromCookie != null && isSessionKeyFromCookieValid
+ && sessionKeyFromParams != null && isSessionKeyFromParamsValid;
}
- return true;
}
}
diff --git a/utils/src/test/java/com/cloud/utils/HttpUtilsTest.java b/utils/src/test/java/com/cloud/utils/HttpUtilsTest.java
index e10a5a36b27..9047934c75c 100644
--- a/utils/src/test/java/com/cloud/utils/HttpUtilsTest.java
+++ b/utils/src/test/java/com/cloud/utils/HttpUtilsTest.java
@@ -60,35 +60,97 @@ public class HttpUtilsTest {
final String sessionKeyValue = "randomUniqueSessionID";
// session and sessionKeyString null test
- assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString));
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
sessionKeyString = "sessionkey";
- assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString));
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
// param and cookie null test
session = new MockHttpSession();
+ final String sessionId = session.getId();
session.setAttribute(sessionKeyString, sessionKeyValue);
- assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString));
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
- // param null, cookies not null test
+ // param null, cookies not null test (JSESSIONID is null)
params = null;
cookies = new Cookie[]{new Cookie(sessionKeyString, sessionKeyValue)};
- assertFalse(HttpUtils.validateSessionKey(session, params, cookies, "randomString"));
- assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString));
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, "randomString", HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
+ assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
+
+ // param null, cookies not null test (JSESSIONID is not null and matches)
+ cookies = new Cookie[2];
+ cookies[0] = new Cookie(sessionKeyString, sessionKeyValue);
+ cookies[1] = new Cookie("JSESSIONID", sessionId + ".node0");
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, "randomString", HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
+
+ // param null, cookies not null test (JSESSIONID is not null but mismatches)
+ cookies = new Cookie[2];
+ cookies[0] = new Cookie(sessionKeyString, sessionKeyValue);
+ cookies[1] = new Cookie("JSESSIONID", "node0xxxxxxxxxxxxx.node0");
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, "randomString", HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
// param not null, cookies null test
params = new HashMap();
params.put(sessionKeyString, new String[]{"randomString"});
cookies = null;
- assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString));
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
params.put(sessionKeyString, new String[]{sessionKeyValue});
- assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString));
+ assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
- // both param and cookies not null test
+ // both param and cookies not null test (JSESSIONID is null)
params = new HashMap();
- cookies = new Cookie[]{new Cookie(sessionKeyString, sessionKeyValue)};
+ cookies = new Cookie[2];
+ cookies[0] = new Cookie(sessionKeyString, sessionKeyValue);
params.put(sessionKeyString, new String[]{"incorrectValue"});
- assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString));
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
params.put(sessionKeyString, new String[]{sessionKeyValue});
- assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString));
+ assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
+
+ // both param and cookies not null test (JSESSIONID is not null but mismatches)
+ params = new HashMap();
+ cookies = new Cookie[2];
+ cookies[0] = new Cookie(sessionKeyString, sessionKeyValue);
+ cookies[1] = new Cookie("JSESSIONID", "node0xxxxxxxxxxxxx.node0");
+ params.put(sessionKeyString, new String[]{"incorrectValue"});
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
+ params.put(sessionKeyString, new String[]{sessionKeyValue});
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
+
+ // both param and cookies not null test (JSESSIONID is not null amd matches)
+ params = new HashMap();
+ cookies = new Cookie[2];
+ cookies[0] = new Cookie(sessionKeyString, sessionKeyValue);
+ cookies[1] = new Cookie("JSESSIONID", sessionId + ".node0");
+ params.put(sessionKeyString, new String[]{"incorrectValue"});
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
+ params.put(sessionKeyString, new String[]{sessionKeyValue});
+ assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
+
+ // param not null, cookies null test (JSESSIONID is not null amd matches)
+ params = new HashMap();
+ cookies = new Cookie[1];
+ cookies[0] = new Cookie("JSESSIONID", sessionId + ".node0");
+ params.put(sessionKeyString, new String[]{"incorrectValue"});
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.ParameterOnly));
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieAndParameter));
+ params.put(sessionKeyString, new String[]{sessionKeyValue});
+ assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.ParameterOnly));
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieAndParameter));
+
+ // param not null (correct), cookies not null test (correct)
+ cookies = new Cookie[2];
+ cookies[0] = new Cookie(sessionKeyString, sessionKeyValue);
+ cookies[1] = new Cookie("JSESSIONID", sessionId + ".node0");
+ assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
+ assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.ParameterOnly));
+ assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieAndParameter));
+
+ // param not null (correct), cookies not null test (wrong)
+ cookies = new Cookie[2];
+ cookies[0] = new Cookie(sessionKeyString, "incorrectValue");
+ cookies[1] = new Cookie("JSESSIONID", sessionId + ".node0");
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.ParameterOnly));
+ assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieAndParameter));
}
}
diff --git a/vmware-base/pom.xml b/vmware-base/pom.xml
index 21cd9cad6b0..dc17f15a0e1 100644
--- a/vmware-base/pom.xml
+++ b/vmware-base/pom.xml
@@ -24,7 +24,7 @@
org.apache.cloudstack
cloudstack
- 4.20.0.0-SNAPSHOT
+ 4.20.0.0